왜 배열의 색인 생성이 1이 아닌 C에서 0으로 시작합니까?
왜 배열의 색인 생성이 1이 아닌 C에서 0으로 시작합니까?
답변:
C에서 배열의 이름은 기본적으로 포인터 (그러나 주석 참조)이며 메모리 위치에 대한 참조이므로 표현식 array[n]
은 n
시작 요소에서 떨어진 메모리 위치 요소를 나타냅니다. 이는 인덱스가 오프셋으로 사용됨을 의미합니다. 배열의 첫 번째 요소는 해당 배열이 참조하는 메모리 위치 (0 개의 요소)에 정확히 포함되므로로 표시되어야합니다 array[0]
.
더 많은 정보를 위해서:
http://developeronline.blogspot.com/2008/04/why-array-index-should-start-from-0.html
sizeof arr
포인터의 크기가 아닌 배열 객체의 크기를 산출합니다.
sizeof
이거나 단항 &
연산자이거나 배열을 초기화하는 데 사용되는 문자열 리터럴 인 경우"배열 유형의 표현식 "of type"은 배열 객체의 초기 요소를 가리키고 lvalue가 아닌 "pointer to type"유형의 표현식으로 변환됩니다. 배열 객체에 레지스터 스토리지 클래스가 있으면 동작이 정의되지 않습니다. "
이 질문은 1 년 전에 게시되었지만 여기에갑니다 ...
하지만 다 익스트라의 기사 (이전에 지금은 삭제에서 참조 대답은 ) 수학적 관점에서 의미가 있습니다, 그것은 관련으로하지 않습니다 이 프로그램에 올 때.
언어 사양 및 컴파일러 디자이너가 내린 결정은 컴퓨터 시스템 디자이너가 0부터 카운트를 시작하기로 한 결정을 기반으로합니다.
대니 코헨 (Danny Cohen)의 평화 에 대한 간청 에서 인용 .
모든 b의 경우, 첫 번째 b ^ N 음이 아닌 정수는 번호가 0에서 시작하는 경우에만 정확히 N 자리 (앞의 0 포함)로 표시됩니다.
이것은 매우 쉽게 테스트 할 수 있습니다. base-2에서 2^3 = 8
8 번째 숫자는 다음과 같습니다.
111
3
비트 를 사용하여 표현할 수 있지만 1000
추가 비트 (4 비트)가 필요합니다.
컴퓨터 메모리 주소에는 비트 단위의 2^N
셀 이 있습니다 N
. 이제 1부터 계산을 시작하면 2^N
셀에 N+1
주소 줄 이 필요 합니다. 정확히 하나의 주소에 액세스하려면 추가 비트가 필요합니다. ( 1000
위의 경우). 이를 해결하는 또 다른 방법은 마지막 주소에 액세스 할 수 없게하고 N
주소 행을 사용하는 것 입니다.
둘 다 최적의N
주소 라인을 사용하여 모든 주소에 액세스 할 수있는 시작 카운트 0에 비해 차선책입니다 .
에서 시작하기로 결정한 0
이후에는 실행중인 소프트웨어를 포함한 모든 디지털 시스템에 코드가 침투 하여 기본 시스템이 해석 할 수있는 코드로 코드를 변환하는 것이 더 간단 해졌습니다. 그렇지 않은 경우, 머신과 프로그래머 사이에서 모든 어레이 액세스에 대해 불필요한 변환 조작이 하나 있습니다. 컴파일이 쉬워집니다.
논문에서 인용 :
a[b]
는 훨씬 간단하다고 생각하지만 *(a+b)
초기 컴파일러에서 와 같이 구현되었습니다 . 오늘도 2[a]
대신에 글을 쓸 수 있습니다 a[2]
. 이제 인덱스가 0에서 시작하지 않으면 a[b]
로 바뀝니다 *(a+b-1)
. 이것은 0 대신에 CPU에 2 개의 추가를 요구했을 것인데, 이는 속도의 절반을 의미합니다. 분명히 바람직하지 않습니다.
0 기반 인덱스가 허용하기 때문에 ...
array[index]
...로 구현하려면 ...
*(array + index)
인덱스가 1 기반 인 경우 컴파일러는 다음을 생성해야합니다. *(array + index - 1)
이 "-1"은 성능을 저하시킵니다.
컴파일러와 링커를 더 간단하게 만들 수 있기 때문입니다 (작성하기 쉬움).
참고 :
"... 주소와 오프셋으로 메모리를 참조하는 것은 거의 모든 컴퓨터 아키텍처의 하드웨어에서 직접 표현되므로 C의이 디자인 세부 사항으로 인해 컴파일이 더 쉬워집니다."
과
"... 이것은 더 간단한 구현을 만듭니다 ..."
배열 인덱스는 항상 0으로 시작합니다. 기본 주소가 2000이라고 가정합니다 arr[i] = *(arr+i)
. 이제이 if i= 0
의미 *(2000+0
는 배열에서 첫 번째 요소의 기본 주소 또는 주소와 같습니다. 이 인덱스는 오프셋으로 취급되므로 deaault 인덱스는 0부터 시작합니다.
같은 이유로 수요일이고 누군가가 수요일까지 며칠을 물으면 1이 아니라 0이라고 말하고 수요일이 며칠 동안 목요일까지 며칠을 물으면 2가 아니라 1을 말합니다.
0에서 시작하는 번호 매기기에 대해 읽은 가장 우아한 설명은 값이 숫자 줄의 표시된 위치가 아니라 그 사이의 공백에 저장된다는 관찰입니다. 첫 번째 항목은 0과 1 사이에 저장되고 다음 항목은 1과 2 사이에 저장됩니다. N 번째 항목은 N-1과 N 사이에 저장됩니다. 항목의 범위는 양쪽의 숫자를 사용하여 설명 할 수 있습니다. 개별 항목은 일반적으로 아래의 숫자를 사용하여 설명됩니다. 범위 (X, Y)가 주어지면 아래 숫자를 사용하여 개별 숫자를 식별하면 산술을 사용하지 않고 첫 번째 항목을 식별 할 수 있지만 (항목 X) 마지막 항목을 식별하려면 Y에서 하나를 빼야합니다 (Y -1). 위의 번호를 사용하여 항목을 식별하면 범위의 마지막 항목을 쉽게 식별 할 수 있습니다 (항목 Y 임).
위의 숫자를 기준으로 항목을 식별하는 것은 끔찍하지는 않지만 범위 (X, Y)에서 첫 번째 항목을 X 위의 항목으로 정의하면 일반적으로 아래 항목으로 정의하는 것보다 더 잘 작동합니다 (X + 1).
1 기반 행렬에서 X, Y 좌표를 사용하여 픽셀 화면에 액세스하십시오. 공식은 완전히 복잡합니다. 왜 복잡한가? X, Y 좌표를 오프셋 인 하나의 숫자로 변환하게됩니다. 왜 X, Y를 오프셋으로 변환해야합니까? 그것이 메모리가 연속적인 메모리 셀 스트림으로 컴퓨터 내부에서 구성되는 방식이기 때문입니다. 컴퓨터가 배열 셀을 처리하는 방법 오프셋 사용 (제로 기반 인덱싱 모델 인 첫 번째 셀로부터의 변위).
따라서 코드의 어느 시점에서 1 기반 수식을 0 기반 수식으로 변환하는 데 필요한 (또는 컴파일러 필요) 컴퓨터가 메모리를 처리하는 방식이기 때문입니다.
우리는 크기 5의 배열을 만들려면 가정
int 배열 [5] = [2,3,5,9,8]
배열의 첫 번째 요소는 위치 (100)에 놓고 보자
우리가 1없는에서 인덱싱 시작을 생각해 보자 0.
이제
정수의 크기가 4 비트
이므로 인덱스의 도움으로 첫 번째 요소의 위치를 찾아야합니다
(1 번째 요소의 위치는 100임을 기억하십시오) 따라서 인덱스 1을 고려하면 위치는
크기가됩니다 of index (1) * integer (4) = 4의 크기
이므로 실제 위치는 다음과 같습니다.
100 + 4 = 104입니다.
이것은 초기 위치가 100에 있었기 때문에 사실이 아닙니다.
104
가 아닌 100을 가리켜 야합니다 . 이것은
이제 0에서 인덱싱을 취한
다음
첫 번째 요소의 위치
는 index (0) * integer의 크기 여야합니다 (4) = 0
따라서->
첫 번째 요소의 위치는 100 + 0 = 100
이며 이는 요소의 실제 위치이므로
색인이 0에서 시작하는 이유입니다.
나는 그것이 당신의 요점을 분명히하기를 바랍니다.
우선 "배열 이름 자체에 배열의 첫 번째 요소 주소가 포함되어 있기 때문에"배열이 내부적으로 포인터로 간주된다는 것을 알아야합니다.
ex. int arr[2] = {5,4};
배열이 주소 100에서 시작한다고 가정하면 요소 첫 번째 요소는 주소 100에 있고 두 번째는 104에 있습니다. 배열 색인이 1에서 시작하면
arr[1]:-
이것은 포인터 식에서 다음과 같이 쓸 수 있습니다.
arr[1] = *(arr + 1 * (size of single element of array));
int의 크기가 4 바이트라고 생각하십시오.
arr[1] = *(arr + 1 * (4) );
arr[1] = *(arr + 4);
아시다시피 배열 이름에는 첫 번째 요소의 주소가 포함되므로 arr = 100입니다.
arr[1] = *(100 + 4);
arr[1] = *(104);
그것은,
arr[1] = 4;
이 표현으로 인해 공식 첫 번째 요소 인 주소 100의 요소에 액세스 할 수 없습니다.
이제 배열 인덱스가 0에서 시작한다고 가정하십시오.
arr[0]:-
이것은 다음과 같이 해결됩니다
arr[0] = *(arr + 0 + (size of type of array));
arr[0] = *(arr + 0 * 4);
arr[0] = *(arr + 0);
arr[0] = *(arr);
이제 배열 이름에 첫 번째 요소의 주소가 포함되어 있다는 것을 알고 있습니다.
arr[0] = *(100);
올바른 결과를 제공합니다
arr[0] = 5;
따라서 배열 인덱스는 항상 c에서 0부터 시작합니다.
참조 : 모든 세부 사항은 "Brian Kerninghan 및 Dennis ritchie의 C 프로그래밍 언어"책에 작성되었습니다.
배열 address
에서 오른쪽을 가리켜 야하기 때문 element
입니다. 아래 배열을 가정 해 봅시다.
let arr = [10, 20, 40, 60];
우리는 이제 주소 존재의 시작 살펴 보겠습니다 12
과의 크기 element
BE를 4 bytes
.
address of arr[0] = 12 + (0 * 4) => 12
address of arr[1] = 12 + (1 * 4) => 16
address of arr[2] = 12 + (2 * 4) => 20
address of arr[3] = 12 + (3 * 4) => 24
그것이 경우 되지 zero-based
는 기술적으로 우리의 첫 번째 요소의 주소 array
것 16
그것의 위치는 다음과 같이 잘못된 것입니다 12
.
배열 이름은 기본 주소를 가리키는 상수 포인터입니다. arr [i]를 사용할 때 컴파일러는이를 * (arr + i)로 조작합니다. int 범위가 -128 ~ 127이므로 컴파일러는 -128 ~ -1은 음수와 0 ~ 128은 양수이므로 배열 인덱스는 항상 0으로 시작합니다.
int
타입 지원 적어도 16 비트 범위에 필요한 대부분의 시스템 요즘 32 비트를 지원한다. 귀하의 논리에 결함이 있다고 생각하며 귀하의 답변은 다른 사람들이 이미 제공 한 다른 답변에서 실제로 향상되지 않습니다. 이것을 삭제하는 것이 좋습니다.