본문 바로가기
Basic/C/C++

[C언어] 제 14 강 : 포인터의 기본적인 개념

by boxbop 2012. 1. 19.
반응형


 드디어 C언어의 '포인터'에 입문할 차례입니다.
사실 손으로 쓰면 이해하기 쉽도록 그림이라도 그리기 편할텐대 이놈의 귀차니즘이 포토샵을 켜질 않내요...... 나름 개인적인 복습이니까~ 라는 사고방식이 합리화를 시키기는 하지만 뭔가 걸리적 거리기는 합니다.

 포인터란 무엇일까?
결론적으로 포인터는 주소 값을 담고 있는 변수이다.
그렇다면 왜 굳이 포인터라는 어려운 개념을 알아야 할까? 간단합니다. 좀 더 프로그램에 깊숙히 접근해서 보다 더 자유롭게 프로그래밍을 하기 위해서 입니다.

 일반적으로 메모리는 1바이트 블록 단위로 아주 자자자자잘하게 나뉘어 있습니다. 각각의 바이트마다 고유한 주소값을 가지고 있습니다. 즉 0x11번지라고 하면 1바이트, 8개의 비트를 가리키고 있습니다.

 그럼이제 실제 프로그래밍 코드를 살펴봅시다.

 int value = 10;
 printf("변수의 저장위치는? %#x", &value);
 printf("변수 주소값의 크기는? %d",sizeof(&value));

 변수 앞에 '&'연산자를 붙여서 반환된 결과 값을 16진수의 형태로 출력합니다. '%#x' 라는 서식문자 배웠죠~? (
# : 8진수, 16진수 출력 시 각각 0과 0x를, 실수의 경우 소수점 이하 0 출력) 변수 주소값의 크기는 4가 출력됩니다. 실제 주소 값의 크기가 4바이트로 표현된다는 사실을 확인한거죠~

 포인터 변수란 포인터를 저장할 수 있는 변수입니다. 포인터 변수 선언의 규칙을 한번 살펴 봅시다. int형 변수를 선언 할 때 int value; 라고 적습니다. 이때! 이 변수의 주소 값을 저장하기 위한 포인터 변수의 선언은 다음과 같이 합니다.

            
int* value;

 이 뜻은, int형 변수의 주소 값을 저장하는 포인터 변수 value라고 생각하시면 됩니다. 이렇게 선언한 후에는

           
value = &number;

 라고 선언해주시면 number의 주소값이 포인터 변수 value에 저장됩니다.
다른 자료형도 마찬가지 입니다.

 
char* charValue;
 double* doubleValue;

 똑같죠? 근대 중요한 사실이 하나 있습니다. 각각의 자료형을 달리하여 변수의 주소값의 크기를 출력해보세요~ int형이건 char형이건 double형이건 모두 변수의 크기는 4바이트가 출력됩니다. 중요한 사실을 하나 발견했습니다.
'포인터는 상수이건 변수이건 항상 4바이트이다!!!!'라는 사실이죠. 일단은 알고 있으세요~

 변수에는 서로다른 자료형이 있듯이 포인터 변수에도 각각의 자료형이 있습니다. 그러나 이는 변수의 자료형과 포인터의 자료형은 동일합니다. 단지 '*'만 붙여주면 됩니다. char*, int*, long*, float*, double* ..등등 이처럼 포인터에도 포인터 형이 존재하죠~

 이번에는 연산자 '*' 에 대해서 알아보도록 하겠습니다. 이 연산자를 간접 참조 연산자라고 부릅니다. 이항연산자로 사용이 되면 곱셈을 의미합니다. 그러나 단항 연산자로 사용될 경우에는 포인터가 가리키는 메모리 공간의 접근을 의미합니다.

 int num = 10;
 int* ptr;

 ptr = #
 printf(" ptr이 가리키는 변수의 값 : %d", *ptr);
 printf(" num에 저장된 값 : %d", num);

 *ptr = 20;
 printf(" ptr이 가리키는 변수의 값 : %d", *ptr);
 printf(" num에 저장된 값 : %d", num);

 위와 같은 예제를 살펴봅시다. printf 문의 출력을 보면 포인터 변수 ptr앞에 연산자 '*'가 붙었습니다. 즉, 포인터 변수 ptr에 저장된 값을 참조하라는 의미입니다. ptr은 변수 num의 주소값을 가지고 있기때문에 이 주소값이 참조하는 값은 num의 값, 10이 되겠죠? *ptr = 20; 이문장은 ptr이 가리키는 변수에 20을 저장하를 의미입니다. 즉, *ptr 과 변수 num은 동일한 의미가 됩니다.

 아까 포인터의 형에 대하여 하다만 얘기를 좀 더 해봅시다. 예를들어
변수 100을 저장하기 위해 포인터 변수를 int형 char형 double형으로 선언하고 위의 예제와 같이 printf문으로 포인터 변수가 참조하는 값을 출력한다고 가정한다고 가정해봅시다. 물론 정수 100이 저장된다는 사실은 동일합니다. 그러나 저장되는 방식!!! 다시한번 ㅋㅋㅋ 저장되는 방식에는 아주아주 큰 차이가 있습니다. 즉, 포인터의 형은 포인터가 가리키는 메모리 공간의 데이터 저장 및 참조 방식을 결정한다. 아주 중요한 사실이니까 꼭 기억해두세요~

  이번에는 포인터의 형 변환에 대한 내용입니다.

 int num = 10;
 char * p =#

 이러한 코드는 정상적으로 작동됩니다. 포인터의 형을 암시적으로 변환시켜 주고 있는 모습이죠. 원래 num의 자료형은 int입니다. 때문에 int형 포인터 변수를 선언해주어 주소값을 저장해야되지만 char으로 선언했습니다. 아까 얘기했듯이 포인터 변수 자체는 무조건 4바이트, 형으로 따지면 int형이므로 크기에 따른 문제는 발생하지 않습니다. char형 포인터 변수나 int형 포인터 변수나 4바이트로 크기는 동일하다는 이야기죠. 위의 코드는 int형 변수의 주소값을 char형 포인터에 저장합니다. 때문에 원래 &num이라는 주소값은 int* 형 이지만 char*으로 변환해서 저장합니다. char * p = (char *)# 이 코드와 동일하죠 다만 괄호 내의 부분은 생략되어있는 것 뿐입니다. 마찬가지로 변수에 저장되어 있는 값에는 변함이 없으나 메모리 공간의 데이터 저장 및 참조 방식에서는 분명한 차이를 보여주게 됩니다.

 마지막으로 문자열을 참조하는 포인터에 대해서 알아보고 마치도록 하겠습니다. 일단 C언어에서 문자열을 표현하는 방식은 크게 2가지 입니다. 변수 형태로 표현하는 방식과 상수 형태로 표현하는 방식입니다.

 배열을 이용해서 선언하는 문자열은 변수 형태의 문자열이다!
char stringValue[30] = "welcome boxbop";
여기서는 char형 배열을 통해서 문자열이 표현됩니다. 각각의 문자가 각각의 배열에 요소에 저장이 되기때문에 변수 형태의 문자열이라고 합니다.

 
포인터를 이용해서 선언하는 문자열은 상수 형태의 문자열이다!
char* stringValuePtr = "welcome boxbop";
사실 이 코드를 정확하게 이해하기 위해서는 한가지 더 알아야 할 것이 있습니다. 배열로 표현되지 않은 문자열은 상수의 형태로 메모리 공간에 저장이 됩니다. 즉 'welcome boxbop'이라는 문자는 메모리에 저장이되고 문자열의 시작 주소, 즉 문자가 저장된 주소의 값이 반환 됩니다. 그럼 다음과 같겠죠~? char* stringValue = 0x12; 또 한가지! 왜 char* 형을 사용했을까요? int*형도 있고 다른 형들도 많은대? 사실 0x12가 실제로 가리키는 대상은 첫번째 문자인 char형 값인 'w'이므로 char형 포인터에 값을 저장하는 것 입니다^-^

 
반응형