왜 0부터 시작하는 배열이 표준입니까?


112

여기에서질문 은 동료 프로그래머와의 토론을 상기시켜주었습니다. 그는 0부터 시작하는 어레이는 어레이와 포인터 및 컴퓨터 하드웨어가 작동하는 방식에서 비롯된 구현 세부 사항이므로 0부터 시작하는 어레이는 1 기반 어레이로 대체해야한다고 주장했지만 이러한 종류의 물건은 더 높은 수준으로 반영되어서는 안됩니다 언어.

이제 나는 토론에 능숙하지 않아서 제로 기반 배열을 고수 해야하는 이유가 없었습니다. 어레이의 공통 시작점 0 인 이유 무엇 입니까?


n- 요소 배열에서 'n'요소가 없습니다. n- 요소 배열에는 0에서 n-1까지의 숫자 만있는 멤버가 있습니다. 따라서 1부터 시작하는 배열이 있으므로 n 요소 배열이 실제로 배열에 존재하는 n 요소를 나타내는 것이 더 좋지 않습니다.

바이트의 첫 번째 비트가 2 ^ 1이 아니라 2 ^ 0이기 때문에 0 기반 배열을 좋아합니다. 이것은 때때로 나를 도와줍니다 :)
e-MEE

예를 들어 en.wikipedia.org/wiki/… 이 목록을 보면 대부분의 도메인 별 언어가 1부터 색인을 시작하고 cs School of Think의 언어는 0으로 시작한다는 것을 알 수 있습니다. 그는이 주제에 대해 너무 많은 멍청한 토론이 이루어졌으며, 두 사람 중 한 사람과 이야기를 바꾸어 자신의 길을 바꾸려고 시도하는 것은 무의미하다는 것을 알게 될 것입니다. "1"을 방어하기 위해 전 세계 대부분의 사람들이이 것을 사용합니다. 대부분의 프로그래머는 "0"을 사용합니다. 대부분의 사람들은 프로그래머를 이해하지 못하므로 그렇게 생각하게 ...
Rook

이 질문이 StackOverflow에서 프로그래머로 마이그레이션 된 다음 믿을 수없는 것으로 닫혔습니다. 이건 바보 야
paercebal

답변:


105

Edsger W. Dijkstra의 기사 "번호가 0부터 시작해야하는 이유" 보다 강력한 주장을 제시 할 수있는 사람은 없다고 생각합니다 .


그는 몇 가지 통계를 제시하고 수학 스타일 증명을 사용했습니다. 그러나 나는 누군가가 여전히 논쟁 할 수 있다고 확신합니다. 나는 승인하지만 그렇게하지 않을 것입니다.

6
Dijkstra의 기사는 스타일에 관한 것이지만, 그의 주장은 단순성과 사용 편의성에 관한 것입니다 ... +1.
paercebal

80

권위 주장

글쎄요 .. 최근 언어를 포함한 대부분의 언어는 0부터 시작합니다. 이 언어는 숙련 된 사람들이 작성 했으므로 친구는 틀렸어 야합니다 ...

왜 하나?

왜 1이 0보다 나은 시작 색인입니까? 왜 2 또는 10이 아닌가? 답 자체는 흥미 롭습니다. 왜냐하면 사람들이 아이디어를 변호하는 과정에 대해 많은 것을 보여주기 때문입니다.

번째 주장은 그것이 더 자연 스럽다는 것 입니다 . 첫 번째 는 적어도 대부분의 사람들에게 보통 다른 보다 먼저 있기 때문 입니다 ...

번호 - 하나 개의 인수는 마지막 인덱스는 배열의 크기이다 ...

나는 이런 종류의 논쟁에 대해 일반적으로 듣는 이유의 "품질"에 여전히 깊은 인상을받습니다 ...

왜 제로가 아닌가?

... "1 기반"표기법은 서양 문화에서 남은 것이지만, 더 이상은 아니지만 수세기 동안 0의 존재를 무시했습니다.

믿거 나 말거나, 원래의 gregorian calendar는 -3, -2, -1, 1, 2, 3에서 나옵니다 ... 서양 과학에 기여한 문제를 상상해보십시오 (예 : 1 월 1 일부터 몇 년까지 -2 년) 원래 gregorian calendar보다 뺄셈처럼 단순한 것과 충돌하는 것을 보려면 1 월 2 일 1 일까지 ...).

1 기반 배열을 유지하는 것은 21 세기의 마일과 야드를 유지하면서 (글쎄, 나는 그것을 위해 수정 될 것입니다 ... ^ _ ^ ...)과 같습니다 ...

왜 제로? 수학이기 때문에!

먼저 (죄송합니다 ... 다시 시도하겠습니다)

Zero , Zero는 아무것도 아니며, 하나는 무언가입니다. 그리고 일부 종교 문헌들은 "처음에는 아무것도 없었다"고 주장합니다. 일부 컴퓨터 관련 토론은 종교 토론만큼이나 불타고있을 수 있습니다. 따라서이 시점은 주제에서 벗어나지 않습니다 ... ^ _ ^

첫째 , 0 기반 배열로 작업하고 1 기반 배열로 작업하고 0 값을 찾기 위해 해킹하는 것보다 0 값을 무시하는 것이 더 쉽습니다. 이 이유는 이전과 마찬가지로 어리석은 일이지만 1 기반 배열을 선호하는 원래의 주장도 상당히 잘못된 것입니다.

둘째 , 숫자를 다룰 때 기회가 높을 때마다 수학을 다루게 될 것이고, 수학을 다룰 때 기회가 좋다는 것을 기억하십시오. 어리석은 해킹이 쓸모없는 규칙을 피할 수는 없습니다. One-based 표기법은 수세기 동안 수학과 날짜를 괴롭 혔으며, 실수로부터 배움으로써 미래 지향적 과학 (컴퓨터 언어 포함)에서 피하기 위해 노력해야합니다.

