왜 배열의 index는 0부터 시작할까?

NCOOKIE·2025년 2월 21일
0

TIL

목록 보기
2/20

여러 프로그래밍 언어들을 공부하면서, Array나 List의 인덱스가 0부터 시작하는 것은 "상식"이 되었다. 그렇지만 "왜?"라는 내용에 대한 답은 명확하게 내릴 수 없었다. 그래서 이번 기회에 알아봤다.

직관성

다음과 같은 배열이 있다고 하자.
int arr[100]

배열의 인덱스가 0부터 시작하는 이유는 컴파일러가 arr[i]를 해석하는 방식과 관련이 있다.

arr[i]*(arr+i)와도 같다. 즉, 이 arr은 배열의 주소 또는 0번쨰 인덱스의 배열 요소를 의미한다. 배열의 요소들은 메모리에서 연속적으로 저장되므로, 다음 요소의 주소는 arr + 1, 그 다음 요소의 주소는 arr + 2가 된다. 일반적으로 arr + i는 배열의 시작 요소에서 i만큼 떨어진 위치의 주소를 의미한다.

따라서, 배열의 시작 요소(0번째 요소)는 배열의 시작점에서 0만큼 떨어진 위치에 있으므로, i 값은 0이 되어야 한다. 이러한 논리를 따르다 보면, 배열의 인덱싱은 자연스럽게 0부터 시작하게 된다.

#include <iostream>
using namespace std;

int main()
{
    int arr[] = { 1, 2, 3, 4 };

    // 아래 두 구문은 완전히 같은 동작을 한다.
    cout << *(arr + 1) << " ";
    cout << arr[1] << " ";

    return 0;
}

효율성

현대 프로그래밍 언어에서는 행 우선(row-major) 순서를 사용하여 2차원 배열을 저장한다. 아래는 2차원 배열의 인덱스가 시작되는 위치에 따른 주소 계산이다.

배열의 인덱스가 1부터 시작하는 경우

&( arr[i][j] ) = address + [ ( i-1 )*n + ( j-1 ) ]*( sizeof(int) ) ]

여기서 (i-1)과 (j-1)이 추가적으로 계산되므로, 총 6개의 연산이 필요하다.

배열의 인덱스가 0부터 시작하는 경우

&( arr[i][j] ) = address + [ ( i )*n + ( j ) ]*( sizeof(int) ) ]

이 경우 (i-1)이나 (j-1) 같은 추가적인 연산이 없으므로, 총 4개의 연산만 필요하다.

위의 계산을 보면 0부터 시작하는 배열의 경우 연산 횟수가 2개 줄어든다. 이 차이는 작은 데이터에서는 미미할 수 있지만, 대규모 데이터를 처리할 때는 성능과 속도에 영향을 미칠 수 있다.

따라서, C++, Python, Java 같은 대부분의 언어들은 0부터 시작하는 인덱스를 사용하며, Lua 같은 일부 언어만 1부터 시작하는 인덱스를 사용한다.

결론

  • 1부터 시작하는 인덱스는 사용자 친화적일 수 있지만, 인덱스가 0부터 시작하는 것이 성능 면에서 더 효율적이기 때문에 널리 사용된다.
  • 행렬(Matrix), 벡터 연산, 좌표계 등은 1부터 시작하는 경우가 많기 때문에, 프로그래머가 아닌 과학/공학자들이 많이 사용하는 MATLAB과 같은 일부 언어들은 1부터 시작하는 인덱스를 채택하기도 한다.
  • 파이썬의 numpy, pandas 같은 라이브러리는 인덱스가 1부터 시작할 수 있도록 지원한다고 한다. 수학/과학 계산을 위해 비전공자들이 많이 사용하기 때문이다.

참고

profile
일단 해보자

0개의 댓글