GREEN나무 2025. 4. 15. 20:36
728x90

8. 포인터

포인터란?

포인터(pointer)는 메모리 주소를 저장하는 변수입니다. 즉, 특정 변수의 메모리 주소를 가리키며, 이를 통해 해당 변수의 값을 간접적으로 접근하고 수정할 수 있습니다.

기본 개념

// 포인터 변수 선언 및 초기화
int* pint = nullptr; // nullptr은 0x00000000을 의미하며, 포인터가 아무것도 가리키지 않음을 나타냄
int i = 100;
// & : 변수의 주소값을 가져오는 연산자
int* pint2 = &i; // i의 주소를 pint2에 저장

// 주소를 이용한 값 변경
(*pint2) = 200; // pint2가 가리키는 변수 i의 값을 200으로 변경

// 다른 데이터 타입의 포인터
float f = 3.14f;
float* pf = &f; // f의 주소를 pf에 저장

주소의 단위는 바이트(Byte)

C++에서 메모리 주소는 16진수(HEX)로 표현됩니다. 주소 앞의 0x는 해당 숫자가 16진수임을 나타냅니다.

데이터 타입에 따른 포인터 정리

데이터 타입 포인터 타입 설명
int int* 정수형 포인터
float float* 실수형 포인터
double double* 배정밀도 실수형 포인터
char char* 문자형 포인터 (C 스타일 문자열 처리 가능)
bool bool* 불리언형 포인터
void void* 타입이 지정되지 않은 포인터 (범용 포인터)
int[] int* 정수형 배열 포인터 (배열의 첫 번째 요소 주소)
float[] float* 실수형 배열 포인터
double[] double* 배정밀도 실수형 배열 포인터
char[] char* 문자형 배열 포인터 (C 스타일 문자열)
struct MyStruct MyStruct* 구조체 포인터
class MyClass MyClass* 클래스 객체 포인터
int** int** 이중 포인터 (포인터를 가리키는 포인터)
int*& int*& 포인터에 대한 참조 (포인터 자체를 변경 가능)
int* const int* const 상수 포인터 (포인터 주소 변경 불가)
const int* const int* 상수 데이터를 가리키는 포인터 (값 변경 불가)
const int* const const int* const 상수 데이터를 가리키는 상수 포인터 (값 및 주소 변경 불가)
std::unique_ptr<int> std::unique_ptr<int> C++ 스마트 포인터 (유일한 소유권)
std::shared_ptr<int> std::shared_ptr<int> C++ 스마트 포인터 (공유 소유권)
std::weak_ptr<int> std::weak_ptr<int> C++ 스마트 포인터 (약한 참조)

 

포인터 예제 코드

✅ 코드 설명

  1. int, double, char 타입의 변수를 선언합니다.
  2. 각 변수의 주소를 포인터에 저장하여 출력합니다.
#include <iostream>

int main() {
    int a = 10;
    double b = 3.14;
    char c = 'X';

    int* ptrA = &a;
    double* ptrB = &b;
    char* ptrC = &c;

    std::cout << "변수 a의 값: " << a << ", 주소: " << ptrA << std::endl;
    std::cout << "변수 b의 값: " << b << ", 주소: " << ptrB << std::endl;
    std::cout << "변수 c의 값: " << c << ", 주소: " << static_cast<void*>(ptrC) << std::endl;
    
    return 0;
}

🔹 실행 결과 (예시)

※ 주소 값은 실행할 때마다 달라질 수 있음

변수 a의 값: 10, 주소: 0x7ffee9b2a9fc
변수 b의 값: 3.14, 주소: 0x7ffee9b2a9f8
변수 c의 값: X, 주소: 0x7ffee9b2a9f7

✅ 주요 개념 정리

  1. &변수 → 변수의 주소를 가져옴
  2. int*, double*, char* → 해당 타입의 포인터 선언
  3. static_cast<void*>(ptrC) → char*는 std::cout에서 문자열로 해석될 수 있어 void*로 변환 후 출력

🔹 배열과 포인터

📌 포인터 변수란?

C++에서 포인터(pointer) 변수는 메모리 주소를 저장하는 변수입니다. 일반 변수는 값 자체를 저장하지만, 포인터는 그 값을 어디에 저장했는지(주소) 를 저장합니다.

