如何使用指针expression式访问C中二维数组的元素?
我知道对于一维数组x=a[i]
等价于x=*(a+i)
,但是如何使用指针访问二维数组的元素?
总结:如果你有一个定义为int [][]
的multidimensional array,那么x = y[a][b]
等价于x = *((int *)y + a * NUMBER_OF_COLUMNS + b);
镗孔细节:
上面的(int *)
铸造值得一些解释,因为它的必要性可能不是首先直观的。 要理解为什么它必须在那里考虑以下几点:
-
C / C ++中的types指针算术总是通过标量进行加/减/递增/递减时,按字节大小调整types指针值(这是一个地址)。
-
multidimensional array声明的基本types (不是元素types; variablestypes)是一个比最终维度小一维的数组types。
后者(#2)真的需要一个例子来巩固。 在下面,variablesar1
和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.
现在指针算术部分。 就像一个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列的整数表时:
到达元素
我们可以通过以下方式联系到这些人员:
int element = table[row-1][column-1];
但是我们也可以用下面的代码来做到这一点:
int element = *(*(table+row-1)+column-1);
在这些例子中, row
和column
从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
返回第一个元素的值。 在以下示例中,您可以看到*table
和table
指向相同的内存地址。
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