기타 지식

C++) 포인터를 알아보자.

주의) 이건 초보자 강좌가 아닙니다. C / C++의 함수 부분까지 이해한 사람이 읽기를 추천드립니다.

 

안녕 개붕이들아

오늘은 C++ 기초중에 가장 같은걸로 유명한걸 알아보자 ㅎㅎ

(참고로 C에서도 같은 원리이기 때문에 포인터가 어려우면 읽어보는걸 추천해)

 

바로 포인터야.

영어로는 Pointer 라고 하는데

2021-02-09 23_20_12.png

사전에 있는것처럼 무언가를 가리키는걸 뜻해.

근데 뭘 가리키는걸까..?

 

바로 변수의 주소야.

주소가 뭔 소리냐고?

 

이 변수는 메모리 (RAM) 라는 공간에 저장돼.

이 메모리 공간에는 각각 번호가 붙어있고,

이 번호가 바로 변수의 주소값이야.

 

사진으로 쉽게 설명해보자.

2021-02-09 23_42_23.png

이게 우리의 램 공간이야.

여기에 int age = 34;

라는 명령어가 실행되면 무슨 일이 일어날까?

 

컴퓨터는 여기서, 자동으로 램에 빈 공간을 찾아.

그 다음에 그 빈 공간에다가 34라는 값을 저장하는 거지.

2021-02-09 23_51_12.png

봐바!

우리의 똑똑한 친구 컴퓨터가 0x01 ~ 0x04에 34라는 값을 저장했어!

age = 53; 같은 명령을 실행시켜주면 저 34라는 값이 53이라는 값으로 바뀌는거야!

(여기서 age 변수가 메모리 공간을 4개나 차지한 이유는, int 자료형의 크기가 4바이트여서 그래.)

 

그럼 포인터는 뭘까?

포인터 변수는 바로 주소값을 저장할 수 있는 변수야.

일단 예시로 한번 알아보자.

int* pointer = &age;

일반적인 변수 선언같았는데, 자료형 뒤에 별이 붙어있지?

이렇게 별을 자료형 뒤에 붙이고 변수 이름을 적어주면 포인터 변수가 생성돼.

즉,

가리키고_싶은_자료형* 변수이름;

형식이야.

 

그럼 이 변수에 넣고있는 값인 &age는 뭘까?

&는 레퍼런스 라고 불러.

 

2021-02-10 00_03_00.png

사전에서 말하는 것 처럼, 참조라는 뜻이야.

근데 참조한다는게 뭔 소리냐고?

 

정말 간단해.

레퍼런스(&) 기호를 변수 이름 앞에 붙이면 그 변수의 주소값을 알려주는거야.

예를 들어서 std::cout << &age << std::endl; 이라는 명령어를 실행하면,

age의 주소값인 0x01 이 출력되겠지.

std::cout << age << std::endl; 을 했을 때 34라는 age 변수에 저장된 값이 출력되는거랑은 다르게 출력되는게 보이지..?

 

그럼 이 포인터 변수는 메모리에 어떻게 저장되는걸까?

int *pointer = &age; 를 실행 했을때의 메모리 상태를 한번 보자.

2021-02-10 00_01_25.png

봐바!!

우리의 메모리 공간에 새로운 변수가 생겼어.

0x05 ~ 0x08 위치에 새로운 값이 들어갔네!

포인터 변수는 바로 특정 변수의 주소값을 저장하고 있는 변수라는거지.

 

그럼 이 포인터를 어따가 쓰는걸까?

한번 응용해볼게.

 

int age = 65;

int* p = &age;

 

std::cout << p << std::endl;

std::cout << *p << std::endl;

 

어라? 마지막 std::cout 명령어에서 출력하는 변수가 이상하지 않아?

포인터 변수 이름 앞에 * 을 붙여놨잖아?!

 

일단 출력해보자.

2021-02-10 00_20_20.png

????

std::cout << p << std::endl; 에서는 012FFB84 라는 값이 출력되고,

std::cout << *p << std::endl; 에서는 65라는 값이 출력됐네??

 

