본문 바로가기
Topos Uranos

요약

지금까지 이 강좌의 모든 데이터는 저마다 자기 이름을 가진 자기 변수에 살았다. 그러나 같은 자료형의 많은 데이터, 예컨대 한 주의 기온은 하나하나가 다른 이름을 가지면 반복문으로 순회할 수 없다. 이 수업은 강좌의 첫 자료 구조인 인덱스가 있는 시퀀스를 소개한다. 같은 자료형의 원소들이 메모리의 이웃한 위치에 놓이고, 0부터 번호가 매겨진 것이다. 현대 C++에서는 std::array로 쓰며, 그 크기는 컴파일할 때 고정된다. 그 선언, 인덱스의 타입인 std::size_t, 그리고 두 가지 순회, 곧 인덱스를 쓰는 순회와 범위 기반 for 문을 쓰는 순회를 공부한다. 단원 전체를 지배하는 규칙도 세운다. 인덱스는 0과 크기 빼기 1 사이에 있으면 유효하며, 반복문 안의 각 접근에서 이 유효성을 불변식으로 정당화한다. 규칙이 지켜지지 않을 때 무슨 일이 일어나는지, 곧 정의되지 않은 동작을 보이고, [] 접근과 검사하는 접근인 .at() 함수를 비교한다. 끝으로, 남의 코드를 읽기 위해 C 배열을 소개한다.

학습 목표

  1. std::array를 선언하고 초기화하며, 인덱스와 범위 기반 for 문으로 순회할 수 있다.
  2. 반복문의 불변식으로, 각 접근에서 인덱스가 범위 안에 있음을 정당화할 수 있다.
  3. 표준이 검사하지 않는 [] 접근과 언제나 검사되는 .at() 접근을 구별하고, 각각이 언제 알맞은지 설명할 수 있다.
  4. C 배열을 쓴 코드를 읽고, std::array와 비교한 단점을 설명할 수 있다.

인덱스가 있는 시퀀스

많은 데이터, 하나의 이름

지금까지 배운 것으로 한 주 기온의 평균을 계산하려면 monday, tuesday, 이런 식으로 sunday까지 일곱 개의 변수와 일곱 항의 합이 필요하다. 한 해의 기온이라면 변수가 365개가 되고, 어떤 반복문도 그것들을 순회할 수 없다. 반복문의 본문에서 변수의 이름은 언제나 같기 때문이다. 모자란 것은 전체를 가리키는 하나의 이름과 각 원소를 가리키는 하나의 번호이며, 그 번호가 반복문이 앞으로 진행시키는 변수일 수 있어야 한다.

인덱스가 있는 시퀀스가 바로 그것이다. 같은 자료형의 원소 nn개의 모임으로, 원소들은 메모리의 이웃한 칸에 차례로 저장되고 자기 위치로 지정되며, 이 위치를 인덱스라고 한다. 수학은 이 대상을 알고 있다. 유한수열 (a0,a1,…,an−1)(a_0, a_1, \dots, a_{n-1})에서 aia_i는 자리 ii에 있는 원소를 나타낸다. 또는 대수학과 기하학 I 강좌의 벡터 같은 벡터이다. C++에서는 a[i]로 쓰며, 인덱스로는 어떤 정수 식이든 쓸 수 있다. 2, i, i + 1 같은 것이다.

왜 0부터인가

C++에서는 오늘날 대부분의 언어에서처럼 첫 원소의 인덱스가 0이고, 마지막 원소의 인덱스가 n−1n - 1이다. 이유는 변덕스러운 관례가 아니라 원소를 찾는 방식에 있다. 시퀀스가 메모리의 어떤 주소에서 시작하고 각 원소가 ss바이트를 차지한다면, 인덱스 ii의 원소는 시작 주소에 i⋅si \cdot s를 더한 주소에 있다. 따라서 인덱스는 오프셋, 곧 첫 원소에서부터 건너뛰어야 하는 원소의 개수이다. 첫 원소는 자기 자신에게서 0번 건너뛴 곳에 있다.

여기서 이 단원 전체를 지배하는 정의가 나온다. 원소 nn개의 시퀀스에서 인덱스 ii는 0≤i<n0 \leq i < n일 때, 그리고 그때에만 유효하다. 오른쪽 부등식은 엄격하며, 시퀀스를 다룰 때 가장 흔한 오류, 곧 하나 차이 오류의 근원이다. i≤ni \leq n으로 써 버리는 것(올바르게는 i<ni < n), 또는 1부터 시작해 버리는 것(올바르게는 0부터)이다. nn과 같은 인덱스는 마지막 원소가 아니라, 시퀀스 바로 뒤에 있어 시퀀스에 속하지 않는 칸을 가리킨다.