20260516 프로그래밍기초 11주차
강의 핵심 요약 — 포인터 고급 & 캐시 최적화
이번 강의는 단순 포인터 문법이 아니라:
- 메모리 구조
- 포인터의 실제 동작 방식
- 함수 포인터
- 배열 포인터
- 캐시 최적화
- AoS vs SoA
같은 저수준 시스템 프로그래밍 관점으로 설명한 수업이었음.
1. 이중 포인터(Double Pointer)
강의 핵심:
int **
는:
포인터를 가리키는 포인터
라는 뜻임.
2. 왜 이중 포인터가 필요한가
교수 핵심 설명:
함수 내부에서 원본 포인터 자체를 바꾸기 위해 사용
핵심 문제
예를 들어:
int *p;
가 있음.
함수에:
test(p);
로 넘기면?
문제점
포인터 주소값의 복사본만 전달됨
즉:
- 원본 p 변경 안 됨
- 함수 안에서 바꿔도 원본 영향 없음
3. 그래서 필요한 것
test(&p);
즉:
포인터 변수 자체의 주소 전달
4. 교수 비유 핵심
교수 비유 꽤 중요했음 ㅋㅋ
단일 포인터
복사본 종이 전달
→ 수정해도 원본 안 바뀜
이중 포인터
원본 종이 위치 전달
→ 원본 직접 수정 가능
5. 메모리 관점
핵심 구조:
p → 실제 데이터 주소 저장
그런데:
&p → p 변수 자신의 주소
임.
이중 포인터는
p의 주소를 참조
해서:
p 자체를 수정 가능
하게 함.
6. malloc과 이중 포인터
대표 활용 예시.
void allocate(int **ptr)
형태 사용.
이유
malloc 결과를 원본 포인터에 반영해야 하기 때문
7. 동작 흐름
메인
int *myarray = NULL;
allocate(&myarray);
함수 내부
*ptr = malloc(...);
→ 원본 myarray 변경됨.
8. 함수 포인터(Function Pointer)
강의 핵심:
함수도 메모리 주소를 가진다
9. 함수 포인터 의미
함수도:
텍스트 세그먼트 메모리
에 로딩됨.
그리고:
고유 주소 존재
함.
10. 함수 포인터 역할
함수 주소 저장
해서:
실행 중 어떤 함수 호출할지 동적 결정
가능.
11. 함수 포인터 배열
핵심 문법:
int (*operations[3])(int, int);
12. 의미 해석
엄청 헷갈리는 문법인데 분해하면:
operations[3]
→ 배열 3개
(*operations[3])
→ 포인터 배열
(int,int)
→ int,int 매개변수 함수 가리킴
int
→ 반환형 int
즉:
함수를 가리키는 포인터 3개 저장 배열
13. Dispatch Table
교수 핵심:
if/switch 없이 함수 분기 가능
예
operations[0]();
operations[1]();
operations[2]();
이렇게:
- add
- sub
- mul
호출 가능.
14. 장점
인덱스만으로 함수 실행
가능.
활용
- 상태 머신
- 이벤트 시스템
- 게임 엔진
- 콜백 구조
- 비동기 처리
15. 콜백(Callback)
교수 설명:
특정 이벤트 발생 시 자동 호출
예시
- 파일 열림
- 네트워크 데이터 도착
- 버튼 클릭
- 카카오톡 메시지 도착
핵심 특징
비동기 이벤트 기반 동작
16. 포인터 배열 vs 배열 포인터
시험 단골 함정.
교수 계속 강조함.
17. 포인터 배열(Array of Pointers)
int *arr[3];
의미:
포인터 3개 저장 배열
구조
arr[0] → 주소
arr[1] → 주소
arr[2] → 주소
18. 배열 포인터(Pointer to Array)
int (*arr)[3];
의미:
3칸짜리 배열 전체를 가리키는 포인터
19. 교수 설명 핵심
괄호 위치가 핵심
왜 중요?
*arr[3]
와
(*arr)[3]
는 완전히 다름.
20. 배열 포인터 활용
대표적으로:
2차원 배열 함수 전달
에 사용.
21. 2차원 배열 전달
예:
void print(int (*mat)[3])
이유
2차원 배열은:
행 단위 크기 정보 필요
하기 때문.
22. 배열 이름의 decay
강의 핵심 개념.
배열 이름은 포인터로 붕괴(decay)
예
int matrix[2][3];
에서:
matrix
는:
첫 번째 행 주소
로 변환됨.
23. mat + 1 의 의미
엄청 중요.
교수 설명:
4바이트 증가가 아니다
이유
int (*mat)[3]
은:
3칸 배열 단위 이동
함.
따라서
3 × 4 = 12바이트
씩 이동.
24. 캐시 지역성(Cache Locality)
강의 후반 핵심.
정의:
캐시 히트율 극대화 기법
25. 왜 중요한가
CPU:
캐시 접근은 빠름
RAM 접근은 느림
목표
RAM 접근 최소화
26. 지역성(Locality) 종류
시간적 지역성
최근 사용 데이터 다시 사용 가능성 높음
공간적 지역성
인접 메모리 접근 가능성 높음
27. 2차원 배열 메모리 구조
중요.
C언어는:
행 우선(Row-Major)
저장 방식 사용.
실제 저장
[0][0]
[0][1]
[0][2]
[1][0]
[1][1]
...
순서.
28. 그래서 좋은 방식
행 우선 순회
이유
메모리가:
연속 접근
되기 때문.
29. 나쁜 방식
열 우선 순회
문제
메모리 점프 발생:
Cache Miss 증가
30. Cache Thrashing
강의 핵심 용어.
정의:
캐시 교체 비용이 계산보다 커지는 현상
결과
성능 급락
31. 행 우선 vs 열 우선
행 우선
캐시 라인 100% 활용
열 우선
캐시 로딩 후 대부분 버려짐
32. AoS vs SoA
시험 가능성 높음.
33. AoS(Array of Structures)
구조:
[X Y Z]
[X Y Z]
[X Y Z]
특징
객체 중심.
단점
특정 값만 반복 계산 시:
불필요 데이터까지 캐시 로딩
34. SoA(Structure of Arrays)
구조:
[X X X]
[Y Y Y]
[Z Z Z]
특징
데이터 중심.
장점
필요 데이터만 연속 접근 가능
→ 캐시 효율 매우 좋음.
35. volatile 키워드
강의 후반 나온 개념.
의미:
컴파일러 최적화 금지
사용하는 이유
값이:
자주 바뀌는 변수
일 경우.
예시
- 멀티스레드
- 하드웨어 레지스터
- 인터럽트
- 공유 메모리
교수 전체 핵심 메시지
이번 수업 핵심은 사실:
포인터 문법 암기
가 아니었음.
진짜 핵심은:
메모리 구조를 이해하고
CPU 친화적으로 코드를 짜라
이거였음 ㅋㅋ
시험 직전 핵심 암기
이중 포인터
int **
→ 포인터 자체 수정
함수 포인터
int (*fp)(int,int)
포인터 배열
int *arr[3]
배열 포인터
int (*arr)[3]
2차원 배열 전달
void func(int (*mat)[3])
행 우선 저장
C언어 2차원 배열은 Row-Major
좋은 순회
행 우선 순회
나쁜 순회
열 우선 순회
Cache Thrashing
캐시 교체 비용 폭증
AoS
객체 중심
SoA
데이터 중심
volatile
최적화 금지