2011-07-21 152 views
3

我有試圖通過一個結構體的二維數組循環功能:分配到二維數組二維數組中的一個結構

typedef struct node 
{ 
    int grid[3][3]; 
} Node; 


void someFunction(Node *node) { 
    int grid[3][3] = node->grid; 
    //loop through 
} 

當我嘗試編譯這個,但是我得到一個

mp.c:42: error: invalid initializer

+0

一件事,爲什麼不只是傳遞一個int [] [3],而不是在一個節點包裹它,因爲它只是一個1名成員結構? –

+0

@Jesus Ramos我打算在結構中加入其他屬性。 – Jeune

+1

@Jesus Ramos:儘管Jeune表示它不會那樣,但將數組變成「頭等」類型是一種常見的方式。簡單地說,就是爲了帶來諸如允許賦值(自動複製數組)或從函數返回數組等優點。 – sidyll

回答

11

你不能在C中分配數組,這是不允許的。當你寫:

int grid[3][3] = node->grid; 

您試圖初始化本地陣列,grid,從傳遞node。如果這是允許的(事實並非如此),那麼你以後不需要循環。

您可以分配結構,不過,即使它們包含數組,因此,如果局部結構是一個Node,你可以寫:

Node local = *node; 

您將無法通過陣列需要循環之後初始化local

你可以通過數組循環,拷貝一個元素在同一時間做:

for (int i = 0; i < 3; i++) 
    for (int j = 0; j < 3; j++) 
     grid[i][j] = node->grid[i][j]; 

您還可以使用memmove()memcpy()

int grid[3][3]; 

assert(sizeof(grid) == sizeof(node->grid)); 
memcpy(grid, node->grid, sizeof(grid)); 

在同一時間,另一答案建議:

Change the line:

int grid[3][3] = node->grid; 

to:

int **grid = node->grid; 

我注意到這不起作用 - 並且被合理地解釋了原因。這需要空間和格式。

首先,編譯器注意事項:

warning: initialization from incompatible pointer type 

即說「你是在玩火」。

假設我們忽略該警告。當地的grid現在指向數組的左上角(如果您看到陣列從左向右逐漸增大)。存儲在那裏的值是一個普通數字,不是初始化的指針,但是當編譯器評估grid[0]時,它被迫假設會產生一個指針。如果node->grid[0][0]包含0,那麼您可能會得到一個分段錯誤和核心轉儲來取消引用空指針(假設指針和int的大小相同,在32位系統上通常是這樣),或者其他未定義的行爲。如果node->grid[0][0]包含另一個值,那麼行爲仍然是未定義的,但不是很可預測。

+0

,然後我可以像正常的二維數組一樣循環網格? – Jeune

+0

@Jeune:是的,它只是一個初始化數組,其中有一個其他內容的副本,您可以在任何您認爲有必要的地方操作該數組。無論使用哪種(可編譯)機制來初始化本地數組,這都可以工作。 –

+0

請注意,您將在此處製作數組的副本,而不僅僅是使用結構中已有的數組。這可能是你想要的,但是如果你只是想要一個局部變量指向結構中的同一個數組,請參見下面的答案。 –

0

看到這個其他線程對同一問題,答案,不涉及複製內存:

Create a pointer to two-dimensional array

+1

否;這將無法正常工作。爲了工作,'grid [0]','grid [1]'和'grid [2]'每個都必須是一個指向數組的指針,儘管出現了,但它不是。 'node-> grid'中的地址被分配給'grid',但'grid [1]'沒有被正確地初始化。答案很難解釋這一點;在評論中這完全是不重要的。 –

+0

爲什麼它不工作? –

+0

雖然我得到這個警告:mp.c:42:警告:從不兼容的指針類型初始化那是什麼意思? – Jeune

1

如果你不想做的拷貝,只想要一個指針陣列中的結構(注意:如果分配值*pointer,在結構中的陣列的內容將被改變),就可以以兩種方式實現這個目的:

#include <stdio.h> 

typedef struct node 
{ 
    int grid[3][3]; 
} Node; 


void someFunction1(Node *node) { 
    int i, j; 
    int (*grid)[3] = node->grid; 
    for(i=0; i<3; i++){ 
     for(j=0; j<3; j++){ 
      printf("%d ", grid[i][j]); 
     } 
     printf("\n"); 
    } 
} 

void someFunction2(Node *node) { 
    int i, j; 
    int *grid = (int*) node->grid; 
    for(i=0; i<3; i++){ 
     for(j=0; j<3; j++){ 
      printf("%d ", grid[i*3+j]); // i * column_number + j 
     } 
     printf("\n"); 
    } 
} 

int main() 
{ 
    Node t; 
    int i, *p; 

    //initialization: t.grid[0][0]=0, ..., t.grid[2][2]=8 
    for(i=0, p=(int*)t.grid; i<9; p++, i++){ 
     *p = i; 
    } 

    printf("Function1:\n"); 
    someFunction1(&t); 

    printf("Function2:\n"); 
    someFunction2(&t); 

    return 0; 
} 

上面的代碼顯示一個簡單的函數使用指針。他們都是安全的,達到標準。

如果要使用指針指針int**,則必須以不同的方式創建它,因爲數組是線性存儲器(因此上述代碼可以使用指向開頭的int*數組並操作它),但不是int**

編輯

所以來這裏的someFunction3()

void someFunction3(Node *node) 
{ 
    int i, j; 
    int **p; 

    // 3 is the row number. Ignore checking malloc failure 
    p = malloc(sizeof(int)*3); 
    for(i=0; i<3; i++) { 
     p[i] = (int*) node->grid[i]; //assign address of each row of array to *p 
    } 

    for(i=0; i<3; i++) { 
     for(j=0; j<3; j++) { 
      printf("%d ", p[i][j]); 
     } 
     printf("\n"); 
    } 

    free(p); 
} 
+0

使用'&node-> grid [0] [0]'(或者只是'node-> grid [0]')初始化'int *'值時,可以避免強制轉換。 – caf

+0

@caf:謝謝。你是對的。這是我的壞習慣。我懶得考慮類型問題:-p – Stan