我已经阅读了许多指针和二维数组关系的帖子,但我似乎无法理解概念。
假设有一个2d数组int a[3][2]
和一个数组int b[2]
now a
返回一个指向大小为3的整数数组的指针。它的类型为int (*)[2]
。
正如我对这个概念的理解所解释它(*a
)会给我数组本身而这会衰减到指向1d数组的第一个元素并且类型为(int *)的指针。现在大胆的部分是怀疑。
为什么和如何这种衰变发生在数组本身(完整的1d数组a [0])衰变到1d数组的第一个元素? / strong>
(似乎不知道为什么以及如何部分)并且似乎也无法在其他链接上找到它。
作为a[0]
,*a
,&a[0][0]
代表相同的指针。这里作为[0]是第一个1d数组。那么b
(在上面声明)和a[0]
表示相同的事情(两者都是1d数组然后衰减到指向第一个元素的数组(int *)中的第一个元素?
答案 0 :(得分:2)
为什么以及如何在数组本身衰减到1d数组的第一个元素时发生这种衰变?
除非它是
sizeof
运算符的操作数,_Alignof
运算符 1 ,一元&
运算符,或者是一个字符串文字用于初始化一个数组,一个类型为''array of type''的表达式被转换为一个类型为''指向类型'的指针的表达式 到数组对象的初始元素,而不是左值。
简单;数组名称可以转换为指向其第一个元素的指针。
由于a
是一个数组名称,它会衰减到指向其第一个元素的指针,该元素是一维数组。它的类型是int(*)[2]
。由于a
(在衰减之后)是指向2
int
数组的指针,*a
是2
int
的数组。由于这是一个数组类型,即*a
是第一个1D数组的数组名称,它会衰减到指向数组对象的第一个元素(a[0][0]
)的指针。所以,它的类型是int *
。
这是真的,
b
(在上面声明)和a[0]
表示相同的事情(都是1d数组然后衰减到指向类型数组(int*
的第一个元素的指针) )?
是b
和a[0]
都属于int *
类型(在衰退后)。
<子> 1。通过Keith Thompson阅读commat。另请阅读此answer,其中指出: C11标准的草案说数组有另一个例外,即当数组是新_Alignof
运算符的操作数时。这是草案中的错误,在最终公布的C11标准中得到纠正; _Alignof
只能应用于带括号的类型名称,而不能应用于表达式。
答案 1 :(得分:2)
你&#34;为什么&#34;问题是:因为语言规范是这样说的。数组始终衰减到指向其第一个元素的指针(除了许多特定的上下文之外)。因此,正确地指出*a
的类型为int [2]
。这是一个数组。由于它是一个数组,语言需要衰减到指向int *
的{{1}}类型的指针(同样,除少数特定的上下文外) )。您的原始(*a)[0]
是a
类型的数组,它会衰减为int [3][2]
指针。同时int (*)[2]
是一个*a
类型的数组,它会衰减为int [2]
指针。这就是原因。
至于&#34;如何&#34;,目前尚不清楚你究竟在问什么。 &#34;衰变&#34;在这种情况下意味着在表达式中,数组类型的值被指针类型的值隐式替换。这就是它的全部内容。
是的,您示例中的int *
和a[0]
都是b
类型的数组,它们与int [2]
类型的指针相同地衰减。即他们是同样的事情&#34;关于腐朽的行为。
答案 2 :(得分:1)
指定此转换的规则隐藏在C11章6.3.2:
中...具有类型“数组类型”的表达式将转换为 带有“指向类型的指针”类型的表达式,指向初始值 数组对象的元素,而不是左值。
这意味着如果你有一个表达式,其中使用了b
的数组名int b[3]
,它将转换为指向int的指针int*
。
此规则是通用的。如果你有一个数组int a[3][2]
,那么正式你有一个“大小为3的数组大小为2的int数组”。这将转换为一个指向type的指针,它是“指向int类型为2的数组的指针”,int(*)[2]
。
请注意,“衰减”只会“向下”一个级别,因此通过使用二维数组名称a
,您将始终获得一个数组指针而不是指向第一个元素的指针。数组指针和普通int指针之间的区别主要是风格,以保持语言的一致性。如果将指针的实际地址打印为整数,则无论指针类型如何都是相同的。
因此,我对这个概念的理解是去除它
(*a)
会给我数组本身,这会衰减到指向1d数组的第一个元素的指针,类型为(int*)
它将为您提供数组本身,它将衰减为数组指针。它不会再从那里腐烂,只有一个层次。所以*a
不会给你一个指向第一个元素的指针。
为什么以及如何在数组本身衰减到1d数组的第一个元素时发生这种衰变?
每当在表达式中使用数组名称时,它将从“数组到类型”变为“指向类型的指针”。如果“type”碰巧是一个数组,那么你会得到一个指向数组的指针。
还有一个人怀疑。作为
a[0]
,*a
,&a[0][0]
表示相同的指针。这里的[0]是第一个1d数组。
a[0]
和*a
是等价的,两者都给出一个数组指针。 &a[0][0]
是指向int的指针。它们有不同的类型,但在实践中指向相同的记忆。
答案 3 :(得分:1)
请尝试以下代码:
int x[3][10];
printf("%d\n", x[0]);
printf("%d\n", x[1]);
printf("%d\n", x[2]);
请查看以下表达式
if(&x[0][9] + 1 == &x[1][0])
printf("I've entered here");
这个值为true ...当你向指针添加1时,它的地址增加4(或者你的机器具有的任何int大小),显示在内存中,元素x [1] [0]紧随其后元素x [0] [9]
一个大小为4的整数,你会看到这些版画之间的差异是40(4 * 10)个元素......
这个数组是在编译时分配的,因此它已经知道它需要多少空间,它为3 * 10个整数连续分配空间,就像它被声明为
时一样。 int x[30];
当你单独使用名字x时,得到的是它指向的第一个元素的地址......
第二个维度仅供我们程序员使用......但是编译器的成本很低......当你访问
时 x[1][8];
它必须计算添加到起始地址以访问该元素的程度,
这将是(1 * 10 + 8)* SIZE_OF_ARRAY_TYPE(这里是int)......
在上面的表达式中,1 =第一个维度上的数字,乘以10(第二个维度中第一行中的元素数量)加到第二个维度中的元素数量[]
如果你有1维数组:
x[23]
唯一的帐户是23 * SIZE_OF_ARRAY_TYPE(这里是int)
你也可以在这里尝试这个IF语句:
if(&x[0][10] == &x[1][0])
printf("I've entered here");
甚至是
等作业x[1][4] = 20;
printf("%d\n", x[0][14]);
指针给你很大的力量,但强大的力量带来了很大的责任;)
答案 4 :(得分:1)
数组int a[3][2]
作为1d数组存储在内存中row major order,所以这个数组:
int a[3][2] = {
{1, 2},
{3, 4},
{5, 6}
};
将存储为:
int a[] = {1, 2, 3, 4, 5, 6};
例如:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
size_t i;
int a[3][2] = {
{1, 2},
{3, 4},
{5, 6}
};
for(i = 0 ; i < sizeof(a) / sizeof(int) ; i++)
{
printf("%d\n", ((int *) a)[i]);
}
return 0;
}