2009-10-16 50 views
2

我想知道C將如何分配多維數組的數據項,以及它們的分配是否跨機器一致。C如何在多維數組中分配數據項?

我知道,在最低級別,數據項是鄰居,但我不知道他們如何進一步安排。

例如,如果我將3D數組分配爲int threeD[10][5][6],我可以假設&(threeD[4][2][5]) + 1 == &(threeD[4][3][0])?在所有機器上?

在此先感謝您的幫助。

+1

是的,所有數組元素都是連續分配的。 – 2009-10-16 16:23:29

+0

當你有多個維度時,我通常喜歡使用結構(結構)。在調試器中使用它更容易,而且您不必將尺寸的大小傳遞給其他函數。 – toto 2009-10-16 16:33:09

回答

2

元素存儲在Row Major的順序。所以沿着最後維度的元素是連續的。但是,行之間的元素(如您的示例所示)不保證是連續的。這取決於如何分配初始內存。

#include <malloc.h> 
#include <stdio.h> 
#include <stdlib.h> 

// only elements in a single row are guaranteed to be 
// contiguous because of the multiple mallocs 
void main(void) 
{ 
// 3 rows, 4 columns 
int *a[3]; 

for (int row = 0; row < 3; row++) 
    a[row] = (int *)malloc(4*sizeof(int)); 
} 


// all elements are guaranteed to be contiguous 
// in a row major order. 
void main(void) 
{ 
// 3 rows, 4 columns 
int *a[3]; 

int *buf = (int *)malloc(3*4*sizeof(int)); 

for (int row = 0; row < 3; row++) 
    a[row] = buf+4*row; 

assert((&a[1][3] + 1) == &a[2][0]); 
} 
+0

像例子rossmcf中給出的元素保證在行之間是連續的。 C標準對此非常具體。 – hirschhornsalz 2009-10-16 15:17:33

+0

據我瞭解,最初的問題是關於稱爲「多維數組」的語言特徵,即明確聲明爲多維數組的多維數組,因此問題中的「... C分配...」位。儘管您在示例中手動構建的數據結構實現了「多維數組」的概念,但這些手工製作的多維數組實際上都不是語言級C多維數組。 – AnT 2009-10-16 16:49:42

3

C標準在將數組下標和指針算術等同時非常具體,並指定數組按行的主要順序存儲。

考慮由該聲明

int x[3][5]; 

這裏x定義的陣列的對象是3×5陣列的整數;更確切地說,x是一個由三個元素對象組成的數組,每個元素都是一個由五個整數組成的數組。在相當於 (*((x)+(i))),x的表達式x[i]中,首先轉換爲指向五個整數的初始數組的指針。然後 i根據x的類型進行調整,其概念上需要將指針指向的對象的大小乘以i,即由五個int對象組成的數組。結果被添加並且間接被應用以產生五個整數的數組。當在表達式x[i][j]中使用時,該數組又被轉換爲指向第一個整數的指針,因此x[i][j]會生成一個int。

5

是的,在C編譯器的所有實現中,數組以行爲主要順序存儲。
標準說(我施加一些重新格式化):

 
6.5.2.1 Array subscripting 
    Constraints 

3 Successive subscript operators designate an element of a multidimensional 
    array object. 
    If E is an n-dimensional array (n >= 2) with dimensions i * j * . . . * k, 
    then E (used a s other than an lvalue) is converted to a pointer to an 
    (n - 1)-dimensional array with dimensions j * . . . * k. 
    If the unary * operator is applied to this pointer explicitly, or 
    implicitly as a result of subscripting, the result is the pointed-to 
    (n - 1)-dimensional array, which itself is converted into a pointer if 
    used as other than an lvalue. It follows from this that arrays are stored 
    in row-major order (last subscript varies fastest). 
1

首先,在C語言中的地址算術僅給定陣列的邊界內定義。 (我想說「一維(SD)數組」),但從技術上講,C中的所有數組都是SD,多維數組構造爲SD數組的SD數組,這種數組視圖最適合於這個主題) 。在C中,您可以從指針開始到數組的開始,並使用加法操作在該數組內來回移動。你不能跨越你開始的數組的邊界,除非形成一個指向最後一個元素後面的虛構元素的指針是合法的。但是,當訪問元素(讀取和寫入)時,您只能訪問從您開始的陣列中真實存在的元素。其次,在你的例子'& threeD [4] [2] [5] + 1'中,你正在形成一個指向數組''3D [4] [2]的虛構「last-the-last」元素的指針, 」。這本身是合法的。但是,語言規範並不保證該指針等於'& threeD [4] [3] [0]'的地址。它唯一說的是它可能是等於。確實,語言規範強加給數組的其他要求幾乎「強制」了這種關係。但它沒有正式保證。一些迂腐的(有點惡意的)實現完全被允許使用某種編譯器魔術來打破這種關係。第三,實際訪問'*(threeD [4] [2] [5] + 1)'總是非法的。即使指針指向下一個數組,編譯器也可以執行必要的運行時檢查並生成分段錯誤,因爲您正在'threeD [4] [2]'數組上使用指針運算並嘗試訪問超出其界限的東西。第三,做'threeD [4] [2] [5] + 2','... + 3'等總是非法的,出於類似的原因(記住:最後一個是OK,但是2, 3個或更多是非法的)。最後,第五:是的,我知道在很多(如果不是大多數的話)(如果不是全部的話)將'TA [2] [3] [4]'陣列解釋爲扁平'TA [2 * 3 * 4]'陣列將工作。但是,從形式語言的角度來看,這是非法的。如果這個完美工作的代碼有一天會從靜態或動態代碼分析工具(如果不是來自編譯器本身)觸發大量的警告,請不要驚訝。