C2009.11.09 16:10


이번 강좌에서는
  • 포인터에 대한 완벽한 이해
  • *, & 단항 연산자의 의미


  우왕~ 안녕하세요 여러분. 아마 C 언어를 배웠거나 배우고 있는 사람들은 포인터에 대해 익히 들어 보셨을 것 입니다. 이해하기 힘들기로 악명 높은 그 포인터를 말이죠. 하지만, 저와 함께 한다면 큰 무리 없이 배우 실 수 있을 것이라 생각됩니다.


   포인터를 이해하기 앞서
 

  앞서 3 강에서 이야기 하였지만 모든 데이터들은 메모리 상에 특정한 공간에 저장 되어 있습니다. 우리는 앞으로 편의를 위해, 메모리의 특정한 공간을 '방' 이라고 하겠습니다. 즉, 각 방에는 데이터들이 들어가게 되는 것 입니다. 보통 사람들은 한 방의 크기를 1 바이트 라고 생각합니다. 우리가 만약 int 형 변수를 정의한다면 4 바이트 이므로 메모리 상의 4 칸을 차지하게 됩니다. 그런데 말이죠. 프로그램 작동 시 컴퓨터는 각 방에 있는 데이터를 필요로 하게 됩니다. 따라서, 서로 구분하기 위해 각 방에 고유의 '주소(address)' 를 붙여 주었습니다. 우리가 아파트에서 각 집들을 호수로 구분하는 것 처럼 말입니다. 예를 들어 우리가 아래와 같은 int 변수 a 를 정의하였다면 특정한 방에 아래 그림 처럼 변수 a 가 정의됩니다.

int a = 123; // 메모리 4 칸을 차지하게 한다.


메모리에 123 이란 수가 있고 이 수는 메모리에 0x152839 (앞에 0x 는 이 수가 16 진수로 표시되었다는 것을 의미해요) 에 위치


이 때, 0x152839 는 제가 아무렇게나 정한 이 방의 시작 주소 입니다. 참고로, 0x 가 뭐냐고 물어보는 사람들이 있을 텐데, 이전 강좌에서도 이야기 하였지만 16 진수라고 표시한 것 입니다. 즉, 16 진수로 152839 (10 진수로 1386553) 라는 위치에서 부터 4 바이트의 공간을 차지하며 123 이라는 값이 저장되어 있게 하라는 뜻이지요.

그렇다면 아래와 같은 문장은 어떻게 수행 될까요?

a = 10;

사실 컴파일러는 위 문장을 아래와 같이 바꿔주게 됩니다.

메모리 0x152839 위치에서 부터 4 바이트의 공간에 있는 데이터를 10 으로 바꾸어라!

결과적으로, 컴퓨터 내부에서는 올바르게 수행되겠지요.
참고적으로 말하는 이야기 이지만 현재 (아마 이 블로그에 접속하는 사람들 중 99% 이상이) 많은 사람들은 32 비트 운영체제를 사용하고 있습니다. 이 32 비트에서 작동되는 컴퓨터들은 모두 주소값의 크기가 32 비트 (즉, 4 바이트.. 까먹었다면 2-3 강 참조) 로 나타내집니다. 즉 주소값이 0x00000000 ~ 0xFFFFFFFF 까지의 값을 가진다는 것이지요. 어랏! 조금 똑똑하신 분들이라면 32 비트로 사용할 수 있는 주소값의 가지수는 2 의 32 승 바이트, 즉 RAM 은 최대 4 GB 까지 밖에 사용할 수 없다는 사실을 알 수 있습니다. 맞습니다. 이 때문에 32 비트 운영체제에서는 RAM 의 최대 크기가 4 GB 로 제한되지요(즉, 돈을 마이 들여서 RAM 10GB 로 만들어도 컴퓨터는 4 GB 까지 밖에 인식하지 못합니다. 어찌 이렇게 슬플수가..) [각주:1]

여기까지는 상당히 직관적이고 단순해서 이해하기 쉬웠을 것 입니다. 그런데 C 를 만든 사람은 아주 유용하면서도 골때리는 것을 하나 새롭게 만들었습니다. 바로 '포인터(pointer)' 입니다. 영어를 잘하는 분들은 이미 아시겠지만 '포인터' 라는 단어의 뜻이 '가리키는 것(가르켜지는 대상체를 말하는 것이 아닙니다)' 이란 의미를 가지고 있습니다.

사실, 포인터는 우리가 앞에서 보았던 int 나 char 변수들과 다른 것이 전혀 아닙니다. 포인터도 '변수' 입니다. int 형 변수가 정수 데이터, float 형 변수가 실수 데이터를 보관했던 것 처럼, 포인터도 특정한 데이터를 보관하는 '변수' 입니다. 그렇다면 포인터는 무엇을 보관하고 있을 까요?

