본문 바로가기
CS(computer science) 지식/프로그래밍

[C언어] 문제로 풀어보는 포인트 개념

by QueryJun 2025. 10. 30.

포인터 핵심 개념

 

int *p;
  • p는 주소를 저장하는 변수(포인터)
  • *p는 p가 가리키는 값

 

int x = 10;
printf("%p", &x); // x가 저장된 메모리 주소 출력
  • &x → x의 주소

 

int x = 10;
int *p = &x;   // 포인터 변수 선언 (x의 주소 저장)
printf("%d", *p); // p가 가리키는 곳의 값 → 10

 

print 출력 결과

x x의 값 10
&x x의 주소 0x7ffeefbff45c (주소는 매번 달라짐)
p x의 주소가 저장됨 0x7ffeefbff45c
*p p가 가리키는 값(x의 값) 10
*&x 주소 → 값 10
&*p 값에 접근했다가 다시 주소 0x7ffeefbff45c

 

p == &x      // ✅같다!
*p == x      // ✅같다!
&*p == p     // ✅같다!
*&x == x     // ✅같다!

 

 

포인터 이동 (p + 1)

포인터가 가리키는 다음 요소로 이동
하지만 한 칸 이동이 그냥 +1이 아님 → 자료형 크기만큼 이동

int arr[3] = {10, 20, 30};
int *p = arr; // arr == &arr[0]

printf("%p\n", p);      // 예: 0x100
printf("%p\n", p + 1);  // 예: 0x104 (int 크기=4바이트 → +4)
printf("%p\n", p + 2);  // 예: 0x108

 

 

배열과 포인터의 차이

int arr[3] = {1,2,3};
int *p = arr;

printf("%zu\n", sizeof(arr)); // 3 * 4 = 12
printf("%zu\n", sizeof(p));   // 포인터 크기 = 8 (64bit 시스템)

 

 

이중포인터란

int x = 10;
int *p = &x;  // p는 x의 주소를 저장
int **pp = &p; // pp는 p의 주소를 저장

 

p 값이 아니라 주소를 저장
*p p가 가리키는
**p p가 가리키는 주소 안에 있는 값!

 


 

예상 문제)

1. printf 결과

int arr[5] = {1,2,3,4,5};
int *p = arr;
printf("%d", *(p+3));
 

A) 1

B) 2

C) 3

D) 4

E) 5


arr → 배열 이름은 첫 요소의 주소와 동일 → &arr[0]
p = arr; → p는 arr[0]의 주소를 가리킴
p + 3 → arr[3]의 주소를 의미
*(p + 3) → arr[3] 값을 참조 → 4
즉, 0부터 세므로
p+0 → 1, p+1 → 2, p+2 → 3, p+3 → ✅ 4

2) printf 결과

 
int x[3]={10,20,30};
int *p=x;
int a = *p++;      // (1)
int b = (*p)++;    // (2)
printf("%d %d", a, x[1]);

 

A) 10 20

B) 10 21

C) 11 20

D) 11 21

E) 20 21

*p++
후위 ++는 먼저 참조 나중에 포인터 증가
a = *p → a = 10
이후 p = p + 1 → p → x[1] (값:20)

(*p)++
이번엔 포인터가 아니라 가리키는 값 을 증가
b = *p→ b = 20
그 뒤 x[1] = 21로 변경

 


3) (가정: int는 4바이트, 포인터는 8바이트인 64비트 환경)

 
int arr[10]; int *p = arr; printf("%zu %zu", sizeof(arr), sizeof(p));

 

A) 10 8

B) 40 8

C) 40 4

D) 10 4

E) 8 40


4) 다음 중 컴파일이 되는 것은? (가정: int x=1, y=2;)

A) const int *p = &x; *p = 3;

 

B) int * const p = &x; p = &y;

 

C) const int *p = &x; p = &y;

 

D) int const * const p = &x; p = &y;

 

E) int *p = &x; const int *q = p; *q = 5;


const 오른쪽에 int(값)가 있으면, 값 수정 ❌ 주소 이동 ✅
const 오른쪽에 p(포인터 이름)이 있으면,값 수정 ✅ 주소 이동 ❌

5) printf 결과

void set(int **pp){
    static int v = 42;
    *pp = &v;
}
int *p = NULL;
set(&p);
printf("%d", *p);

A) 0

B) 1

C) 42

D) 쓰레기값

E) 컴파일 에러


6) (64비트 기준 포인터 8바이트)

void f(int a[]) { printf("%zu", sizeof(a)); }
int main(void){
    int arr[5];
    f(arr);
}

 

A) 4

B) 5

C) 8

D) 20

E) 40

 

컴파일러는 아래처럼 해석합니다
void f(int *a)

배열 이름을 넘기면 그냥 첫 요소의 주소만 전달합니다.

정답 : 8

7) printf 결과

typedef struct { int x; int y; } P;
P pt = {1,2};
P *pp = &pt;
printf("%d", pp->y);

A) 0

B) 1

C) 2

D) 주소값

E) 컴파일 에러


8) 다음 함수의 동작으로 맞는 것은?

 
int* foo(void){
    int a = 10;
    return &a;
}

A) 항상 10을 가리키는 유효한 포인터 반환
B) 메모리 누수 발생
C) 정의되지 않은 동작(댕글링 포인터)
D) 컴파일러가 자동으로 정적 영역에 올려 안전
E) 호출할 때마다 새 힙 메모리 할당

 

함수 종료 후, 이미 해제된 메모리 주소를 반환하게 됨
이를 댕글러 포인터라고 함

정의되지 않은 동작으로 어떤 결과가 나올지 모름
정답 : C

9) free(p)의 결과

int *p = malloc(3*sizeof(int));
int *q = p;
p[0]=1; p[1]=2; p[2]=3;
p++;          // 포인터 이동
free(p);      // ?


A) 정상 해제
B) 메모리 누수지만 안전
C) 컴파일 에러
D) 부분 해제되어 2개만 해제
E) 정의되지 않은 동작(잘못된 포인터로 free) 

malloc ⟶ 메모리 빌려오기
free ⟶ 메모리 돌려주기


만약 메모리를 계속 빌리기만 하고 free를 안 하면?
메모리 누수(memory leak) 발생, 프로그램 메모리 부족해짐, 시스템 느려짐

malloc으로 받은 "원래 주소"가 아닌,
포인터 이동된 주소를 free하면 오류!!

 


10) printf 결과

int add(int a,int b){ return a+b; }
int (*fp)(int,int) = add;
printf("%d", fp(2,3));


A) 2

B) 3

C) 5

D) 주소값

E) 컴파일 에러

 

함수 포인터란?
함수의 주소를 저장하는 포인터
반응형