셋째 , 하드웨어에 연결된 컴퓨터 언어 배열의 경우 21 개의 정수로 구성된 C 배열을 할당하고 포인터 10을 오른쪽으로 이동하면 자연스러운 [-10-10] 배열이됩니다. 이것은 하드웨어에 자연스러운 것이 아닙니다. 그러나 수학을위한 것입니다. 물론 수학은 쓸모가 없었지만 마지막으로 확인했을 때 세계 대부분의 사람들은 그렇지 않다고 믿었습니다.

넷째 , 이미 다른 곳에서 지적했듯이 불연속 위치 (또는 불연속 값으로 거리가 줄어든 경우)에도 건물의 바닥 (0에서 시작)과 같이 첫 번째 인덱스는 0이되고 카운트 다운이 감소합니다 (3, 2, 1, ZERO !), 지상고도, 이미지의 첫 번째 픽셀, 온도 (273K의 수냉 온도로서 절대 0 또는 섭씨 0 도의 경우 켈빈 0). 실제로, 실제로 하나에서 시작하는 유일한 것은 " 첫번째 , 두번째 , 세번째 등" 의 전통적인 방법입니다 . 반복 표기법으로 자연스럽게 다음 지점으로 안내합니다.

다섯 개 다음 (자연스럽게 다음 지점 이전은 ) 높은 수준의 컨테이너가없는 인덱스로, 액세스해야한다는 것입니다,하지만 의해 반복자 , 인덱스하지 않는 자체가 고유 값을 갖는다. 나는 당신의 "고수준 언어"옹호자가 그것을 언급하지 않은 것에 놀랐습니다. 지수 자체가 중요한 경우 수학 관련 질문을 염두에 두는 시간의 절반을 걸 수 있습니다. 따라서 컨테이너는 수학 친화적이고 1에서 시작하는 "당신의 오래된 gregorian calendar"와 같이 수학적으로 비활성화되지 않고 작동하기 위해 역류 핵이 필요합니다.

결론

동료 프로그래머가 말한 주장은 본질적으로 모호한 컴퓨터 언어 (명령을 흐리게하고 싶지 않은 곳)와 말하고 쓰는 언어 습관을 불필요하게 묶고 하드웨어를 잘못 부여했기 때문에 오류입니다. 이 문제의 원인으로, 그는 추상화가 점점 더 높아짐에 따라 제로 기반 배열이 과거의 일이라는 것을 확신시키기를 희망합니다.

제로 기반 배열은 수학 관련 이유로 제로 기반입니다. 하드웨어 관련이 아닙니다.

이제 이것이 동료 프로그래머에게 문제가된다면 반복자 및 foreach 루프와 같은 실제 고수준 구조로 프로그래밍을 시작하십시오.


) 제로 섭씨는 273,15K입니다

2
나는 (물리학 석사 학위를 소지하고 있음) 알고 있지만, 십진수로 연주하는 것은 내가 논증을 칠하려는 유머러스 한 측면보다 덜 중요하다고 생각했습니다 ... ^ _ ^ ...
paercebal

20
단락에는 "제로, 첫째, 둘째, 셋째, 넷, 다섯"이라는 레이블이 붙어 있습니다. 일관성을 유지하려면 기수 ( "제로, 1, 2, 3, 4, 5") 또는 서수 ( "제로, 1, 2, 3, 4, 5")를 사용해야합니다. :-)
ShreevatsaR

10
마찬가지로, 우리 삶의 첫해에 우리는 1 살이 아니라 0 살입니다.

3
@Nikita Rybak : 놀라운 것은 당신이 전에 모든 주석가들이 본 것을 놓쳤다는 것입니다. 물론 Bill the Lizard의 답변이 맞습니다. 이것이 내가 그에게 +1 투표 한 이유이며, 이것이 질문의 가장 좋은 답변으로 선택된 이유입니다. 내 대답은 1 기반 배열의 잘못된 이유를 재미있게 만들고 1 기반 배열이 성가신 구체적인 사례를 제공하는 것입니다. 아직도, 나는 당신이 "단 하나 설득력있는 사람이 아니라"라는 것을 발견 한 것에 놀랐다. 이유가 아이러니와 섞여 있다는 것을 고려하더라도 ..
Paercebal

47

반 개방 간격이 잘 구성됩니다. 다루고 있고 요소 0 <= i < lim별로 확장하려는 n경우 새 요소의 범위는 인덱스입니다 lim <= i < lim + n. 0부터 시작하는 배열을 사용하면 배열 분할하거나 연결 하거나 요소를 계산할산술이 더 쉬워집니다 . 간단한 산술 연산이 펜스 포스트 오류줄 이길 바랍니다 .


반 개방 간격 +1-모든 것이 더 쉬워집니다.
Eclipse

29

특정 유형의 배열 조작은 1 기반 배열에서는 복잡하지만 0 기반 배열에서는 더 단순합니다.

한 지점에서 수치 분석 프로그래밍을했습니다. FORTRAN과 C ++로 작성된 압축 된 희소 행렬을 조작하는 알고리즘을 사용하고있었습니다.

FORTRAN 배열은 1을 기반으로하고 C ++ 배열은 0을 기반으로했기 때문에 FORTRAN 알고리즘은 많은 a[i + j + k - 2]반면 C ++은을 a[i + j + k]갖습니다.


동의한다. 1 기반 배열이 유용한 유일한 순간은 null 항목 인덱스를위한 공간을 만들고 싶을 때입니다. 예를 들어 객체 배열이 있고 색인을 핸들로 사용하고 null 핸들을 원한다면.
Fabio Ceconello

나는 1 기반 배열의 불필요한 복잡성에 부딪 쳤습니다. 제로 제한된 경험으로 0 기반 배열은 항상 드문 예외로 배열 인덱싱을위한 명확한 코드를 생성했습니다.

