混淆指针和多维数组 [英] Confusion about pointers and multidimensional arrays

查看:98
本文介绍了混淆指针和多维数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果以下是可能的:

 的MyFunction(INT *数组,INT大小)
{
    的for(int i = 0; I<大小;我++)
    {
        的printf(%d个,数组[我]);
    }
}主要()
{
    int数组[6] = {0,1,2,3,4,5};
    MyFunction的(数组,6);
}

为什么下面是不是?

 的MyFunction(INT **阵列,诠释行,诠释山口)
{
    的for(int i = 0; I<排;我++)
    {
        对于(INT J = 0; J<西; J ++)
        {
            的printf(%d个,数组[I] [J]);
        }
    }
}主要()
{
    int数组[3] [3] = {0,1,2,3,4,5,6,7,8};
    MyFunction的(阵列,3,3);
}


解决方案

首先,一些的标准语言:


6.3.2.1左值,数组和功能代号的结果
...结果
3除非当该值是sizeof运算符或单目&运算符的操作数,或者是用于初始化数组,即具有类型的前pression文字字符串类型的数组转换为前pression,类型为指针输入指向数组对象的初始元素,不是左值。如果数组对象有注册存储类,这种行为是未定义。

由于声明

  INT myArray的[3] [3];

键入 myarray中是3个元素的数组的3元素数组的 INT 。由规则上面去,当你写

  MyFunction的(myarray中,3,3);

前pression myarray中已经从3元的三元素数组的类型隐式转换(衰变) INT 到指向的三元素数组 INT ,或的int数组(*)[3]

这样,你的函数原型将需要

  INT的MyFunction(INT(*数组)[3],诠释行,诠释山口)

注意 INT **阵列不可以一样 INT(*数组)[3] ;指针运算将是不同的,所以你的下标将不拉闸指向正确的地方。请记住,数组索引是的定义的在指针运算方面: A [I] == *(A + I) A [I] [J] == *(*(A + I)+ J) A + I 将根据产生不同的值是否 A INT ** INT(*)[N]

这个特殊的例子假定你总是传递 INT 的NX3元素的数组;不,如果你想,以应付任何的​​N×M大小的数组非常灵活。要解决这个问题的方法之一是明确地传递数组的第一个元素的的地址的,所以你只是传递一个简单的指针,然后计算出正确的手动偏移:

 无效MyFunction的(INT *改编,诠释行,诠释山口)
{
  INT I,J;
  对于(i = 0; I<排;我++)
     为(J = 0; J<西; J ++)
       的printf(%d个,一个[我* COL + J]);
}INT主要(无效)
{
  INT myArray的[3] [3] = {{1,2,3},{4,5,6},{7,8,9}};
  ...
  MyFunction的(安培; myArray的[0] [0],3,3);

由于我们通过一个简单的指针 INT ,我们不能用在双标 MYFUNC ; 的改编结果[I] 是一个整数,而不是一个指针,所以我们必须要计算全偏移在一个下标操作的数组。请注意,这一招只对真正的多维数组。

现在,一个 ** 可以的表明,在一个2-D结构组织的价值观,但建一个不同的方法之一。例如:

 无效AnotherFunc(INT **改编,诠释行,诠释山口)
{
  INT I,J;
  对于(i = 0; I<排;我++)
    为(J = 0; J<西; J ++)
      的printf(%d个,编曲[I] [J]);
}INT主要(无效)
{
  INT D0 [3] = {1,2,3};
  INT D1 [3] = {4,5,6};
  INT D2 [3] = {7,8,9};  为int *一个[3] = {D0,D1,D2};  AnotherFunc(一,3,3);
  ...
}

由规则去上面,当前pressions D0 D 1 和<$ C > $ C> D 2 出现在初始化为,它们的类型都是从为int的3元素数组转换到指针 INT 。同样,当前pression A 出现在调用 AnotherFunc ,其类型从3转换指针-element阵列 INT ,以指针的指针的 INT

请注意,在 AnotherFunc 我们下标两个维度,而不是计算偏移就像我们在 MYFUNC 一样。这是因为 A 指针的值的数组。这位前pression 改编[I] 我们得到第i的指针的值从位置偏移改编;我们再找到第j个整数值从指针值的偏移量。

下面的表格可以帮助 - 它显示的类型不同的阵列前pressions和它们衰变什么根据它们的声明( T(*)[N] 是指针类型,不是数组类型,因此它不衰减):


声明防爆pression类型隐式转换(衰变)到
----------- ---------- ---- ------------------------- -------
     T A [N]一个T [N] T *
                               &一个T(*)[N]
                               *在
                             一个[我] T ...  T A [M] [N]一个T [M] [N] T(*)[N]
                               &一个T(*)[M] [N]
                               *一个T [N] T *
                             一个[I] T [N] T *
                            &A [I] T(*)[N]
                            *一个[我] T ...
                          一个[I] [J] T ...T A [L] [M] [N]一个T [L] [M] [N] T(*)[M] [N]
                               &一个T(*)[L] [M] [N]
                               *一个T [M] [N] T(*)[N]
                             一个[I] T [M] [N] T(*)[N]
                            &一个[I] T(*)[M] [N]
                            * A [I] T [N] T *
                          一个由[i] [j]的T [N] T *
                         &A [I] [J] T(*)[N]
                         * A [I] [J] T ...
                       一个由[i] [j]的[K] T ...

有关高维阵列模式应该是清楚的。

If the following is possible:

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

Why the following is not?

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

解决方案

First, some standard language:

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.

Given the declaration

int myarray[3][3];

the type of myarray is "3-element array of 3-element array of int". Going by the rule above, when you write

MyFunction(myarray, 3, 3);

the expression myarray has its type implicitly converted ("decay") from "3-element array of 3-element array of int" to "pointer to 3-element array of int", or int (*)[3].

Thus, your function prototype would need to be

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

Note that int **array is not the same as int (*array)[3]; the pointer arithmetic will be different, so your subscripts won't wind up pointing to the right places. Remember that array indexing is defined in terms of pointer arithmetic: a[i] == *(a+i), a[i][j] == *(*(a + i) + j). a+i will yield a different value depending on whether a is an int ** or an int (*)[N].

This particular example assumes you're always passing an Nx3-element array of int; not terribly flexible if you want to deal with any NxM-sized array. One way to get around this would be to explicitly pass the address of the first element in the array, so you're just passing a simple pointer, and then compute the proper offset manually:

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

Since we pass a simple pointer to int, we can't use a double subscript in MyFunc; the result of arr[i] is an integer, not a pointer, so we have to compute the full offset into the array in the one subscript operation. Note that this trick will only work for truly multidimensional arrays.

Now, a ** can indicate values that are organized in a 2-D structure, but one that was built a different way. For example:

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

Going by the rule above, when the expressions d0, d1, and d2 appear in the initializer for a, their types are all converted from "3-element array of int" to "pointer to int". Similarly, when the expression a appears in the call to AnotherFunc, its type is converted from "3-element array of pointer to int" to "pointer to pointer to int".

Note that in AnotherFunc we subscript both dimensions instead of computing the offset like we did in MyFunc. That's because a is an array of pointer values. The expression arr[i] gets us the i'th pointer value offset from the location arr; we then find the j'th integer value offset from that pointer value.

The following table might help - it shows the types of various array expressions and what they decay to based on their declarations (T (*)[N] is a pointer type, not an array type, so it doesn't decay):

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

The pattern for higher-dimensional arrays should be clear.

这篇关于混淆指针和多维数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