포스트

[C++] 포인터

[C++] 포인터

C++ 포인터 정리

1. 기본 포인터 (Raw Pointer)

일반적인 포인터로, 변수의 메모리 주소를 저장하고 가리킬 수 있다.

1
2
3
int x = 10;
int* ptr = &x;  // x의 주소 저장
std::cout << *ptr;  // 출력: 10 (역참조)
  • *ptr을 사용하여 포인터가 가리키는 값을 가져올 수 있음.
  • nullptr 또는 NULL로 초기화하여 쓰레기 값 방지.
1
int* ptr = nullptr;  // 안전한 초기화

2. 상수 포인터 (Pointer to Constant)

포인터가 가리키는 값 자체를 변경할 수 없도록 제한하는 포인터.

1
2
3
4
const int x = 10;
const int* ptr = &x;  // 상수 포인터 (const int*)
*ptr = 20;  // ❌ 오류! 값을 변경할 수 없음
ptr = &y;   // ✅ 다른 주소는 가리킬 수 있음

3. 포인터 상수 (Constant Pointer)

포인터가 항상 동일한 메모리 주소만 가리키도록 제한하는 포인터.

1
2
3
4
5
int x = 10;
int y = 20;
int* const ptr = &x;  // 포인터 자체가 상수
ptr = &y;  // ❌ 오류! 다른 주소로 변경 불가
*ptr = 30; // ✅ 값 변경은 가능

4. 상수 포인터 상수 (Constant Pointer to Constant)

포인터가 가리키는 값과 주소 모두 변경 불가능한 포인터.

1
2
3
4
const int x = 10;
const int* const ptr = &x;
*ptr = 20;  // ❌ 오류! 값 변경 불가
ptr = &y;   // ❌ 오류! 주소 변경 불가

5. void* 포인터 (Generic Pointer)

특정한 데이터 타입을 지정하지 않은 포인터.

1
2
3
int x = 10;
void* ptr = &x;
std::cout << *(static_cast<int*>(ptr));  // 출력: 10

6. 함수 포인터 (Function Pointer)

함수를 가리키는 포인터로, 동적으로 함수 호출 가능.

1
2
3
4
5
void hello() { std::cout << "Hello, world!"; }
int add(int a, int b) { return a + b; }

void (*funcPtr)() = hello;
funcPtr();  // 실행: Hello, world!

7. 배열 포인터 (Pointer to Array)

배열 전체를 가리키는 포인터.

1
2
3
int arr[3] = {1, 2, 3};
int (*ptr)[3] = &arr;
std::cout << (*ptr)[1];  // 출력: 2

8. this 포인터 (클래스 내부 포인터)

클래스 내부에서 객체 자기 자신을 가리키는 포인터.

1
2
3
4
class Test {
public:
    void show() { std::cout << "This address: " << this << std::endl; }
};

9. 스마트 포인터 (Smart Pointer)

C++11부터 제공되는 메모리 자동 관리 포인터.

unique_ptr (소유권 단독)

1
2
#include <memory>
std::unique_ptr<int> ptr = std::make_unique<int>(10);

shared_ptr (참조 카운트)

1
2
3
#include <memory>
std::shared_ptr<int> ptr1 = std::make_shared<int>(10);
std::shared_ptr<int> ptr2 = ptr1;  // 참조 카운트 증가

weak_ptr (순환 참조 방지)

1
2
#include <memory>
std::weak_ptr<int> weakPtr;

10. 널 포인터 (Null Pointer)

1
int* ptr = nullptr;  // 안전한 초기화

11. 메모리 주소 계산용 포인터 (Pointer Arithmetic)

1
2
3
int arr[] = {10, 20, 30};
int* ptr = arr;
std::cout << *(ptr + 1);  // 출력: 20

12. 📌 포인터 종류 정리

포인터 종류설명
기본 포인터일반적인 포인터
상수 포인터가리키는 값 변경 불가
포인터 상수포인터 주소 변경 불가
완전 상수 포인터값 + 주소 변경 불가
void* 포인터타입이 없는 포인터
함수 포인터함수를 가리키는 포인터
배열 포인터배열을 가리키는 포인터
this 포인터클래스 내에서 자기 자신 참조
스마트 포인터메모리 자동 관리 포인터
널 포인터어떤 객체도 가리키지 않는 포인터
메모리 주소 계산 포인터포인터 연산 사용

번외.

1. int* x; or int *x;

포인터 기호 ‘*‘는 자료형에 붙일까 이름에 붙일까?

정해진 답은 없고 실제도 두 가지 스타일 모두 볼 수있다. 구글 C++ 스타일 가이드에는 두 가지 스타일 모두 사용 가능 하지만, 한 파일에서 한 가지 스타일을 유지 해야 한다고 정한다.

다만, int * x이런 식으로 공백을 둘 다 주는 경우는 잘 없고 구글 스타일 가이드에서도 권장하지 않는다.

You should do this consistently within a single file. When modifying an existing file, use the style in that file.

char * c; // Bad - spaces on both sides of *

구글 C++ 스타일 가이드


참고로 char *x 형식이 전통적인 C스타일 이고 변수를 여러개 선언할때 더 직관적이다.

1
2
3
    char* a, b; // a, b 둘다 char* 처럼 보이지만 a는 char*, b는 char다.

    char *a, b; // 이런 경우는 변수명에 기호를 붙이는 것이 더 직관적일 수 있다.


하지만 두 가지 모두 혼란을 야기하기 때문에 구글 가이드에서는 한 번에 변수를 여러개 선언할때 포인터나 참조 기호가 들어가는 것을 금지 한다.

1
2
3
4
5
6
7
8
9
10
// Fine if helpful for readability.
int x, y;

int x, *y;  // Disallowed - no & or * in multiple declaration
int* x, *y;  // Disallowed - no & or * in multiple declaration; inconsistent spacing


// 최소한 이런식으로 사용하자.
int x; int *y;
int* x, int y;

결론적으로 일관성을 유지한다면 int* x; or int *x; 둘 다 괜찬다. 포인터 변수 선언은 개별로 하자.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.