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

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

总结:如果你有一个定义为int [][]的multidimensional array,那么x = y[a][b]等价于x = *((int *)y + a * NUMBER_OF_COLUMNS + b);


镗孔细节:

上面的(int *)铸造值得一些解释,因为它的必要性可能不是首先直观的。 要理解为什么它必须在那里考虑以下几点:

  1. C / C ++中的types指针算术总是通过标量进行加/减/递增/递减时,按字节大小调整types指针值(这是一个地址)。

  2. multidimensional array声明的基本types (不是元素types; variablestypes)是一个比最终维度小一维的数组types。

后者(#2)真的需要一个例子来巩固。 在下面,variablesar1ar2是等价的声明。

 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. 

现在指针算术部分。 就像一个types化的结构指针可以通过字节结构的大小来提高一样,一个数组的全维也可以被跳过。 这很容易理解,如果你想到multidimensional array,我声明上面的ar2:

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

因此,在进行二维数组的指针运算时,以下操作无法在multidimensional array的[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)添加到y的指针运算将增加12 ,从而计算和地址等价于&(y[12]) ,这显然是不正确的,事实上,在编译时警告或直接不能完全编译。 这可以通过(int*)y的强制转换来避免,并且expression式的结果types基于裸指针int:

 #define NUMBER_OF_COLUMNS 5 int y[5][NUMBER_OF_COLUMNS]; int x = *((int *)y + 2 * NUMBER_OF_COLUMNS + 2); // Right! 

桌子

在C二维数组是连续的一系列线(不像在帕斯卡)。
当我们创build一个4行5列的整数表时: 一个5 * 4的整数表。

到达元素

我们可以通过以下方式联系到这些人员:

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

但是我们也可以用下面的代码来做到这一点:

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

在这些例子中, rowcolumn从1开始计数,即-1的原因。
在下面的代码中,你可以testing这两种技术是正确的。 在这种情况下,我们从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; } 

说明

这是一个double poiner算术,所以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); 

在记忆中

内存中的表

二维数组被视为一维数组的数组。 也就是说,二维数组中的每一行都是一维数组。 因此给定一个二维数组A

 int A[m][n]. 

一般来说,

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

 A[i] = *(A+i) 

所以,

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

以前的答案已经解释得很好,我只是根据我的理解列出指针expression式,并将它们与arr [i] [j]格式进行比较。

 二维数组的指针expression式:
    数组名本身就是一个指向第一个子数组的指针,

     arr :
        将是第一个子数组的指针,而不是第一个子数组的第一个元素 
        数组,根据数组&指针的关系,也表示 
        arrays本身,

     arr + 1 :
        将是第二个子数组的指针,而不是第一个子数组的第二个元素 
        arrays,

     *(arr + 1) :
        将指针指向第二个子数组的第一个元素,
        根据数组和指针的关系,也代表第二
        子数组,与arr [1]相同,

     *(arr + 1)+2 :
        将指针指向第二个子数组的第三个元素,

     *(*(arr + 1)+2) :
        将得到第二个子数组的第三个元素的值,
        与arr [1] [2]相同

类似于二维数组, 多维数组具有相似的expression式。

 #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