ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 포인터도 타입이 필요한 이유
    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;
    }

    1. int a = 1025
      • int 타입은 일반적으로 4바이트(32비트) 메모리를 할당받습니다
      • 1025는 이진수로 00000000 00000000 00000100 00000001로 저장됩니다
    2. int* p_int = &a
      • p_int는 a의 메모리 주소를 저장합니다
      • *p_int로 역참조할 때 시스템은 이 주소에서 4바이트를 읽습니다
      • 따라서 올바른 값 1025를 얻을 수 있습니다
    3. 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 = &num;  // int 주소 저장
    ptr = &ch;   // char 주소 저장
    ptr = &pi;   // double 주소 저장

    하지만 void 포인터는 다음과 같은 중요한 제약사항이 있습니다

     

    1. 직접 역참조가 불가능합니다

    void* ptr = &a
    *ptr; // 컴파일 에러!

     

    2. 포인터 연산을 할 수 없습니다

    void* ptr = &num;
    ptr++;  // 컴파일 에러!

     

    이러한 제약이 있는 이유는 앞서 설명했던 것처럼 시스템이 메모리에서 얼마만큼의 크기를 읽어야 할지 알 수 없기 때문입니다.

    따라서 void 포인터를 사용할 때는 반드시 적절한 타입으로 변환 후 사용해야 합니다

    int num = 42;
    void* void_ptr = &num;
    
    // int 포인터로 캐스팅 후 사용
    int* int_ptr = static_cast<int*>(void_ptr);
    cout << *int_ptr << endl;  // 42 출력

     

     

    'Programming🧑‍💻 > Cpp' 카테고리의 다른 글

    콜 스택 동작을 통해 알아보는 함수 호출  (0) 2025.02.04
    포인터의 크기는 어떻게 결정될까?  (0) 2025.02.03
    이중 포인터  (0) 2025.02.01
    변수와 포인터  (0) 2025.01.30

    댓글

Designed by Tistory.