2017-09-03 129 views
1

如果我有一個多維數組這樣的:多維陣列參考

int arr2d[2][3] = {{0,1,2}, {10,11,12}}; 

我可以將它傳遞給這樣的功能:

void foobar(int arg[][3]) 

這不是由呼叫值,這是通過引用調用的,所以只是一個指向開始地址的指針,但編譯器仍然知道它是一個二維數組,並且我可以像訪問函數一樣訪問它。

現在如何在一個結構中工作?

typedef struct { 
    int arr2d[][3]; 
} Foobar_t 

首先這給了我:error: flexible array member in otherwise empty struct。我可以這樣解決這個問題:

typedef struct { 
    int dummy; 
    int arr2d[][3]; 
} Foobar_t 

它將編譯沒有錯誤或警告。但是,當我嘗試使用它像Foobar_t foobar = {1337, arr2d}我得到一些警告:

missing braces around initializer 
initialization makes integer from pointer without a cast 

和訪問時:subscripted value is neither array nor pointer nor vector

一維數組很容易被視爲指針。但對於多維數組,編譯器需要知道不同維度的大小才能正確計算偏移量。有沒有方法(int (*)[3])和爲什麼語法不同於函數參數?

所以這是變通我想避免:

#include <stdio.h> 

static int testArr[2][3] = {{0,1,2},{10,11,12}}; 

typedef struct { 
    int *arr2d; 
} Foobar_t; 


int main(int argc, char** argv) { 
    Foobar_t foobar = {(int*)testArr}; 
    int (*arr2d)[3] = (int (*)[3]) foobar.arr2d; 
    printf("testStruct_0_0: %d\n", arr2d[0][0]); 
    printf("testStruct_1_0: %d\n", arr2d[1][0]); 

    return 1337; 
} 

編輯:

一些言論表明,引用不正確的單詞。當然在C語言中,這是通過一個指針來實現的。 因此,這個問題的TLDR是:指針類型到多維數組的語法是怎樣的。

答案已經可以在我的解決方法代碼中看到。所有這一切,一起前進,沒什麼可看的;)儘管如此,謝謝你的回覆。

+0

有一個結構,只是爲FAM在用C –

+1

沒有提到你不能有不完全類型至少有一個其他成員(因此是你的「虛擬」成員)的結構的結尾。當你有一個FAM時,你必須動態地分配正確數量的內存結構。 –

+0

在你的解決方法中,你的代碼行'Foobar_t foobar = {(int *)testArr};'可以寫得更乾淨'Foobar_t foobar = {&testArr [0] [0]};' - 不需要強制轉換。第二個演員不容易避免。 –

回答

0

原來只是在尋找工作,圍繞給我的解決方案:

typedef struct { 
    int (*arr2d)[3]; 
} Foobar_t; 

這是正確類型的指針,一個二維數組。 type (*name)[n]也適用於功能參數。

那麼爲什麼其他語法type name[][n]仍然對函數參數有效?可能與結構的靈活數組功能的衝突使它無法在那裏工作。

0

你可以嘗試使用int **arr2d,這將允許你通過arr2d[x][y]訪問它,或者簡單地將它轉換爲像int *arr2d = malloc(2*3*sizeof(int));這樣的一維數組。 這樣,您需要訪問像這樣的值:arr2d[x*m + y];,其中xy與前面的示例相同,而m是行的大小。

我也建議你將二維數組的行號和列號存儲到結構中。

+1

如果類型是'int **'並通過'arr2d [x] [y]'來訪問,那麼編譯器如何知道y的偏移量是1,int的偏移量是3? – cubei

+0

它根本不知道任何這一點;事實上,你應該傳遞額外的參數來「手動」檢查你不會超出任何大小。請記住,儘管使用int **變量,您應該手動初始化每個單獨的變量,如下所示: 'int ** arr2d;' '// n =行數,m =列數 - >分配n * m「places」' 'arr2d =(int **)malloc(n * m * sizeof(int));' '//對於每一行i,分配m個「位置」' 'for(int i = 0; i

+0

如果它不知道,那麼通過'arr2d如果沒有如上所述的鑄造,[x] [y]'是不可能的。 malloc的東西並不涉及questen。因爲有人說這個陣列已經可用,應該只是提及。 – cubei

1

C語言中沒有「引用調用」。函數參數是總是按值傳遞。數組確實顯得特別,因爲數組在大多數表達式(包括函數調用)中衰減爲指向其第一個元素的指針。這意味着當一個數組被用作函數調用的參數時,指向第一個元素的指針被傳遞給函數而不是數組;但它是傳遞的這個指針的值。

在函數聲明符中,數組類型被調整爲指向適當類型的指針。這是特定於函數聲明符的語義。因此,像一個函數聲明:

void foobar(int arg[][3]); 

被調整到一個指針指向三個int秒的數組作爲參數:

void foobar(int (*arg)[3]); 

通常,一種類型的表達式如int arg[][3]不完整類型,因爲不可能知道沒有更多信息的數組arg[][]的大小。

C中的結構不允許使用不完整類型指定成員類型(有一個例外),因爲如果沒有這些信息,無法知道struct的大小。此外,struct說明符不會對函數聲明器所做的數組類型進行相同的調整,因爲struct可能實際上包含數組成員。

struct s中的不完整類型規則的例外是彈性陣列成員。具有至少兩個命名成員的struct的最後一個成員可能具有不完整的數組類型。

問題的簡單解決方案是更改struct的說明符以使用指向數組的指針。需要注意的是這裏的成員.arr2d不是一個數組,而是一個指向三個int秒的數組:

typedef struct { 
    int (*arr2d)[3]; 
} Foobar_t; 
+0

通過引用調用意味着數據是由引用給出的:這裏是地址,可以由*運算符取消引用(或者對某些類型使用 - >運算符隱式引用)。 – cubei

+0

感謝您的回答。 'int(* arr2d)[3]'是我正在尋找的東西。我注意到這一問題,因爲在我的解決方法中,我使用的是確切類型... – cubei

+0

@ cubei--我看到你找到了解決方案,但不是'int arr2d [] [3] '可以在函數聲明器中工作,但不能在'struct'指定符中工作;這是我的答案的主要焦點。另外,C沒有引用,但指針。有些語言使用引用,但在C中,它總是一個傳遞給函數的值(例如,「int」或指向「int」的指針);區別很重要。 –