FORTRAN과 C ++ 지수가 각각 1 씩만 상쇄되는 경우 2와 어떻게 다릅니 까? 또한 왜 빼기 2입니까? FORTRAN이 1 기반 인 경우 2 (또는 1)를 추가하지 않습니까?
RexE

@RexE : 이것이 작동하는 방식이므로 1 기반 배열에서는 매우 복잡합니다.
Jay Bazuzi

@RexE : 평평한 배열로 3D 배열을 에뮬레이트한다고 가정합니다. 그런 다음 0 기준에서 요소 (0 0 0)은 평면 배열의 요소 0에 해당합니다. OTOH가 1 기반 인 경우 요소 (11 1)은 플랫 배열의 요소 1에 해당합니다. 1 + 1 + 1-2.

22

배열의 인덱스는 실제로 인덱스가 아닙니다. 그것은 단순히 배열의 시작점으로부터의 거리 인 오프셋입니다. 첫 번째 요소는 배열의 시작 부분에 있으므로 거리가 없습니다. 따라서 오프셋은 0입니다.


3
요즘 설계되는 대부분의 언어의 경우 실제로 구현 세부 사항으로, 언어로 표시되지 않아야합니다 (다른 더 좋은 이유가있는 경우 제외)
Jens Schauder

17

그 이유는 역사적 일 뿐이 아닙니다. C와 C ++는 여전히 주변에 널리 사용되고 있으며 포인터 산술은 배열이 인덱스 0에서 시작하는 데 매우 유효한 이유입니다.

포인터 산술이 부족한 다른 언어의 경우 첫 번째 요소가 인덱스 0에 있는지 또는 1에 있는지 여부는 다른 규칙이 아닌 규칙에 가깝습니다.
문제는 인덱스 1을 첫 번째 요소로 사용하는 언어는 진공 상태로 존재하지 않으며 대개 C 또는 C ++로 작성된 라이브러리와 상호 작용해야한다는 것입니다.

VB와 그 파생 된 풍미는 어레이가 0 또는 1에서 시작하는 데 어려움을 겪었으며 오랫동안 문제의 원인이었습니다.

결론은 : 전체에서 일관성이있는 한 언어가 첫 번째 요소 색인을 고려하는 것은 중요하지 않습니다. 문제는 1을 첫 번째 인덱스로 고려하면 실제로 작업하기가 더 어렵다는 것입니다.


동의했다. 일관성이 중요하며 저수준 코드 (C / C ++ 포함)를 완전히 피할 수 없다면 1 기반 배열로 작업하는 것이 문제입니다.
Shog9

우리가 문제를 해결하는 동안 한 가지 질문이 있습니다. 플랫폼 이외의 방식으로 저수준 코드를 사용하십니까? 다시 말해, 당신은 항상 하나의 플랫폼 또는 다른 플랫폼에 있고 어떤 것을 알고 있어야합니까?
Dan Rosenstark

1
VB .NET이 일반적으로 불공평하다고 생각하는 사람은 배열에 대한 VB .NET 연습이 끔찍하다고 말해야합니다. 차이점을 나누고 더 혼란스럽게 만들었습니다. 배열은 0에서 시작하지만 Integer (5)로서 Dim a는 6 개의 위치를 가진 배열을 만듭니다 . 이론적 근거는 추가 길이를 갖는 것이 어레이의 길이를 넘어서 해결하는 것보다 낫다는 것 같았다. 불행히도 (그리고 And and Or와 같은 다른 문제) 그들은 어쨌든 VB .NET을 사용하지 않은 많은 VB6 프로그래머의 요구에 부딪 쳤습니다.
Kyralessa

1
@Kyralessa : 아닙니다.이 표기법은 반 직관적이고 오류가 발생하기 쉽다는 점을 잘 알고 있었지만 VB6 (자동 업그레이드 지원 기능)과의 호환성을 가져야했습니다. 반면에, And하고 Or있는 비트가 VB6 함께 할 아무것도있다, 그것은 VB 형 언어에 대한 유일한 논리적 인 솔루션입니다. 당신은 않는AndAlsoOrElse당신의 논리 연산합니다.
Konrad Rudolph

And그리고 Or그들은 VB6에 비트 단위 않았기 때문에 비트있는 것은, VB6 함께 할 모든 것을 갖추고 있습니다. 비트 단위 연산은 논리 연산보다 훨씬 덜 일반적이기 때문에 못생긴 연산자 AndAlso이며 OrElse비트 단위로 이루어져야합니다. ByVal이 기본값이더라도 모든 곳에서 석고로 칠해진다는 사실과 같이, "역방향 호환성"으로 인해 언어에 남아있는 못생긴 사마귀가 많이 있습니다.
Kyralessa

10

제로 기반 배열은 C와 어셈블러에 뿌리를두고 있습니다. C를 사용하면 포인터 수학은 기본적으로 다음과 같이 작동합니다.

  • 배열의 각 요소는 특정 바이트 수를 차지합니다. 32 비트 정수는 4 바이트입니다.
  • 배열의 주소는 배열의 첫 번째 요소가 차지하고 그 이후에 같은 크기의 연속 블록에있는 후속 요소가 있습니다.

예를 들어, int a[4]0xFF00에 있다고 가정 하면 주소는 다음과 같습니다.

  • a [0]-> 0xFF00;
  • a [1]-> 0xFF04;
  • a [2]-> 0xFF08;
  • a [3]-> 0xFF0C.

따라서 0부터 시작하는 인덱스를 사용하면 주소 계산은 간단합니다.

요소 주소 = 배열 ​​주소 + 색인 * sizeof (type)

실제로 C의 표현은 모두 동일합니다.

  • a [2];
  • 2 [a]; 과
  • * (a + 2).

1 기반 배열의 경우 수학은 약간 더 복잡합니다.

따라서 그 이유는 대부분 역사적입니다.


1
원래 질문은 "배열이 0을 기반으로하는 배열은 배열과 포인터 및 컴퓨터 하드웨어가 작동하는 방식에서 비롯된 구현 세부 사항이지만 이러한 종류의 내용은 더 높은 수준의 언어로 반영되어서는 안됩니다."

