본문 바로가기
Programming

C 포인터 기초

by 나무수피아는 지식의 가지를 뻗어가는 공간입니다. 2025. 8. 16.
반응형
포인터 기초

포인터 개념

포인터는 프로그래밍에서 매우 중요한 개념으로, 메모리 주소를 저장하는 변수입니다. 일반 변수는 데이터를 직접 저장하지만, 포인터 변수는 데이터가 저장된 메모리의 위치, 즉 주소값을 저장합니다. 따라서 포인터를 사용하면 변수의 실제 메모리 위치를 참조하거나 조작할 수 있습니다. 포인터는 메모리를 효율적으로 관리하고, 함수 간 변수 값을 전달하거나 배열과 문자열을 다룰 때 매우 유용합니다.

포인터는 다양한 자료형에 대해 선언할 수 있으며, 포인터가 가리키는 데이터 타입에 따라 메모리를 해석하는 방식이 달라집니다. 예를 들어 int*는 정수형 변수를 가리키는 포인터, char*는 문자형 변수를 가리키는 포인터입니다. 포인터 자체도 메모리를 차지하며, 시스템 아키텍처에 따라 보통 4바이트(32비트) 또는 8바이트(64비트)를 사용합니다.

포인터 선언과 초기화

포인터를 선언하는 기본 문법은 다음과 같습니다:

int *ptr; // int형 데이터를 가리키는 포인터 변수

위 코드는 ptr이라는 포인터 변수를 선언한 것이며, 이는 int형 데이터의 주소를 저장할 수 있습니다. 그러나 이 상태로는 어떤 주소도 가리키지 않으므로 초기화 후 사용하는 것이 중요합니다.

포인터 초기화는 변수의 주소를 할당하는 방식입니다:

int num = 10;
int *ptr = # // num 변수의 주소를 ptr에 저장

이제 ptrnum의 메모리 주소를 가리키게 되며, 역참조 연산자를 통해 num의 값을 간접적으로 읽거나 변경할 수 있습니다.

포인터와 변수의 관계

포인터는 변수의 메모리 주소를 저장하므로 변수와 밀접한 관계가 있습니다. 포인터를 통해 변수의 값을 직접 수정하거나, 함수에 주소를 전달하여 원본 데이터를 조작할 수 있습니다.

메모리 주소 연산자 (&)

& 연산자는 변수 앞에 붙여 그 변수의 메모리 주소를 얻습니다.

int num = 10;
int *ptr = # // num 변수의 주소를 ptr에 저장
printf("num의 주소: %p\n", &num);

역참조 연산자 (*)

* 연산자는 포인터가 가리키는 메모리 공간에 접근(읽기/쓰기)할 수 있게 해 줍니다.

    int num = 10;
    int *ptr = # // num의 주소를 ptr에 저장

    printf("ptr이 가리키는 값: %d\n", *ptr); // 10 출력
    *ptr = 20; // num의 값을 20으로 변경
    printf("num의 값: %d\n", num); // 20 출력

*ptrptr이 가리키는 주소의 값을 의미하므로, 이를 변경하면 원본 num의 값도 변경됩니다.

포인터와 메모리

컴퓨터의 메모리는 연속된 바이트 공간으로 구성되며, 각 공간은 고유한 주소를 가집니다. 변수는 메모리 공간을 점유하고, 포인터는 그 공간의 주소를 저장합니다.

포인터를 사용하면 동적 메모리 할당, 배열 처리, 다양한 자료구조 구현이 가능해지며, 배열과 포인터는 특히 밀접한 관계가 있습니다.

배열과 포인터

    int arr[5] = {10, 20, 30, 40, 50};
    int *ptr = arr;

    for (int i = 0; i < 5; i++) {
        printf("ptr[%d] = %d\n", i, ptr[i]);  // 또는 *(ptr + i)
    }

배열 이름 arr은 배열의 첫 번째 요소의 주소와 같으며, ptr[i] 또는 *(ptr + i)로 배열 요소에 접근할 수 있습니다.

포인터 산술 연산

포인터는 + / - 연산을 통해 메모리 내 위치를 이동할 수 있습니다.

    int arr[5] = {10, 20, 30, 40, 50};
    int *ptr = arr;

    printf("%d\n", *(ptr + 2)); // arr[2] 값 출력 → 30

이처럼 포인터 산술은 배열 순회나 동적 자료구조 구현에 자주 사용됩니다.

포인터와 함수

포인터는 함수 인자로 자주 사용되며, 이를 통해 원본 변수에 직접 접근하거나 큰 데이터를 복사하지 않고 처리할 수 있어 효율적입니다.

포인터를 이용한 함수 인자 전달

void changeValue(int *p) {
    *p = 100;
}

int main() {
    int num = 10;
    changeValue(&num);
    printf("num의 값: %d\n", num); // 100 출력
    return 0;
}

함수에 포인터를 넘겨줌으로써 함수 내부에서 실제 변수 값을 변경할 수 있습니다.

NULL 포인터와 포인터 초기화

초기화되지 않은 포인터는 쓰레기 값을 가지므로, NULL 또는 C++에서는 nullptr로 초기화하는 것이 좋습니다.

int *ptr = NULL; // 유효한 주소가 없음을 명시

포인터를 사용할 때는 항상 NULL 여부를 검사한 후 역참조해야 안정적인 프로그램이 됩니다.

포인터 사용 시 주의사항

  • 초기화되지 않은 포인터 사용 금지: 반드시 유효한 주소나 NULL로 초기화하세요.
  • 잘못된 주소 접근 금지: 해제된 메모리나 무효한 주소 접근은 프로그램 오류를 유발합니다.
  • 포인터 산술 조심: 배열 범위를 초과하면 예기치 않은 동작이 발생할 수 있습니다.
  • 메모리 해제 필수: malloc 또는 new로 할당한 메모리는 free 또는 delete로 반드시 해제하세요.
  • NULL 검사 습관화: 역참조 전에 항상 NULL 여부를 확인하세요.

요약 및 결론

포인터는 메모리 주소를 저장하는 변수로, 변수와 함수의 값을 직접 조작할 수 있는 중요한 도구입니다. 배열, 문자열, 구조체, 동적 메모리 등 다양한 분야에서 필수적으로 사용됩니다.

포인터를 잘 사용하려면 &, * 연산자의 의미와 포인터 산술, 함수 인자 전달 방식 등을 정확히 이해해야 하며, 초기화, NULL 체크, 메모리 해제 등의 관리도 철저히 해야 합니다.

이 글을 통해 포인터의 기본 개념부터 활용법까지 체계적으로 익혀 C 언어 프로그래밍 실력을 한 단계 업그레이드하시길 바랍니다.

반응형

'Programming' 카테고리의 다른 글

C 구조체와 공용체  (60) 2025.08.18
C 파일 입출력  (53) 2025.08.17
C 배열과 문자열  (36) 2025.08.15
C 함수  (63) 2025.08.14
C 다차원 배열과 포인터  (62) 2025.08.13