원소 수와 마지막 인덱스 구별하기

길이가 다섯인 배열의 유효한 인덱스는 보통 0부터 4까지입니다. 원소 수인 5를 마지막 위치로 착각하면 반복문의 마지막 실행에서 배열 밖을 읽거나 쓰게 됩니다. 이런 오류는 메모리 바로 옆에 무엇이 놓였는지에 따라 결과가 달라집니다. 즉시 충돌할 수도 있고, 다른 변수의 값을 바꾼 뒤 한참 지나서 문제가 나타날 수도 있습니다. 디버거에서 같은 주소의 값이 정상적으로 읽힌다고 해서 배열 범위 안이라는 뜻은 아닙니다. 메모리 접근 가능 범위와 프로그램이 소유한 배열의 논리적인 범위는 다르다는 점부터 구분해야 합니다.

비어 있을 때와 하나일 때부터 재현하기

반복문을 조사할 때 큰 입력부터 넣기보다 길이 0, 길이 1, 경계 바로 아래, 경계와 같은 크기를 차례로 확인합니다. 특히 빈 입력에서 마지막 원소를 찾는다고 길이에서 1을 빼는 코드는 타입에 따라 매우 큰 값으로 바뀔 수 있습니다. 실패하는 가장 작은 크기를 찾았다면 반복문 진입 전과 마지막 반복에 집중하세요. 초기 인덱스, 비교 연산, 증가 시점 중 어디에서 한 번 더 실행되는지 확인할 수 있습니다. DBG Desk에는 조건부 중단점 UI가 없으므로 작은 재현 입력을 만들어 여러 번 멈춰도 부담이 적게 만드는 방식이 유용합니다.

문자 수와 바이트 수를 섞지 않기

문자열 처리에서는 배열 길이와 별개로 끝 문자 공간이 필요할 수 있습니다. C 문자열의 널 종료 문자를 고려하지 않고 데이터 길이만큼만 할당하면 끝을 기록할 때 한 바이트를 넘길 수 있습니다. 한글처럼 여러 바이트로 표현되는 문자열은 화면에 보이는 글자 수와 실제 저장되는 바이트 수도 다릅니다. 또한 배열을 함수에 넘기면서 포인터로 바뀐 뒤 sizeof를 사용하면 원래 배열 전체 크기를 얻지 못하는 경우가 있습니다. 길이를 계산하는 코드가 어느 범위에서 실행되는지, 변수의 실제 타입이 무엇인지 소스와 함께 확인해야 합니다.

수정 후에는 경계의 양쪽을 확인하기

비교 연산을 작거나 같다에서 작다로 바꾸는 수정만으로 모든 경계 문제가 끝나는 것은 아닙니다. 함수가 받는 길이가 원소 수인지 마지막 인덱스인지부터 호출자와 일치해야 합니다. 한쪽에서 마지막 인덱스를 넘기고 다른 쪽에서 개수로 사용하면 조건을 바꿔도 일부 입력이 누락될 수 있습니다. 실패 입력에서 정확히 몇 번 반복되어야 하는지 적고 실제 반복 횟수를 비교하세요. 수정 뒤에는 빈 배열과 한 원소 배열, 일반 크기, 최대 허용 크기를 다시 확인합니다. 메모리 오류 검사 도구를 함께 사용할 수 있다면 범위를 넘는 순간을 더 빠르게 찾을 수 있습니다.

반복 횟수를 손으로 먼저 적기

길이가 3인 입력에서는 유효한 인덱스가 0, 1, 2라는 기대를 먼저 적습니다. 실제 루프가 0, 1, 2, 3까지 도달했다면 마지막 주소를 계산하기 전에 반복 조건이 한 번 더 허용한 이유를 확인하세요. 시작 인덱스가 1인 설계라면 반대로 첫 원소를 의도적으로 건너뛰는지 점검해야 합니다. 코드에서 숫자 하나를 바꾼 뒤 기대값을 그에 맞춰 바꾸는 방식은 검증이 아닙니다. 먼저 정한 데이터 계약과 실행 결과를 비교하세요. 경계를 포함하는 범위인지 제외하는 범위인지 함수 이름이나 인수 설명에 드러내면 호출자와 구현이 서로 다른 기준을 쓰는 실수도 줄어듭니다.