我知道对于C中的一维数组,您可以使用数组的名称作为地址:
int k;
double x[6], sum=0;
...
/* Sum the values in the array x. */
for (k=0; k<=5; k++)
sum += *(x+k);
我的问题是,为什么这对二维数组不起作用?
int g[2][4]={{5,2,2,3},{1,2,3,4}};
int g_count=8, k, sum=0;
for (k=0; k<=g_count-1; k++)
sum += *(g+k);
我注意到虽然&g[0][0]
和g
保持相同的值,但&g[0][0]+1
和g+1
却没有。有人可以解释一下原因吗?感谢。
答案 0 :(得分:2)
声明为(*g)
时g[M][N]
的大小是N
乘以元素的大小。原因很简单,第一个索引的增量将“跳过”内存中的N
个元素。因此*(g+k)
相当于&g[k][0]
。请注意,取消引用g
或(g+k)
会返回子阵列的地址。
答案 1 :(得分:2)
问题1
我的问题是,为什么这对二维数组不起作用?
<强>答案强>
for (k=0; k<=g_count-1; k++)
sum += *(g+k);
有两个错误。
*(g+k)
未评估为int
。*(g+k)
在k > 1
。当g
被声明为:
int g[2][4];
g
衰减为int (*)[4]
类型的指针。它不会衰减为int*
类型的指针。
g+k
评估的是哪种类型?它还会计算为int (*)[4]
类型的指针。
它指向哪里?用图表来看是很有帮助的。
|<--- memory used by g -->|
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
address of g
|
v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
address of g[0] address of g[1]
| |
v v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
在表达式中使用时,g
会衰减到g[0]
的地址。
表达式g
的计算结果为g[0]
的地址
表达式g+1
的计算结果为g[1]
。
g g+1 g+2
| | |
v v v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
如您所见,g+k
指向k > 1
之后超出有效限制的位置。在g+k
时,Derefercencing k > 1
将导致未定义的行为。
您可以使用:
int* ptr = &g[0][0]; // Pointer to the first int in the 2D array.
for (k=0; k<=g_count-1; k++)
sum += *(ptr+k);
// ^^^ ptr, not g
这将有效地使用数组和指针。
问题2
我注意到虽然
&g[0][0]
和g
保持相同的值,但&g[0][0]+1
和g+1
却没有。有人可以解释一下原因吗?
<强>答案强>
鉴于阵列,我们有:
g g+1
| |
v v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
&g[0][0]
| &g[0][0]+1
| |
v v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
从图中,您可以看到为什么表达式g
和&g[0][0]
计算到同一地址。但是,表达式的类型不一样。表达式g
评估为int (*)[4]
,而&g[0][0]
评估为int*
。
由于表达式g
的类型为int (*)[4]
,因此g
和g+1
之间的偏移量与4 int
的大小相同。
由于表达式&g[0][0]
的类型为int*
,因此&g[0][0]
和&g[0][0]+1
之间的偏移量与int
的大小相同。< / p>
这解释了为什么g+1
评估的地址与&g[0][0]+1
不同,即使g
和&g[0][0]
评估到同一地址。
答案 2 :(得分:0)
为了理解这是如何工作的,你必须考虑你正在创造什么。在创建数组数组时,实际上是在创建一个指针数组。即
mainFcty
这里,抓取第一个数组中的第0个值与抓取[0] [0]相同。但是,抓取第一个数组中的第一个值与抓取[0] [1]不同,它与抓取[1] [0]相同。
<强>更新强>
我修改了图表,以显示第一个数组如何指向一组独立的数组以形成2D数组,以更好地说明我的观点。
第二次更新
经过一番讨论后,看来这实际上并不正确。第一个数组不是指向数组的指针数组,如前所述。第一个数组包含类型&#34;数组&#34;的元素。 (它与类型&#34;指针&#34;不同),因此不等同于指向数组的指针数组。更合适的图表如下:
0 1 2 3 4
0[] -> [][][][][]
1[] -> [][][][][]
2[] -> [][][][][]
3[] -> [][][][][]
4[] -> [][][][][]
顶行显示第一个数组的索引,底行显示第二个数组的索引。现在,看看原始问题,它只是偏移到该阵列的问题。第一对(&amp; g [0] [0]和g)都偏移到数组0中。第二对(&amp; g [0] [0] +1和g + 1)具有不同的数组偏移量因此提供不同的价值观。有关详细说明,请参阅@R Sahu的答案。
答案 3 :(得分:0)
对于2D数组,数组的名称也是地址,但是
所以,
g[0]
是第一个1D数组的地址。g[1]
是第二个1D数组的地址。要访问单个元素,例如第一个1D数组,您需要以下内容:
*( g[0] + 0 )
g[0][0]
{li> *( g[0] + 1 )
g[0][1]
通常,您需要*( g[i] + k )
才能访问元素g[i][k]
答案 4 :(得分:0)
首先需要了解指针与数组和指针算术之间的关系 在表达式中使用时,在大多数上下文中,数组将转换为指向其第一个元素的指针 对于1D阵列
double x[6];
x
将转换为指向其第一个元素x[0]
的指针。对于2D阵列
int g[2][4];
g
将转换为指向其第一个元素g[0]
的指针。请注意,g[0]
本身就是一个数组,因此g
实际上转换为指向数组的指针。
请注意,如果p
是指向T
类型的指针,则添加1
会将其增加到内存中的sizeof(T)
,即下一个连续元素的地址。
因此,表达式*(g+k)
等同于*(&g[0] + k)
。由于&g[0]
是数组的地址,因此添加1
将提供g[1]
的地址,并向其添加k
将提供g[k]
的地址。
答案 5 :(得分:-1)
sum += *(x+k);
有效,因为此处(因为x
是int
的一维数组)x
是指向int
的指针所以当递增{时{1}}它指向位置k
x[k]
不起作用,因为此处(因为sum += *(g+k);
是g
的二维数组)int
是指向{{1}的一维数组的指针所以当我们将g增加g
时,它指向数组int
。因此,当您通过k
取消引用它时,您将获得数组g[k]
,这是第一个元素的地址。
因此,对于以下代码段:
*(g+k)
您将获得g[k]