바로, 특정한 데이터가 저장된 주소값을 보관하는 변수 입니다. 여기서 강조할 부분은 '주소값' 이라는 것 이지요. 여기서 그냥 머리에 박아 넣어 버립시다. 이전에 다른 책들에서 배운 내용을 싹 다 잊어 버리고 그냥 망치로 때려 넣듯이 박아버려요. 포인터에는 특정한 데이터가 저장된 주소값을 보관하는 변수 라고 말이지요. 크게 외치세요. '주소값!!!!!'

암튼, 뇌가 완전히 세뇌되었다고 생각하면 다음 단계로 넘어가도록 하겠습니다. 아직도 이상한 잡념이 머리에 남아 있다면 크게 숨을 호흡하시고 주소값이라고 10 번만 외쳐 보세요..

자. 되었습니다. 이제 포인터의 세계로 출발해 봅시다. 뿅

   포인터
 

다시 한 번 정리하자면

"포인터" : 메모리 상에 위치한 특정한 데이터의 (시작)주소값을 보관하는 변수!

우리가 변수를 정의할 때 int 나 char 처럼 여러가지 형(type) 들이 있었습니다. 그런데 놀랍게도 포인터에서도 형이 있습니다. 이 말은 포인터가 메모리 상의 int 형 데이타의 주소값을 저장하는 포인터와, char 형 데이터의 주소값을 저장하는 포인터가 서로 다르다는 말입니다. 응?? 여러분의 머리속에는 아래와 같은 생각이 번개 처럼 스쳐 지나갈 것입니다.

"야 이 Psi 같은 놈아. 아까 포인터는 주소값을 저장하는 거래며. 근데 우리가 쓰는 컴퓨터에선 주소값이 무조건 32 비트, 즉 4 바이트래며!! 그러면 포인터의 크기는 다 똑같은것 아냐? 근데 왜 포인터가 형(type)을 가지는 건데!! 아아아아악"

휴우우. 진정좀 하시고. 여러분 말이 백번 맞습니다 - 단, 현재 까지 배운 내용을 가지고 생각하자면 말이지요. 포인터를 아주 조금만 배우면 왜 포인터에 형(type) 이 필요한지 알게 될 것입니다.

C 언어에서 포인터는 다음과 같이 정의할 수 있습니다.

(포인터에 주소값이 저장되는 데이터의 형) *(포인터의 이름);

혹은 아래와 같이 정의할 수 도 있습니다.

(포인터에 주소값이 저장되는 데이터의 형)* (포인터의 이름);

  예를 들어 p 라는 포인터가 int 데이터를 가리키고 싶다고 하면 ...

int *p; // 라고 하거나
int* p; // 로 하면 된다

라 하면 올바르게 됩니다. 즉 위 포인터 p 는 int 형 데이터의 주소값을 저장하는 변수가 되는 것 입니다. 와우!

   & 연산자
 

그런데 말입니다. 아직도 2% 부족합니다. 포인터를 정의하였으면 값을 집어 넣어야 하는데, 도대체 우리가 데이터의 주소값을 어떻게 아냐는 말입니까? 하지만, 여러분의 이러한 욕구를 충족시키는 연산자가 C 에 (당연히) 있습니다. 바로 & 연산자 이지요.

그런데, 아마 복습을 철저하게 잘하신 분들은 당황할 수 도 있습니다. 왜냐하면 & 가 AND 연산자이기 때문입니다. (4 강 참조) 그런데, & 연산자는 두 개의 피연산자를 필요로 했습니다. 즉,

a & b; //o.k
a & // NOT ok

와 같이 언제나 2 개가 필요 하다는 것이지요. 그런데, 여기에서 소개할 & 연산자는 오직 피연산자가 1 개인 연산자 입니다. (이러한 연산자를 단항(unary) 연산자라 합니다) 즉, 위의 AND 연산자와 완전히 다르 다는 것이지요. 이는 데이터의 주소값을 불러 옵니다. 사용은 그냥 아래와 같은 꼴로 사용해 주면 됩니다.

& (주소값을 계산할 데이터)

백설(說)이 불여일행(行). 한 번 프로그램을 짜 봅시다.

/* & 연산자 */
#include <stdio.h>
int main()
{
    int a;
    a = 2;

    printf("%x \n", &a);
    return 0;
}

성공적으로 컴파일 했다면


