C/Chapter08. 포인터

lullaby ·2025년 10월 1일

C언어

목록 보기
8/10
post-thumbnail

1. 포인터의 기본 개념

포인터란?

  • 주소(address)를 저장하는 변수
  • 다른 변수의 메모리 위치를 가리키는 변수
  • 변수의 이름 없이도 주소로 변수에 접근 가능

포인터 선언

데이터형 *포인터명;
int *p;      // int형 변수를 가리키는 포인터
char *pc;    // char형 변수를 가리키는 포인터
double *pd;  // double형 변수를 가리키는 포인터

핵심 포인트

  • 포인터의 크기는 데이터형에 관계없이 항상 같음 (32비트: 4바이트, 64비트: 8바이트)
  • 포인터가 가리키는 변수의 데이터형과 포인터의 데이터형이 일치해야 함

2. 포인터 연산자

주소 구하기 연산자 (&)

  • 변수의 주소를 구함
  • &변수명 → 변수의 주소 반환
  • 주의: 상수, 수식, 매크로 상수에는 사용 불가

역참조(간접참조) 연산자 (*)

  • 포인터가 가리키는 변수에 접근
  • 포인터명 → 포인터가 가리키는 변수
  • 주의: 반드시 포인터 변수 앞에만 사용 가능

3. 포인터 초기화 및 사용

초기화 방법

int a = 10;
int *p = &a;    // a의 주소로 초기화
int *q = NULL;  // 널 포인터로 초기화 (아무것도 가리키지 않음)

사용 예시

int x = 5;
int *p = &x;
*p = 20;        // p가 가리키는 변수(x)에 20 대입
printf("%d", x); // 출력: 20

4. 포인터 사용 시 주의사항

1) 초기화 필수

  • 포인터를 초기화하지 않고 사용하면 실행 에러 발생
  • 널 포인터 검사 후 사용: if(p != NULL) *p = 10;

2) 데이터형 일치

  • 포인터형과 가리키는 변수의 데이터형이 일치해야 함
  • 불일치 시 컴파일 경고 및 실행 에러 발생

5. const 포인터

3가지 형태

  1. 읽기 전용 포인터: const int *p
    • 포인터가 가리키는 값 변경 불가
    • 포인터 자체는 변경 가능
  2. 상수 포인터: int * const p
    • 포인터 자체 변경 불가 (특정 변수 전용)
    • 가리키는 값은 변경 가능
  3. 읽기 전용 상수 포인터: const int * const p
    • 포인터와 값 모두 변경 불가

6. 포인터 연산

포인터 + 정수 연산

  • p + N: p가 가리키는 데이터형 N개 크기만큼 증가된 주소
  • (p + i)는 배열에서 arr[i]와 동일한 의미

포인터 증감 연산

  • p++: 다음 데이터형 크기만큼 주소 증가
  • p--: 이전 데이터형 크기만큼 주소 감소

포인터 - 포인터 연산

  • 두 포인터 간의 거리(데이터형 개수)를 구함

7. 배열과 포인터의 관계

핵심 개념

  • 배열명 = 배열의 시작 주소
  • arr[i](arr + i)는 동일한 표현
  • p[i](p + i)는 동일한 표현

차이점

  • 배열명: 주소 변경 불가능 (상수 포인터와 유사)
  • 포인터 변수: 주소 변경 가능
  • sizeof(배열명): 전체 배열 크기
  • sizeof(포인터명): 포인터 변수 크기

8. 함수와 포인터

값에 의한 호출 vs 참조에 의한 호출

구분값에 의한 호출참조에 의한 호출
전달 방법값을 복사해서 전달주소를 전달
원본 변경불가능가능
매개변수일반 변수포인터 변수

매개변수 역할별 분류

  1. 입력 매개변수: 값에 의한 호출
  2. 출력 매개변수: 참조에 의한 호출 (포인터 사용)
  3. 입출력 매개변수: 참조에 의한 호출 (포인터 사용)

배열 전달

  • 배열은 항상 포인터로 전달
  • 배열 크기는 별도 매개변수로 전달 필요
  • 입력용 배열은 const 포인터로 선언 권장

🎯 예상 문제 및 풀이

문제 1 (기본 개념)

다음 코드의 실행 결과를 예측하시오.

