security
CHAPTER 87 / 96
읽기 약 2분
FUNCTION
포인터 기초: 메모리 주소의 세계
핵심 개념
포인터 선언(*)·주소 연산자(&)·역참조 — 메모리 주소가 무엇인가. swap 함수로 포인터 이해.
본문
포인터 = 주소를 담는 변수
#include <stdio.h>
int main(void) {
int x = 42;
int *p = &x; // p는 x의 주소를 저장
printf("x = %d\n", x); // 42
printf("&x = %p\n", (void*)&x); // x의 주소 (16진수)
printf("p = %p\n", (void*)p); // p의 값 = x의 주소
printf("*p = %d\n", *p); // p가 가리키는 곳의 값 = 42
*p = 100; // 역참조해서 값 변경
printf("x = %d\n", x); // 100 (x도 같이 변경됨)
return 0;
}메모리 주소 시각화
변수 x: 값 42 주소 0x7ffe1234
변수 p: 값 0x7ffe1234 주소 0x7ffe1238
↓
x를 가리킴
*p = 역참조 = "p가 가리키는 곳의 값"포인터 종류
#include <stdio.h>
int main(void) {
int i = 10; int *pi = &i;
char c = 'A'; char *pc = &c;
double d = 3.14; double *pd = &d;
// 각 포인터는 자기 타입의 주소만 저장
// int* 에 char 주소 저장 — 경고/에러
printf("int* size: %zu\n", sizeof(pi)); // 8 (64-bit)
printf("char* size: %zu\n", sizeof(pc)); // 8
printf("double* size: %zu\n", sizeof(pd)); // 8
// 포인터 자체 크기는 모두 동일 (메모리 주소 길이)
// 단, 가리키는 데이터 크기는 다름
return 0;
}NULL 포인터
#include <stdio.h>
int main(void) {
int *p = NULL; // 아무것도 안 가리킴
if (p == NULL) {
printf("p is null\n");
}
// ❌ NULL 역참조 — Segmentation fault
// *p = 10;
// ✅ 항상 NULL 검사
if (p != NULL) {
*p = 10;
}
return 0;
}swap 함수 — 포인터의 필요성
#include <stdio.h>
// ❌ 값 전달 — 변경 안 됨
void swap_bad(int a, int b) {
int tmp = a;
a = b;
b = tmp;
// 함수 안의 a, b만 바뀜 — 호출자 변수 무관
}
// ✅ 포인터 전달 — 원본 변경
void swap_good(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
int main(void) {
int x = 1, y = 2;
swap_bad(x, y);
printf("bad: x=%d y=%d\n", x, y); // 1, 2 (변경 안 됨)
swap_good(&x, &y);
printf("good: x=%d y=%d\n", x, y); // 2, 1 (변경됨)
return 0;
}배열 = 포인터?
#include <stdio.h>
int main(void) {
int arr[3] = {10, 20, 30};
// arr 자체는 첫 원소의 주소
printf("arr = %p\n", (void*)arr);
printf("&arr[0] = %p\n", (void*)&arr[0]);
// 같은 주소
// 그러나 sizeof는 다름
printf("sizeof(arr) = %zu\n", sizeof(arr)); // 12 (배열 전체)
int *p = arr;
printf("sizeof(p) = %zu\n", sizeof(p)); // 8 (포인터)
// 함수에 배열 전달 시 — 포인터로 변환됨 (sizeof 정보 손실!)
return 0;
}
// 함수 인자 — 배열 size를 명시적으로 전달
void print_array(int *arr, size_t len) {
for (size_t i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}포인터 함정
#include <stdio.h>
int *bad_function(void) {
int local = 42; // 지역 변수 — 함수 종료 시 사라짐
return &local; // ⚠️ dangling 포인터 반환
}
int main(void) {
int *p = bad_function();
// *p = ? // 정의되지 않은 동작
return 0;
}다음 챕터
CH.4 "포인터 연산" — 주소 계산의 수학.
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 C 코드의 포인터 사용을 분석해서 NULL 검사 누락 + dangling pointer 위험 위치를 보고해줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
한국 시스템 프로그래머가 자주 만나는 포인터 함정 Top 10과 디버깅 팁을 알려줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 코드베이스 전체에서 포인터 안전성을 자동 분석해서 우선 수정 위치를 만들어줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 Rust의 차용 검사기 vs C의 수동 메모리 관리, 학습 곡선 차이를 솔직히 알려줘.
⭐ 이것만 기억하세요
포인터 기초: 메모리 주소의 세계는 이 3가지만 확실히 잡으세요
1.포인터는 주소를 담는 변수 — &로 주소 얻고, *로 역참조
2.swap·배열·문자열 등 함수에 데이터를 전달할 때 포인터가 필수 (값 전달은 복사만)
3.다음 챕터 CH.4에서 포인터 연산 — 배열과 포인터의 깊은 관계
공유하기
진행도 87 / 96