N 기반 배열을 허용하는 언어는 일반적으로 런타임 비용없이 자동으로 배열 '오프셋'으로 코드를 생성한다는 점을 언급 할 가치가 있습니다.
Roddy December

8

0부터 시작하는 배열을 사용하는 경우 배열의 길이는 유효한 인덱스 집합입니다. 적어도 Peano 산술은 다음과 같이 말합니다.

0 = {}
1 = 0 U {0} = {0}
2 = 1 U {1} = {0,1}
3 = 2 U {2} = {0,1,2}
...
n = n-1 U {n-1} = {0,1,2...n-1}

어떤 의미에서 가장 자연스러운 표기법입니다.


7

C에서 배열과 포인터 사이에는 강한 상관 관계가 있기 때문에

char* p = "hello";
char q[] = "hello";

assert(p[1] == q[1]);

assert(*p == *q)

* p는 * (p + 0)과 동일

시작 색인이 1이면 나중에 두통이 생길 것입니다


5

힙은 1 기반 어레이의 장점 중 하나입니다. 인덱스 i가 주어지면 i 의 부모와 왼쪽 자식의 인덱스 는

PARENT[ i ] = i ÷ 2

LCHILD[ i ] = i × 2

그러나 1 기반 배열에만 해당됩니다. 0 기반 배열의 경우

PARENT[ i ] = ( i + 1) ÷ 2-1

LCHILD[ i ] = ( i + 1) × 2-1

그리고 당신은 i 가 그 인덱스에 대한 하위 배열의 크기 라는 속성을 가지고 있습니다 (즉, [1, i ] 범위의 인덱스 ).

그러나 결국 중요하지 않습니다. 왜냐하면 평소보다 하나 이상의 요소를 할당하고 0을 무시하여 0 기반 배열을 1 기반 배열로 만들 수 있기 때문입니다. 따라서 적절한 경우 1 기반 배열의 이점을 얻도록 선택하고 거의 모든 다른 상황에서 더 깔끔한 산술을 위해 0 기반 배열을 유지할 수 있습니다.


4

내 느낌은 그것이 완전히 임의적이라는 것입니다. 0 또는 1 기반 배열에는 특별한 것이 없습니다. Visual Basic (주로 Excel에서 작은 작업을 수행함)에서 벗어나기 때문에 1 기반 배열로 작업하지 않았으며 ... 동일합니다. 사실 배열의 세 번째 요소가 필요한 경우 3 또는 2라고하는 구현 세부 사항 일뿐입니다. 그러나 배열로 수행하는 작업의 99 %는 두 가지 절대 지점에만 관심이 있습니다. 첫 번째 요소와 개수 또는 길이 다시 말하지만, 첫 번째 요소는 1 대신 0이라고하거나 마지막 요소는 count-1 또는 count라고합니다.

편집 : 일부 응답자들은 1 기반 배열이 펜스 포스트 오류가 발생하기 쉽다고 언급했습니다. 내 경험상 지금 그것에 대해 생각하면 이것은 사실입니다. 나는 VB에서 "이것이 하나가되어서 작동하거나 터질 것"이라고 생각한 것을 기억합니다. Java에서는 결코 발생하지 않습니다. 나는 점점 나아지고 있다고 생각했지만 일부 응답자들은 0 기반 배열이 더 낮은 산술을 처리 할 필요가 없을 때 더 나은 산술 연산을하는 경우를 지적합니다.


PHP에서 문자열 함수 내부의 대부분의 검색은 찾을 수 없을 때 FALSE를 반환합니다. -1이 아닙니다.
jmucchiello

카운트를 마지막 요소의 인덱스와 혼동하고 있습니다. 빈 배열의 개수는 0부터 시작하거나 1부터 시작하는 배열을 사용하든 항상 0입니다. 1 기반 배열의 장점은 개수가 마지막 요소의 위치라는 점입니다 (단, 이것이 유일한 이점입니다).

이 두 가지 점 모두 참 : 마지막 반은 0부터 시작하거나 1부터 시작하는 배열과 동일하므로 삭제되었습니다. 요소가 0이면 count는 0입니다.
Dan Rosenstark

내 대답의 마지막 절반을 의미했습니다 ...
Dan Rosenstark

4

파스칼과 델파이에서 매우 강한 배경을 가진 10 년 이상의 C / C ++ 프로그래머 인 저는 여전히 파스칼의 강력한 배열 바운드 및 인덱스 유형 검사와 함께 제공되는 유연성과 안전성을 놓치고 있습니다. 이것의 명백한 예는 매월 값을 보유하는 배열 데이터입니다.

파스칼:

 Type Month = (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);

  Var Days[Month] of integer;

  ... 
  if Year mod 4 = 0 then // yes this is vastly simplified for leap years and yes i don't know what the comment marker is in pascal and no i won't go look it up
    Days[Feb] := 29
  else
    Days[Feb] := 28;

+/- 1 또는 '마법 숫자'를 사용하지 않고 C 언어로 유사한 코드를 작성하는 것은 매우 어려운 일입니다. Days [2] 및 Days [Jan + Dec]와 같은 표현식은 컴파일되지 않으며 C 또는 어셈블러에서 여전히 생각하는 사람들에게는 잔인하게 보일 수 있습니다.

Pascal / Delphi 언어에는 많은 부분이 있지만 C 제로 기반 배열은 비교할 때 "멍청한"것처럼 보입니다.


그것은 당신의 알고리즘은 2100 년에 대한 정확하지 않은 것을 지적 가치가있을 수도 있습니다 en.wikipedia.org/wiki/Leap_year#Algorithm

2
나는 ;-) 알고있다. 그러나 그것은 2000 년에 맞았다. 나는 단지 "pedant"스팟을 연주하고있다.
Roddy

pedant를 발견하십시오! LOL.
jcollum

