리눅스 Tips, 리눅스 C/C++ 프로그래밍, 모바일 클라우드 동향 및 테스트 등

2012년 11월 1일 목요일

리눅스 C/C++ : 10장 포인터(2)

 출처 http://coolprogramming.springnote.com    저작자 NetGong


< Reveiw >

 포인터는 주소를 저장하는 변수라고 정의 했습니다. 이때 포인터 변수가 4byte 메모리 공간을 사용하므로 4개의 주소를 사용합니다. 그렇다면 포인터 변수의 시작주소를 저장하려면 어떤 포인터 변수에 저장해야 할까요?

(힌트)
  • int 변수의 주소는 int * 형 변수에 저장한다.
  • char 형 변수의 주소는 char 형 변수에 저장한다.
 그렇다면,
  • int * 형 변수의 주소는 int *  * 형 변수에 저장한다.
  • char * 형 변수의 주소는 char *  * 형 변수에 저장한다.

1, int형과 포인터

    
     int n = 100;
     int *pn = &n;
          int **ppn = &pn;

 n은 정수를 저장하는 변수(메모리)이며, pn은 int형 주소를 저장하는 변수(메모리)이며 ppn은 int*형 주소를 저장하는 변수(메모리)입니다. 아래 그림을 참고하세요.




 위 그림에서 ppn은 pn의 주소(&pn)을 pn은 n의 주소(&n)을 각각 저장합니다. 또 * 연산자를 주소앞에 붙이면 그 주소의 메모리이름이 된다고 했습니다. 그러므로

  • ppn에 * 붙인 *ppn은 pn 메모리가 됩니다.
  • pn에 * 붙인 *pn은 n 메모리가 됩니다.
  • *ppn에 * 붙인  **ppn은 n 메모리가 됩니다.

 위 내용을 확인하는 코드입니다.

void main( )
{    
    int n = 100;
    int *pn = &n;    
    int **ppn = &pn;
    printf("%x %x %x\n", &n, pn, *ppn);
    printf("%x %x \n", &pn, ppn);
    printf("===================\n");
    printf("%d %d  %d\n", n, *pn, **ppn);
}
  1. 12ff60 12ff60 12ff60
    12ff54 12ff54
    ===================
    100 100  100

 위 그림을 이해 했다면 어렵지 않습니다.

 int n에서 n은 변수(정수, 값을 저장하는)입니다.
 int *pn에서 pn은 포인터입니다.(싱글 포인터라고도 합니다.)
 int **ppn에서 ppn은 포인터의 포인터라합니다.(더블 포인터라고도 합니다.)
 int ***pppn에서 pppn은 포인터의 포인터의 포인터라합니다.
...

 부르기 힘들죠? 그래서 우리는

 int *pn에서 pn은 1차 포인터라고 합니다.
 int **ppn에서 ppn은 2차 포인터라고 합니다.
 int ***pppn에서 pppn은 3차 포인터라고 합니다.
 ...
 pn이 저장하는 &n은 1차 주소라고 합니다. 
 ppn이 저장하는 &ppn 2차 주소라고 합니다.
 pppn이 저장하는 &ppn은 3차 주소라 합니다.

 꼭 정리하고 기억하세요~!

 또 한가지 정리하고 가야합니다. 값(value)와 address(주소)입니다. 메모리 정리를 보시면 아시겠지만 메모리 내의 내용물을 값이라고 합니다. 한마디로,

  • n에 저장되어 있는 정수 10도 값(value)입니다.
  • pn에 저장되어 있는 주소 &n(12ff60)도 pn의 값(value)입니다.
  • ppn에 저장되어 있는 주소 &pn(12ff54)도 ppn의 값(value)입니다.

 하지만 그것은 컴퓨터의 일반적인 메모리에서의 이야기이며 보통 C언어에서는,

  • n에 저장되어 있는 정수 10을 값(value)라합니다. (raw value라고도 합니다.)
  • pn에 저장되어 있는 &n(12ff60)은 값이라 하지 않고 그냥 주소라고합니다. -> 12ff60은 숫자만의 의미가 아닌 int형 주소의 의미이며 데이터이기 때문입니다.
  • ppn에 저장되어 있는 &pn(12ff54)도 값이라 하지 않고 그냥 주소라고합니다. -> 12ff54도 숫자만의 의미가 아닌 int*형 주소의 의미이며 데이터이기 때문입니다.

 한마디로 기본 자료형 변수의 저장된 내용물만 값(value)라 하고 포인터 변수에 저장된 내용물은 주소라 합니다. * 연산자와 []연산자를 보여주는 예제입니다.

void main( )
{
    int n = 100;
    int *pn = &n;
    int **ppn = &pn;
    int ***pppn = &ppn;
    printf("%d %d %d\n", *pn, **ppn, ***pppn);
    printf("%d %d %d\n", pn[0], ppn[0][0], pppn[0][0][0]);
}
  1. 100 100 100
    100 100 100

 모두 100이 출력됩니다. *pn은 pn[0]와 같습니다. 우리 눈에는  달라도 컴파일러 눈에는 같다고 했습니다. 혹 기억이 안나시면 앞 페이지를 참고하세요.

  • * *pn은 pn[0][0]와 같습니다.
  • * **pn은 pn[0][0][0]와 같습니다.

 그러나 여기서 어떤 연산자를 사용할까요? 두 연산자 모두 사용 가능하지만 여기서는 []연산자 보다 *연산자를 사용하는게 좋습니다. []연산자는 주소를 기준으로 여러 메모리를 접근할 때 사용합니다. 조금만 공부해 보시면 알겠지만 주소로 메모리의 내용을 접근할 때 *연산자를 사용하는게 좋을 때가 있고 []연산자를 사용하는게 좋을 때가 있습니다.

2, char형과 포인터


void main( )
{
    char c = 'A';
    char *pc = &c;
    char **ppc = &pc;
    printf("%c %c %c\n", c, *pc, **ppc);
    printf("%x %x %x\n", &c, pc, *ppc);
}
  1. A A A
    12ff63 12ff63 12ff63
 위 내용을 공부하고 이해했다면 이 예제도 너무 당연한 결과입니다. 아래 그림을 참고하세요.




 여기까지입니다. ^^


.....


댓글 없음:

댓글 쓰기