如何使用指针表达式访问 C 中的二维数组的元素?
Posted
技术标签:
【中文标题】如何使用指针表达式访问 C 中的二维数组的元素?【英文标题】:How to use pointer expressions to access elements of a two-dimensional array in C? 【发布时间】:2012-11-13 07:17:32 【问题描述】:我知道对于一维数组x=a[i]
等价于x=*(a+i)
,但是如何使用指针访问二维数组的元素呢?
【问题讨论】:
你了解多维数组在内存中是如何布局的吗?你能访问a[0][0]
吗? a[0][1]
? a[0][ARY_N_Y]
? a[1][0]
?
C 实际上没有二维数组。
@RussellBorogove 这种说法依赖于 “数组数组与二维数组不同” 的说法,这总是归结为一些吊坠声称一块内存是一个二维数组意味着什么。在任何情况下,int a[5][5];
看起来和行为都像一个二维数组。至少在它衰减为指针之前。
是“学究”,不是“吊坠”。
e: touché 上应该有一个重音 aigu。在 Mac 上,您可以使用 Alt-E(又名 option-E)E 获得该字符。
【参考方案1】:
总结:如果你有一个定义为int [][]
的多维数组,那么x = y[a][b]
等价于x = *((int *)y + a * NUMBER_OF_COLUMNS + b);
无聊的细节:
上面的y
的(int *)
演员值得一些解释,因为它的必要性一开始可能并不直观。要理解为什么它必须存在,请考虑以下几点:
C/C++ 中的类型化指针算法在通过标量进行加/减/递增/递减时,总是通过 类型 的大小(以字节为单位)调整类型化指针值(这是一个地址) .
多维数组声明的基本类型(不是元素类型;变量类型)是一维数组类型比最终尺寸。
后者(#2)确实需要一个例子来巩固。在下文中,变量ar1
和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.
现在是指针算术部分。就像一个类型化的结构指针可以按结构的大小(以字节为单位)前进一样,数组的整个维度也可以跳过。如果您想到我在上面声明的 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].
因此,在对二维数组进行指针运算时,以下方法无法获取多维数组[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
的强制转换和基于裸指针int 的表达式的结果类型可以避免这种情况:
#define NUMBER_OF_COLUMNS 5
int y[5][NUMBER_OF_COLUMNS];
int x = *((int *)y + 2 * NUMBER_OF_COLUMNS + 2); // Right!
【讨论】:
@WhozCraig 那么它将是 ROW_SIZE,不是吗?还是改了。 我尝试通过打印像 printf("%d",*(a + 2 * 3 + 3)); 这样的二维数组的一个元素来测试它。它应该打印行宽为 3 的矩阵的元素 a[2][3]。在我的情况下,元素 a[2][3] 是 6,但打印的是 0。我做错了吗? @TudorCiotlos “我做错了吗?”我怎么知道?您没有提供来源(顺便说一句,请在另一个问题中提供)。 @TudorCiotlos 可能不是,这里的指针算法不对。正确的算法在the other answer 中,忽略最后一句,二维数组与int**
非常不同。
这是不正确的。 y+1
已经跳过了整个第一行。【参考方案2】:
桌子
在 C 中,二维数组是一系列连续的线(不像在 Pascal 中)。 当我们创建一个 4 行 5 列的整数表时:
到达元素
我们可以通过以下方式到达元素:
int element = table[row-1][column-1];
但我们也可以使用以下代码来做到这一点:
int element = *(*(table+row-1)+column-1);
在这些示例中,row
和 column
从 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
将返回第一个元素的值。在下面的例子中你可以看到*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);
在记忆中
【讨论】:
我喜欢你的图形,但你必须提到 table 将被视为 char 指针,你仍然必须添加元素的 sizeof。如果它仍然是 2d 数组的类型,则通过添加 1 来跳过整行int table[rows][cols];
不正确。在(table + integer_expression)
中,table
被转换为int (*)[cols]
。【参考方案3】:
二维数组被视为一维数组的数组。也就是说,二维数组中的每一行都是一维数组。因此给定一个二维数组A
,
int A[m][n].
一般来说,
A[i][j] = *(A[i]+j)
还有
A[i] = *(A+i)
所以,
A[i][j] = *(A[i]+j) = * ( *(A+i)+j).
【讨论】:
太接近投票了,但最后一句话太不正确,无法按原样投票。不要将二维数组 (int arr[rows][cols];
) 与双指针 (int **pp;
) 混淆。如果您删除它,我将非常乐意投票。【参考方案4】:
前面的答案已经解释的很好了, 我只是根据我的理解列出指针表达式,并将它们与 arr[i][j] 格式进行比较。
2-D 数组的指针表达式: 数组名本身是指向第一个子数组的指针, arr: 将是指向第一个子数组的指针,而不是第一个子数组的第一个元素 数组,根据数组和指针的关系,也表示 数组本身, arr+1: 将是指向第二个子数组的指针,而不是第一个子数组的第二个元素 大批, *(arr+1): 将指向第二个子数组的第一个元素, 根据数组和指针的关系,它也代表第二个 子数组,同arr[1], *(arr+1)+2: 将指向第二个子数组的第三个元素, *(*(arr+1)+2): 将获得第二个子数组的第三个元素的值, 与 arr[1][2] 相同,类似于二维数组,多维数组有类似的表达。
【讨论】:
【参考方案5】:一种使用指针访问的实用方法。
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;
输出
12 5 4 8 3 6
【讨论】:
【参考方案6】:#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
【讨论】:
请编辑您的答案并为您的解决方案添加一些解释。以上是关于如何使用指针表达式访问 C 中的二维数组的元素?的主要内容,如果未能解决你的问题,请参考以下文章