포인터 핵심 개념
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) 컴파일 에러
함수 포인터란?
함수의 주소를 저장하는 포인터
'CS(computer science) 지식 > 프로그래밍' 카테고리의 다른 글
| [Python] 문제로 익히는 Python (0) | 2025.10.30 |
|---|---|
| [JAVA] 문제로 풀어보는 JAVA (0) | 2025.10.30 |