回答
他們被分配如下:
1 2 3
4 5 0
零是因爲你已經分配的大小6陣列,但只有指定的5個元素。
這被稱爲「行主要訂單」。
您可能希望稍微正式確定您的代碼。您的代碼是目前:
int a[2][3] = {1,2,3,4,5};
如果編譯這個與gcc main.c -Wall -pedantic --std=c99
,你會得到一些警告:
temp.c:2:17:警告:缺少初始化左右括號[-Wmissing -braces]
解決此使用
int a[2][3] = {{1,2,3,4,5}};
這會給你一個新的警告:
temp.c:2:25:警告:在數組初始化多餘元素
解決此使用:
int a[2][3] = {{1,2,3},{4,5,0}};
這明確地表示數據因爲每個都有兩行三個元素。
上存儲器佈局
int a[2][3]
思考將產生一個 「數組的數組」。這與「陣列指針數組」類似,但與之不同。兩者都具有相似的訪問語法(例如a[1][2]
)。但僅限於「陣列陣列」,您可以使用a+y*WIDTH+x
可靠地訪問元素。
有些代碼可能澄清:
#include <stdlib.h>
#include <stdio.h>
void PrintArray1D(int* a){
for(int i=0;i<6;i++)
printf("%d ",a[i]);
printf("\n");
}
int main(){
//Construct a two dimensional array
int a[2][3] = {{1,2,3},{4,5,6}};
//Construct an array of arrays
int* b[2];
b[0] = calloc(3,sizeof(int));
b[1] = calloc(3,sizeof(int));
//Initialize the array of arrays
for(int y=0;y<2;y++)
for(int x=0;x<3;x++)
b[y][x] = a[y][x];
PrintArray1D(a[0]);
PrintArray1D(b[0]);
}
當你運行它,你會得到:
1 2 3 4 5 6
1 2 3 0 0 0
印刷b
給出零(我的機器上),因爲它運行到未初始化的內存。結果是使用連續的內存可以讓你做一些方便的事情,讓所有的值都可以不需要雙循環。
出於好奇,int a [2] [3] = {{1,2},{3,4},{5}}'會觸發什麼警告? –
「這不一定如此。」 - 請詳細說明!「包含int [3]數組的數組可能在內存中不連續。」 - 那是錯的。 'int a [2] [3]'**是**數組的數組,並保證在內存中連續不斷!它不能是別的。如果你引用類似'int * a [3]'的東西:這是一個完全不同的數據類型,而不是一個數組數組! – Olaf
@Olaf:的確如此。 'int a [2] [3]'在內存中是連續的,所有訪問都是有效的。但是,在您分開分配行的情況下,陣列數組上的'a [2] [3]'訪問模式不能保證有效。 – Richard
在C中,一維數組存儲在所謂的「行優先」順序在存儲器中的單個線性緩衝器中。行重大意味着最後一個索引因元素而變化最快。例如,列主要意味着第一個索引變化最快,正如它在MATLAB中所做的那樣。
您聲明的數組僅僅是2D,因爲編譯器通過爲您計算元素的線性地址來幫助您。計算一維數組中元素的地址爲linear[x] = linear + x
。同樣,對於你的2D陣列,a[y][x] = a + 3 * y + x
。一般來說,a[y][x] = a + num_cols * y + x
。
您可以將數組初始化爲單個元素向量,它將首先填充第一行,然後填充第二行,依此類推。由於您有兩行三個元素,第一行變爲1, 2, 3
,第二行變爲4, 5, 0
。
只要編譯器至少關心,對行尾進行索引是完全有效的。在您給出的示例中,a[0][3]
正在訪問三元素寬的數組中第一行的第四個元素。使用環繞式,您可以看到這只是第二行的第一個元素,更明確地指出爲a[1][0]
。
由於鬆散索引檢查,只要提供初始化程序,就可以完全忽略任何數組中的第一個索引。計算線性地址的公式不依賴於第一個索引(因爲它是主要的行),並且元素的總數由初始化程序本身指定。一個例子是int linear[] = {1, 2, 3};
。
請記住,數組的名稱也指向指向其第一個元素的指針。這些是可以用同一個名字訪問的兩種不同的東西。
一般性聲明「C沒有對指針算術和數組索引進行任何邊界檢查」實際上並非如此,因爲甚至數組邊界之外的指針算術都是未定義的行爲;它甚至是一個討論,如果違反子數組的邊界是未定義的行爲。 –
@StephanLechner。雖然確實,編譯器明確允許你觸發這種未定義的行爲,但這還不夠公平。正如您所指出的那樣,我刪除了這些違規行,因此與討論無關。 –
允許此初始化程序實際上是一項遺留問題,與內存中的數組佈局無關。 Moern編譯器會警告這些代碼。 – Olaf
從解釋如何訪問像解碼「a[1][2]
」這樣的二維數組的定義來看,「由此得出數組以行優先順序存儲」(例如,參見此online C standard comitee draft/array subscripting)。 這意味着對於訪問a[r][c]
的數組int a[ROWS][COLUMNS]
,按照(r*COLUMNS + c)
計算int值的偏移量。
因此對於陣列int a[2][3]
,接入a[0][1]
已偏移0*3 + 1 = 1
和接入a[1][0]
具有偏移1*3 + 0 = 3
。也就是說,a[0][3]
可能會導致抵消3
,而a[1][0]
肯定會導致3
。我寫了「might」,因爲我認爲使用a[0][3]
訪問數組int a[2][3]
是未定義的行爲,因爲最後一個下標的範圍是0..2
。因此根據6.5.6(8),表達式a[0][3]
正在討論的範圍之外尋找子陣列a[0]
,例如,here。
現在來解釋如何解釋int a[2][3] = {1,2,3,4,5}
。這項聲明是在section 6.7.9 of this online C standard comitee draft定義的初始化,以及第(20)(26)描述了這裏所需要的東西:
(20)如果聚集或聯合包含的元素或成員是 聚集或工會,這些規則遞歸地適用於 子集或包含的聯合。如果 子集或包含的聯合的初始化程序以左大括號開始,則大括號及其匹配的右大括號 所包含的初始值設定項會初始化子集或包含聯合的 的元素或成員。否則,從清單中只有足夠的初始化程序是 是考慮到子集的要素或成員或包含工會的第一個成員的 ;任何其餘的初始化程序 都將被初始化爲當前子集聚或包含的聯合是其一部分的集合 的下一個元素或成員。
(21)如果在一個大括號內的列表更少初始化值多於 是用於初始化已知大小的陣列之外還有 是元件的元件或聚集體的成員,或更少的字符在 字符串文字在數組中,聚合的其餘部分應該是 ,隱含地初始化爲具有靜態存儲持續時間的對象。
26實施例
(3)該聲明
int y[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, };
是與完全括號初始化一個定義:
1
,3
,和5
初始化的y
第一行(陣列對象y[0]
),即y[0][0]
,y[0][1]
和y[0][2]
。同樣,接下來的兩行初始化爲y[1]
和y[2]
。初始化程序提前結束,所以y[3]
用 零初始化。正是同樣的效果可能是由int y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };
爲
y[0]
的初始化不與左括號開始實現的,因此從列表中的三個項目中使用。同樣,接下來的三個 連續取得y[1]
和y[2]
。
cppreference不是權威資源。爲什麼不參考標準,最後的草稿? – Olaf
@Olaf:對,cppreference不是規範性的;但我只是在尋找示例,而我在這裏找到更簡短的參考。無論如何,你有最終的網上草稿嗎?我總是找到我用於引用的那個... –
@ StephanLechner--這是我的[C11 Draft Standard]的轉到鏈接(http://port70.net/~nsz/c/c11/n1570.html#內容)。引用非常方便。 –
- 1. 二維數組初始化
- 2. 初始化二維數組
- 3. 初始化二維數組
- 4. 在Python中初始化二維數組
- 5. Malloc錯誤初始化二維數組
- 6. 處理/初始化二維數組(Java)
- 7. C++二維數組初始化
- 8. 的Clojure/core.matrix /初始化二維數組
- 9. 初始化二維數組對象
- 10. 打字稿初始化二維數組
- 11. C中的二維數組初始化
- 12. Typescript - 初始化二維數組錯誤
- 13. 動態二維數組初始化
- 14. 初始化二維數組的問題
- 15. 二維數組未正確初始化
- 16. 初始化多維數組
- 17. 初始化多維數組
- 18. C - 如何初始化一個預初始化的二維數組數組?
- 19. OpenMP - 初始化一維數組
- 20. 如何初始化二維數組以包含圖像?
- 21. 一維數組和二維數組
- 22. 將一維數組爲二維數組
- 23. 如何在Swift 2中初始化一個二維數組?
- 24. 如何初始化一個PHP二維數組
- 25. C編程 - 初始化一個結構二維數組
- 26. 初始化一個二維數組的字符串
- 27. 正在初始化一個二維數組
- 28. 如何在一個類中初始化二維數組?
- 29. 如何初始化一個二維數組?
- 30. 在C++中初始化一個二維數組
查找「行大訂單」。 –
我很驚訝,我找不到這個問題的重複。 –
爲什麼[0] [3]和[1] [0]都指向4? – Fullmetal