如何使用指针表达式访问C中二维数组的元素?

时间:2012-11-25 18:49:19

标签: c pointers multidimensional-array

我知道对于单维数组x=a[i]相当于x=*(a+i),但是如何使用指针访问二维数组的元素?

6 个答案:

答案 0 :(得分:52)

摘要:如果您将多维数组定义为int [][],则x = y[a][b]相当于x = *((int *)y + a * NUMBER_OF_COLUMNS + b);


无聊细节:

上面(int *)的{​​{1}}演员应该得到一些解释,因为它的必要性可能不是直觉上的。要了解为什么必须考虑以下因素:

  1. C / C ++中的类型指针运算总是通过标量加/减/递增/递减时的字节数类型的大小调整类型指针值(地址)

  2. 多维数组声明的基本类型(不是元素类型; 变量类型)是一维维度的数组类型比最后的维度。

  3. 后者(#2)确实需要一个固化的例子。在下文中,变量yar1是等效的声明。

    ar2

    现在指针算术部分。正如类型结构指针可以按字节结构的大小前进,因此可以跳过数组的完整维度。如果您在我上面声明ar2时想到多维数组,这将更容易理解:

    int ar1[5][5]; // an array of 5 rows of 5 ints.
    
    typedef int Int5Array[5];  // type is an array of 5 ints
    Int5Array ar2[5];          // an array of 5 Int5Arrays.
    

    所有这一切都消失了:

    int (*arptr)[5] = ar1; // first row, address of ar1[0][0].
    ++arptr;               // second row, address of ar[1][0].
    

    因此,在对二维数组执行指针运算时,以下方法不能在多维数组的int *ptr = ar1; // first row, address of ar1[0][0]. ++ptr; // first row, address of ar1[0][1]. 处获取元素:

    [2][2]

    当你记得#define NUMBER_OF_COLUMNS 5 int y[5][NUMBER_OF_COLUMNS]; int x = *(y + 2 * NUMBER_OF_COLUMNS + 2); // WRONG 是一个数组数组(声明性地说)时,原因是显而易见的。将缩放器y添加到(2*5 + 2)的指针算法将添加12个,从而计算和地址相当于y,这显然不对,并且事实上,要么在编译时抛出一个胖警告,要么完全无法编译。使用&(y[12])的强制转换避免了这种情况,并且表达式的结果类型基于裸指针到int:

    (int*)y

答案 1 :(得分:23)

表格

在C中,2D阵列是连续的一系列线(不像Pascal那样) 当我们创建一个包含4行和5列的整数表时: A 5*4 integer table.

到达元素

我们可以通过以下方式与大家联系:

int element = table[row-1][column-1];

但我们也可以使用以下代码执行此操作:

int element = *(*(table+row-1)+column-1);

在这些示例中,rowcolumn从1开始计算,这就是-1的原因。 在以下代码中,您可以测试两种技术是否正确。在这种情况下,我们计算从0开始的行和列。

实施例

#include <stdio.h>
#include <stdlib.h>
#define HEIGHT 4
#define WIDTH 5

int main()
{
    int table[HEIGHT][WIDTH] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
    int row = 2;
    int column = 2;
    int a = *(*(table+row)+column);
    printf("%d\n",a);//13
    printf("%d\n",table[row][column]);//13
    return 0;
}

解释

这是一个双精算算术,因此table指向第一行,*table指向第一个元素,如果你取消它,则**table将返回第一行的值元件。在以下示例中,您可以看到*tabletable指向相同的内存地址。

printf("%d\n",table);//2293476
printf("%d\n",*table);//2293476
printf("%d\n",**table);//1

在内存中,表的所有行都是相互跟随的。因为如果我们在表中添加所需元素所在的行号,table指向第一行,我们将得到一个指向该行的指针。在这种情况下,*(table+row)将包含给定行的第一个元素的地址。现在我们只需要添加像*(table+row)+column这样的列号,我们就会得到给定行和列中元素的地址。如果我们取消这个,我们得到这个元素的确切值 因此,如果我们从零开始计算行和列,我们就可以从表中获取元素:

int element = *(*(table+row)+column);

在内存中

The table in the memory.

答案 2 :(得分:18)

2D阵列被视为1D阵列的阵列。也就是说,2D阵列中的每一行都是一维阵列。因此给定2D数组A

int A[m][n].

一般来说,

A[i][j] = *(A[i]+j) 

A[i] = *(A+i)

所以,

A[i][j] = *(A[i]+j) = * ( *(A+i)+j).

答案 3 :(得分:6)

之前的答案已经解释得很清楚, 我会根据我的理解列出指针表达式,并将它们与 arr [i] [j] 格式进行比较。

Pointer expression of 2-D array:
    the array name itself is a pointer to first sub array,

    arr:
        will be pointer to first sub array, not the first element of first sub 
        array, according to relationship of array & pointer, it also represent 
        the array itself,

    arr+1:
        will be pointer to second sub array, not the second element of first sub 
        array,

    *(arr+1):
        will be pointer to first element of second sub array,
        according to relationship of array & pointer, it also represent second
        sub array, same as arr[1],

    *(arr+1)+2:
        will be pointer to third element of second sub array,

    *(*(arr+1)+2):
        will get value of third element of second sub array,
        same as arr[1][2],

与2-D阵列类似, multiple-D 阵列具有相似的表达式。

答案 4 :(得分:2)

使用指针进行访问的实用方法。

typedef struct
{
    int  Array[13][2];
} t2DArray;

t2DArray TwoDArray =
{
   { {12,5},{4,8},{3,6},{7,9},{3,2},{3,3},{3,4},{3,5},{3,6},{3,7},{4,0},{5,0},{5,1} }
};

t2DArray *GetArray;

int main()
{
    GetArray = &TwoDArray;
    printf("\n %d\n %d\n %d\n %d\n %d\n %d\n",
    GetArray->Array[0][0], 
    GetArray->Array[0][1], 
    GetArray->Array[1][0], 
    GetArray->Array[1][1], 
    GetArray->Array[2][0], 
    GetArray->Array[2][1]);

    getchar();
    return 0;
}

OUT

12 5 4 8 3 6

答案 5 :(得分:0)

#include <iostream>
using namespace std;

int main()
{
   //FOR 1-D ARRAY THROUGH ARRAY
   int brr[5]= {1,2,3,4,5};

   for(int i=0; i<5; i++)
   {
      cout<<"address ["<<i<<"] = "  <<&brr[i]<<" and value = "<<brr[i]<<endl;        
   }

   //FOR 1-D ARRAY THROUGH POINTER
   cout<<endl;  //  endl TO MAKE OUT PUT LOOK CLEAR AND COOL :)
   int (*q)=brr;

   for(int i=0; i<5; i++)
   {
      cout<<"address ["<<i<<"] = "  <<&brr[i]<<" and value = "<<*(q+i)<<endl; //(p[i][j])
   }

   cout<<endl;

   //FOR 2-D ARRAY THROUGH ARRAY        
   int arr[2][3] = {1,2,3,4,5,6};

   for(int i=0; i<2; i++)
   {
      for(int j=0; j<3; j++)
      {
         cout<<"address ["<<i<<"]["<<j<<"] = "  <<&arr[i][j]<<" and value = "<<arr[i][j]<<endl;
      }
   }

   //FOR 2-D ARRAY THROUGH POINTER        
   int (*p)[3]=arr; //  j value we give
   cout<<endl;

   for(int i=0; i<2; i++)
   {
      for(int j=0; j<3; j++)
      {
         cout<<"address ["<<i<<"]["<<j<<"] = "  <<(*(p+i)+j)<<" and value = "<<(*(*(p+i)+j))<<endl; //(p[i][j])
      }
   }
   return 0;
}

==============OUT PUT======================

//FOR 1-D ARRAY THROUGH ARRAY

address [0] = 0x28fed4 and value = 1
address [1] = 0x28fed8 and value = 2
address [2] = 0x28fedc and value = 3
address [3] = 0x28fee0 and value = 4
address [4] = 0x28fee4 and value = 5

//FOR 1-D ARRAY THROUGH POINTER

address [0] = 0x28fed4 and value = 1
address [1] = 0x28fed8 and value = 2
address [2] = 0x28fedc and value = 3
address [3] = 0x28fee0 and value = 4
address [4] = 0x28fee4 and value = 5

//FOR 2-D ARRAY THROUGH ARRAY

address [0][0] = 0x28fee8 and value = 1
address [0][1] = 0x28feec and value = 2
address [0][2] = 0x28fef0 and value = 3
address [1][0] = 0x28fef4 and value = 4
address [1][1] = 0x28fef8 and value = 5
address [1][2] = 0x28fefc and value = 6

//FOR 2-D ARRAY THROUGH POINTER

address [0][0] = 0x28fee8 and value = 1
address [0][1] = 0x28feec and value = 2
address [0][2] = 0x28fef0 and value = 3
address [1][0] = 0x28fef4 and value = 4
address [1][1] = 0x28fef8 and value = 5
address [1][2] = 0x28fefc and value = 6