我有試圖通過一個結構體的二維數組循環功能:分配到二維數組二維數組中的一個結構
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
我有試圖通過一個結構體的二維數組循環功能:分配到二維數組二維數組中的一個結構
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
你不能在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]
包含另一個值,那麼行爲仍然是未定義的,但不是很可預測。
,然後我可以像正常的二維數組一樣循環網格? – Jeune
@Jeune:是的,它只是一個初始化數組,其中有一個其他內容的副本,您可以在任何您認爲有必要的地方操作該數組。無論使用哪種(可編譯)機制來初始化本地數組,這都可以工作。 –
請注意,您將在此處製作數組的副本,而不僅僅是使用結構中已有的數組。這可能是你想要的,但是如果你只是想要一個局部變量指向結構中的同一個數組,請參見下面的答案。 –
看到這個其他線程對同一問題,答案,不涉及複製內存:
否;這將無法正常工作。爲了工作,'grid [0]','grid [1]'和'grid [2]'每個都必須是一個指向數組的指針,儘管出現了,但它不是。 'node-> grid'中的地址被分配給'grid',但'grid [1]'沒有被正確地初始化。答案很難解釋這一點;在評論中這完全是不重要的。 –
爲什麼它不工作? –
雖然我得到這個警告:mp.c:42:警告:從不兼容的指針類型初始化那是什麼意思? – Jeune
如果你不想做的拷貝,只想要一個指針陣列中的結構(注意:如果分配值*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);
}
一件事,爲什麼不只是傳遞一個int [] [3],而不是在一個節點包裹它,因爲它只是一個1名成員結構? –
@Jesus Ramos我打算在結構中加入其他屬性。 – Jeune
@Jesus Ramos:儘管Jeune表示它不會那樣,但將數組變成「頭等」類型是一種常見的方式。簡單地說,就是爲了帶來諸如允許賦值(自動複製數組)或從函數返回數組等優點。 – sidyll