와 같이 나옵니다. 참고로, 여러분의 컴퓨터에 따라 결과가 다르게 나올 수 도 있습니다. 사실, 저와 정말 인연 이상의 무언가가 있지 않는 이상 전혀 다르게 나올 것 입니다. 더 놀라운 것은 실행할 때 마다 결과가 달라질 것입니다.

2 번째 실행한 것


위와 같이 나오는 이유는 나중에 설명하겠지만 주목할 것은 '값' 이 출력되었다는 것 입니다.

    printf("%x \n", &a);

위 문장에서 &a 의 값을 16 진수 (%x) 로 출력하라고 명령하였습니다. 근데요. 눈치가 있는 사람이라면 금방 알겠지만 위에서 출력된 결과는 4 바이트(16 진수로 8 자리)가 아닙니다! (여러분의 컴퓨터는 다를 수 있습니다. 아무튼..) 하지만 저는 32 비트 운영체제를 사용하고 있습니다. 그렇다면 뭐가 문제인가요? 사실, 문제는 없습니다. 단순히 앞의 0 이 잘린 것 이지요. 주소값은 언제나 4 바이트 크기, 즉 16 진수로 8 자리 인데 앞에 0 이 잘려서 출력이 안된 것일 뿐입니다. 따라서 변수 a 의 주소는 아마도 0x001EF8D4 가 될 것입니다.

 아무튼 위 결과를 보면, 적어도 제 컴퓨터 상에선 int 변수 a 는 메모리 상에서 0x001EF8D4 를 시작으로 4 바이트의 공간을 차지하고 있었다는 사실을 알 수 있습니다.

 자, 이제 & 연산자를 사용하여 특정한 데이터의 메모리 상의 주소값을 알 수 있다는 사실을 알았으니 배고픈 포인터에게 값을 넣어 봅시다.

/* 포인터의 시작 */
#include <stdio.h>
int main()
{
    int *p;
    int a;

    p = &a;

    printf("포인터 p 에 들어 있는 값 : %x \n", p);
    printf("int 변수 a 가 저장된 주소 : %x \n", &a);

    return 0;
}

실행해 보면 많은 이들이 예상했던 것 처럼....


똑같이 나옵니다. 어찌 보면 당연한 일입니다.

    p = &a;

에서 포인터 p 에 a 의 주소를 대입하였기 때문이죠. 참고로, 한 번 정의된 변수의 주소값은 바뀌지 않습니다. 따라서 아래 printf 에서 포인터 p 에 저장된 값과 변수 a 의 주소값이 동일하게 나오게 됩니다. 어때요. 쉽죠?

   * 표 
 

  이제, 드디어 포인터의 핵심에 다다랐습니다. 현재 까지 우리가 배운 바로는 "포인터는 특정한 데이터의 주소값을 보관한다. 이 때 포인터는 주소값을 보관하는 데이터의 형에 * 를 붙임으로써 정의되고, & 연산자로 특정한 데이터의 메모리 상의 주소값을 알아올 수 있다" 까지 알고 있습니다. 참고로 아래에서 설명하는 * 는 앞서 포인터를 정의할 때 사용하였던 * 와 다른 의미를 지닌 다는 사실을 알고 있으세요.

  앞서 & 연산자가 2% 부족한 부분을 채워준다고 했지만 안타깝게도 1% 가 남았습니다. 하지만 * 연산자가 이 1% 를 채워질 것 입니다.... 잠깐만. * 연산자?? 어디서 많이 들어본 것 같네요.. 맞아요. * 연산자도 & 처럼 피연산자를 2 개 가질 때 에는 곱셈 연산자로 사용됩니다. 즉

a * b; // a 와 b 를 곱한다.
a *; // Not OK

하지만 이 연산자는 위 & 처럼 1 개의 피연산자를 가지는 단항 연산자 입니다. * 연산자는 쉽게 풀이하자면

 "나(포인터)를 나에게 저장된 주소값에 위치한 데이터라고 생각해!"

  라는 의미의 연산자 입니다. 한 번 아래 예제를 봅시다.

/* * 연산자의 이용 */
#include <stdio.h>
int main()
{
    int *p;
    int a;

    p = &a;
    a = 2;

    printf("a 의 값 : %d \n", a);
    printf("*p 의 값 : %d \n", *p);

    return 0;
}

성공적으로 컴파일 한다면


가 됩니다.

    int *p;
    int a;

일단 int 데이터를 가리키는 포인터 p 와 int 변수 a 를 각각 정의하였습니다. 평범한 문장 이지요.

    p = &a;
    a = 2;

그리고 포인터 p 에 a 의 주소를 집어 넣었습니다. 그리고 a 에 2 를 대입하였습니다.

    printf("a 의 값 : %d \n", a);
    printf("*p 의 값 : %d \n", *p);

