포인터는 메모리를 사용하는 또 다른 방법입니다.
주소 연산자로 변수가 할당된 메모리의 위치를 확인할 수 있습니다.
포인터로 가리키는 변수를 사용할 때 간접참조 연산자를 사용합니다.
포인터 연산자
주소 연산자 | & | 변수 앞에 붙여 사용하며 변수가 할당된 메모리의 시작 주소값을 구한다. |
포인터 | * | 시작 주소값을 저장하는 변수며 가리키는 자료형을 표시하여 선언한다. 자료형 또는 변수명에 ‘*’을 붙여서 선언한다. |
간접 참조 연산자 | * | 포인터에 사용하며 포인터가 가리키는 변수를 사용한다. 선언된 포인터 변수에 ‘*’을 붙여서 사용한다. |
포인터 기본 개념
주소는 변수가 할당된 메모리의 시작 주소를 사용합니다.
포인터를 선언할 때는 저장할 주소가 어떤 변수의 주소인지 그 자료형을 적습니다.
포인터가 가리키는 변수를 사용할 때는 간접 참조 연산자를 사용합니다.
포인터에 간접 참조 연산자를 사용한 결과는 가리키는 변수와 완전히 같습니다.
포인터에 const를 사용하면 가리키는 변수의 값을 바꿀 수 없습니다. 포인터를 통해서만 못바꾸고 변수 자체는 바꿀 수 있습니다.
주소와 포인터의 크기
모든 주소와 포인터는 가리키는 자료형과 관계없이 크기가 같습니다.
#include <stdio.h>
int main(void)
{
char ch;
int in;
double db;
char* pc = &ch;
int* pi = ∈
double* pd = &db;
printf("char형 변수의 주소 크기 : %d\n", sizeof(&ch));
printf("int형 변수의 주소 크기 : %d\n", sizeof(&in));
printf("double형 변수의 주소 크기 : %d\n\n", sizeof(&db));
printf("char* 포인터의 크기 : %d\n", sizeof(pc));
printf("int* 포인터의 크기 : %d\n", sizeof(pi));
printf("double* 포인터의 크기 : %d\n\n", sizeof(pd));
printf("char* 포인터가 가리키는 변수의 크기 : %d\n", sizeof(*pc));
printf("int* 포인터가 가리키는 변수의 크기 : %d\n", sizeof(*pi));
printf("double* 포인터가 가리키는 변수의 크기 : %d\n\n", sizeof(*pd));
return 0;
}
실행결과 |
char형 변수의 주소 크기 : 4 int형 변수의 주소 크기 : 4 double형 변수의 주소 크기 : 4 char* 포인터의 크기 : 4 int* 포인터의 크기 : 4 double* 포인터의 크기 : 4 char* 포인터가 가리키는 변수의 크기 : 1 int* 포인터가 가리키는 변수의 크기 : 4 double* 포인터가 가리키는 변수의 크기 : 8 |
포인터의 대입 규칙
포인터는 가리키는 변수의 형태가 같을 때만 대입해야 합니다.
#include <stdio.h>
int main(void)
{
int a = 10;
int* p = &a;
double* pd;
pd = p;
printf("%lf\n", *pd);
return 0;
}
실행결과 |
-92559592117432107884277659021957555520241347761778250032873472.000000 |
위 예제는 double형 포인터 변수에 int형 포인터 변수를 대입하였습니다. 이 상태에서 간접참조 연산자(*)로 가리키는 변수를 출력하면 쓰레기값처럼 이상한 값이 출력됩니다.
그 이유는 double형 포인터가 참조하는 변수는 크기를 8바이트로 인식합니다. 하지만 지금은 int형 변수를 가리키고 있고 int형 변수의 크기는 4바이트 입니다.
int형 변수보다 큰 8바이트 영역(double형)을 해석하므로 알 수 없는 결과를 출력합니다.
그러나 형변환을 사용한 포인터의 대입은 언제나 가능합니다.
하지만 같은 두 포인터가 같은 공간을 공유하므로 어떤 경로를 통해서든 값이 변할 수 있으니 주의해야 합니다.