[C++] 포인터에 대해서

오늘 날씨는 야옹·2024년 9월 30일
0

C++

목록 보기
8/8

아 오늘 자료구조 수업을 들었는데
포인터에 대해서 굉장히 자세하게 알려 주셨다
나름 재미있었어서 복습겸 정리


▶ Pointer Variable: 변수의 주소를 저장하는 변수

  • address-of operator &: 주소값을 저장
  • * : pointer variable을 의미하기도 하고, pointer 변수 앞에 쓰이면 Dereferencing
    (해당 포인터를 쫓아가서 원하는 Object를 얻음.)

만약 cout << ptr을 하면, 2000이 출력될 것이고
cout << *ptr을 하면 Dereferencing을 하여 12를 출력할 것임.

int a = 12;
int *p1 = &a
int **p2 = &p1

cout << *p1;
cout << **p2;

Dereferencing 횟수는 몇 번 쫓아가면 원하는 Object가 있는지를 의미함.
그래서 p2를 통해 a를 출력하고 싶다면, Dereferencing을 두 번 붙이면 된다.

cf. 아래 코드에서, q는 pointer가 아니다. 가장 가까이 있는 p만 pointer이다.

int *p, q


▶ 포인터 크기와 타입

int ptr; // integer 변수의 주소를 저장함
char
q; // character 변수의 주소를 저장함

위의 두 포인터는 다른 Type의 변수 주소를 저장하지만
사실 포인터의 크기는 모두 동일하다
어차피 주소를 저장하는 데 타입이 뭐가 중요해

(실제로 찾아보니 컴파일러의 설정에 따라 포인터 변수의 크기가 달라지는 것 같다.
16bit에서는 2바이트, 32bit에서는 4바이트, 64bit에서는 8바이트)

그러나 최종적으로, 그 포인터를 따라가서 해당 주소에 무슨 타입이 있는지 알기 위해서 표기한다.

int a[2] = { ... };
int *p = &a;

float b[2] = { ... };
float *q = &b;

이 상태에서 p++, q++를 한다면?
두 표기법 모두 배열의 두 번째 원소를 접근하는 코드이다.
그러나 p는 int 크기만큼, q는 float 크기만큼 더해져야 한다.
때문에 포인터에 type을 표기하는 거임.


▶ void 포인터 (Generic 포인터)

void *q

최종적으로 뭘 가리키고 있는지 모르겠다는 포인터
그 어떤 타입이든 객체든 가리킬 수 있는 포인터 (심지어는 함수도 가능)

어떤 것이든 주소값만 대입하면 된다.

int a = 10;
float b = 10.1f;

void *aPtr = a;
void *bPtr =
b;

그러나 사용할 때에는 조심해야 함. 이 포인터가 어떤 타입을 가리키는지 모르기 때문.
최종적으로 무슨 type이 되었는지 알려 주고 사용해야 함.

cout << *(int*)aPtr => (int*)로 형변환
cout << *(float*)bPtr => (float*)로 형변환


▶ 함수형 포인터

void print() { ... }

void (*funcPtr)(int);
funcPtr = print;
funcPtr(); // print 함수 실행

포인터는 함수도 가리킬 수 있음.
선언할 때에는 반환형과 인수를 명시해 주면 된다.

그리고 이런 함수형 포인터는 typedef를 이용하여 자료형으로 만들 수도 있음.

typedef void(*funcPointer)(void);
funcPointer p = print;

마지막으로, void 포인터는 함수도 가리킬 수 있다고 하였다.
void 포인터를 생성하여 함수를 가리킨 후, 나중에 함수 포인터로 형변환하면 됨.

typedef void(*funcPointer)(void);
...
void* ptr;
ptr = print;
((funcPointer)ptr)(); // 함수 포인터로 형변환하여 함수 호출


▶ Null 포인터

원래 Null은 어떤 특정한 이 아니라 "아무것도 가리키지 않겠다"라는 symbol이었음.
그래도 일단 정의해야 하니 #define NULL 0 을 했는데...
그래서 NULL + 3과 같은 연산도 가능함. 이런 목적으로 만든 게 아닌데...

때문에 cpp에서는 자체적으로 연산을 막는 nullptr을 사용할 수 있음.


참조

0개의 댓글