배열 경계 문제는 대부분 마지막 칸을 하나 넘기는 순간 시작합니다.
- 반복문 하나가 왜 마지막 칸을 넘어가는지 찾고 있다
arr + n은 괜찮은데arr[n]은 왜 안 되는지 다시 확인하고 싶다- 문자열 버퍼에서도 같은 off-by-one이 왜 반복되는지 설명해야 한다
숏컷 코드
c
for (size_t i = 0; i < n; i++) {
arr[i] = 0;
}문법
배열은 같은 타입 원소가 연속 메모리에 놓인 블록입니다. arr[i]는 시작 주소에서 i * sizeof(arr[0])만큼 이동한 원소를 읽는 표현이라서, 인덱스 하나가 곧 주소 계산입니다.
c
int values[4] = {10, 20, 30, 40};
size_t n = sizeof(values) / sizeof(values[0]);
for (size_t i = 0; i < n; i++) {
printf("%d\n", values[i]);
}반대로 아래처럼 <=를 쓰면 마지막 반복에서 values[4]를 읽게 됩니다.
c
for (size_t i = 0; i <= n; i++) {
printf("%d\n", values[i]); // 마지막 반복에서 경계 초과
}경계 이해
포인터로는 마지막 다음 위치를 가리키는 것까지는 허용됩니다. 하지만 그 위치를 실제 원소처럼 읽거나 쓰면 안 됩니다.
c
int *end = values + n; // 가능
// int x = *end; // 불가문자열 버퍼도 같은 규칙을 따릅니다. 문자열은 문자 수뿐 아니라 널 종료 문자 '\0'를 위한 한 칸이 더 필요합니다.
c
char name[5];
strncpy(name, "abcd", sizeof(name));
name[4] = '\0';체크포인트
- 길이
n배열의 유효 인덱스는0..n-1입니다. - 순회의 기본은 거의 항상
i < n입니다. arr + n은 만들 수 있지만*(arr + n)은 읽으면 안 됩니다.- 문자열 버퍼는 문자 수와
'\0'공간을 같이 계산해야 합니다. - 함수로 넘긴 뒤에는 길이 정보가 자동으로 따라가지 않으므로 별도 길이 인자를 같이 봐야 합니다.
주의할 점
경계 초과는 바로 크래시가 나지 않을 때 더 위험합니다. "지금은 돌아가지만 옆 메모리를 조용히 덮어쓰는" 경우가 가장 흔하므로, 배열 코드는 로직보다 먼저 반복 범위와 길이 계산을 확인하는 습관이 중요합니다.
참고 링크
1 sources