// 일반 변수
int normalInt = 5;

// 포인터 변수
int* pInt = nullptr;  // 아무것도 가리키지 않는 포인터

// short형 포인터
short* pShort = nullptr;

👉 nullptr은 해당 포인터가 현재 아무 메모리도 가리키지 않음을 의미합니다.


🔍 포인터 변수의 크기

자료형에 상관없이, 포인터 변수의 크기는 동일합니다. 이는 포인터가 실제로 저장하는 값이 주소(메모리 위치) 이기 때문이며, 주소는 운영체제와 아키텍처(32비트/64비트)에 따라 크기가 결정됩니다.

💻 플랫폼 포인터 크기 (byte) 포인터 크기 (bit)
32비트 Windows (x86) 4 32
64비트 Windows (x64) 8 64
32비트 Linux (x86) 4 32
64비트 Linux (x86_64) 8 64
64비트 macOS (ARM64 등) 8 64
32비트 임베디드 (ARMv7 등) 4 32
64비트 임베디드 (ARMv8 등) 8 64

🧠 참고

  • 32비트 시스템: 주소공간 2³² → 약 4GB → 포인터 크기 4byte
  • 64비트 시스템: 주소공간 2⁶⁴ → 약 18EB → 포인터 크기 8byte
int iSize = sizeof(int*);     // int형 포인터 크기 확인
int sSize = sizeof(pShort);   // short형 포인터 크기 확인

📌 둘 다 8 출력됨 (64비트 기준)


✅ sizeof와 strlen의 차이점

명령어 설명 예시
sizeof 메모리에서 차지하는 크기(byte) 반환 sizeof(int) → 4
strlen C 문자열의 문자 수(null 제외) strlen("Hello") → 5
sizeof(array) 배열 전체 메모리 크기 반환 sizeof(arr) → 20 (int[5])
string::length() 문자열의 길이 반환 s.length() → 3
string::size() length()과 동일 s.size() → 3

⚠️ 주의

  • sizeof(char*)는 포인터 크기
  • strlen(char*)은 문자열 길이
  • sizeof(arr)/sizeof(arr[0]) → 배열 요소 개수 구할 때 사용

🧪 예시 코드로 확인해보기

#include <iostream>
#include <cstring>
#include <string>

int main() {
    int a = 10;
    int* p = &a;
    char str[] = "Hello";
    std::string cppStr = "World";

    std::cout << "sizeof(int): " << sizeof(int) << "\n";          // 4
    std::cout << "sizeof(p): " << sizeof(p) << "\n";              // 8
    std::cout << "strlen(str): " << strlen(str) << "\n";          // 5
    std::cout << "sizeof(str): " << sizeof(str) << "\n";          // 6
    std::cout << "cppStr.length(): " << cppStr.length() << "\n";  // 5

    return 0;
}

🔗 포인터와 주소값

int i = 0;
int* pInt = &i;
  • &i는 변수 i의 주소값
  • *pInt는 그 주소에 저장된

📌 포인터 변수에 +1을 하면?

pInt += 1; 
  • 주소가 단순히 +1 되는 것이 아니라,
  • sizeof(int) 만큼 더해져 다음 int 위치를 가리키게 됩니다.

즉, pInt는 int*이기 때문에 포인터 연산이 해당 자료형 단위로 작동합니다.


📦 포인터와 배열

배열을 이해할 때, 포인터 개념은 필수입니다.

배열의 특징

  1. 메모리상에 연속된 공간
  2. 배열 이름 자체가 시작 주소
int iArr[10] = {};   // 모든 값 0 초기화

*iArr = 5;           // iArr[0] = 5
*(iArr + 1) = 10;    // iArr[1] = 10
iArr[2] = 3;         // 배열 인덱스 사용한 일반적 접근

💡 즉, iArr + n → 배열 시작 주소에서 n칸 떨어진 위치


📌 요약 정리

 

개념 설명
포인터 메모리 주소 저장
* 연산자 해당 주소의 값 참조
& 연산자 변수의 주소 반환
포인터 연산 자료형 크기 단위로 이동
배열 이름 배열의 시작 주소
sizeof 메모리 크기 확인
strlen 문자열 길이 확인