예. 전체 문제를 피하고 원하는 배열을 기반으로하십시오.
Loren Pechtel

기계 코드를 생성 할 때 평균 Pascal 컴파일러가 Jan = 0, Dec = 11을 할당해도 놀라지 않을 것입니다. :-)

4

이것이 1이 아닌 0에서 시작하는 이유는 오프셋을 어레이 메모리의 시작에서이 요소까지의 거리만큼 생각할 수 있기 때문입니다. 그것은 0 번째 요소를 말해주지 않습니다. 시작부터 0 번째 요소를 알려주세요.

그것을 보는 또 다른 방법은 이것들이 (대부분) 동등하다는 것입니다.

array[n]

*(array + n)

표준이 변경되지 않는 이유는 C가 약 40 년 동안 존재했기 때문입니다. 변경해야 할 강력한 이유가 없으며 변경 한 경우 0의 배열 시작에 의존하는 기존 코드가 모두 손상됩니다.


사실, C에서 array[n]와 같이 다시 쓸 수 있습니다 n[array]. 좋은 생각이 아니고 혼란 스럽습니다! 그러나 위의 정체성과 첨가가 교환 적이라는 사실 때문에 합법적입니다 (적어도 C89까지).
Donal Fellows

그것은 그것을 작성하는 미친 방법입니다. 유지 해야하는 코드에서 보았을 때 커다란 경고 신호가 될 것입니다. 고맙게도 나는 그것을
뛰어 넘지

4

원래 위치 / 상대 위치 정보를 포함하는 코드는 0에서 시작하는 배열로 훨씬 깨끗합니다.

더 큰 벡터에서 정의 된 위치에 벡터를 복사하는 코드는 1부터 시작하는 배열의 고통입니다.

function copyAtPos (dest, vect, i):
    for i from 1 -> vect.length do
        dest[pos+i-1] = vect[i]

0에서 시작하는 배열과의 반대

function copyAtPos (dest, vect, i):
    for i from 0 -> vect.length-1 do
        dest[pos+i] = vect[i]

큰 컨볼 루션 수식을 작성하기 시작하면 필수입니다.


3

왜 2 또는 3 또는 20이 아닌가? 1 기반 배열을 사용하는 것이 0 기반 배열을 이해하는 것이 더 쉽고 간단하지는 않습니다. 1 기반 배열로 전환하려면 모든 프로그래머가 배열 작업 방법을 다시 배워야합니다.

또한 기존 배열에 대한 오프셋을 처리 할 때 더 의미가 있습니다. 배열에서 115 바이트를 읽은 경우 다음 청크가 115에서 시작한다는 것을 알 수 있습니다. 계속해서 다음 바이트는 읽은 바이트의 크기입니다. 1 기반의 경우 항상 하나를 추가해야합니다.

"true"포인터 산술이없는 언어에서도 배열의 데이터 청크를 처리해야하는 경우가 있습니다. Java에서는 메모리 매핑 파일 또는 버퍼에 데이터가있을 수 있습니다. 이 경우 블록 i의 크기가 * i라는 것을 알고 있습니다. 1 기반 인덱스를 사용하면 블록 * i + 1에있게됩니다.

1 기반 인덱싱을 사용하면 많은 기술에서 모든 장소에 +1이 필요합니다.


왜 2 또는 3 또는 20이 아닌가? 0은 가산 성 ID이고 1은 곱셈식 ID이기 때문입니다. 그들은 가장 이해가됩니다.

3

1 기반 배열을 사용하여 1 차원 배열을 다차원 배열로 변환합니다.

int w = 5, h = 5, d = 5;

int[] a1 = new int[w * h * d], new a2 = int[w,h,d];

for (int z = 1; z <= d; z++)

  for (int y = 1; y <= h; y++)

    for (int x = 1; x <= w; x++)

      a1[x + (y - 1) * w + (z - 1) * h] = a2[x,y,z];

배열이 1을 기준으로해도 y 및 z 인덱스는 0부터 시작합니다 (y-1, z-1). 경우에 따라 0 기반 인덱스를 피할 수 없습니다. 일관성을 유지하기 위해 항상 0 기반 인덱스를 사용하지 않는 이유는 무엇입니까?


3

왜 배열이 하나에서 시작되기를 원합니까?

당신이 말할 때 a[x][y], 컴파일러는 이것을 다음으로 번역합니다 : a+(x*num_cols+y). 배열이 하나에서 시작되면 이것이 a+(x*num_cols+y-1)됩니다. 이것은 배열 요소에 액세스하려고 할 때마다 추가 산술 연산 입니다. 왜 프로그램 속도를 늦추고 싶습니까?


1
실제로는 + ((x-1) * num_cols) + y-1)이어야합니다. x와 y는 모두 1부터 시작합니다.
Dennis Munsie

2

여기서 사지로 나가 정수 'keyed'배열과 다른 것을 제안합니다.

동료가 우리가 항상 1부터 계산하기 시작하는 실제 세계에서 '세트'의 일대일 매핑을 작성하고 있다고 생각합니다. 이해 할 수 있습니다. 소프트웨어와 실제 세계간에 1 대 1을 매핑 할 때

나의 제안

저장하는 모든 것에 정수 기반 배열을 사용하지 말고 다른 종류의 사전 또는 키 값 쌍을 사용하십시오. 임의의 정수에 구속되지 않으므로 실제 생활에 더 잘 어울립니다. 이것은 그 자리를 가지고 있으며 소프트웨어와 실제 세계 사이의 매핑 개념 1 대 1의 이점으로 인해 최대한 많이 사용하는 것이 좋습니다.

kvp['Name Server'] = "ns1.example.com"; (이것은 가능한 백만 개의 예 중 하나 일뿐입니다).

Discaimer

수학이 컴퓨터의 실제 구현에 더 가깝기 때문에 수학 기반의 개념으로 작업 할 때는 가장 확실하게 작동하지 않습니다. kvp 세트를 사용하면 여기서 도움이되지 않지만 실제로는 문제를 일으키고 더 문제가됩니다. kvp 또는 배열로 더 잘 작동 할 수있는 모든 경우를 생각하지 못했습니다.

