양주종 강사님의 하단의 유뷰트 영상을 보면서 필기한 글임을 미리 알려드립니다.
https://www.youtube.com/watch?v=LtmJm068muw&list=PLlDAu2fzBjC6HjVmhYVlSMYSk4NAJiMnc&index=20
c포인터 강의를 들으면서 필기를 하고 있는데
후반부에 정신을 차리고 보니 소설을 쓰면서 필기하고 있는 나 자신을 발견했다.
천생 문과생이 이과 과목 공부하면 이런 일도 생기는 거 같다.
도대체 어떻게 필기를 소설로 바꿀 수 있는지 궁금하다면
맨 하단을 보면 답이 나온다. 필기를 이런 식으로 할 수도 있다는 걸 나도 이번에 처음 알았다.
이렇게 소설 써서 올리면 분명 나중에 흑역사라면서 후회할 거 같기도 한데
C 포인터 개념이 어려우신 분들께 조금이나마 도움이 되었으면 해서 그냥 올려본다.
이 글은 포인터의 기초적인 개념이 무엇인지 설명하는 글이다.
한 번에 이해가 가지 않을 수 있다. 그게 원래 맞다.
포인터 개념 자체가 너무 어렵기로 유명하니 말이다.
나도 강의를 3번 돌려보고 나서야 이해했다.
그러니 처음에 포인터 내용을 보고 바로 이해가 가지 않았다고 해서
너무 좌절하거나 실망하진 않았으면 한다.
바로 이해가 안 간다면 '아. 난 보통 사람'이구나 하면 되는 거고
바로 이해가 간다면, '아, 난 천재구나'하면 된다.
1. 포인터 정의
point는 무언가를 지목한다는 의미다.
포인터(pointer)도 마찬가지다. 무언가를 지목할 때 쓰인다.
그렇다면 뭘 지목하는 걸까? 바로 주소다. 주소를 저장하는 변수가 바로 포인터다.
지금 이게 무슨 소리인가 싶을 거다.
하단의 추가적인 설명으로 넘어가보자.
미리 언급하자면 설명이 조금 길고, 왜 지금 이걸 설명하는 건지 싶을 거다.
그냥 한 번 읽어주면 왜 이렇게 길게 쓰는지 이해할 수 있다.
일단은 책을 가볍게 훑는다는 느낌으로 눈으로 읽어보길 추천한다.
2. 포인터 설명
int a = 20;
int* p =&a;
/*
a= 20
&a = 100번지
p = 100 번지
&p = 130번지
*p = 20
*/
첫 번째. int a = 20;
위에 작성된 코드를 보면 맨 첫 번째 줄에 int a =20; 이 보인다.
a라는 그릇에 20이라는 숫자가 담겨있다는 뜻이다.
int는 정수형을 뜻한다.
정수는 0과 양수(+1, +2, +3), 음수(-1, -2, -10)를 포함한 숫자를 의미한다.
20은, +20이기도 하다. 즉 20은 양수고
위에서 '정수 = 양수+음수+ 0'이라고 했으므로
20은 양수임과 동시에 정수이기도 하다.
int는 integer의 약자로 integer를 해석하면 정수다.
고로 20은 정수 즉 int가 맞다.
만약 int a = 24.5 처럼 실수를 넣으면 안된다.
int는 정수만 담을 수 있는 그릇이라 실수는 담지 못한다.
아이스크림은 냉장고에 넣어둬어야지 햇 빛 잘 드는 베란다에 넣어두면 안되는 것처럼.
두 번째 &
int a = 20; 아래를 보면
int* p =&a;가 있다.
a에 &이 붙었다. &는 주소를 뜻한다.
즉 &a는 a라는 그릇이 정확히 어디있는지, 그 주소를 가리킨다.
만약 a에 &이가 붙어있지 않았다면 a는 그냥 20이었을 것이다.
그런데 a 앞에 &가 붙음으로서 a의 값이 아닌 a가 위치한 장소를 나타낸다.
a가 만약에 100번지에 살고 있다고 한다면
&a = 100; 이 되는 거다.
정리하자면 이렇다.
a= 20;
&a =100; <a가 위치한 주소. a는 100번지에 산다고 한다.
예시를 들어보자.
엄마가 나한테 씨리얼을 먹고 그릇을 어디에 뒀냐고 물었을 때
나는 내 방 책상 위에 뒀다고 말했다.
여기서 씨리얼 그릇이 a가 되고,
20이란 숫자는 씨리얼에 비유할 수 있으며
씨리얼 그릇이 있었던 장소인 내 방 책상은 &a가 된다.
세 번째 int* p =&a;
* 라고 못보던 녀석이 보인다.
* 아이의 이름은 '간접참조연산자'다.
이름이 참 어려운데 간접참조연산자를 비유를 통해 풀어서 쓰자면
'나는 가리키기만 했을 뿐인데, 값이 바껴버렸어.'
이다. 아직 잘 와닿지 않을 것이다. 아래 예시를 봐보자.
int a = 10;
int a = 10;은 a에 10이란 값을 넣어라!라는 걸 나타내는 것인데
a에 값을 담을 때 다르게 표현할 수도 있다.
*&a = 10;
이것 또한 a에 10을 넣어라! 라고 표현한 것이 된다.
&a는 a의 주소를 뜻한다고 했었다.
&a에 *가 붙으면 즉 *&a가 되면
'저는 지금 a의 주소(100번지)를 가리키고 있어요.
즉 a가 살고 있는 집의 주소를 알아낸 건데요,
a의 주소를 알아내서 a의 집으로 들어갔고,
a의 집에 있던 값을 이제 제 맘대로 바꿀 수 있어요.'가 된다.
*&a = 10;
을 정리해보자면
*&a는 a의 주소 100번지를 가리키고 있고,
a의 값을 마음대로 바꾸겠다고 선언한 것이다.
뭐로 바꾸겠냐고 물어봤더니
*&a 뒤에 =10;이 보인다.
즉 a의 값을 10으로 바꾸겠다고 한다.
근데 예초에 int a = 10;이였기 때문에 바꿨다고 하기도 뭐하지만 아무튼 그렇다.
여기서 깜짝 퀴즈 하나를 내보겠다.
*&a = 10 이었었다.
그렇다면
*&a + 10은 뭐가 될까?
정답은
*&a + 10 = 20이 된다.
간접참조연산자 *를 설명하느라 딴 길로 가버렸는데
이제 다시 본론으로 돌아가보자.
int a = 20;
int* p =&a;
/*
a= 20
&a = 100번지
p = 100 번지
&p = 130번지
*p = 20
*/
위에서 int a = 20; 이 있었다.
여기서 int는 숫자(20)만 담는 그릇이었다면
int* p는 a라는 그릇의 주소(100번지)만 담는 것이다.
int* p= &a을 해석해보자면
a가 살고있는 곳의 주소를 p라는 그릇에 담아라고 말하는 거다.
a가 살고 있는 곳의 주소가 100(번지)라고 임의로 저장해뒀을 때
그럼 int* p = &a; 에서 p라는 그릇(변수)에는 100이 담길 것이다.
네 번째 &p
&p는 p의 주소를 물어보는 거다.
a의 주소는 100이라고 임의로 지정해뒀었다.
p의 주소는 130이라고 임의로 지정하겠다.
그럼 &p = 130이 된다.
다섯 번째 *p
위의 코드블럭을 보면 *p = 20이 있다.
여기서 *p는 뭘까? 위에서 int* p =&a;를 봤었다.
p는 여기서 a의 주소를 담고 있다고 이야기했었다.
즉 p가 가지고 있는 건 진짜 데이터가 아니라, 데이터의 번지수(주소)다.
즉 p는 씨리얼을 가지고 있는 게 아니라 씨리얼 그릇이 놓인 장소가 적힌 주소종이만 가지고 있는 거다.
* 소설 시작 *
p는 씨리얼 그릇이 놓인 장소(주소)가 적힌 종이가 아닌 씨리얼(a가 가지고 있는 거)을 가지고 싶다.
하다못해 a가 가지고 있는 씨리얼을 공유해서 먹고 싶었다.
그래서 열심히 운동을 한다. 씨리얼을 찾으라 가는 길이 험난할 거 같아서 운동을 한거다.
그렇게 p는 *p로 각성했다.
운동을 열심히 한 *p는 본인이 가지고 있는 &a(a의 주소가 적힌 종이다. 100번지라고 적혀 있었다.)를 가지고
100번지에 찾아간다.
똑똑
a(씨리얼 그릇): 누구세요?
p: a씨네 집(100번지) 맞죠? 저는 p라고 해요. a씨가 가지고 있는 걸 가지러 왔어요.
a(씨리얼 그릇): 제가 가지고 있는 거요?
전 가지고 있는 게 씨리얼(20) 밖에 없어요.
이유> int a = 20; 을 통해서 a라는 그릇에 20을 넣어줬기 때문에 a는 20을 가지고 있다.
p: 그 씨리얼(20)이 바로 제가 가지고 싶었던 거에요.
a는 황당함에 입을 다물지 못했다.
갑자기 남의 집에 찾아온 것도 모자라
본인이 유일하게 가지고 있는 씨리얼(20)을 주라고 요구받는 입장에 처했으니 그럴 만도 했다.
p: 저한테 주는 게 내키지 않으신다면 씨리얼(20)을 공유해 주세요.
a는 어서 빨리 이 *p라는 아이와 떨어지고 싶어서 알겠다고 했다.
그리해서 *p는 씨리얼(20)을 a와 공유할 수 있게 됐다.
그런데 여기서 문제가 발생했는데, 바로 *p가 가지고 있는 너무 강한 특징이 문제였었다.
포인터 변수 *p의 특징
1) 포인터 변수가 가리키고 있는 곳의 값을 바꿀 수 있다.
열심히 운동해서 *p는 씨리얼(20)을 a와 공유하게 됐지만 *p는 씨리얼(20)이 금방 질려버렸다. 그래서 씨리얼(20)을 버리고, 초코파이(30)을 데려왔다.
이제 *p는 *p = 20;이 아니었다.
* p = 30; 이 된 것이다.
이렇게 되면 a한테 변화가 생긴다.
a는 원래 씨리얼(20)을 가지고 있었는데 a가 가지고 있던 게 씨리얼(20)에서 초코파이(30)으로 변하면서 덩달아 a도 씨리얼(20)을 버리고 초코파이(30)를 가지고 있는 것으로 변해버린다.
어째서냐고 묻는다면 *p라는 포인터 변수의 기능 중에 본인이 가리키고 있는 곳의 값을 변화시킬 수 있는 능력이 있기 때문이다. *p는 a를 가리키고 있고, a는 20이란 값을 가지고 있었다. 즉 20이란 값을 *p는 변화시킬 수 있는 능력을 가지고 있는 것이다.
a 입장에선 황당할지도 모른다. 본인이 가지고 있는 씨리얼(20)을 공유해줬을 뿐인데 갑자기 *p가 씨리얼(20)을 버리고 초코파이(30)을 택했다는 이유 하나만으로 본인의 의사와는 상관없이
int a =20;
에서
int a = 30;
으로 변해야 했으니 말이다.
'BOX-IT > C++' 카테고리의 다른 글
[C++] ‘strcpy’ was not declared in this scope 해결방법 (0) | 2022.04.11 |
---|---|
C언어에서 '100< X <200' 은 잘못된 표현이다. (0) | 2022.04.10 |
[C++] #include <stdio.h>는 뭐고, 왜 쓰는 걸까? (8) | 2022.04.04 |
[C++] Scanf 함수의 정의와 사용 방법 (0) | 2022.03.27 |
[C++] 컴파일, 컴파일러, 바이트코드(바이너리코드)는 무슨 뜻일까? (0) | 2022.03.01 |