关于指针和多维数组的困惑

标签 c pointers multidimensional-array

如果以下是可能的:

MyFunction(int *array, int size)
{
    for(int i=0 ; i<size ; i++)
    {
        printf(“%d”, array[i]);
    }
}

main()
{
    int array[6] = {0, 1, 2, 3, 4, 5};
    MyFunction(array, 6);
}

为什么下面不是?

MyFunction(int **array, int row, int col)
{
    for(int i=0 ; i<row ; i++)
    {
        for(int j=0 ; j<col ; j++)
        {
            printf(“%d”, array[i][j]);
        }
    }
}

main()
{
    int array[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
    MyFunction(array, 3, 3);
}

最佳答案

首先,一些standard语言:

6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

给出声明

int myarray[3][3];

myarray类型是“int 的三元素数组的三元素数组”。按照上面的规则,当你写的时候

MyFunction(myarray, 3, 3);

表达式 myarray其类型从“int 的三元素数组的三元素数组”隐式转换(“衰减”)为“指向int 的三元素数组的指针”,或int (*)[3] .

因此,您的函数原型(prototype)需要是

int MyFunction(int (*array)[3], int row, int col)

请注意 int **arrayint (*array)[3]相同;指针算法会有所不同,因此您的下标不会指向正确的位置。请记住,数组索引是根据指针算法定义的:a[i] == *(a+i) , a[i][j] == *(*(a + i) + j) . a+i将根据是否 a 产生不同的值是一个 int **int (*)[N] .

此特定示例假设您始终传递一个 Nx3 元素数组 int ;如果你想处理任何 NxM 大小的数组,就不是很灵活。解决这个问题的一种方法是显式传递数组中第一个元素的地址,这样您只需传递一个简单的指针,然后手动计算正确的偏移量:

void MyFunction(int *arr, int row, int col)
{
  int i, j;
  for (i = 0; i < row; i++)
     for (j = 0; j < col; j++)
       printf("%d", a[i*col+j]);
}

int main(void)
{
  int myarray[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
  ...
  MyFunction(&myarray[0][0], 3, 3);

由于我们将一个简单的指针传递给 int , 我们不能在 MyFunc 中使用双下标; arr[i] 的结果是一个整数,而不是一个指针,所以我们必须在一个下标操作中计算数组中的完整偏移量。请注意,此技巧仅适用于真正的多维数组。

现在,一个 ** 可以表示以二维结构组织的值,但构建方式不同。例如:

void AnotherFunc(int **arr, int row, int col)
{
  int i, j;
  for (i = 0; i < row; i++)
    for (j = 0; j < col; j++)
      printf("%d", arr[i][j]);
}

int main(void)
{
  int d0[3] = {1, 2, 3};
  int d1[3] = {4, 5, 6};
  int d2[3] = {7, 8, 9};

  int *a[3] = {d0, d1, d2};

  AnotherFunc(a, 3, 3);
  ...
}

按照上面的规则,当表达式 d0 , d1 , 和 d2出现在 a 的初始化程序中,它们的类型都从“int 的三元素数组”转换为“指向int 的指针”。同样,当表达式 a出现在对 AnotherFunc 的调用中,其类型从“指向int 的指针的三元素数组”转换为“指向int 的指针的指针”。

请注意,在 AnotherFunc 中我们对两个维度都下标,而不是像在 MyFunc 中那样计算偏移量.那是因为 a指针 值的数组。表达式 arr[i]从位置 arr 获取第 i 个指针值偏移量;然后我们找到从该指针值偏移的第 j 个整数值。

下表可能会有所帮助 - 它显示了各种数组表达式的类型以及它们根据声明衰减到什么(T (*)[N] 是指针类型,而不是数组类型,因此它不会衰减):

Declaration            Expression            Type            Implicitly Converted (Decays) to
-----------            ----------            ----            --------------------------------
     T a[N]                     a            T [N]           T *
                               &a            T (*)[N]
                               *a            T
                             a[i]            T

  T a[M][N]                     a            T [M][N]        T (*)[N]
                               &a            T (*)[M][N] 
                               *a            T [N]           T *
                             a[i]            T [N]           T *
                            &a[i]            T (*)[N] 
                            *a[i]            T
                          a[i][j]            T

T a[L][M][N]                    a            T [L][M][N]     T (*)[M][N]
                               &a            T (*)[L][M][N]
                               *a            T [M][N]        T (*)[N]
                             a[i]            T [M][N]        T (*)[N]
                            &a[i]            T (*)[M][N]
                            *a[i]            T [N]           T *
                          a[i][j]            T [N]           T *
                         &a[i][j]            T (*)[N]
                         *a[i][j]            T 
                       a[i][j][k]            T

高维数组的模式应该很清楚。

关于关于指针和多维数组的困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3911244/

相关文章:

c - 从函数获取结构输入

c - 如何使用 openssl API 解密 ASN.1 DER 编码的 CMS 文件?

c++ - 重载运算符<<用于查找二维数组的总和

arrays - 如何按作为结构​​值包含的数组进行过滤

c - 使用宏定义在 C 中声明多版本结构

c - 修改链接列表中的值 - 返回已编辑的列表,但缺少节点。 (C)

c - 左值无效,函数指针也无效,这有什么用?调用函数就简单多了

c++ - 这些 C++ 函数返回什么? ClassA*& func1()

c - GCC 编译的 Win32 程序在系统 DLL 调用期间崩溃

java - 检查二维数组中的相邻元素并替换它们