최종 아이디어는 제로 기반 배열 또는 키 값 쌍을 사용하는 것이 합리적입니다. 해머 만있을 때 모든 문제가 손톱처럼 보이기 시작한다는 것을 기억하십시오 ...


2

개인적으로, 하나의 인수는 배열 인덱스를 오프셋으로 볼 때입니다. 이해가 되네요

첫 번째 요소라고 말할 수 있지만 배열의 원점에 대한 첫 번째 요소의 오프셋은 0입니다. 따라서 배열 원점을 취하고 0을 추가하면 첫 번째 요소가 생성됩니다.

따라서 계산에서 첫 번째 요소를 찾아서 제거하는 것보다 0을 추가하는 것이 더 쉽습니다.

저수준의 물건을 한 사람은 항상 기본 제로 방식을 생각한다고 생각합니다. 그리고 더 높은 수준의 알고리즘에 익숙하지 않은 사람들은 종종 기본 시스템을 원할 것입니다. 아니면 우리는 과거 경험에 편향되어있을 수도 있습니다.


정확히-기본적으로 낮은 수준의 언어를 중심으로 한 협약입니다.

2

유일한이 (매우) 심각한 이유는 것 대신 1 기반 인덱스의 0 기반 인덱스를 사용 할 수 없는 프로그래머의 많은 재교육 피하기 위해 AND 뒤로 compatiblity를 들어 .

나는 당신이받은 모든 답변에서 1 기반 지수에 대한 다른 심각한 주장을 보지 못했습니다.

실제로, 지수는 자연스럽게 1을 기준으로하므로 여기에 이유가 있습니다.

먼저, 우리는 물어야합니다 : 배열은 어디에서 왔습니까? 그들은 실제로 동등한 것을 가지고 있습니까? 대답은 '예'입니다. 컴퓨터 과학에서 벡터와 행렬 을 모델링하는 방법 입니다. 그러나 벡터와 행렬은 컴퓨터 시대 이전에 1 기반 인덱스를 사용하던 수학 개념이며 현재는 여전히 1 기반 인덱스를 사용합니다.

실제 세계에서 지수는 1-베이스입니다.

Thomas가 위에서 말했듯이, 0-베이스 인덱스를 사용하는 언어는 실제로 인덱스가 아닌 오프셋을 사용 합니다 . 그리고 이러한 언어를 사용하는 개발자는 지수가 아니라 오프셋 에 대해 생각 합니다 . 사물이 명확하게 언급 된 경우에는 문제가되지 않지만 그렇지 않습니다. 오프셋을 사용하는 많은 개발자는 여전히 인덱스에 대해 이야기합니다. 그리고 인덱스를 사용하는 많은 개발자들은 여전히 ​​C, C ++, C #, ...이 오프셋을 사용한다는 것을 알지 못합니다.

이것은 문구 문제 입니다.

