Programming🧑💻/Cpp
포인터도 타입이 필요한 이유
생각 깎는 아이
2025. 1. 31. 12:33
포인터 연산
포인터 연산에서 중요한 점은 포인터의 타입에 따라 실제 증감되는 메모리 주소의 크기가 달라진다는 것입니다.
char* ptr1 = (char*)1000; // char는 1바이트
int* ptr2 = (int*)1000; // int는 4바이트
double* ptr3 = (double*)1000; // double은 8바이트
ptr1++; // 주소값: 1001
ptr2++; // 주소값: 1004
ptr3++; // 주소값: 1008
- char 포인터는 1바이트씩 증가
- int 포인터는 4바이트씩 증가
- double 포인터는 8바이트씩 증가
즉, ptr++ 연산을 수행할 때 실제로는 다음과 같은 계산이 이루어집니다.
새로운주소 = 현재주소 + (sizeof(포인터타입) * 1)
포인터 타입을 제한하는 이유
C++에서는 int 타입의 변수는 int* 타입의 포인터에, char 타입의 변수는 char* 타입의 포인터에만 저장할 수 있도록 제한합니다.
포인터가 단순히 메모리 주소만을 저장하는데 왜 이런 제한이 필요할까요?
이는 포인터의 역참조(Dereferencing) 연산과 관련이 있습니다.
역참조를 통해 포인터가 가리키는 메모리 주소의 값을 읽거나 수정할 때, 시스템은 해당 메모리 위치에서 얼마만큼의 바이트를 읽어야 할지 알아야 합니다.
int main() {
// 1. int 변수 선언 및 초기화
int a = 1025; // 이진수로 00000000 00000000 00000100 00000001
// 2. int 포인터로 접근
int* p_int = &a;
cout << "Value using int pointer: " << *p_int << endl; // 출력: 1025
// 3. char 포인터로 잘못 접근하는 경우
char* p_char = (char*)&a;
cout << "Value using char pointer: " << (int)*p_char << endl; // 출력: 1
return 0;
}
int a = 1025
- int 타입은 일반적으로 4바이트(32비트) 메모리를 할당받습니다
- 1025는 이진수로 00000000 00000000 00000100 00000001로 저장됩니다
int* p_int = &a
- p_int는 a의 메모리 주소를 저장합니다
*p_int
로 역참조할 때 시스템은 이 주소에서 4바이트를 읽습니다- 따라서 올바른 값 1025를 얻을 수 있습니다
char* p_char = (char*)&a
- char 포인터로 캐스팅하면 시스템은 이 주소에서 1바이트만 읽습니다
- 첫 번째 바이트인 00000001만 읽게 되어 값 1을 얻게 됩니다
이처럼 포인터 타입은 역참조 시 얼마만큼의 메모리를 읽어야 하는지를 결정합니다. 잘못된 타입의 포인터를 사용하면 데이터를 부분적으로만 읽거나, 잘못된 방식으로 해석할 수 있습니다.
void 포인터
예외적으로 C++에는 모든 타입의 주소를 저장할 수 있는 특별한 포인터가 있습니다. 바로 void 포인터(void*)입니다.
int num = 10;
char ch = 'A';
double pi = 3.14;
// void 포인터는 어떤 타입의 주소든 저장 가능
void* ptr;
ptr = # // int 주소 저장
ptr = &ch; // char 주소 저장
ptr = π // double 주소 저장
하지만 void 포인터는 다음과 같은 중요한 제약사항이 있습니다
1. 직접 역참조가 불가능합니다
void* ptr = &a
*ptr; // 컴파일 에러!
2. 포인터 연산을 할 수 없습니다
void* ptr = #
ptr++; // 컴파일 에러!
이러한 제약이 있는 이유는 앞서 설명했던 것처럼 시스템이 메모리에서 얼마만큼의 크기를 읽어야 할지 알 수 없기 때문입니다.
따라서 void 포인터를 사용할 때는 반드시 적절한 타입으로 변환 후 사용해야 합니다
int num = 42;
void* void_ptr = #
// int 포인터로 캐스팅 후 사용
int* int_ptr = static_cast<int*>(void_ptr);
cout << *int_ptr << endl; // 42 출력