int main() {
    int a = 10, b = 20;
    int *p1 = &a, *p2 = &b;

    printf("a=%d, b=%d\n", a, b);
    *p1 = *p2;
    printf("a=%d, b=%d\n", a, b);

    p1 = p2;
    *p1 = 30;
    printf("a=%d, b=%d\n", a, b);

    return 0;
}

풀이:

a=10, b=20
a=20, b=20    // *p1 = *p2; → a = b의 값
a=20, b=30    // p1 = p2; *p1 = 30; → p1이 b를 가리키므로 b = 30

문제 2 (포인터 연산)

다음 코드에서 출력되는 값들을 구하시오. (int는 4바이트)

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

printf("%d\n", *p);        // (1)
printf("%d\n", *(p+2));    // (2)
printf("%d\n", *p+2);      // (3)
printf("%d\n", *(++p));    // (4)
printf("%d\n", *p++);      // (5)

풀이:

(1) 10     // *p = arr[0]
(2) 30     // *(p+2) = arr[2]
(3) 12     // *p + 2 = 10 + 2
(4) 20     // ++p 후 *p = arr[1]
(5) 20     // *p 출력 후 p++, 현재 p는 arr[1]을 가리킴

문제 3 (함수와 포인터)

다음 함수를 완성하여 두 정수의 값을 교환하는 swap 함수를 작성하시오.

void swap(_______ x, _______ y) {
    // 함수 구현
}

int main() {
    int a = 5, b = 10;
    printf("Before: a=%d, b=%d\n", a, b);
    swap(_____, _____);
    printf("After: a=%d, b=%d\n", a, b);
    return 0;
}

풀이:

void swap(int *x, int *y) {
    int temp = *x;
    *x = *y;
    *y = temp;
}

int main() {
    int a = 5, b = 10;
    printf("Before: a=%d, b=%d\n", a, b);
    swap(&a, &b);
    printf("After: a=%d, b=%d\n", a, b);
    return 0;
}

문제 4 (배열과 포인터)

다음 중 올바른 것은? (복수 선택 가능)

int arr[10];
int *p = arr;
  1. arr[5](arr+5)는 같다
  2. p[3](p+3)은 같다
  3. arr++는 가능하다
  4. p++는 가능하다
  5. sizeof(arr)sizeof(p)는 같다

풀이:

  • 정답: 1, 2, 4
  • 1번: 맞음 (배열 표기법과 포인터 표기법은 동일)
  • 2번: 맞음 (포인터 배열 표기법과 포인터 연산은 동일)
  • 3번: 틀림 (배열명은 상수 포인터, 증감 연산 불가)
  • 4번: 맞음 (포인터 변수는 증감 연산 가능)
  • 5번: 틀림 (sizeof(arr)는 전체 배열 크기, sizeof(p)는 포인터 크기)

문제 5 (const 포인터)

다음 선언들의 의미를 설명하고, 각각에 대해 가능한/불가능한 연산을 표시하시오.

int a = 10, b = 20;
const int *p1 = &a;      // (1)
int * const p2 = &a;     // (2)
const int * const p3 = &a; // (3)

풀이:

(1) const int *p1: 읽기 전용 포인터
    - *p1 = 30;  // 불가능 **(값 변경 불가)**
    - p1 = &b;   // 가능 (포인터 변경 가능)

(2) int * const p2: 상수 포인터
    - *p2 = 30;  // 가능 (값 변경 가능)
    - p2 = &b;   // 불가능 (포인터 변경 불가)

(3) const int * const p3: 읽기 전용 상수 포인터
    - *p3 = 30;  // 불가능 (값 변경 불가)
    - p3 = &b;   // 불가능 (포인터 변경 불가)

문제 6 (배열 함수 전달)

배열의 모든 원소를 출력하는 함수를 작성하시오.

void print_array(__________, int size) {
    // 함수 구현
}

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    print_array(numbers, 5);
    return 0;
}

풀이:

// 방법 1
void print_array(int arr[], int size) {
    for(int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

// 방법 2 (동일한 의미)
void print_array(int *arr, int size) {
    for(int i = 0; i < size; i++) {
        printf("%d ", *(arr + i));
    }
    printf("\n");
}

0개의 댓글