일단 위의 문장은 단순 합니다. a 의 값을 출력하란 말이지요. 당연하게도 2 가 출력됩니다. 그런데, 아래에서 *p 의 값을 출력하라고 했습니다. * 의 의미는 앞서, "나를 나에 저장된 주소값에 해당하는 데이터로 생각하시오!" 로 하게 하는 연산자라고 하였습니다. 즉, *p 를 통해 "p 에 저장된 주소(변수 a 의 주소)에 해당하는 데이타, 즉 변수 a" 를 의미할 수 있게 되었습니다. 다시 말해 *p 와 변수 a 는 정확히 동일합니다. 즉, 위 두 문장은 아래 두 문장과 10000% 일치합니다.

   printf("a 의 값 : %d \n", a);
    printf("*p 의 값 : %d \n", a);

마지막으로 * 와 관련된 예제 하나를 더 살펴 봅시다.

/* * 연산자 */
#include <stdio.h>
int main()
{
    int *p;
    int a;

    p = &a;
    *p = 3;

    printf("a 의 값 : %d \n", a);
    printf("*p 의 값 : %d \n", *p);

    return 0;
}

성공적으로 컴파일 하였다면


아마 많은 여러분들이 예상했던 결과 이길 바랍니다^^

    p = &a;
    *p = 3;

위에서도 마찬가지로 p 에 변수 a 의 주소를 집어 넣었습니다. 그리고 *p 를 통해 "나에 저장된 주소(변수 a 의 주소)에 해당하는 데이터(변수 a) 로 생각하시오" 를 의미하여 *p = 3 은 a = 3 과 동일한 의미를 지니게 되었습니다. 어때요. 간단하지요? 이로써 여러분은 포인터의 50% 이상을 이해하신 것 입니다~~! 짝짝짝짝

 자. 그럼 '포인터' 라는 말 자체의 의미를 생각해 봅시다. int 변수 a 와 포인터 p 의 메모리 상의 모습을 그리면 아래와 같습니다.

포인터 p 도, a 도 메모리 상에 각각 존재합니다만, 그 위치에는 a 의 경우 3 이 있지만 p 의 경우 a 의 주소값이 있습니다.

참고로 주소값은 제가 임의로 정한 것 입니다.


  즉, 포인터  p 는 * 를 통해 a 를 의미 할 수 (가리 킬 수) 있게 되었지요. 흔히 많은 책들은 포인터 p 가 변수 a 를 가리키고 있다 라고 말합니다. 사실 저는 이 말이 여러분에게 어렵게 다가올 까봐 여태까지 하고 있지 않았지만 아무튼, 포인터 p 에 어떤 변수 a 의 주소값이 저장되어 있다면 '포인터 p 는 변수 a 를 가리킨다' 라고 말합니다. 참고적으로 말하지만 포인터 또한 엄연한 변수 이기 때문에 특정한 메모리 공간을 차지합니다. 따라서 위 그림과 같이 포인터도 자기 자신만의 주소를 가지고 있지요.

 이제 여러분들은 포인터에 왜 '형(type)' 이 필요한지 이야기 할 수 있는 단계가 되었습니다. (아마 여러분들 중 반 수 이상은 이미 짐작하고 계실 것 입니다.) 다시 말해 '형' 이 없다는 것은 포인터가 자신이 가리키고 있는 대상에 대해 어떠한 정보도 가지지 않아도 된다는 것 입니다. 여기서 포인터를 선언하기 위해 pointer 라는 저 만의 키워드를 이용했다고 합시다. (실제로 이런게 사용되는 것이 아닙니다;;;)

int a;
pointer *p;
p = &a;
*p = 4;

자. 위 명령이 올바른 결과를 출력할까요? 포인터 p 에는 명백히 변수 a 의 '시작 주소' 가 들어 있습니다. '시작 주소' 란 말입니다. 즉, *p 라고 했을 때 포인터 p 에는 자신이 가리키는 대상의 시작 주소가 있지만 대상의 크기에 대한 정보가 없습니다. 헉! 컴퓨터는 *p 라고 했을 때 메모리에서 0x12345678 로 부터 (&a 가 0x12345678 이라 가정합시다) 몇 개의 바이트를 더 읽어 들어서
값을 변경해야 할 지 모른다는 말입니다. 결국 포인터는 쓸모 없게 됩니다.

하지만, 우리가 여태까지 해왔던 것 처럼

int a;
int *p;
p = &a;
*p = 4;