(Diskstra의 논문에 대한 참고 사항- 그것은 내가 위에서 말한 것을 정확하게 말합니다 : 수학자 는 1 기반 인덱스를 사용 하지만, Diskstra 일부 표현이 추악하기 때문에 메이트 학자 는 이것을 사용 해서는 안된다고 생각합니다 (예 : 1 <= n <= 0 글쎄, 그가 그 하나에 옳은지 확실하지 않습니다-예외적 인 빈 시퀀스를 피하기 위해 그러한 패러다임 전환을하는 것은 작은 결과에 많은 문제가되는 것 같습니다 ...)


2
수학자들이 항상 1 기반 인덱스를 사용하는 것은 아닙니다. x0이 시퀀스의 초기 값으로 많은 시간을 사용하는 것을 보았습니다. 어느 것이 더 편리한 지에 달려 있습니다.

2

실제로 1900 년대를 언급 한 "20 세기"에 화가 났습니까? 글쎄, 그것은 1 기반 배열을 사용할 때 항상 다루는 지루한 일에 대한 좋은 비유입니다.

.net IO.stream 읽기 방법과 같은 일반적인 배열 작업을 고려하십시오.

int Read(byte[] buffer, int offset, int length)

다음은 0 기반 배열이 더 낫다는 것을 확신시키기 위해 제안하는 것입니다

각 인덱싱 스타일에서 읽기를 지원 하는 BufferedStream 클래스를 작성하십시오 . 1 기반 배열에 대해 읽기 기능의 정의를 변경할 수 있습니다 (예 : 오프셋 대신 하한 사용). 멋진 것이 필요하지 않습니다. 간단하게 만드십시오.

이제 그 구현 중 어느 것이 더 간단합니까? 어느 쪽이 여기저기서 +1 및 -1 오프셋을 뿌렸습니까? 그것이 내가 생각했던 거죠. 사실 인덱싱 스타일이 중요하지 않은 유일한 경우는 Set과 같이 배열이 아닌 것을 사용해야했을 때입니다.


정수 논리와 부동 소수점을 혼동하는 나쁜 유추입니다.

2

배열이 구성되는 방식 때문입니다. 그들이 처음부터 시작하는 것은 의미가 없습니다. 배열은 메모리의 기본 주소, 크기 및 색인입니다. n 번째 요소에 액세스하려면 다음과 같습니다.

base + n * element_size

따라서 0은 분명히 첫 번째 오프셋입니다.


1

실제로 이것을 구현하는 여러 가지 방법이 있습니다.

  • 0 기반 배열 인덱스
  • 1 기반 배열 인덱스
  • 0 또는 1 기반 배열 (VB 6.0과 같이 ... 이것은 정말 끔찍합니다)

궁극적으로 언어가 0 또는 1 기반 배열을 사용하는지 여부는 중요하지 않습니다. 그러나 가장 좋은 선택은 대부분의 프로그래머가 해당 규칙에 익숙하다는 단순한 이유 때문에 0 기반 배열을 사용하는 것이며 이미 작성된 코드의 대다수와 일치합니다.

그러나 실제로 잘못 될 수있는 유일한 방법은 Visual Basic과 일치하지 않는 것입니다. 현재 유지 관리중인 코드베이스는 0과 1 기반 배열로 나뉩니다. 어느 것이 어느 것인지 알아내는 것은 대단히 어렵습니다. 이것은 짜증나게 장황한 for 루프로 이어집니다.

dim i as integer, lb as integer, ub as integer
lb = LBound(array)
ub = UBound(array)
for i = lb to ub
       '...
next

하하 나는 기억해, 그 남자는 ...
Dan Rosenstark

음수로 시작하는 배열조차도 기억합니다. VB에서 멀리 떨어져있는 많은 이유 중 하나입니다.

1

선형 컬렉션에서 항목 의 위치 에 대해 이야기 할 때 자연 스럽습니다 .

책으로 가득 찬 선반을 생각해보십시오. 첫 번째 책은 선반의 측벽과 같은 높이에 위치합니다. 그 위치는 0입니다.

따라서 배열 인덱스를 물건을 찾거나 물건을 참조하는 수단으로 간주하는지 여부에 달려 있다고 생각합니다.


1

모듈로 (및 모듈로에 사용될 때 AND 연산자)가 항상 일부 값에 대해 0을 반환하기 때문에 0 기반 인덱스를 선호합니다.

종종 다음과 같은 배열을 사용합니다.

int blah = array[i & 0xff];

1 기반 인덱스를 사용할 때 종종 그런 종류의 코드가 잘못됩니다.


1

문자열 검색 및 다양한 정렬 / 병합 알고리즘과 같은 많은 배열 기반 코드를 프로그래밍하거나 단일 차원 배열에서 다차원 배열을 시뮬레이션하지 않으면 0 기반을 방어하기가 어렵습니다. Fortran은 1 기반이며 이러한 종류의 코드를 올바르게 수행하려면 많은 커피가 필요합니다.

그러나 그것은 그것을 넘어서고 있습니다. 요소의 지표보다는 무언가의 길이를 생각할 수있는 것은 매우 유용한 정신 습관입니다. 예를 들어, 픽셀 기반 그래픽을 수행 할 때 좌표가 픽셀이 아닌 픽셀간에 떨어지는 것으로 생각하는 것이 훨씬 더 명확합니다. 이렇게하면 3x3 사각형에 16이 아닌 9 픽셀이 포함됩니다.

좀 더 많이 가져온 예는 구문 분석 또는 테이블의 소계 인쇄에서 미리보기라는 개념입니다. "상식"접근 방식은 1) 다음 문자, 토큰 또는 테이블 행을 가져오고 2) 그것으로 무엇을 할 것인지 결정합니다. 미리보기 접근법은 1) 당신이 그것을 볼 수 있다고 가정하고, 당신이 그것을 원한다면 결정하고, 2) 당신이 그것을 원한다면, 그것을 "수락"합니다 (다음 것을 볼 수있게 해줍니다). 그런 다음 의사 코드를 작성하면 훨씬 간단합니다.

또 다른 예는 MS-DOS 배치 파일과 같이 선택할 수없는 언어로 "goto"를 사용하는 방법입니다. "상식"접근 방식은 수행 할 코드 블록에 레이블을 첨부하고 레이블을 지정하는 것입니다. 종종 더 나은 접근 방법은 레이블을 건너 뛸 목적으로 코드 블록 끝에 레이블을 배치하는 것입니다. 이를 통해 "구조화"되고 훨씬 쉽게 수정할 수 있습니다.


1

그것은 단지 그렇고 수년 동안되었습니다. 그것을 바꾸거나 토론하기 위해서는 변화하는 신호등을 바꾸거나 토론하는 것만 큼 의미가 없습니다. blue = stop, red = go를 만들어 봅시다.

Numerical Recipes for C ++에서 시간이 지남에 따른 변경 사항을 살펴보십시오. 그들은 매크로를 사용하여 1 기반 인덱싱을 가짜로 만들었지 만 2001 년 판에서 포기하고 무리에 합류했습니다. www.nr.com 사이트에서 이에 대한 이유를 밝히는 자료가있을 수 있습니다.

BTW, 또한 성가신 것은 배열에서 범위를 지정하는 변형입니다. 예 : 파이썬 대 IDL; a [100 : 200] 대 a [100 : 199] 100 개의 원소를 구합니다. 각 언어의 단점을 배워야합니다. 한 가지 방법으로 다른 언어와 일치하는 언어를 변경하면 치아가 삐걱 거리거나 뭉개지고 실제 문제는 해결되지 않습니다.


1

다른 사람들이 언급했듯이 수학을 쉽게하기 때문에 0 기반 배열을 선호합니다. 예를 들어, 10x10 그리드를 에뮬레이트하는 100 개의 요소로 구성된 1 차원 배열이있는 경우 행 r, col c에있는 요소의 배열 인덱스 i는 무엇입니까?

0 기반 : i = 10 * r + c
1 기반 : i = 10 * (r-1) + c

그리고 인덱스 i가 주어지면 행과 열로 돌아가는 것은 다음과 같습니다.

0 기반 : c = i % 10
         r = 층 (i / 10)
1 기준 : c = (i-1) % 10 + 1
         r = ceil (i / 10)

1 기반 배열을 사용할 때 위의 수학이 분명히 더 복잡하다는 것을 감안할 때 0 기반 배열을 표준으로 선택하는 것이 논리적으로 보입니다.

