2011-07-21 112 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