“Arrays = Pointers”*心灵狂热*。 许多年后:“实际上,他们没有”*心灵再次爆炸*
语境:
我在C中打开和关闭编程大约2年,然后发现a[i]
只是*(a + i)
语法糖,因此相当于* (i + a)
和i[a]
。 我的现实被颠倒了,很多都是“AHA!” 在接下来的几天研究和阅读之后出现了启示时刻(“那就是为什么数组总是通过引用传递!”等)。 从那时起,我已经内化了指针/数组的等价并使它紧贴我的心脏,所以想象一下,当我偶然发现这个名为“arrays衰变”的东西时,这是多么的震撼。 这是典型的例子:
码:
#include int Length(int*); int main () { int arr[100]; printf("Length of array: %d\n",(int)(sizeof(arr)/sizeof(arr[0]))); printf("Length of array: %d\n",Length(arr)); return 0; } int Length(int arr[]) { return sizeof(arr)/sizeof(arr[0]); }
结果:
Length of array: 100 Length of array: 2
题:
事实certificate,C毕竟对数组有一些认识! 在声明数组的main中,程序能够正确地报告它的大小。 现在我想知道有多少数组语法只是指针操作的语法糖(以前我曾假设:所有这些)。 C实际上确实有数组,它们的局限性是什么? 这个例子表明只要你处于相同的function就可以获得它们的长度,你可以做些什么呢? 在这个腐烂的东西开始之前你能走多远?
“旧”C语言中有两个运算符不触发数组类型衰减: sizeof
运算符和一元运算符。 sizeof
计算整个数组的大小(而不是指针大小),而&
返回指针指向数组类型的指针(不是指向指针类型的指针)。 正如埃里克在评论中指出的那样,C99增加了_Alignof
。
有时还会提到另外一个上下文:使用字符串文字初始化char数组(即字符串文字不会衰减到指针)。
也可以这样说:在对象上下文 (AKA左值上下文)中,数组保留其“数组”,而在值上下文 (AKA右值上下文)中,它们会立即衰减为指针。
PS作为历史评论:C语言的一个祖先–B语言 – 实际上实现了数组作为物理指针,这意味着B中的每个数组实际上都是一个指向独立分配的内存块的指针。 最初假设此实现也将转移到C。 但是,C必须具有struct
类型。 并且B样式的数组创建了不必要的复杂性,将数组作为struct
对象的成员。 他们会使struct
对象的初始化变得非常简单, struct
对象将变成不可复制的原始memcpy
等。这在C中被认为是不可接受的。因此,数组被重新设计为它们当前的forms。 C数组不是指针,但他们仍然模仿他们的祖父母从B语言的指针式行为,这经常混淆人们学习C.
(有关完整故事,请参见http://cm.bell-labs.com/cm/cs/who/dmr/chist.html 。)
传递给函数时,数组的大小“丢失”。 正如你所指出的那样, sizeof
是一个编译时的东西,看到了“真正的”大小。 这可以起作用,因为sizeof
根本不是一个函数,因为你可以通过使用它而没有括号来certificate(例如sizeof arr
,虽然奇怪的sizeof some_type
不合法C)。
说数组和指针是“等价的”意味着它们既不相同也不可互换。 这意味着它的指针算法和数组索引在C中是等价的,指针和数组是不同的。
对表达式中出现的array-of-T类型的对象的引用会衰减为指向其第一个元素的指针; 结果指针的类型是指向T的指针。 也就是说,只要数组出现在表达式中,编译器就会隐式生成指向数组第一个元素的指针,就像程序员编写了&a[0]
。
sizeof
或& operator
是此规则的例外。
另外,我推荐专家C编程一书,它使用整章来解释指针和数组的差异和混淆。
将数组声明为局部变量或全局变量是指针与指针的不同之处。 int arr[100];
分配400个字节的空间,而int *p
只分配4.你可以使用类似于数组的int *p
局部变量,如果你为它设置一些空间,比如
int *p = (int *)malloc(100 * sizeof(int));
当然,你还必须记得以后释放那些记忆。 您还可以随意将声明为int arr[100]
的局部变量传递给其forms参数类型为int *
的函数。 说到函数参数,数组和指针更相同。
i[a]
不,如果我是一个int,这将无法工作。 但其他三种forms是等价的。