아하, 즉 포인터 변수인 p를 그대로 출력하면 포인터 변수가 가리키고 있는 주소가 출력되고,

포인터 변수인 p 앞에 별 (*) 을 붙인 상태로 출력하면 포인터 변수가 가리키고 있는 주소에 있는 변수의 값이 나오는구나!

 

그럼 실험을 조금 해보자!

 

int age = 65;

int* p = &age;

 

std::cout << "age : " << age << std::endl;

std::cout << "p : " << *p << std::endl;

 

age = 34;

 

std::cout << "age : " << age << std::endl;

std::cout << "p : " << *p << std::endl;

 

처음 age 변수에 65라는 값을 넣어주고,

age 와 *p 의 값을 각각 출력해준 다음,

age 변수에 34라는 값을 넣어주고,

다시 age 와 *p 의 값을 출력하는 코드야.

실행해보면...

2021-02-10 00_28_00.png

우와!

age 의 값이 변함과 동시에 *p 의 값도 변했어!

왜냐고? p 는 포인터 변수고, 이 p는 age의 위치를 가리키고 있거든,

즉 age 의 값이 아닌 위치를 가리키고 있기 때문에, age가 변하면 *p 의 값도 변하는거야!

 

그럼 또 다른 실험을 해보자!

 

int age = 65;

int* p = &age;

 

std::cout << "age : " << age << std::endl;

std::cout << "p : " << *p << std::endl;

 

*p  = 34;

 

std::cout << "age : " << age << std::endl;

std::cout << "p : " << *p << std::endl;

 

이렇게 하면 어떻게 될까??

이번에는 age 의 값을 바꾼게 아니라, *p 의 값을 바꿔봤어,

한번 보자.

 

2021-02-10 00_30_39.png

오!! 이번에도 값이 변했어!

여기서 알 수 있는건 바로,

*p = 34; 는 즉, p가 가리키고 있는 메모리 주소에 있는 값을 바꾸는거지!

그러기 때문에 age 랑 *p 랑 같은 값이 나오는거고!

 

근데 이걸 어디에 써먹냐고?

엄청 좋은 예시로 함수가 있어.

 

주의) 이 예시는 조금 어려우니 이해가 안되면 그냥 건너뛰고 그 밑에 있는 예시를 읽어보세요.

예를 들어서 "23:37:54" 라는 문자열을 시간, , 로 잘라서 변수 3개에 넣는 함수를 만들어보자.

 

void cutTime(std::string time, int* hour, int* minute, int* second) {

    *hour = std::stoi(time.substr(0, 2));

    *minute = std::stoi(time.substr(3, 2));

    *second = std::stoi(time.substr(6, 2));

}

 

어라 오류뜬다고?

당연하지! std::stoi 함수는 iostream 에 없거든!

#include <string>#include <iostream> 아래에 적어주자!

 

여기서 알아갈게 조금 있는데,

time.substr() 은 std::string 변수에 기본적으로 있는 기능이야.

.substr(위치, 크기);

형식으로 사용하고, 문자열의 위치 위치에 크기 만큼 문자열을 잘라내는 기능을 해.

그래서 substr(0, 2) 해준거지 (0위치에 2길이의 문자열을 잘라서 return)

 

어쨌든, 이걸 실행해보자.

 

int main(int argc, char* argv[]) {

    int hour;
    int minute;
    int second;

 

    cutTime("23:37:54", &hour, &minute, &second);

 

    std::cout << hour << std::endl;
    std::cout << minute << std::endl;
    std::cout << second << std::endl;

 

    return 0;

}

함수를 위에 선언해줬으니, 저렇게 main 문에 적어주면 실행되겠지?

각 변수들에 무슨 값이 들어갔는지도 알아야하니깐, 마지막에 저렇게 출력문도 적어보자.

 

이 상태로 실행하면?!

2021-02-10 00_52_36.png

오오 23:37:54 라는 문자열이 23, 37, 54 라는 각각의 숫자로 나뉘어서 hour, minute, second 변수에 각각 들어갔어!

 

근데 뭔가 예시가 어려우니 좀 더 쉬운 예시를 들고와볼게.

 

