20260509 프로그래밍기초 10주차
강의 핵심 요약 — 배열과 반복문(고급), 메모리 구조, 달팽이 배열
이번 강의는:
배열 = 메모리
관점으로 접근한 심화 수업이었음.
특히:
- 2차원 배열 메모리 구조
- 배열 포인터
- 배열 퇴화(Array Decay)
- 포인터 역참조
- 달팽이 배열(Snail Matrix)
- 정적 배열 vs 동적 배열
- 2차원 배열과 더블 포인터 차이
- 캐시 효율(Cache Hit Rate)
이 부분이 핵심.
1. 교수 핵심 메시지
교수가 계속 강조한 거:
배열은 단순 변수 묶음이 아니다
연속된 메모리 블록이다
즉:
int arr[5];
를:
정수 5개
로만 보면 안 되고,
메모리에 연속 저장된 구조
로 이해해야 한다는 거.
2. 달팽이 배열(Snail Matrix)
이번 강의 메인 예제.
정의:
2차원 배열을 나선형으로 채우는 알고리즘
예:
1 2 3
8 9 4
7 6 5
형태.
3. 달팽이 배열 핵심
교수 강조:
방향 전환
반복 횟수 감소
이 핵심.
4. 이동 방향 원리
순서:
오른쪽
↓
아래
↓
왼쪽
↓
위
반복.
5. limit 변수
핵심 아이디어.
처음:
5칸 이동
다음:
4칸 이동
다음:
3칸 이동
계속 감소.
6. direction 변수
강의에서 중요했던 부분.
int direction = 1;
그리고:
direction *= -1;
사용.
의미
direction = 1
증가 방향
direction = -1
감소 방향
즉:
if문 없이 방향 전환
하는 테크닉.
교수가 꽤 강조함.
7. 배열 포인터
핵심 선언:
int (*arr)[SIZE]
의미
SIZE 크기 배열을 가리키는 포인터
8. 왜 괄호가 중요한가
이건 배열 포인터
int (*arr)[SIZE]
이건 포인터 배열
int *arr[SIZE]
완전히 다름.
9. 배열 포인터를 쓰는 이유
교수 핵심 설명:
2차원 배열은 함수 전달 시
포인터로 퇴화된다(Array Decay)
10. Array Decay (배열의 퇴화)
배열은 함수에 전달되면:
배열 전체 복사 X
포인터 전달 O
됨.
교수 계속 강조함:
배열 전체가 넘어가는 게 아니다
첫 번째 주소만 넘어간다
11. 역참조(Dereference)
강의에서 중요하게 다시 설명함.
참조
p = &a;
→ p가 a 주소 가리킴
역참조
*p
→ p가 가리키는 실제 값 읽기
12. 2차원 배열 역참조
핵심 코드:
*(*(arr + i) + j)
13. 해석 과정
1단계
arr + i
→ i번째 행 이동
2단계
*(arr+i)
→ 해당 행 시작 주소
3단계
*(arr+i)+j
→ j번째 열 이동
4단계
*(*(arr+i)+j)
→ 실제 값 접근
14. Row-Major Order
중요 개념.
C언어 2차원 배열은:
행 단위(Row)로 연속 저장
됨.
예
int arr[3][3];
메모리:
1 2 3 4 5 6 7 8 9
이렇게 연속.
15. 캐시 효율(Cache Hit Rate)
이번 강의 핵심 고급 내용.
교수:
고급 프로그래머는
메모리 접근 효율도 고려해야 한다
캐시(Cache)
CPU는:
자주 쓰는 메모리를
캐시에 저장
함.
캐시 적중(Cache Hit)
필요한 데이터가:
이미 캐시에 있음
→ 매우 빠름
16. 왜 Row-Major가 성능 좋은가
연속 접근:
1 2 3 4 5
→ 캐시 효율 높음
비연속 접근:
1 6 11 16
→ 캐시 미스 증가
교수 설명:
달팽이 배열은 세로 이동 때문에
비연속 접근 발생
17. 2차원 배열 vs 더블 포인터
이번 강의 최대 핵심 중 하나.
정적 2차원 배열
int matrix[SIZE][SIZE];
메모리:
완전 연속
더블 포인터
int **arr;
메모리:
행들이 흩어져 있음
18. 왜 int** 로 받으면 안 되는가
교수 엄청 강조함.
int matrix[3][3];
를:
int **arr
로 받으면 안 됨.
이유
메모리 구조가 다름.
배열
행 단위 연속 저장
더블 포인터
포인터들의 집합
19. 발생 문제
강제로 캐스팅하면:
| 문제 | 설명 |
|---|---|
| 타입 불일치 | 컴파일 경고 |
| Segmentation Fault | 런타임 터짐 |
20. 왜 Segmentation Fault 발생?
교수 설명:
정수 값을 주소로 오해함
예:
1
을:
메모리 주소 0x00000001
처럼 잘못 해석.
당연히 터짐.
21. 더블 포인터의 진짜 용도
동적 2차원 배열
에서 사용.
구조
1단계
int **arr = malloc(...)
→ 행 포인터 배열 생성
2단계
arr[i] = malloc(...)
→ 각 행 실제 메모리 생성
22. 동적 배열 메모리 구조
정적 배열:
한 덩어리
동적 배열:
행마다 따로 malloc
즉:
메모리 여기저기 흩어질 수 있음
23. 메모리 해제
동적 배열은:
free 필수
핵심
for(i=0;i<3;i++)
free(arr[i]);
free(arr);
행 먼저 해제 후:
포인터 배열 해제
24. 교수 핵심 메시지
전체 수업 핵심:
배열 문법이 아니라
메모리 구조를 이해하라
였음.
특히:
배열 = 연속 메모리
포인터 = 주소 체계
이 관점.
시험 관점 핵심
진짜 중요:
배열 포인터
int (*arr)[SIZE]
의미 이해.
Array Decay
- 배열 → 포인터 변환
역참조
*(*(arr+i)+j)
해석 가능해야 함.
Row-Major
- 행 단위 저장
- 캐시 효율
달팽이 배열
- 방향 전환
- limit 감소
- direction *= -1
정적 배열 vs 동적 배열
| 정적 | 동적 |
|---|---|
| 연속 메모리 | 흩어진 메모리 |
| 배열 포인터 사용 | 더블 포인터 사용 |
절대 헷갈리면 안 되는 거
int matrix[3][3]
는:
int **arr
로 받으면 안 됨.
교수가 거의:
이거 많이 틀린다
급으로 계속 강조했음 ㅋㅋ