코드 여행자

포인터(Pointer) - 기본1 본문

포인터(Pointer) 변수

포인터(Pointer) - 기본1

코드여행자12 2019. 10. 20. 16:32

포인터 변수 기본 개념

c언어를 배우게 되면 포인터 변수라는 개념을 접하게 되고 프로그래밍을 하다보면 포인터 변수를 사용해야 할 상황이 오게 됩니다.
오랜만(?)에 사용하게 되면 기본 개념에 대해서 한번 쯤 다시 생각하게 되고 관련 정보를 찾아 보게 됩니다.
이런 과정들이 반복되다보면 머리속에 포인터변수 개념이 자리 잡힐 것입니다.
지금부터 포인터에 대해서 정리하고자 합니다.

먼저 포인터 변수를 알아보기 전에 일반 변수에 대해서 간단하게 살펴보면 포인터 변수를 이해하는데 도움이 됩니다.


코드

   
#include<stdio.h>

int main()
{
    int a;

    printf("value of a = %d\n",a);
    printf("address of a = %p\n",&a);

    a = 10;

    printf("value of a = %d\n",a);
    printf("address of a = %p\n",&a);

    printf("size of a = %lu\n",sizeof(a));

    return 0;
}


실행 결과

value of a = 1
address of a = 0x7ffee70f7b3c
value of a = 10
address of a = 0x7ffee70f7b3c

size of a = 4 


초기화 하지 않은 변수a의 값을 출력해보면 1이라고 찍혀있습니다. 이값은 그 메모리에 남아 있는 쓰레기값이라고 부릅니다. 

예전에 누군가가 그 주소에 write 했던 값이겠지요
이제 10이라는 값을 변수 a에 대입합니다.
a변수가 할당된 메모리 위치에 10이라는 값이 저장됩니다.
당연한 이야기지만 변수 a값을 출력해보면 10이 찍힙니다. 주소는 좀전과 동일합니다.
마지막으로 변수 a의 사이즈를 알아봅니다. 변수 a의 사이즈는 int의 사이즈라고 생각하면 됩니다.(int a라고 선언했기에)
int는 4바이트라고 출력됩니다.
이때 변수 a가 차지하는 메모리에(4바이트 : 0x7ffee70f7b3c ~ 0x7ffeea2e8b3f) 10이라는 값은 어떻게 저장되어 있을까요


그림1을 보면 시작 주소에서 1바이트 공간에 0xa (십진수 10)이 저장되어 있습니다.
만약에 변수 a에 1000을 대입한다면 메모리는 그림 2와 같을 것입니다.( 16^2 * 3 + 16^1 * 14(e) + 8 == 1000) 

변수 a의 메모리 상태

변수에 저장하는 값이 커질수록 많은 바이트를 사용하는 것을 볼 수 있습니다. 
단, 변수 a는 integer이며 최대 4바이트까지만 값을 저장할 수 있기 때문에 이보다 큰 값은 저장할 수 없다는점 주의해야 합니다.


이제 다시 포인터 변수로 돌아와 보겠습니다.

포인터와 포인터 변수

포인터는 메모리 주소(번지)를 의미합니다.
포인터 변수는 메모리 주소를 담을 수 있는 변수입니다.
포인터 변수는 일반 변수의 주소를 저장할 수 있습니다. 일반 변수라고 하면 int, char, long, double 같은 변수를 이야기합니다.
즉, 포인터 변수는 변수(일반 변수 또는 포인터 변수)를 가리킬 수 있습니다. 

포인터 변수의 정의

integer형 값이 저장된 주소를 가리키고 싶다면
int * temp;
char형 값이 저장된 주소를 가리키고 싶다면  아래와 같이 선언하면 됩니다.
char * temp;

포인터 변수의 사용

그리고 포인터 변수에 메모리 주소를 대입할때는 &기호를 사용합니다.
int a = 10;
int * temp;
temp = &a; 
이제 temp 포인터 변수는 변수 a의 메모리 주소를 가리키게 됩니다.

그리고 * 기호를 사용하여 포인터 변수가 가리키는 주소에 저장되어 있는 값을 역참조(dereference) 할 수 있습니다.



코드
#include<stdio.h>

int main()
{
        int a;
        a = 5;

        printf("value of a = %x\n",a);
        printf("address of a = %p\n",&a);
        printf("size of a = %lu\n",sizeof(a));
 
        int * temp = &a;

        printf("address of temp = %p\n",&temp);
        printf("size of temp = %lu\n",sizeof(temp));
        printf("value of temp = %p\n",temp);
        printf("dereference temp = %d\n",*temp);

        return 0;
}


실행결과

value of a = 5

address of a = 0x7ffee13eab38

size of a = 4


address of temp = 0x7ffee13eab30

size of temp = 8

value of temp = 0x7ffee13eab38

dereference temp = 5


그림 3은 변수 a와(주황색 가지) 포인터 변수 temp(파랑색 가지)의 메모리 상태를 표시한 그림입니다.

그림 4는 그림3을 간단하게 표현한 그림입니다.


그림 3에 나타나 있듯이 integer 변수 a 에는 정수 5가 저장되어 있습니다. 그리고 변수 a의 메모리 시작 주소는 7ffee13eab38 입니다.

integer형의 temp 포인터 변수를 선언하고 변수 a의 주소 값을 대입하면 그 포인터 변수는 7ffee13eab38 값을 가리키게 됩니다.

이때 시스템은 7ffee13eab38값을 temp 변수가 할당하고 있는 8바이트 공간에 저장합니다.


temp 변수도 메모리 어딘가에 자리 잡고 있습니다. &temp 를 사용하여 주소값을 확인 수 있습니다. 실행결과를 보면 temp 변수의 메모리 주소는 0x7ffee13eab30입니다.


다시 말해 temp는 변수 a의 주소를 가리키고, &temp는 자기 자신의 메모리 주소를 가리킵니다.


메모리 상에서 변수 a는 4바이트를 차지하고 temp 포인터 변수는 8바이트를 차지하므로

시스템은 변수 a값을 읽을 때는 변수 a 메모리 시작주소부터 4바이트에 저장되어 있는 값을 읽어옵니다.

그리고 temp값을 읽을 때는 temp 변수의 시작주소부터 8바이트에 저장된 값을 읽어 옵니다.


그림 3에서 보듯이 temp 변수가 차지하는 8개의 바이트에는  0x0 0x0 0x7f 0xfe 0xe1 0x3e 0xab 0x38값들이 저장되어 있습니다.

이를 자릿수 감안하여 계산하면 0x7ffee13eab38 입니다. 이 값은 변수의 a의 메모리 주소와 동일합니다. int * temp = &a 를 하였기 때문입니다.


그림 4를 보면 *temp는 temp가 가리키는 주소(즉 , 변수 a의 주소)에 저장되어 있는 값을 역참조 합니다.

temp는 변수 a를 가리키므로(temp == 0x7ffee13eab38) 역참조한 값은 변수 a의 값인 정수 5입니다.


포인터 변수의 메모리 상태


지금까지 포인터 변수의 기본적인 내용에 대해서 알아 보았습니다.

다음에는 이번 글에서 다 설명하지 못한 남은 부분에 대해서 설명 드릴 예정입니다.

예를 들면 포인터 변수를 사용하여 역참조된 값을 수정하는 것, 그리고 포인터 변수를 사용하는 이유에 대해서 설명 드리겠습니다.



'포인터(Pointer) 변수' 카테고리의 다른 글

배열과 포인터(Array and Pointer)  (0) 2019.11.11
포인터 기본2- call by reference  (0) 2019.11.03
Comments