핵심 정리

포인터와 메모리

포인터는 메모리의 특정 위치를 가리킬 때 사용하며, 정수형으로 된 메모리 주소가 저장되어 있습니다. 포인터는 *를 사용하여 선언하며, 이미 선언된 포인터에 *를 사용하면 포인터에 저장된 메모리 주소에 접근(역참조)하여 값을 가져오거나 저장할 수 있습니다.

자료형 *포인터이름;    // 포인터 선언

*포인터;         // 포인터를 역참조하여 값을 가져옴
*포인터 = ;    // 포인터를 역참조하여 값을 저장

변수의 메모리 주소를 구할 때는 주소 연산자 &를 사용합니다. &로 구한 주소는 포인터에 할당할 수 있습니다. 즉, 포인터와 변수의 메모리 주소는 자료형이 같습니다.

포인터 = &변수;    // 변수의 메모리 주소를 포인터에 저장

포인터와 역참조 연산자 *, 주소 연산자 &의 관계를 그림으로 표현하면 다음과 같은 모양이 됩니다.

그림 포인터와 *, & 연산자의 관계

다음은 포인터에 변수의 메모리 주소를 저장하고, 포인터를 역참조하여 값을 출력하는 예제입니다.

int age = 20;

int *pointer = &age;    // 포인터를 선언하고 변수의 메모리 주소를 저장

printf("%d\n", *pointer);     // 20

포인터와 포인터 역참조를 그림으로 표현하면 다음과 같은 모양이 됩니다.

그림 포인터와 포인터 역참조

포인터와 주소의 자료형

int *a;는 pointer to int라고 읽으며, *a와 같이 변수를 역참조하면 pointer to를 제거하여 int로 만듭니다.

int b;에서 &b와 같이 변수의 주소를 구한 것을 address of int라고 읽습니다. 특히 address of int는 pointer to int와 자료형이 같으므로 포인터에 주소를 할당할 수 있습니다. 즉, 포인터와 주소는 표기법만 차이가 있을 뿐 본질은 같습니다.

포인터의 자료형과 역참조

포인터는 포인터를 선언한 자료형의 크기만큼 역참조하는 크기가 결정됩니다.

char *cPtr1;          // char형 포인터 선언
*cPtr1 = 'a';         // char의 크기 1바이트만큼 역참조하여 값을 저장

short *numPtr1;       // short형 포인터 선언
*numPtr1 = 100;       // short의 크기 2바이트만큼 역참조하여 값을 저장

int *numPtr2;         // int형 포인터 선언
*numPtr2 = 100;       // int의 크기 4바이트만큼 역참조하여 값을 저장

long long *numPtr3;   // long long형 포인터 선언
*numPtr3 = 100;       // long long의 크기 8바이트만큼 역참조하여 값을 저장

void 포인터

void 포인터는 어떤 자료형으로 된 포인터든 모두 저장할 수 있습니다. 반대로 다양한 자료형으로 된 포인터에도 void 포인터를 저장할 수 있습니다. 이런 특성 때문에 void 포인터는 범용 포인터라고 합니다. 단, 자료형의 크기가 정해지지 않았으므로 역참조는 할 수 없습니다.

이중 포인터

포인터도 일반 변수이므로 다른 포인터의 메모리 주소를 저장할 수 있습니다. 이때 포인터의 메모리 주소를 담고 있는 포인터를 이중 포인터라고 합니다. 이중 포인터를 선언할 때는 *를 두 개 사용하며, 역참조할 때도 *를 두 개 사용합니다.

자료형 **포인터이름;    // 이중 포인터 선언

**포인터;        // 이중 포인터를 역참조하여 값을 가져옴
**포인터 = ;    // 이중 포인터를 역참조하여 값을 저장

예를 들어 int **a;는 pointer to pointer to int 입니다.

메모리 할당하기

malloc 함수를 사용하면 메모리를 바이트 단위로 할당할 수 있습니다. 단, 메모리를 할당했으면 반드시 free 함수로 메모리를 해제해야 합니다.

자료형 *포인터이름 = malloc(크기);    // 일정 크기만큼 동적 메모리 할당

free(포인터);    // 동적 메모리 해제

메모리를 특정 값으로 설정하기

memset 함수를 사용하면 메모리의 내용을 한꺼번에 특정 값으로 설정할 수 있습니다. 값을 설정하는 단위는 바이트 단위입니다.

memset(포인터, 설정할값, 크기);

널 포인터

포인터가 아무것도 가리키고 있지 않는 상태를 널 포인터(null pointer)라고 하며 포인터에 NULL을 할당하면 됩니다.

자료형 *포인터이름 = NULL;    // 포인터에 NULL 할당

잘못된 포인터 사용

포인터에는 임의의 값을 할당하면 안 됩니다. 반드시 이미 있는 변수의 메모리 주소를 구해서 할당하거나, malloc 함수로 메모리를 할당해야 합니다.

int *numPtr = 0x100;    // 잘못된 포인터 사용, 임의의 값을 할당하면 안 됨

int num1;
int *numPtr = &num1;    // 변수 num1의 메모리 주소를 포인터 변수에 저장

int *numPtr = malloc(sizeof(int));    // int의 크기만큼 동적 메모리 할당