라고 한다면 어떨 까요? 컴퓨터는 0x12345678 로 부터 포인터 p 가 int * 라는 사실을 보고 "아하. 이 포인터는 int 데이터를 가리키는 구나!" 라고 알게 되어 정확히 4 바이트를 읽어 들어 값을 바꾸게 됩니다. 따라서 정확한 값이 출력될 수 있겠지요.

여러분이 현재 까지 배운 내용에 대해 완벽하게 이해를 하고 있다면 아래와 같은 궁금증이 생길 것 입니다.

"야. 그런데 말야. 주소값은 무조건 4 바이트 잖아? 그러면 int *p; 처럼 귀찮게 * 을 붙이지 말고 int p; 라고 한다음에 p = &a; 라고 해도 상관 없는거 아니야? 그지? 그지? 그지? "

  훌륭한 생각입니다. 한 번 해봅시다.

/* 될까? */
#include <stdio.h>
int main()
{
    int p;
    int a;

    p = &a;
    a = 3;

    printf("*p 의 값? : %d \n", *p);

    return 0;
}

안타깝게도 printf 부분에서 아래와 같은 오류가 출력됩니다.

error C2100: 간접 참조가 잘못되었습니다.

사실, 우리가 현재 까지 배운 내용을 바탕으로 이해해 보자면 위에서 왜 오류가 발생하는지 이해하기 힘듦니다. 그냥 단순히 * 연산자는 포인터들에게만 적용된다는 사실만을 알아 두시면 감사하겠습니다.

/* 포인터도 변수이다 */
#include <stdio.h>
int main()
{
    int a;
    int b;
    int *p;

    p = &a;
    *p = 2;
    p = &b;
    *p = 4;

    printf("a : %d \n", a);
    printf("b : %d \n", b);
    return 0;
}

성공적으로 컴파일 하였다면



    p = &a;
    *p = 2;
    p = &b;
    *p = 4;

  사실, 이런 예제까지 굳이 보여주어야 하나 하는 생각이 들었지만 그래도 혹시나 하는 마음에 했습니다. 앞에서도 말했듯이 포인터는 '변수' 입니다. 즉, 포인터에 들어간 주소값이 바뀔 수 있다는 것이지요. 위와 같이 처음에 a 를 가리켰다가, (즉 p 에 변수 a 의 주소값이 들어갔다가) 나중에 b 를 가리킬 수 (즉 p 에 변수 b 의 주소값이 들어감) 있다는 것 이지요. 뭐 특별히 중요한 예제는 아니였습니다만. 나중에 상수 포인터, 포인터 상수에 대해 이야기 하면서 다시 다루어 보도록 하겠습니다.

마지막으로, 강의를 마치며 여러분에게 포인터에 대해 완벽히 뇌리에 꽂힐 만한 동화를 들려드리겠습니다.

옛날 옛날에 .. 대략 2 년 전에 (뭐.. 전 여러분과 옛날의 정의가 다릅니다ㅋ) 변철수, 변수철, 포영희라는 세 명의 사람이 OO 아파트에 살고 있었습니다.

int chul, sue;
int *young;

그런데 말이죠. 포영희는 변철수를 너무나 좋아한 나머지 자기 집 대문 앞에 큰 글씨로 "우리집에 오는 것들은 모두 철수네 주세요" 라고 써 놓고 철수네 주소를 적어 놓았습니다

young = &chul;

어느날 택배 아저씨가 영희네 집에 물건을 배달하러 왔다가 영희의 메세지를 보고 철수네에 가져다 주게 됩니다.

*young = 3; // 사실 chul = 3 과 동일하다!

영희에 짝사랑이 계속 되다가 어느날 영희는 철수 보다 더 미남인 수철이를 보게 됩니다. 결국 영희는 마음이 변심하고 수철이를 좋아하기로 했죠. 영희는 자기 대문 앞에 있던 메세지를 떼 버리고 "우리집에 오는 것은 모두 수철이네 주세요." 라 쓰고 수철이네 주소를 적었습니다.

young = &sue;

며칠이 지나 택배 아저씨는 물건을 배달하러 영희네에 왔다가 메세지를 보고 이번엔 수철이네에 가져다 줍니다.

*young = 4; // 사실 sue = 4 와 동일하다

이렇게 순수한 사랑이 OO 아파트에서 모락 모락 피어났습니다..... 끝

return 0; // 종료를 나타내는 것인데, 아직 몰라도 되요. (정확히 말하면 리턴...)

생각해 볼 문제

* 와 & 연산자의 역할이 무엇인지 말해보세요 (난이도 : 下)

int **a; 와 같은 이중 포인터(double-pointer) 에 대해 생각해 보세요 (난이도 : 中上)




