2017-09-03 96 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”的指针);区别很重要。 –