그러나 누군가 2D 데이터를 1D 배열로 표현할 이유가 있다고 가정하기 때문에 내 논리에 결함이 있다고 주장 할 수 있다고 생각합니다. 나는 C / C ++에서 여러 가지 상황에 처해 있었지만 그러한 계산을 수행 해야하는 것은 언어에 따라 다르다는 것을 인정해야합니다. 배열이 클라이언트에 대해 항상 모든 인덱스 수학을 수행했다면 컴파일러는 컴파일 타임에 M 기반 배열 액세스를 0 기반으로 변환하고 사용자에게 이러한 구현 세부 정보를 모두 숨길 수 있습니다. 실제로 컴파일 타임 상수는 동일한 연산 세트를 수행하는 데 사용될 수 있지만 이러한 구문은 이해할 수없는 코드로 이어질 수 있습니다.

아마도 더 나은 논거는 1 기반 배열을 가진 언어에서 배열 인덱스 연산의 수를 최소화하려면 상한 함수를 사용하여 정수 나누기를 수행해야한다는 것입니다. 그러나 수학적 관점에서 정수 나누기는 d 나머지 r을 반환해야합니다. 여기서 d와 r은 모두 양수입니다. 따라서 수학을 단순화하기 위해 0 기반 배열을 사용해야합니다.

예를 들어 N 개의 요소가있는 룩업 테이블을 생성하는 경우 x 값에 대한 현재 값 이전의 배열에 가장 가까운 인덱스는 다음과 같습니다 (반올림하기 전에 정수인 결과는 무시)

바닥이있는 0 기반 : 바닥 ((N-1) * x / xRange)
바닥을 포함한 1 기반 : 바닥 ((N-1) * x / xRange) + 1
ceil을 사용한 1 기반 : ceil ((N-1) * x / xRange)

반올림의 표준 규칙을 사용하는 경우 1 기반 배열에는 추가 작업이 필요하므로 바람직하지 않습니다. 이러한 종류의 수학은 뒤에서 일어나는 일에 대한 하위 수준의 지식이 필요하므로 컴파일러가 숨길 수 없습니다.


다차원 배열을 지원하는 고급 언어를 사용할 때까지는 그럴만한 이유가 있습니다.

1

나는 프로그래머가 매일 0 기반 배열의 반 직관적 인 생각에 짜증을 내고 배열을 설명하는보다 직관적 인 수단을 주장했다. 인간으로서 우리는 코드에서보다 인간적인 방법으로 설명 할 수 있도록 "클래스"를 만드는 데 너무 많은 시간을 보냈지 만 0 대 1 배열을 볼 때 우리는 매달린 것처럼 보입니다. 그것의 논리.

컴퓨터에 관한 한 수학적으로 0이 더 나을 것 같지만 여기서 요점을 놓치고 있다고 생각합니다. 좀 더 인간적인 방식으로 (예를 들어 수업) 설명하고 싶다면 왜 언어의 다른 부분에서도 동일하지 않겠습니까? 언어를 인간이보다 쉽게 ​​이해하고 사용할 수있게하여 논리적으로 버그를 일으키고 경향이있는 시나리오에 덜 영향을 미치는 것은 똑같이 논리적이거나 타당하지 않은가 (또는 그 문제에 우선 순위가 더 높음)? 쓸만한 창작물을 더 빨리 생산할 수 있습니다. PHP 예 :

array(1 => 'January', 'February', 'March');

요청에 따라 1 기반 배열을 제공합니다.

하지 규범이있다 :

array('January', 'February', 'March');

예외는 다음과 같습니다.

array(0 => 'Value for scenario where 0 *has* to be used as the key',
      'value2', 'value3');

PHP의 경우 내 베팅은 기본 구문 인 1 기반 배열이 실제 사용 사례에서 논리 버그를 줄이거 나 적어도 평균을 더 많이 발생시키지 않으면 서 80 %의 시간의 80 %입니다. 사용 가능한 코드를 더 빨리 생성하기 위해 코더에서 더 쉽습니다. 필자는 필요할 때 array (0 => 'value') 옵션이 여전히 존재한다고 가정하지만, 실제 설명에 더 가까운 것을 갖는 것이 실질적인 시간이라고 가정합니다.

이 관점에서 볼 때 요청이 너무 많이 들리지 않습니다. 인터페이스에 접근 할 때, 그것은 프로그래머를위한 OS 나 언어, 우리가 디자인하는 인간의 사고와 습관에 더 가까워지고, 대부분의 경우 더 행복하고 인간과 컴퓨터 사이의 오해가 적습니다 (인간 논리- 버그) 및 더 빠른 생산 등이 있습니다. 만약 현실 세계에서 시간의 80 %가 목록을 만들거나 계산할 때 1로 물건을 묘사한다면, 컴퓨터는 정보를 거의 이해하지 못하거나 가능한 한 설명하는 일반적인 방법과는 다른 방식으로 이해하는 방식으로 이상적으로 해석해야합니다. 요컨대 우리는 현실 세계를 더 가깝게 모델링할수록 추상화 품질이 향상됩니다. 그래서 그가 원하는 것은 결코 바보가 아닙니다. 왜냐하면 그것이 궁극적 인 목표이고 더 추상화가 필요한 증거 일 것이기 때문입니다. 컴퓨터는 여전히 0 기반 배열의 특별한 사용으로 볼 수 있습니다. 시간이 지남에 따라 더 적은 버그로 원하는 것을 설명 할 수있는 더 간단하고 직관적 인 방법을 사용하는 한 컴퓨터가 컴퓨터를 해석하는 방식에 신경 쓸 필요가 없습니다.

그래서 그것은 내 두 센트입니다. 나는 그가 무슨 말을했는지, 무엇을 해석했는지에 대해 진심으로 의심합니다. 그가 의미 한 바는 "컴퓨터에 내가 원하는 것을 알려주는 덜 직관적 인 방법이 싫어"였습니다. :) 우리 모두 아닌가요? lol.


1

"자체"코드를 작성하는 동안주의를 기울이면 가능합니다. 모든 n> = 0에 대해 인덱스가 n에서 시작한다고 가정하고 그에 따라 프로그램 할 수 있습니다.

표준과 관련하여 Borealid는 큰 논쟁을 가지고 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.