C中的二维数组和指针 - 如何访问元素?
Posted
技术标签:
【中文标题】C中的二维数组和指针 - 如何访问元素?【英文标题】:2D array and pointer in C - how to access elements? 【发布时间】:2012-06-24 12:24:54 【问题描述】:我有一个涉及指向二维数组的指针的示例。有人可以帮我理解这个例子中发生了什么吗?
int main()
int i = 0, j=0, sum0=0, sum1=0;
int data[4][3] = 23,55,50,45,38,55,70,43,45,34,46,60;
int *Ptr;
Ptr = *data; //Why is the indirection operator used here?
// Does Ptr = 23 by this assignment?
for (i=0; i<4; i++)
sum1 = 0;
for (j = 0; j < 3; j++)
sum1 += data[i][j];
if (sum1 > sum0)
sum0 = sum1;
Ptr = *(data + i); // Seems like this statement makes Ptr
// point one row below ... what syntax
// can you use to access columns then?
// Is it possible to use pointer arithmetic
for (i=0; i<3; i++) // to access elements of data[i][j] that
printf("%d\n", Ptr[i]); // are not at j = 0?
return 0;
【问题讨论】:
是的!我正在参加 CS 入门课程,这只是我的讲义中的一个示例。 【参考方案1】:data
是一个二维数组,有 4 行,每行有 3 个元素(即 4 X 3)。
现在,Ptr = *data;
表示您将第一行的起始地址存储到指针变量Ptr
。该语句等效于Ptr = *(data + 0)
。 Ptr = *(data + 1)
- 这意味着我们正在分配第二行的起始地址。
然后*Ptr
或*(Ptr + 0)
将为您提供所指向的行的第一个元素的值。同样,*(Ptr + 1)
会为您提供该行的第二个元素的值。
程序中的for
循环用于识别哪一行的元素之和(3 个元素)的最大值。一旦控件退出 for
循环,Ptr
将指向其元素总和最大的行,sum0
将具有总和的值。
考虑一个数组int a[5];
,我希望你知道a[0]
和0[a]
是一样的。这是因为a[0]
表示*(a+0)
而0[a]
表示*(0 + a)
。同样的逻辑也可以用在二维数组中。
data[i][j]
类似于 *(*(data + i) + j)
。我们也可以写成i[data][j]
。
有关详细信息,请参阅 Yashavant Kanetkar 的《理解 C 中的指针》一书。
【讨论】:
【参考方案2】:Ptr = *data;
是*(data+0)+0
的缩写,它是第一行第一列元素的指针。添加数据的第一个 0 是行号,它是间接的并将我们带到第一行。 * (data+0)
仍然是一个地址,而不是它指向的值(对于二维数组)。所以,Ptr 现在指向第一行第一列的地址。第二个零是列号。因此,选择了第一行和第一列的内存地址。现在再次使用间接 (*) 只会给出地址持有的值。比如* (*(data+0)+0)
或**data
。
一般情况下,如果p是指针名,i行号,j列号,
(*(p+i)+j)
将给出二维数组中元素的内存地址。我是行号。 j是列号,
*(*(p+i)+j)
将给出该元素的值。
*(p+i)
将访问第 i 行
要访问列,请将列号添加到*(p+i)
。您可能必须将指针声明为(*p)[columns]
而不仅仅是*p
。这样做,您将声明指向 2D 数组的指针。
使用指针算法将二维数组视为一维数组。将指针 *Ptr 初始化为第一个元素 (int *Ptr = *data
),然后添加一个编号。 (Ptr + n
) 访问列。添加一个大于列号的数字只会继续计算下一行第一列的元素(如果存在)。
【讨论】:
【参考方案3】:data
是一个由 3 元素整数数组组成的数组。在期望“指向 foo 的指针”的上下文中,您可以使用“foo 数组”,它的行为类似于指向其第一个元素的指针,因此 *data
是指向 data
的第一个元素的指针,即 (可以这么说)23,55,50
.
所以,cmets 中第一个问题的答案:不,Ptr = 23
不是真的。 (不可能;Ptr
是 int *
而 23 是 int
。)
Ptr = *(data+i)
使Ptr
指向data
的第i
行是正确的。更准确地说,data
是一个 3 元素 int 数组的数组,其行为类似于指向 3 元素 int 数组的指针;将i
添加到它会移过i
这样的数组。
访问数组其他列的常用方法是普通的数组索引。如果您引用data[i][j]
,您将获得j
行i
的列。如果您想使用显式指针算术来执行此操作,请注意(例如)示例代码中的Ptr
是“指向整数的指针”类型,因此Ptr+1
(例如)是任何行Ptr
的元素1是指向。 (但是,作为一种风格问题,当您实际上不需要时,通常不应该进行显式指针运算。)
【讨论】:
【参考方案4】:在您的示例中,循环遍历所有矩阵行以找到所有元素之和保持最大值的行。
在开始时分配一个指向第一行的指针:
Ptr = *data;
这意味着以下情况为真:
(Ptr[0] == 23 && Ptr[1] == 55 && Ptr[2] == 50)
请注意,Ptr 是一个指针,因此它拥有一个内存地址,因此 Ptr 不同于 23(除非内存地址恰好23,这不太可能发生)。
【讨论】:
【参考方案5】:C 允许多维数组,将它们作为连续的位置放置在内存中,并在幕后进行更多的地址运算。 考虑一个二维数组。
int arr[ 3 ][ 3 ] = 1, 2, 3, 4, 5, 6, 7, 8, 9;
编译器将二维数组视为数组数组。 其中数组名是指向数组中第一个元素的指针。 因此,arr 指向第一个 3 元素数组,它实际上是二维数组的第一行(即第 0 行)。 类似地,(arr + 1) 指向第二个 3 元素数组(即第 1 行),依此类推。 该指针的值 (arr + 1) 指的是整行。 由于第 1 行是一维数组,因此 (arr + 1) 实际上是指向第 1 行第一个元素的指针。 现在将 2 添加到此指针。因此,((arr + 1) + 2) 是指向第 1 行中元素 2(即第三个元素)的指针。该指针的值 ((arr + 1 ) + 2),引用第 1 行第 2 列中的元素。
【讨论】:
以上是关于C中的二维数组和指针 - 如何访问元素?的主要内容,如果未能解决你的问题,请参考以下文章