강좌를 보다가 조금이라도 궁금한 것이나 이상한 점이 있다면 꼭 댓글을 남겨주시기 바랍니다. 그 외에도 강좌에 관련된 것이라면 어떠한 것도 질문해 주셔도 상관 없습니다. 생각해 볼 문제도 정 모르겠다면 댓글을 달아주세요.

현재 여러분이 보신 강좌는 <<씹어먹는 C 언어 - <12 - 1. 포인터는 영희이다! (포인터)>>> 입니다. 이번 강좌의 모든 예제들의 코드를 보지 않고 짤 수준까지 강좌를 읽어 보시기 전까지 다음 강좌로 넘어가지 말아주세요



Posted by Psi

댓글을 달아 주세요

  1. 이전 댓글 더보기
  2. http://qnshdks.blog.me/202215465
    이해가 잘되서 홍보했습니다..!!

    강좌써주셔서 감사합니다.

    2014.01.11 01:34 [ ADDR : EDIT/ DEL : REPLY ]
  3. R

    참 세상엔 천재들이 많은것같습니다 :-]
    많이 배우고갑니다~

    2014.02.06 09:56 [ ADDR : EDIT/ DEL : REPLY ]
  4. 멍개

    질문이 있습니다

    int a;
    a=3;
    a=7;
    printf("%d \n",a);

    이것처럼 a라는 변수에 같은 수를 여러번 다른 수를 대입하면 마지막에 출력 되는 값은
    가장 마지막에 대입한 숫자가 그 이전에 대입한 숫자 위에 덧씌워진다고 생각하고 있었는데

    p = &a;
    *p = 2;
    p = &b;
    *p = 4;

    printf("a : %d \n", a);
    printf("b : %d \n", b);
    return 0;


    이건 제가 알고 있던 개념과 다른것 같은데 정상적으로 작동하니

    제가 어디를 잘못 알고 있는지

    혹시 지금도 보고 계시다면 답변해주시면 감사하겠습니다


    p = &a;
    *p = 2;
    printf("a : %d \n", a);

    p = &b;
    *p = 4;
    printf("b : %d \n", b);
    return 0;

    포인터가 주소값을 기억하고 있는 '변수' 라면 이렇게 되어야 하지 않나요?

    2014.05.22 08:20 [ ADDR : EDIT/ DEL : REPLY ]
    • p = &a;
      *p = 2;

      바로 이 지점에서 "p 가 가리키고 있는 애의 값을 2 로 만든다" 가 됩니다. 근데 위에서 p = &a 를 통해 p 가 a 를 가리키고 있으므로 (p 의 값은 a 의 주소값), a 의 값이 2 가 됩니다.

      p = &b;

      그리고 이제 p 가 b 를 가리키게 되죠. (즉, b 의 주소값이 p 에 들어갑니다)

      *p = 4;

      역시 p 가 가리키는 애 (b) 의 값을 4 로 만듭니다.

      printf("a : %d ", a);
      printf("b : %d ", b);

      따라서 각각 2 와 4 가 출력되게 됩니다.

      2014.07.29 00:57 신고 [ ADDR : EDIT/ DEL ]
  5. Naurko

    잘 공부하고 갑니다!!
    연대 다니는 친구가 짱짱맨인 페이지라 해서 왔는데 이해가 쑥쑥 잘되네요! (저희 교수님보다 잘 가르치시ㄴ..... ㅎㅎ)

    2014.06.14 17:50 [ ADDR : EDIT/ DEL : REPLY ]
  6. 따봉

    /* 될까? */
    #include <stdio.h>
    int main()
    {
    int p;
    int a;

    p = &a;
    a = 3;

    printf("*p 의 값? : %d \n", *p);

    return 0;
    }

    이 부분에 대해서 궁금한데요, 죄송하지만 이해는 제가 할테니
    왜 오류가 발생하는지 설명해주실 수 있나요ㅠㅠ?

    2014.10.07 21:22 [ ADDR : EDIT/ DEL : REPLY ]
  7. Cprog

    #include<stdio.h>
    int main (void)
    {
    int a=3;
    int* b = &a;

    printf("a : %d %p\n", a, &a);
    printf("b : %d %d %p %p\n", b, *b, b, &b);
    }

    이렇게해보았는데요...
    결과창
    ------------------------------------
    a : 3 00A6F914
    b : 10942740 3 00A6F914 00A6F908
    ------------------------------------
    %d는 정수를, %p는 주소를 출력하는 것이라고알고있는데요..
    %d로 b를 출력했을때 값이 이상한정수가나오는데
    b가a의 주소를 값으로 가지고있는데
    a의주소를 정수로 변환되어서 나오는 것인가요?

    그리고 b와 *b의 차이점을 잘모르겠습니다..ㅠ
    %d로하면 *b는 주소안의 값을 말하는 것인건 알겠습니다. b는 잘모르겠구요
    %p로하면 b는 주소를 말하는 것인건 알겠습니다. *b는 잘모르겠구요..

    2014.11.22 17:13 [ ADDR : EDIT/ DEL : REPLY ]
    • 1) 예 맞습니다. 정수로 변환해서 보여주는 것입니다.

      2) *b 는 (b 의 값을 주소로 하는 곳에 위치한 값) 을 의미하게 되고 여기서는 3 입니다. b 를 출력하면 그냥 a 의 주소값이 정수로 나오겠지요.

      나머지도 마찬가지 입니다.

      2014.11.23 11:40 신고 [ ADDR : EDIT/ DEL ]
  8. 이병석

    강의 잘 보고 있습니다. 제가 본 어떤 초보 책보다 쉽게 설명되어있어 많은 도움이 되고 있습니다. 고맙습니다.^^
    다름이 아니라 main()안에서
    int a;
    int *pa;
    a=100;
    pa=&a;
    printf("%x, %x, %d\n",&a, pa, *pa);
    return 0;
    이렇게 입력하고 컴파일을 하니 경고가 2개 뜨더군요... &a와 pa 주소출력에서 선언된 변수형과 사용된 변수형이 다르다고 나오더라구요... 무시하고 실행하면 결과는 강좌에서 알 수 있듯이 예상한대로 나오긴 하는데, 경고가 이해가 안되어서요... 좀 알려주시면 고맙겠습니다. 참고로 맥os에서 터미널을 이용해서 gcc로 컴파일했습니다.

    2015.01.01 22:03 [ ADDR : EDIT/ DEL : REPLY ]
    • &a 와 pa 는 int* 타입이지요. 그런데 %x 는 정수를 출력할 때 사용하는 것입니다. 엄밀히 말하면 타입이 다릅니다.

      2015.04.11 08:57 신고 [ ADDR : EDIT/ DEL ]
  9. 완전 초보인데요. 본문 중에 이해가 안되는 내용이 있어서요. 32비트주소값을 가지면 2의 32승비트만큼의 메모리를 가져야 할 것 같은데 2의 32승 바이트만큼의 메모리를 가진다고 하셔서요. 아무리 생각해봐도 잘 모르겠는데 가르쳐주시겠어요? 잘 보고 있습니다~

    2015.04.08 07:58 [ ADDR : EDIT/ DEL : REPLY ]
    • 1 바이트에 1 개의 메모리 주소가 대응되어 있습니다. 따라서, 2의 32 승 개의 메모리 주소가 있으므로 2의 32승 바이트 만큼의 메모리를 가질 수 있게 됩니다.

      2015.04.11 08:56 신고 [ ADDR : EDIT/ DEL ]
  10. jj2ona

    학교 교수님께 강의 들을 때 보다 더 이해가 쏙쏙 됩니다....왜 이런 강의를 기말이 다 된 지금에서야 알았을까요ㅠㅠ정말 감사합니다....강의 열심히 보고 기말에 희망을 한 번 걸어보아야겠어요!

    2015.05.27 00:15 [ ADDR : EDIT/ DEL : REPLY ]
  11. 덕분에 이해가 되었습니다 ㅠㅠ. 다만 궁금한것이 있는데요, 포인터에도 타입이있고 타입이 있어야 메모리 상에서 정확히 해당 주소값의 크기만큼 가져올 수 있다 하셨잖아요. 그럼 타입이 없을 때 본문에는 쓸모없어진다고민 나와있는데 구체적으로 메모리 상에서 어떻게 실현되는 건가요??(범위를 모르니 무한히 많은 방에 쓰레기 값을 넣나요?)

    2015.07.21 15:13 [ ADDR : EDIT/ DEL : REPLY ]
  12. 젊으니

    포인터포인터 했었는데 이제서야 제대로 알게되는 것 같아서 행복합니다!^^*

    중간에 궁금한게 있는데, 주소 값을 포인터에 저장하지 않고 그냥 변수에 저장하면 의미가 없겠죠?
    적다보니 의미가 없어보이네요.... ㅡ.ㅡ

    다음 포인터 강의로 넘어가겠습니다!!

    2015.07.21 15:47 [ ADDR : EDIT/ DEL : REPLY ]
    • 뭐 주소값을 가지고 무언가를 할 일이 없다면 큰 의미는 없어보이네요~

      2016.07.16 03:08 신고 [ ADDR : EDIT/ DEL ]
  13. <1번 문제>
    단항 연산자 * 와 & 는
    * : 포인터가 가리키고 있는 주소값의 데이터를 의미합니다.
    & : 주소값을 나타냅니다.

    <2번 문제>
    포인터를 가리키는 포인터 입니다. (?)

    2016.02.17 15:41 신고 [ ADDR : EDIT/ DEL : REPLY ]
  14. 철영수

    포스팅 매번 잘보고갑니다!
    한가지 질문이 있는데,
    포인터 p를 지정했을 때
    int *p;
    int a;
    p = &a;
    이때 p는 a의 주소라는 데이터(ex : 0x12345678, a의 주소라고하고..)가 다른 주소(0x87654321, 별개의 주소)로 저장되는 건가요? (+p의 값은 16진수인가요?)

    2016.08.17 20:38 [ ADDR : EDIT/ DEL : REPLY ]
    • a 의 주소가 p 라는 변수에 저장되게 됩니다. 물론 p 라는 변수는 다른 주소에 위치해 있지요

      2017.03.30 11:05 신고 [ ADDR : EDIT/ DEL ]
  15. thank you

    글 잘 읽었어요! 이때까지 포인터 개념을 이해 못 했었는데 이 글이 도움 많이 됐습니다! 특히 영희의 이야기가 최고였네요 ㅎㅎ 감사합니다!!

    2016.11.12 09:11 [ ADDR : EDIT/ DEL : REPLY ]
  16. 윈도우 10 bash(우분투) 환경에서 gcc로 컴파일을 하고 있는데요.
    #include <stdio.h>
    int main()
    {
    int a;
    a = 2;

    printf("%x \n", &a);
    return 0;
    }

    에서 %x 부분에서 에러가 나네요. %p를 쓰면 안나는데, 이것은 버전 혹은 환경마다 C 가 다르게 컴파일된다고 볼 수 있는 건가요? 그리고 환경설정을 통해 %x도 address를 출력할 수 있는 방법이 있을까요?

    감사합니다.

    2016.12.09 15:24 [ ADDR : EDIT/ DEL : REPLY ]
    • 흠.. GCC 6.3 버전에서는 잘 되네요.

      https://ideone.com/QjnogM

      2017.03.30 11:00 신고 [ ADDR : EDIT/ DEL ]
  17. cjk

    만약 운영체제가 64it라면 주소가 2진법으로 변환 하였을때 숫자의 갯수가 2의 64제곱의 숫자만큼 존재하나요?
    즉 16진수로 따졌을때 8자리가 아니게 되나요?

    2017.01.21 09:23 [ ADDR : EDIT/ DEL : REPLY ]
    • 네. 2^64 = 16^16 이니까 16진수로 16자리가 되겠네요

      2017.03.30 10:59 신고 [ ADDR : EDIT/ DEL ]
  18. 수렴

    강좌 재밌게 보고 있습니다!!!
    그런데 제가 포인터를 제대로 이해한 건지 약간 의문이 드는데
    이런 포인터를 사용해서 게임에서 나오는 맵간의 이동(이른바 포탈)을 구현하는 것인가요?

    2017.08.30 18:36 [ ADDR : EDIT/ DEL : REPLY ]
  19. 유화

    강좌 감사합니다!
    근데 저는 지금 C++을 듣고 있고, 프로그램은 C9을 쓰고 있는데 C9으로는 강좌의 예시들을 컴파일할수없나요? ㅠㅠ

    2017.10.14 16:24 [ ADDR : EDIT/ DEL : REPLY ]
    • C9 이 무슨 프로그램 인가요?

      C++ 컴파일러로 대부분의 C 코드를 컴파일 할 수 있습니다.

      2018.06.02 19:00 신고 [ ADDR : EDIT/ DEL ]
  20. mk

    * 와 & 연산자의 역할이 무엇인지 말해보세요

    - &는 변수 이름앞에 붙어서 그 변수의 주소값을 나타내줘요.

    - *는 두가지로 쓰여요. int *p; 로 쓰일때는 p를 주소값을 대입할수 있는 변수로 만들어줘요. *p로 쓰일때는 주소값에 있는 변수를 가리켜요.

    2018.06.02 02:11 [ ADDR : EDIT/ DEL : REPLY ]
  21. pikachu

    오래된 게시글이지만 도통 이해가 가지 않아서 질문을 남겨 봅니다.

    int *parr;
    parr = arr;



    int *parr = arr;

    의 차이점을 이해하지 못하겠습니다.
    때에 따라서 무엇을 집어넣냐에 따라 컴파일링이 되는 경우가 있고 안 되는 경우가 있고 하네요.

    항상 좋은 강의 감사드립니다.

    2018.08.31 20:53 [ ADDR : EDIT/ DEL : REPLY ]