我可以在C中返回2D数组吗?

时间:2016-06-20 02:09:01

标签: c arrays 2d

我收到了这个错误:

incompatible pointer types returning 'int [4][2]' from a function with result type 'int *'

当我尝试这样做时

int* getValid(int blank[2]){

int row = blank[0];
int col = blank[1];
static int valid[4][2];

valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;

return valid;

}

我正在尝试返回我在函数内部生成的2D数组。

我主要用Python编写代码,所以C中的数组正在踢我的屁股..

3 个答案:

答案 0 :(得分:1)

您无法将数组传入/传出C中的函数。但您可以传递指针。这可以指向数组。

所以,你需要一个像:

这样的函数
#define COLS 2

int (*getValid(int blank[2]))[COLS]
{
    static int valid[4][COLS];
    ...
    return valid;
}

注意括号。我还使用COLS作为内在维度的长度。这避免了幻数,即在整个代码中重复常量。将该宏用于涉及数组的所有声明,包括定义。

这是一个"函数,没有参数返回指向带有COLS int s"的1D数组的指针。有关C中的数组和指针的详细信息,请参阅一本好的C书并自行进行一些研究。请记住,虽然它们是不同的类型,但在实际使用中有很多共同的 (背后的语言机制更难以理解)。

简单地说,如果将return valid与函数的上述声明一起使用,则数组的名称将转换为指向第一个元素的指针。这正是你应该回归的。

调用者需要为结果使用相同的指针类型(指向1D数组的指针):

int (*arr)[COLS] = getValid(...);

可以像原始数组一样访问元素:

arr[row][col]

附加信息:除非您希望在调用之间保持安全状态,否则不应在函数中使用静态数组。使用malloc更好地动态分配数组:

int (*arr)[COLS];
arr = malloc(sizeof(*arr) * 4); // 4 rows of the inner array

请勿忘记检查malloc是否失败并采取适当措施。

一旦你完成了它(但不早点),也不要忘记释放动态分配的数组:

free(arr);

答案 1 :(得分:0)

实际上,必须让n维数组衰减到指向n-1维数组的指针。当您使用静态数组时,可以安全地返回其地址。

唯一棘手的事情是声明一个函数返回一个指向大小为2的数组的指针,但是typedef在这里真的有用:

typedef int Arr2[2];

Arr2* getValid(int blank[2]){

    int row = blank[0];
    int col = blank[1];
    static int valid[4][2];

    valid[0][0] = row;
    valid[0][1] = col-1;
    valid[1][0] = row;
    valid[1][1] = col+1;
    valid[2][0] = row-1;
    valid[2][1] = col;
    valid[3][0] = row+1;
    valid[3][1] = col;

    return valid;

}

你可以安全地使用它:

Arr2 * arr = getValid(blank);

for (i=0; i<4; i++) {
    for (j=0; j<2; j++) {
        printf(" %d", arr[i][j]);
    }
    putc('\n', stdout);
}

编译并运行正常,没有任何警告。

但是要注意:它只是因为有效是通过静态存储声明的,所以是安全的。永远不要返回指向自动数组的指针! (如果您不想要静态存储,请使用动态数组(使用malloc分配)

答案 2 :(得分:-1)

在C阵列中是二等公民。为了传递它们,你需要包裹一个结构。

即:

struct t_array42int{int o[4][2];} getValid(int *blank){

int row = blank[0];
int col = blank[1];
static struct t_array42int valid_container;

int (*valid)[2] = valid_container.o;

valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;

return valid_container;

}

然后您可以存储函数返回值,如:

struct t_array42int tmp = getValid(something);

当然,有一些方法可以简化&#34;包装&#34;但那些通常不标准或太混淆。

使用结构的缺点是结构类型不是通过它们的成员布局进行比较,而是(通常)通过它们的名称进行比较。所以像这样:

struct { int o[2]; } a;

struct { int o[2]; } b;

a = b; //Error

是非法的。

你应该写:

struct t_array2int { int o[2]; } a;

struct t_array2int b;

a = b; //OK

相反。

您也可以返回指向数组的指针,因为它的存储是静态的(即从函数返回后它不会再存在):

int (*getValid(int *blank))[2]{

int row = blank[0];
int col = blank[1];
static int valid[4][2];


valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;

return valid;

}

函数原型:

int (*getValid(int *blank))[2]

意味着如果您使用getValid - int *类型的单个参数调用函数getValid(something)并取消引用它,*getValid(something)您将获得一个数组无法像(*getValid(something))[2]那样访问,因此最多包含int类型的2个元素。

以上示例的简单实例将是:

int (*tmp)[2] = getValid(something);

我还建议用你的实数类型编写你的数组参数(它永远不能是一个数组 - 编译器只是在愚弄你以为数组可以通过值传递)。即:void f(int a[N])调整为void f(int *a)int *int [N]不同。

对于一个新手,我建议你记住,数组与指针不同,但却被严重错误地处理。另外我建议你永远不要用数组参数写函数。如果你想以不同的方式使用数组,那么获得指向第一个元素的指针来使用结构 - 更安全。

数组参数的主要内容是:

void f(int a[2]) 
{ 
    sizeof(a) == sizeof(int *); //evaluates to 1

    sizeof(a) != sizeof(int [2]); //evaluates to 1
}