什么是数组指针衰减?它和数组指针有关系吗?
当前回答
当数组腐烂并被指向时;-)
实际上,如果你想传递一个数组到某个地方,但却传递了指针(因为谁会他妈的为你传递整个数组),人们会说这个可怜的数组衰减为指针。
其他回答
在C语言中,数组没有值。
如果需要对象的值,但对象是数组,则使用其第一个元素的地址,type pointer to(数组元素的类型)。
在函数中,所有参数都是按值传递的(数组也不例外)。当你在函数中传递一个数组时,它“衰减为指针”(原文如此);当你将一个数组与其他东西进行比较时,它再次“衰减为指针”(原文如此);...
void foo(int arr[]);
函数foo期望数组的值。但是,在C语言中,数组没有值!foo得到的是数组第一个元素的地址。
int arr[5];
int *ip = &(arr[1]);
if (arr == ip) { /* something; */ }
在上面的比较中,arr没有值,所以它成为一个指针。它变成了一个指向int的指针。该指针可以与变量ip进行比较。
在数组索引语法中你经常看到,arr被衰减为指针
arr[42];
/* same as *(arr + 42); */
/* same as *(&(arr[0]) + 42); */
只有当数组是sizeof操作符的操作数,或&操作符('address of'操作符)的操作数,或用作初始化字符数组的字符串字面值时,数组才不会衰减为指针。
数组与C/ c++中的指针基本相同,但又不完全相同。一旦你转换一个数组:
const int a[] = { 2, 3, 5, 7, 11 };
转换为指针(不需要强制转换,因此在某些情况下可能会意外发生):
const int* p = a;
你将失去sizeof操作符计算数组中元素的能力:
assert( sizeof(p) != sizeof(a) ); // sizes are not equal
这种丧失的能力被称为“衰退”。
有关更多详细信息,请参阅这篇关于数组衰减的文章。
据说数组会“衰减”成指针。声明为int numbers[5]的c++数组不能被重指向,即不能说numbers = 0x5a5aff23。更重要的是,衰减一词意味着类型和维度的丧失;数字通过丢失维数信息(计数5)衰减为int*,类型不再是int[5]。看看这里没有发生衰变的情况。
如果你是按值传递一个数组,你实际上是在复制一个指针——指向数组第一个元素的指针被复制到形参(形参的类型也应该是数组元素的类型的指针)。这是由于数组的衰减性质;一旦衰变,sizeof就不再给出整个数组的大小,因为它本质上变成了一个指针。这就是为什么首选通过引用或指针传递的原因(以及其他原因)。
传递数组1的三种方法:
void by_value(const T* array) // const T array[] means the same
void by_pointer(const T (*array)[U])
void by_reference(const T (&array)[U])
后两个将提供适当的sizeof信息,而第一个不会,因为数组参数已经衰减为赋值给形参。
常量U应该在编译时已知。
以下是该标准的内容(C99 6.3.3.1 /3 -其他操作数-左值、数组和函数指示符):
除非它是sizeof操作符或一元&操作符的操作数,或者是a 字符串字面值用于初始化数组,具有类型“数组类型”的表达式为 转换为类型为“指针指向类型”的表达式,该表达式指向的初始元素 数组对象和不是左值。
这意味着无论何时在表达式中使用数组名称,它都会自动转换为指向数组中第一项的指针。
请注意,函数名的作用与此类似,但函数指针的使用要少得多,而且使用的方式要专门得多,因此不会像将数组名自动转换为指针那样引起混乱。
c++标准(4.2数组到指针转换)将转换要求放宽为(强调我的):
类型为“N T的数组”或“未知T界的数组”的左值或右值可以转换为右值 类型为“指向t的指针”
因此转换不必像C中那样发生(这让函数重载或模板匹配数组类型)。
这也是为什么在C语言中你应该避免在函数原型/定义中使用数组形参(在我看来-我不确定是否有普遍的共识)。它们会引起混乱,而且无论如何都是虚构的——使用指针形参,混乱可能不会完全消失,但至少形参声明没有说谎。
tl;dr:当您使用已定义的数组时,实际上是在使用指向其第一个元素的指针。
因此:
当你写arr[idx]时,你实际上是在说*(arr + idx)。 函数从来不会真正将数组作为参数,只接受指针——当指定数组参数时可以直接接受,如果将引用传递给数组则可以间接接受。
这条规则的例外情况:
可以将固定长度的数组传递给结构中的函数。 Sizeof()给出数组占用的大小,而不是指针的大小。