OPEN HYPER STEP
← 목록으로 (화이트햇 보안)
SECURITY · 88 / 96
security
CHAPTER 88 / 96
읽기 약 2
FUNCTION

포인터 연산: 주소 계산의 수학


핵심 개념

포인터 덧셈·뺄셈 — arr[i] == *(arr+i). sizeof와 메모리 레이아웃 시각화.

본문

포인터 산술

C📋 코드 (17줄)
#include <stdio.h>

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

    // 포인터 + 정수
    printf("%d\n", *p);       // 10 (arr[0])
    printf("%d\n", *(p+1));   // 20 (arr[1])
    printf("%d\n", *(p+2));   // 30 (arr[2])

    // 사실 arr[i]는 *(arr+i)의 syntactic sugar
    printf("%d\n", arr[3]);   // 40
    printf("%d\n", *(arr+3)); // 40 — 동일

    return 0;
}

주소 계산 — 타입 크기 만큼

C📋 코드 (23줄)
#include <stdio.h>

int main(void) {
    int    iarr[3];
    char   carr[3];
    double darr[3];

    int    *pi = iarr;
    char   *pc = carr;
    double *pd = darr;

    printf("pi   = %p\n", (void*)pi);
    printf("pi+1 = %p\n", (void*)(pi+1));  // +4 (sizeof int)

    printf("pc   = %p\n", (void*)pc);
    printf("pc+1 = %p\n", (void*)(pc+1));  // +1 (sizeof char)

    printf("pd   = %p\n", (void*)pd);
    printf("pd+1 = %p\n", (void*)(pd+1));  // +8 (sizeof double)

    // 포인터+1 = 주소 + sizeof(타입)
    return 0;
}

포인터 차이

C📋 코드 (15줄)
#include <stdio.h>

int main(void) {
    int arr[10];
    int *p1 = &arr[2];
    int *p2 = &arr[7];

    ptrdiff_t diff = p2 - p1;  // 5 (원소 단위)
    printf("diff = %td\n", diff);

    // 바이트 차이 — 포인터를 캐스팅
    printf("byte diff = %td\n",
           (char*)p2 - (char*)p1);  // 20
    return 0;
}

sizeof 연산자

C📋 코드 (27줄)
#include <stdio.h>

struct Point {
    int x;
    int y;
    double z;
};

int main(void) {
    int    i = 0;
    double d = 0;
    char   arr[10];
    struct Point pt;
    int    *p = NULL;

    printf("sizeof(int)        = %zu\n", sizeof(int));     // 4
    printf("sizeof(double)     = %zu\n", sizeof(double));  // 8
    printf("sizeof(char)       = %zu\n", sizeof(char));    // 1
    printf("sizeof(arr)        = %zu\n", sizeof(arr));     // 10
    printf("sizeof(struct Point) = %zu\n", sizeof(pt));    // 16 or padding 적용
    printf("sizeof(int*)       = %zu\n", sizeof(p));       // 8 (64-bit)

    // 배열 길이 매크로
    #define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))
    printf("ARRAY_LEN(arr) = %zu\n", ARRAY_LEN(arr));  // 10
    return 0;
}

메모리 레이아웃

C📋 코드 (20줄)
#include <stdio.h>

int main(void) {
    int arr[5] = {10, 20, 30, 40, 50};

    printf("주소         값     인덱스\n");
    for (int i = 0; i < 5; i++) {
        printf("%p   %d    arr[%d]\n",
               (void*)&arr[i], arr[i], i);
    }

    // 결과 (예시):
    // 0x7ffd1234   10   arr[0]
    // 0x7ffd1238   20   arr[1]   ← +4 바이트
    // 0x7ffd123c   30   arr[2]
    // 0x7ffd1240   40   arr[3]
    // 0x7ffd1244   50   arr[4]

    return 0;
}

배열 순회 — 4가지 스타일

C📋 코드 (34줄)
#include <stdio.h>

int main(void) {
    int arr[5] = {10, 20, 30, 40, 50};
    size_t n = sizeof(arr) / sizeof(arr[0]);

    // 스타일 1: 인덱스
    for (size_t i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 스타일 2: 포인터 산술
    int *p;
    for (p = arr; p < arr + n; p++) {
        printf("%d ", *p);
    }
    printf("\n");

    // 스타일 3: 인덱스 + 포인터 시각화
    for (size_t i = 0; i < n; i++) {
        printf("%d ", *(arr + i));
    }
    printf("\n");

    // 스타일 4: 포인터를 인덱스처럼
    p = arr;
    for (size_t i = 0; i < n; i++) {
        printf("%d ", p[i]);
    }
    printf("\n");

    return 0;
}

포인터 산술의 한계

C📋 코드 (19줄)
#include <stdio.h>

int main(void) {
    int arr[5];

    // ❌ 다른 배열 사이의 포인터 차이 — 정의되지 않음
    int other[3];
    // ptrdiff_t bad = arr - other;  // 정의되지 않은 동작

    // ❌ 배열 끝 너머 포인터 — 1단계만 정의됨
    int *end = arr + 5;        // OK (one-past-the-end)
    // int *bad = arr + 10;    // 정의되지 않음 (역참조 시 위험)

    // ⚠️ 음수 인덱스 — 정의되지 않음 (단, 의도적 트릭은 가능)
    int *p = &arr[2];
    printf("%d\n", p[-2]);  // arr[0] (정의된 동작)
    // p[-3]  // ⚠️ 배열 시작 전 — 정의되지 않음
    return 0;
}

다음 챕터

CH.5 "스택과 힙" — 메모리 영역 이해.


AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 C 코드의 배열·포인터 산술 위치를
분석해서 off-by-one 오류 가능성과
안전한 패턴을 추천해줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

한국 임베디드 개발자의 메모리 레이아웃
디버깅 사례 5가지를 알려줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 C 코드베이스에서 포인터 산술이
복잡한 위치 Top 10을 분석해서
리팩토링 가이드를 만들어줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 C/C++ 메모리 안전 도구
(ASan/MSan/Valgrind)와 실무 활용을 솔직히 알려줘.

⭐ 이것만 기억하세요
포인터 연산: 주소 계산의 수학 이 3가지만 확실히 잡으세요
1.포인터 + 1은 주소 + sizeof(타입) — 타입에 따라 점프 크기 다름
2.arr[i]는 *(arr+i)의 syntactic sugar — C에서 배열과 포인터는 동전의 양면
3.다음 챕터 CH.5에서 스택과 힙 — 메모리가 어디에 어떻게 저장되는가


공유하기
진행도 88 / 96