我可以 return C 中的二维数组吗?

Can I return a 2D array in C?

我收到此错误:

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;

}

我正在尝试 return 我在函数内部生成的二维数组。

我主要在 Python 中编写代码,所以 C 中的数组让我大吃一惊..

您不能传递数组 to/from C 中的函数。但是您可以传递指针。并且可以指向一个数组。

所以,你需要一个像这样的函数:

#define COLS 2

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

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

这是一个"function without arguments returning a pointer to an 1D array with COLS ints"。有关 C 中数组和指针的详细信息,请参阅一本好的 C 书籍并自行研究。请记住,虽然它们是不同的类型,但在实际使用中它们有很多共同点(后面的语言机制更难理解)。

简单地说,如果你在上面的函数声明中使用return valid,数组的名称将被转换为指向第一个元素的指针。这正是您应该 return.

调用方需要对结果使用相同的指针类型(指向一维数组的指针):

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);

在 C 数组中,第二个 class 公民。为了传递它们,您需要包装在一个结构中。

即:

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;

}

然后你可以像这样存储你的函数 return 值:

struct t_array42int tmp = getValid(something);

当然有一些方法可以简化 "wrapping" 的过程,但这些方法通常不标准或过于模糊。

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

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

相反。

你也可以 return 指向你的数组的指针,因为它的存储是静态的(即它不会在 return 从函数中退出后不复存在):

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] 那样访问,因此最多有 2 个 int.

类型的元素

上述示例的简单实例为:

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
}

事实上,你必须让一个n维数组衰减到一个指向n-1维数组的指针。当您使用静态数组时,return 它的地址是安全的。

唯一棘手的事情是声明一个函数 return 指向一个大小为 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);
}

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

但是注意:它是安全的,只是因为 valid 是用静态存储声明的。永远不要 return 指向自动数组的指针! (使用动态数组(如果您不想静态存储,则使用 malloc 分配)