[英]Why does the indexing start with zero in 'C'?
為什么數組中的索引在 C 中從零開始而不是從 1 開始?
在 C 中,數組的名稱本質上是一個指針[但請參閱注釋] ,對內存位置的引用,因此表達式array[n]
指的是距起始元素n
元素的內存位置。 這意味着索引用作偏移量。 數組的第一個元素正好包含在數組引用的內存位置(0 個元素之外),因此它應該表示為array[0]
。
欲了解更多信息:
http://developeronline.blogspot.com/2008/04/why-array-index-should-start-from-0.html
這個問題是一年多前發布的,但在這里......
雖然Dijkstra 的文章(之前在一個現已刪除的答案中引用)從數學的角度來看是有道理的,但在編程方面卻沒有那么重要。
語言規范和編譯器設計者做出的決定是基於計算機系統設計者做出的從 0 開始計數的決定。
引用丹尼科恩的和平請求。
對於任何基數 b,僅當編號從 0 開始時,前b^N 個非負整數才由恰好N 個數字(包括前導零)表示。
這可以很容易地進行測試。 在基數 2 中,取2^3 = 8
第 8 個數字是:
111
可以用3
位表示,而1000
將需要一個額外的位(4 位)。
計算機內存地址有2^N
單元,由N
位尋址。 現在,如果我們從 1 開始計數, 2^N
單元將需要N+1
地址線。 需要額外的位來訪問正好 1 個地址。 (在上述情況下為1000
)。 另一種解決方法是讓最后一個地址不可訪問,並使用N
地址線。
兩者都是次優解決方案,與從 0 開始計數相比,這將保持所有地址可訪問,恰好使用N
地址行!
從0
開始計數的決定已經滲透到所有數字系統,包括在其上運行的軟件,因為它使代碼更容易轉換為底層系統可以解釋的內容。 如果不是這樣,對於每次數組訪問,機器和程序員之間都會有一個不必要的轉換操作。 它使編譯更容易。
引自論文:
因為 0 是指向數組頭的指針到數組第一個元素的距離。
考慮:
int foo[5] = {1,2,3,4,5};
要訪問 0,我們執行以下操作:
foo[0]
但是 foo 分解為一個指針,上面的訪問有類似的指針運算方式來訪問它
*(foo + 0)
如今,指針算法的使用頻率不高。 回到過去,這是一種獲取地址並將 X 個“整數”從該起點移開的便捷方法。 當然,如果你只想呆在原地,你只需加0!
因為基於 0 的索引允許...
array[index]
......實施為......
*(array + index)
如果索引是基於 1 的,編譯器將需要生成: *(array + index - 1)
,這個“-1”會損害性能。
因為它使編譯器和鏈接器更簡單(更容易編寫)。
參考:
“...通過地址和偏移量引用內存在幾乎所有計算機體系結構上都直接在硬件中表示,因此 C 中的這種設計細節使編譯更容易”
和
“......這使得實現更簡單......”
出於同樣的原因,當是星期三並且有人問你到星期三還有多少天時,你說 0 而不是 1,而當是星期三並且有人問你離星期四還有多少天時,你說 1 而不是 2。
數組索引總是從零開始。假設基地址是 2000。現在arr[i] = *(arr+i)
。 現在if i= 0
,這意味着*(2000+0
) 等於基地址或數組中第一個元素的地址。 此索引被視為偏移量,因此默認索引從零開始。
這是因為address
必須指向數組中的正確element
。 讓我們假設以下數組:
let arr = [10, 20, 40, 60];
現在讓我們考慮地址的開頭是12
, element
的大小是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
。
我讀過的關於從零開始編號的最優雅的解釋是觀察到值不是存儲在數軸上的標記位置,而是存儲在它們之間的空間中。 第一個項目存儲在 0 和 1 之間,下一個項目存儲在 1 和 2 之間,等等。第 N 個項目存儲在 N-1 和 N 之間。可以使用任一側的數字來描述一系列項目。 按照慣例,單個項目使用其下方的數字進行描述。 如果給一個范圍 (X,Y),使用下面的數字識別單個數字意味着可以不使用任何算術識別第一個項目(它的項目 X),但必須從 Y 中減去一個才能識別最后一個項目(Y -1). 使用上面的數字識別項目可以更容易地識別范圍中的最后一個項目(它將是項目 Y),但更難識別第一個 (X+1)。
雖然根據上面的數字來識別項目並不可怕,但將范圍 (X,Y) 中的第一個項目定義為 X 上方的項目通常比將其定義為下面的項目 (X+ 1)。
假設我們要創建一個大小為 5 的數組
整數數組[5] = [2,3,5,9,8]
讓數組的第一個元素指向位置 100
讓我們考慮索引從 1 開始,而不是從 0 開始。
現在我們必須在索引的幫助下找到第一個元素的位置
(記住第一個元素的位置是 100)
因為整數的大小是 4 位
因此 --> 考慮到索引 1,位置將是
索引的大小(1)*整數的大小(4)= 4
所以它會顯示給我們的實際位置是
100 + 4 = 104
這不是真的,因為初始位置是 100。
它應該指向 100 而不是 104
這是錯誤的
現在假設我們已經從 0 開始索引
然后
第一個元素的位置應該是
索引大小(0) * 整數大小(4) = 0
因此-->
第一個元素的位置是 100 + 0 = 100
那是元素的實際位置
這就是索引從 0 開始的原因;
我希望它會澄清你的觀點。
嘗試使用基於 1 的矩陣上的 X,Y 坐標訪問像素屏幕。 公式非常復雜。 為什么復雜? 因為您最終將 X、Y 坐標轉換為一個數字,即偏移量。 為什么需要將 X,Y 轉換為偏移量? 因為這就是計算機內部內存的組織方式,作為內存單元(陣列)的連續流。 計算機如何處理陣列單元? 使用偏移量(第一個單元格的位移,基於零的索引模型)。
因此,在代碼中的某個時刻,您需要(或編譯器需要)將基於 1 的公式轉換為基於 0 的公式,因為這就是計算機處理內存的方式。
在數組中,索引表示與起始元素的距離。 因此,第一個元素與起始元素的距離為 0。 所以,這就是數組從 0 開始的原因。
技術原因可能源於這樣一個事實,即指向數組內存位置的指針是數組第一個元素的內容。 如果您使用索引 1 聲明指針,程序通常會將值 1 添加到指針以訪問您不想要的內容,當然。
首先,您需要知道數組在內部被視為指針,因為“數組名稱本身包含數組第一個元素的地址”
ex. int arr[2] = {5,4};
考慮數組從地址 100 開始,所以元素第一個元素將在地址 100,第二個元素現在將在 104,考慮如果數組索引從 1 開始,那么
arr[1]:-
這可以像這樣寫在指針表達式中 -
arr[1] = *(arr + 1 * (size of single element of array));
考慮 int 的大小是 4bytes,現在,
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 編程語言”一書中
數組名是一個指向基地址的常量指針。當你使用 arr[i] 時,編譯器將其操作為 *(arr+i)。由於 int 范圍是 -128 到 127,編譯器認為 -128 到 -1 是負數和 0 到 128 是正數。所以數組索引總是從零開始。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.