티스토리 뷰


 본 강좌는 아래 동영상 강좌와 같이 진행됩니다. 되도록이면 동영상과 같이 보시는 것을 추천합니다.

 

유튜브 채널 가기

 

강좌 13편 동영상 보기

 


 

 이번시간에는 메모리의 주소를 다루는 포인터에 대해 알아보도록 하겠습니다..

 

 

 

 1. 메모리 주소

 

 포인터를 알아보기에 앞서, 우리가 지금까지 사용한 변수들은 어떤 식으로 메모리에 저장이 되는가에 대해 알아보도록 하겠습니다. 다음과 같은 변수가 있다고 합시다.

 

int a = 1; 

 

 int형 a라는 변수를 1로 초기값을 주었습니다. 이것이 메모리에 저장될때는 현재 사용 가능한 메모리 공간의 특정 '주소'에 int형의 크기인 4바이트 만큼 윈도우, 리눅스 등 해당 운영체제에서 공간을 할당받고, 여기에 '값'인 1을 저장하게 됩니다.

  


 그림을 그려보면 이런 식입니다. 각각 바이트단위로 주소가 정해져 있고, 연결된 다음 주소는 1씩 증가하여 부여됩니다. char형으로 하나만 더 예를 들어 보겠습니다.

 

char str[5] = "abc";

 

 이렇게 선언된 변수는 메모리에 다음과 같이 저장됩니다.

 


 char형은 1바이트만큼의 크기를 가지므로 5개만큼의 배열은 5바이트만큼의 크기를 할당받습니다. 여기에 차례대로 'a', 'b', 'c' 가 들어가게 되는 것입니다. (나머지 두 바이트만큼은 지난번 배열을 알아볼때 이야기했던 것처럼 널문자가 들어가게 됩니다.)

 

 위의 예에서 0x01, 0x02 같은 주소값을 흔히 '번지'라고도 합니다. 우리가 살고 있는 집에도 번지수가 있는데, 이와 같은 맥락이라 보시면 되겠습니다.

 

 요약하자면 변수 (상수 등 프로그램에서 사용하는 대부분의 것들도 마찬가지입니다.) 는 메모리의 일정 위치를 운영체제로부터 자신의 크기만큼 할당을 받고, 여기에 값을 저장하여 사용한다는 것입니다. 그리고 메모리는 각각 바이트 단위로 주소가 있고, 바이트가 증가할때마다 1씩 커진다는 것입니다.

 

 위의 예에서 0x01, 0x02 같이 써놓은건 그냥 예일 뿐입니다. 실제로는 32비트 운영체제의 경우 32비트 만큼의 주소를 가지고, 64비트 운영체제의 경우 64비트 만큼의 주소를 가지게 됩니다. (64비트 운영체제에서 32비트 프로그램을 실행하면 프로그램 내부에서는 32비트 주소를 사용합니다.)

 

 다른건 몰라도 저 위에 요약 3줄은 기억하고 계시기 바랍니다.

 

 

 

 2. 포인터

 

 위에서 메모리의 주소에 대해 알아봤는데, 포인터는 이 메모리 주소를 '참조' 하는 녀석입니다. 다음과 같이 변수를 선언했을때

 

int a = 1;

 

 포인터로 변수 a를 참조하게 되면

 


 이런식으로 변수 a의 시작 주소를 가리키게 됩니다. a의 주소를 가리키기 때문에 포인터로 값을 바꾸면 a의 값도 똑같이 바뀌게 되고, a의 값을 바꾸고 포인터로 값을 읽으면 바뀐 값이 나오게 됩니다.

 

 여기서 이해가 가지 않는다면 바탕화면의 아이콘 중 구석에 화살표가 그려진 '바로가기 아이콘'을 살펴봅시다.

 


 이런 모양을 하고 있을겁니다. 이 아이콘 중 아무거나 하나에 마우스 커서를 올려놓고 오른쪽 버튼을 눌러 메뉴가 나오게 한 후, '속성' 혹은 '등록정보' 를 눌러줍니다.

 


 그러면 다음과 같은 창이 열립니다.

 


 이런 '바로가기 아이콘'들은 위의 창에서 보는 것처럼, 실제 프로그램은 다른 곳에 설치되어 있지만 바로가기 아이콘은 실제 프로그램이 설치된 경로를 가리키고 있습니다. 이 바로가기 아이콘을 누르면 실제 설치된 프로그램을 직접 실행한것과 똑같이 실행하여 사용할 수 있습니다.

 

 포인터도 이런 바로가기 아이콘처럼 다른 변수나 상수 등의 주소를 가리키고 있다가, 마치 자기가 그 변수인양 값을 넣거나 변형할 수 있게 됩니다.

 

 그래도 어렵다면 일단은 포인터란건 주소를 저장한다고 생각하는것도 틀리지 않으니, 일단은 그렇게 알고 아래 부분을 보신 후 이 단락을 다시 한번 읽어봐주세요.

 

 

 

 3. 포인터 변수

 

 가장 보편적으로 사용하는 포인터 변수의 선언은 다음과 같습니다.

 

