将多维数组传递给C中的函数

Isr*_*ael 2 c pointers function multidimensional-array pointer-to-pointer

我有这样的功能:

void myfunc(int** arr, int n) {
  int i, j;
  for(i=0; i<n; ++i) {
    for(j=0; j<n; ++j) {
      printf("%d,", *(arr + i*n + j) );  // Print numbers with commas
    }
    printf("\n");                        // Just breakline
  }
}
Run Code Online (Sandbox Code Playgroud)

在其他函数中我有一个二维数组,如下所示:

int main() {
  int seqs[8][8] = {
    {0, 32, 36, 52, 48, 16, 20, 4},
    {0, 16, 20, 52, 48, 32, 36, 4},
    {0, 32, 36, 44, 40, 8, 12, 4},
    {0, 8, 12, 44, 40, 32, 36, 4},
    {0, 32, 36, 38, 34, 2, 6, 4},
    {0, 2, 6, 38, 34, 32, 36, 4},
    {0, 32, 36, 37, 33, 1, 5, 4},
    {0, 1, 5, 37, 33, 32, 36, 4}
  };

  // Call to myfunc
  myfunc(seqs, 8);  // This is the idea
}
Run Code Online (Sandbox Code Playgroud)

但编译器抛出这个错误:

lab.c: In function 'main':
lab.c:75:5: warning: passing argument 1 of 'myfunc' from incompatible pointer type [enabled by default]
lab.c:4:6: note: expected 'int **' but argument is of type 'int (*)[8]'
Run Code Online (Sandbox Code Playgroud)

将此array(seqs)传递给function(myfunc)的正确方法是什么?

Jon*_*ler 5

在C99或C11中,你会这样做:

void myfunc(int n, int arr[n][n])
{
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < n; ++j)
            printf("%d,", arr[i][j]);
        printf("\n");
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,大小在数组之前,而不是在数组之后.此功能可以正常使用:

int main(void)
{
    int seqs[8][8] =
    {
        { 0, 32, 36, 52, 48, 16, 20, 4 },
        { 0, 16, 20, 52, 48, 32, 36, 4 },
        { 0, 32, 36, 44, 40,  8, 12, 4 },
        { 0,  8, 12, 44, 40, 32, 36, 4 },
        { 0, 32, 36, 38, 34,  2,  6, 4 },
        { 0,  2,  6, 38, 34, 32, 36, 4 },
        { 0, 32, 36, 37, 33,  1,  5, 4 },
        { 0,  1,  5, 37, 33, 32, 36, 4 },
    };
    myfunc(8, seqs);

    int matrix3x3[3][3] = { { 1, 2, 3 }, { 2, 4, 6 }, { 3, 6, 9 } };
    myfunc(3, matrix3x3);
}
Run Code Online (Sandbox Code Playgroud)

有人问我:

你的例子确实看起来确实好多了,但它是否定义明确?难道n真的保证之前进行评估int arr[n][n]?功能参数的评估顺序不是未指定的行为吗?

旧标准(ISO/IEC 9899:1999)在§6.7.5.2*数组声明符*中说:

5 如果size是一个不是整数常量表达式的表达式:如果它出现在函数原型范围的声明中,则将其视为替换为*; 否则,每次评估它时,其值应大于零.可变长度数组类型的每个实例的大小在其生命周期中不会改变.如果size表达式是运算sizeof符操作数的一部分,并且更改size表达式的值不会影响运算符的结果,则无法指定是否计算size表达式.

它给出了一个例子(它是非规范性文本,因为它是一个例子,但强烈表明了预期的内容):

示例4可变修改(VM)类型的所有声明必须处于块范围或函数原型范围.使用staticextern存储类说明符声明的数组对象不能具有可变长度数组(VLA)类型.但是,使用static存储类说明符声明的对象可以具有VM类型(即指向VLA类型的指针).最后,使用VM类型声明的所有标识符必须是普通标识符,因此不能是结构或联合的成员.

extern int n;
int A[n];                       // invalid: file scope VLA
extern int (*p2)[n];            // invalid: file scope VM
int B[100];                     // valid: file scope but not VM
void fvla(int m, int C[m][m]);  // valid: VLA with prototype scope
void fvla(int m, int C[m][m])   // valid: adjusted to auto pointer to VLA
{
    typedef int VLA[m][m];      // valid: block scope typedef VLA
    struct tag {
        int (*y)[n];            // invalid: y not ordinary identifier
        int z[n];               // invalid: z not ordinary identifier
    };
    int D[m];                   // valid: auto VLA
    static int E[m];            // invalid: static block scope VLA
    extern int F[m];            // invalid: F has linkage and is VLA
    int (*s)[m];                // valid: auto pointer to VLA
    extern int (*r)[m];         // invalid: r has linkage and points to VLA
    static int (*q)[m] = &B;    // valid: q is a static block pointer to VLA
}
Run Code Online (Sandbox Code Playgroud)

还有其他示例显示可变修改的功能参数.

另外,在§6.9.10 函数定义中,它说:

10进入函数时,将评估每个可变修改参数的大小表达式,并将每个参数表达式的值转换为相应参数的类型,就像通过赋值一样.(数组表达式和函数指示符作为参数在调用之前转换为指针.)

  • 嗯,这是你的答案号码2 ^ 13,非常有诗意:) (2认同)