이번에는 함수에 값이 들어가있는 int 변수를 넣으면 그 변수가 두배가 되도록 해보고 싶어.

해보자.

 

void doubleInt(int* num) {

    *num = *num * 2;

 

이제 main 문에

 

int a = 34;

doubleInt(&a);

std::cout << a << std::endl;

 

넣고 실행해보면...

2021-02-10 00_56_52.png

34의 두배인 68이 변수 a에 저장되어서 나왔어!

어떤식으로 작동된건지 뜯어보자!

 

int a = 34; <- 여기서 a 라는 변수를 만들고 34라는 값을 넣어줬어.

doubleInt(&a); <- 이제 doubleInt 라는 함수를 실행 해주는거야, doubleInt 함수는 int 형 포인터 변수를 필요로 하니깐 a의 주소값을 보내줬어.

 

void doubleInt(int* num) { <- doubleNum 함수의 포인터 변수인 num 에 a의 주소값이 도착했어!

    *num = *num * 2; <- 이 주소값이 가리키고 있는 변수(a) 의 값을 2 곱해서 넣어줘.

 

std::cout << a << std::endl; <- 이제 출력이야!

 

어때..? 이해 좀 됐어..?

나도 포인터라는 개념이 이해도 잘 안되고 어따 써먹는지도 영 모르겠어서 익히기가 엄청 어려웠었는데,

이거라도 읽고 좀 이해했으면 좋겠다.

 

궁금한 점이나 어려운점, 수정 바라는 부분이나 오류 있는 부분은 댓글로 달아줘!

읽어줘서 고마워

104개의 댓글

2021.02.10

이게 아마 내 프로그래밍 시리즈중 마지막이 되지 않을까...?

0
@쿄코

재밌네 좋네 유익하네 잘가르치네 고마워 덕분에 몰랐던걸 좀 더 이해하고 감 ㅇㅇ

0
2021.02.10

ㅊㅊ

0
2021.02.10

정성 ㅊㅊ

포인터 활용은 linked list 예제 어때?

0
2021.02.10
@숲속을샅샅히

linked list는 구조체 개념까지 나가야돼서.. C++ 은 예제 짜기가 상당히 까다롭더라..

0
2021.02.10
@쿄코

그럼 포인터 활용은 함수 인자 전달 방식 중 call by value와 call by reference로 인한 설명도 추가해줘

0
2021.02.10
@숲속을샅샅히

그것들도 설명하고 싶었는데 call by reference는 나도 가끔 햇갈려서 공부 더하고 오겠음 ㅇㅇ

0
2021.02.10
@쿄코
0
2021.02.10

[이미 뇌가 오버플로우 해버린 댓글입니다.]

0
2021.02.10
@무조건항복

뇌가 승희해버렸구나

0
2021.02.10

잘 정리해서 ㅊㅊ

0
2021.02.10
@Istari

간단한 예제로 배열에 포인터 접근 정도 추가하면 좋을 것 같아!

0
2021.02.10

포인터에서 한번 벽느끼지 않나? 나만 그랬나 ㅜ

0
2021.02.10
@3060ti

프로그래밍에서 벽은 꽤 많더라..

 

첫번째 난관 - 반복문

두번째 난관 - 포인터

세번째 난관 - 파일입출력

네번째 난관 - 클래스

다섯번째 난관 - 템플릿

 

내가 지금 다섯번째에 있어서 그 다음은 모르겠다..

템플릿은 아직도 어따 써먹을지 감도 안옴..

0
2021.02.10
@쿄코

반복문에서 난관 겪는 애들은 프로그래머로서의 재능이 없으니 하루라도 빨리 포기하길 추천.

 

컴공 나왔는데 그거 이해 못 한 애들은 90%의 확률로 다른 일 한다.

0
2021.02.10
@3060ti

포인터에서한번 링크드리스트에서한번..

이게 벽 수준이구 이 너머로 그냥 산이었음..

0
2021.02.10

포인터는 처음엔 어려운데 한번 배우면 메모리 주소를 직접 참조가능하다는게 갠적으로 너무 편리함

0
2021.02.10
@저장함보기

솔직히 포인터 없는게 프로그래밍 언어냐 ㅋㅋㅋㅋㅋ

JAVA : ?????

0
2021.02.10
@쿄코

하지만 까보면 다 포인터 ㅋㅋ

0
2021.02.10

고맙다 개붕아

이 글 읽고 덕분에 구글입사했다

0
2021.02.10

사실 포인터는 로우레벨쪽 다룰때 더 확 와닿지 예를 들자면 DWORD *Hpet = (DWORD*)0xFED00000; 뭐 이런거 말이지... 내가 로우레벨쪽으로 밥벌어먹고 살아서 그런지 그냥 메모리 맵에 매핑되는 기분으로 본다.

0
2021.02.10
@콘치즈콘

그거 윈도우에서는 꽤나 위험한 짓이야..이미 다른 프로그램이 그 주소 사용중이라면... 으..

0
2021.02.10
@쿄코

나는 OS보다 위에 군림하는 코드를 만지는 쪽이라서 ㅎㅎ 그리고 저 주소는 일반 프로그램이 손댈일이 없다. High Precision Event Timer base address 거든..

0
2021.02.10
@콘치즈콘
0
2021.02.10
@쿄코
0
2021.02.10
@쿄코

사실 윈도우는 보호모드를 사용하기 때문에 단순 주소지정으로 다른 프로그램이 사용중인 주소에 바로 접근할 수 없음. 그냥 접근하려고 한 주소가 할당되어 있지 않으면 지가 segment fault로 죽을 뿐...

0
2021.02.10
@콘치즈콘

어셈 코딩하는 개붕이야?

0
2021.02.10
@망했떼

어셈도 가끔 쓴다 ㅇㅇ

0
2021.02.10

컴공 뉴비라 강의 듣고 나서 관련 교수들 잡고 계속 질문해도 못 알아들어서 그냥 유야무야 넘겼었는데 가르치는게 우리 학교 교수진들보다 낫네 ㅋㅋ

0
2021.02.10
@안나콤니니

야호 개붕이 교수된다

1
2021.02.10

가긴 어딜가

이제 좌측값 우측값 유니버설 레퍼런스 설명해야지

0
2021.02.10
@멍청이

으앙

a = b;

에서 a 가 좌측값, b가 우측값 (?)

0
2021.02.10
@쿄코

b가 변수라면 b도 좌측값이지

어서 거지같은 c++의 깊고 어두운곳으로 개붕이들을 인도하란말이야

0
2021.02.10
@멍청이

그렇게 원한다면야...

arr[10]은 10[arr] 이랑 같음

0
2021.02.10
@쿄코

[ ]연산자는 *(x+y)니까 당연히 같겠지

0
2021.02.10
@멍청이

x = ( a > b ) ? 5 : 8;

이거 알지?

이거 lValue로도 사용 가능함 ㅋ

(x == 0 ? a : b ) = 1;

0
2021.02.10
@쿄코

어허 이놈 은근슬쩍 나한테 요상망측한거 가르치려들지 말고

얼른 우측값 레퍼런스를 주제로 다음강의를 준비하란말이야

0
2021.02.10
@멍청이

(๑˘・з・˘) 더 괴상한것도 많은데..

sizeof num; 이라 써도 오류가 안난다던지

void함수도 return; 이 가능하다던지

 

0
2021.02.10
@쿄코

void aaa(char *a, char *b) { while (*a++ = *b++) ; } 라고 써도 문제없이 돌아간다던지?

근데 그런건 별 상관없는데, 굳이 우측값 레퍼런스 아니더라도 포인터 다음에 배열 강좌정도 더 써보는게 어떰

0
2021.02.10
@멍청이

C++ 하면서 배열 쓴 적이 거의 없어가지고.. vector만 써서..

배열도 나쁘진 않은데 다음번에 쓰게 된다면 동적할당으로 해볼까 생각중이야

0
2021.02.10
@쿄코

그리고 new delete 강의하면서 스마트포인터까지 강의하게되는것이지

아주좋다

0
2021.02.10
@멍청이

아 스마트 포인터 잘 안써서 잘 설명할 자신 없는데...

나도 공부 많이 해야겠다...

0
2021.02.10
@멍청이

C++ 코드에 http:// 로 시작하는 사이트 주소를 넣어도 오류가 안뜸

0
2021.02.10
@멍청이

형 대학원생이야?

0
2021.02.10
@망했떼

떽 그런말하면 못써요

0
2021.02.10
@멍청이

gcc랑 gpp 차이점도 알려줘

왜 gpp로 c언어 컴파일이 되는거야

0
2021.02.10
@망했떼

c++이 c언어 슈퍼셋이라 그런거 아님? 컴파일러는 잘 몰라

0
2021.02.10
@멍청이

맞아

0
2021.02.10

형냐 이제 시간복잡도도 간단하게 설명해줘

피보나치를 예로 드는거야

0
2021.02.10
@망했떼

미안 시간 복잡도는 나도 도저히 이해가 안돼

어쩐지 나가는 코테마다 시간 초과 뜨더니만은...

0
무분별한 사용은 차단될 수 있습니다.
번호 제목 글쓴이 추천 수 날짜
5248 [기타 지식] 페미니즘은 여성에게 도움이 되었는가 01 17 키룰루 22 1 일 전
5247 [기타 지식] 아무리 만들어봐도 맛이 없는 칵테일, 브롱스편 - 바텐더 개... 3 지나가는김개붕 2 7 일 전
5246 [기타 지식] 일본에 의해서 만들어진 칵테일들 편 - 바텐더 개붕이의 술 ... 2 지나가는김개붕 6 8 일 전
5245 [기타 지식] 중국에서 안드로이드 폰을 사면 안되는 이유? 10 대한민국이탈리아 24 9 일 전
5244 [기타 지식] 최근 지각변동이 일어나는 국내 항공업계 (수정판) 15 K1A1 23 12 일 전
5243 [기타 지식] 도카이촌 방사능 누출사고 실제 영상 21 ASI 2 16 일 전
5242 [기타 지식] 웹툰 나이트런의 세계관 및 설정 - 지구 2부 21 Mtrap 8 16 일 전
5241 [기타 지식] 100년을 시간을 넘어서 유행한 칵테일, 사제락편 - 바텐더 개... 5 지나가는김개붕 1 19 일 전
5240 [기타 지식] 오이...좋아하세요? 오이 칵테일 아이리쉬 메이드편 - 바텐더... 3 지나가는김개붕 2 20 일 전
5239 [기타 지식] 웹툰 나이트런의 세계관 및 설정 - 지구 1부 31 Mtrap 13 20 일 전
5238 [기타 지식] 칵테일의 근본, 올드 패션드편 - 바텐더 개붕이의 술 이야기 15 지나가는김개붕 14 21 일 전
5237 [기타 지식] 웹툰 나이트런의 세계관 및 설정 - 인류 2부 22 Mtrap 14 20 일 전
5236 [기타 지식] 웹툰 나이트런의 세계관 및 설정 - 인류 1부 13 Mtrap 20 21 일 전
5235 [기타 지식] 서부 개척시대에 만들어진 칵테일, 카우보이 그리고 프레리 ... 3 지나가는김개붕 6 26 일 전
5234 [기타 지식] 모던 클래식의 현재를 제시한 칵테일편 - 바텐더 개붕이의 술... 4 지나가는김개붕 2 26 일 전
5233 [기타 지식] 브라질에서 이 칵테일을 다른 술로 만들면 불법이다, 카이피... 5 지나가는김개붕 1 28 일 전
5232 [기타 지식] 럼, 라임, 설탕 그리고 다이키리 편 - 바텐더 개붕이의 술 이... 2 지나가는김개붕 6 29 일 전
5231 [기타 지식] 1999년 도카이촌 방사능누출사고 대량 방사능 피폭 피해자들 ... 9 ASI 5 29 일 전
5230 [기타 지식] 진짜 레시피는 아무도 모르는 칵테일 싱가포르 슬링편 - 바텐... 3 지나가는김개붕 2 29 일 전
5229 [기타 지식] 통계로 보는 연애 상황에서 외모의 중요성 8 개드립에서가장긴... 11 2024.04.04