자료형 *변수명;

 

 주소의 크기는 일정합니다. (32비트, 64비트) 하지만 자료형을 앞에 써주는 이유는, 여기에 저장할 주소가 가리키는 곳에 저장된 '값'이 어떤 형이냐를 정해주는 것입니다. 일단은 int형 변수의 주소를 저장하려면 int형으로 맞춰주는 식이라고만 생각해봅시다.

 

 포인터 변수 선언의 예를 들어봅시다.

 

int a = 0;            // 일반 변수

int *p = NULL;    // 포인터 변수

 

 일반 변수의 선언에서 변수명 앞에 '*'를 붙여주는 것 이외에는 별반 다를게 없습니다. 이렇게 선언하게 되면 포인터 변수로 선언이 되어 여기에 주소를 담을 수 있게 됩니다. 초기화를 해주지 않으면 다른 변수들과 마찬가지로 엉뚱한 값이 들어가 있기 때문에 초기화를 해주는 것이 좋은데, 아무것도 없게 초기화할때는 위와 같이 'NULL'이라는 것을 대입해주면 됩니다. 이렇게 값이 'NULL'인 포인터를 '널 포인터' 라고도 부르니 참고하시기 바랍니다.

 

 포인터 변수를 선언할 때에는 반드시 초기화를 해주는 습관을 들이도록 합시다. 포인터 변수 뿐만 아니라 모든 변수를 선언할때 초기화를 해주는 것이 좋은데, 초기화를 해주지 않으면 기본적으로는 전혀 엉뚱한 값이 들어가 있기 때문에 코드를 작성하다 보면 얘기치 않은 오류를 발생시킬 확률이 높습니다. 또한 포인터 변수는 주소를 다루므로 잘못된 주소값으로 인해 프로그램이 멈추는 현상, 강제종료, 심각한 경우 운영체제가 멈추는 경우도 있습니다.

 

 

 

 4. 포인터 연산자 (&, *)

 

 그럼 위에서 선언한 포인터 변수에 '주소'를 넣어보겠습니다.

 

p = &a;

 

 위의 문장은 int형 포인터 변수 p에, int형 변수 a의 주소를 넣습니다. 여기서 '&'라는 것은 '포인터 연산자' 또는 '참조 연산자'라고 부르는 것 중 하나로, 위에서는 a의 주소를 반환하게 됩니다.

 

 다음은 포인터 연산자 '&'의 사용 예입니다.

 

int a = 0;

int *p1 = &a;            // p1에 a의 주소를 저장

 

int *p2;                // a의 주소를 저장하려고 한다.

p2 = &p1;                // p2에 p1의 주소를 저장 (X)

p2 = p1;                 // p2에 p1의 값인 a의 주소를 저장 (O)

 

 위의 예의 4번째 줄 같이 사용할 경우 포인터 변수 자체의 주소를 '&' 연산자를 이용해 대입하기 때문에 원하는 결과를 얻을 수 없습니다. 예의 포인터 변수 p1의 값은 a의 주소이므로 '&' 연산자를 붙이지 않고 직접 대입해야 원하는 결과를 얻을 수 있습니다.

 

 다음은 포인터 변수에 '값'을 넣어보겠습니다.

 

int a = 0;

int *p = &a;    // a의 주소를 저장

 

*p = 1;

 

printf("a의 값 = %d\n", a);

 

실행 결과

 

a의 값 = 1

 

 3번째 줄에서 포인터 변수 p 앞에 '*'를 붙여주었고, 1을 대입하였습니다. 이 '*' 역시 포인터 연산자 중의 하나로, 포인터 변수에 저장된 주소에 들어있는 '값'을 참조하게 해줍니다. 알기쉽게 포인터 변수에 들어있는 값을 꺼내준다고 생각하셔도 됩니다.

 

 위의 예에서 포인터 변수 p가 가리키는 주소의 값을 1로 대입하였습니다. 그렇기 때문에 그 주소의 원래 주인인 a의 값도 당연히 바뀌어 1이 출력이 되었습니다. 이처럼 포인터 변수를 이용해 다른 변수의 값을 읽거나 변형할 수 있습니다.

 

 정리해보면

 

& : 변수 또는 상수의 주소

* : 포인터가 가리키는 주소에 저장된 값

 

 으로 요약할 수 있습니다.

 

 이번시간에는 포인터의 기본 개념과 포인터 변수를 선언하고, 간단하게 사용하는 방법에 대해 알아보았습니다. 다음시간에는 좀 더 다양한 포인터의 사용법에 대해 다루도록 하겠습니다.

 

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31