포인터(Pointer)란 메모리의 주소 값을 담고있는 변수 혹은 상수이다. 다른 말로, 데이터의 위치를 가리키는 인자라고 할 수도 있다. 의외로 간단해 보일지도 모르겠지만 주소 값과 관련이 있어 메모리의 주소체계를 이해하지 못하면 포인터를 정확히 이해할 수 없다. 여기서 주소란 그 메모리의 저장장소의 위치를 나타내는 값으로 하나의 주소값은 1바이트 크기의 메모리 공간을 표현한다.
<한 블럭(주소)당 1바이트의 메모리 공간 차지, 한개의 주소는 8개의 비트가 묶임>
그렇다면 16비트의 주소 값의 범위는 어디까지 일까요? 2의 16은 65,535이므로 16비트로는 총 65536개의 바이트에 주소를 부여할수 있게 된다. 만약 주소값의 시작이 0번지 부터라면 65535번지까지 주소를 부여할 수 있습니다. 32비트 같은 경우에는 2의 32승, 최대 4,294,967,296(4GB) 바이트까지 주소를 부여할수 있게 되는것이다.
결과:
num의 저장 위치: 0x22ff44
num1의 저장 위치: 0x22ff40
num2의 저장 위치: 0x22ff3c
계속하려면 아무 키나 누르십시오 . . .
10, 11, 12행에서 변수명 앞에 & 연산자를 붙여주어 그 변수의 주소값이 반환되고 16진수의 형태로 출력한다는 의미다. %x는 16진수로 출력시킬때 사용하는 출력 포맷이고, 그 가운데에 들어간 #를 제외하면 앞에 0x가 붙지 않습니다. & 연산자는 '어떤 변수의 주소를 알아내는 역할' 도 하는 연산자이며 상수는 메모리에 위치하지 않으므로 주소가 없으며 & 연산자를 사용할 수 없다.
포인터 변수를 이용하면 프로그램이 간결하고 효율적이며 그 포인터가 가리키는 변수의 자료형에 따라 타입을 맞추어 선언해야 한다. 다음은 포인터 변수에 관한 예제이다.
#include <stdio.h> int main() { int num, num1, num2; num=50; num1=72; num2=94; printf("num의 저장 위치: %#x\n", &num); printf("num1의 저장 위치: %#x\n", &num1); printf("num2의 저장 위치: %#x\n", &num2); return 0; }
결과:
변수 Number의 값: 50
변수 Number의 주소값: 0x22ff44
변수 Number의 값: 60
계속하려면 아무 키나 누르십시오 . . .
앞에서 말했듯이, 포인터 변수는 주소값만 저장할 수 있습니다. 지금까지 우리가 배운 * 연산자의 기능은 곱셈을 할때 사용하거나, 포인터 변수 선언시에도 사용되었다. 그런데 14행에서의 * 연산자는 무슨 기능을 할까? 이것은 간접 참조 연산자로 단항 연산자로 사용되면 이 포인터가 가리키는 메모리 공간의 접근을 의미한다. 즉, 14행의 문장에서는 pNumber이 가리키는 변수 Number를 의미하며 이것은 'Number=60'과 동일한 기능을 합니다. 이 간접 참조 연산자는 포인터 변수를 초기화 하고 사용해야 한다.
주의할 점은 여러개의 포인터 변수를 한번에 선언할때 변수마다 *를 붙여주어야 한다.
1 |
|
아래와 같이 선언해버리면, b와 c는 정수형 포인터가 아닌 정수형 변수가 되어버린다.
1 |
|
한번, 포인터와 포인터를 서로 더하고 뺀 후의 결과를 출력하는 예제를 보도록 합시다.
#include <stdio.h> int main() { char Array[]="Pointer Array"; char *pArray1, *pArray2, *pArray3; pArray1=&Array[0]; pArray2=&Array[11]; pArray3=(char *)((unsigned)pArray1+(unsigned)pArray2); // 아무 의미가 없음! printf("Array1의 주소 값: %#x\n", pArray1); printf("Array2의 주소 값: %#x\n\n", pArray2); printf("Array1과 Array2의 주소를 더한 값: %#x\n", pArray3); printf("Array1(%c)과 Array2(%c)의 거리: %d\n", *pArray1, *pArray2, pArray2-pArray1); return 0; }
결과:
Array1의 주소 값: 0x22ff30
Array2의 주소 값: 0x22ff3b
Array1과 Array2의 주소를 더한 값: 0x45fe6b
Array1(P)과 Array2(a)의 거리: 11
계속하려면 아무 키나 누르십시오 . . .
10행의 포인터끼리의 덧셈 연산은 아무 의미도 없다. (포인터 끼리의 곱셈 또는 나눗셈도 포함한다). 그렇지만 뺄셈은 가능합니다. 포인터 끼리의 뺄셈은 두 포인터 간의 거리를 나타냅니다. 14행에서 P와 a의 거리는 11이며, 그 사이에 'o', 'i', 'n', 't', 'e', 'r', ' ', 'A', 'r', 'r'가 존재함을 확인할 수 있습니다.
만약, 포인터에 정수를 더하거나 빼는 문장을 거친다면 어떤 결과가 출력될까요?
#include <stdio.h> int main() { char *pc; int *pi; double *pd; pc=(char *)100; pi=(int *)100; pd=(double *)100; printf("pc 증가 전: %d\n", pc); printf("pi 증가 전: %d\n", pi); printf("pd 증가 전: %d\n\n", pd); pc++; pi++; pd++; printf("pc 증가 후: %d\n", pc); printf("pi 증가 후: %d\n", pi); printf("pd 증가 후: %d\n", pd); return 0; }
결과:
pc 증가 전: 100
pi 증가 전: 100
pd 증가 전: 100
pc 증가 후: 101
pi 증가 후: 104
pd 증가 후: 108
계속하려면 아무 키나 누르십시오 . . .
결과를 보시면 char는 1, short는 2, int는 4, float는 4, double는 8로 포인터의 자료형의 크기만큼 증가한다는 것을 알수 있다. 만약에 2 이상의 수를 더한다면 '포인터가 가리키는 변수 데이터 타입의 크기 * 정수' 만큼 증가가 되는걸 보실수 있습니다. 뺄셈도 이와 마찬가지다.
포인터에 덧셈과 뺄셈을 하는것 말고도, 포인터끼리의 비교도 가능하다.
#include <stdio.h> int main() { int Num1, Num2; int *pNum1, *pNum2; pNum1=&Num1; pNum2=&Num2; if(pNum1!=NULL) printf("pNum1은 NULL이 아닙니다.\n"); if(pNum1!=pNum2) printf("pNum1과 pNum2은 다릅니다.\n"); if(pNum1<pNum2) printf("pNum1은 pNum2보다 앞에 있습니다.\n"); else printf("pNum1은 pNum2보다 뒤에 있습니다.\n"); return 0; }
pNum1은 NULL이 아닙니다. pNum1과 pNum2은 다릅니다. pNum1은 pNum2보다 뒤에 있습니다. 계속하려면 아무 키나 누르십시오 . . .
참고로, 11행에서의 비교는 pNum1이 널 포인터(NULL Pointer)인지를 확인하기 위해서 이다. 널 포인터는 아무곳도 가리키지 않는 포인터를 말한다.
포인터 배열(Pointer Array)란 말 그대로 포인터 변수로 이루어진 배열을 말하는 것이며 포인터 배열의 선언방식은 우리가 알고있는 배열 선언방식과 크게 다르지 않다.
#include <stdio.h> int main() { int num1, num2, num3; int *pNumArray[3]={&num1, &num2, &num3}; int i; for(i=0; i<3; i++) scanf("%d", pNumArray[i]); printf("입력된 숫자는 각각 %d, %d, %d 입니다.\n", *pNumArray[0], *pNumArray[1], *pNumArray[2]); return 0; }
결과:
4
5
7
입력된 숫자는 각각 4, 5, 7 입니다.
계속하려면 아무 키나 누르십시오 . . .
6행에서 길이가 3인 포인터 배열 pNumArray를 선언후 각각 num1, num2, num3의 주소값으로 초기화 시켰다.
01 #include <stdio.h> 02 #include <stdlib.h> 03 #define MAX 5 04 05 int main() 06 { 07 int i = 10; 08 int *p; 09 10 p=&i; 11 printf("i = %d\n", i); 12 13 *p = 20; 14 printf("i = %d\n", i); 15 16 system("pause"); 17 return 0; 18 }