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

标签 c function pointers 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
  }
}

在其他函数中,我有一个像这样的二维数组:

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
}

但是编译器抛给我这个错误:

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]'

将此数组 (seqs) 传递给函数 (myfunc) 的正确方法是什么?

最佳答案

在 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");
    }
}

请注意,大小在数组之前,而不是之后。此函数将与以下项一起正常工作:

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

有人问我:

Your example does look much better indeed, but is it well-defined? Is n really guaranteed to be evaluated before int arr[n][n]? Wouldn't the order of evaluation of function parameters be unspecified behavior?

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

¶5 If the size is an expression that is not an integer constant expression: if it occurs in a declaration at function prototype scope, it is treated as if it were replaced by *; otherwise, each time it is evaluated it shall have a value greater than zero. The size of each instance of a variable length array type does not change during its lifetime. Where a size expression is part of the operand of a sizeof operator and changing the value of the size expression would not affect the result of the operator, it is unspecified whether or not the size expression is evaluated.

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

EXAMPLE 4 All declarations of variably modified (VM) types have to be at either block scope or function prototype scope. Array objects declared with the static or extern storage-class specifier cannot have a variable length array (VLA) type. However, an object declared with the static storage class specifier can have a VM type (that is, a pointer to a VLA type). Finally, all identifiers declared with a VM type have to be ordinary identifiers and cannot, therefore, be members of structures or unions.

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
}

还有其他示例显示了可变修改的函数参数。

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

¶10 On entry to the function, the size expressions of each variably modified parameter are evaluated and the value of each argument expression is converted to the type of the corresponding parameter as if by assignment. (Array expressions and function designators as arguments were converted to pointers before the call.)

关于c - 将多维数组传递给 C 中的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21822382/

相关文章:

c - 如果字符串在内存中重叠怎么办?

c - strcmp 调用不断使我的程序崩溃

c++ - 在以抽象基类为参数的函数中将指针和赋值运算符与派生类一起使用

C 将 Char* 的二维数组展平为一维

c - 浮点到 C 中的 char 数组,sprintf

c - 读取文件。如何将字符串放入字符数组?

python - 将函数输入和文档字符串显示为 sublime text 2 的提示(代码搜索?)

c - 如何使用指针在另一个函数中分配数组

c - 返回的字符未显示

arrays - 实例成员不能用于数组类型