数组参数是否传递给函数而不是常量指针?

考虑一下代码:

void foo(char a[]){ a++; // works fine, gets compiled //... } 

现在,考虑一下:

 void foo(){ char a[50]; a++; // Compiler error //... } 

我听说一个数组相当于一个常量指针,不能递增,因为它不是一个左值…

那么为什么第一个代码被编译,是这样的,因为函数的数组参数作为指针传递,即T []被转换为T *以传递..所以,foo(a)传递a作为指针。

但它是否再次转换为T [],因为声明为:

 void foo(char a[]); 

将数组作为参数传递给函数时,它会衰减为指针。
所以在函数体内增加的是指针,而不是数组。

这是从C语言inheritance的一个相当不幸的特征,其中有一个令人讨厌的名字“衰变”。 由于C曾经不允许按值传递复合类型,因此他们决定允许程序员将数组指定为函数参数类型,但仅限于美观。 数组类型衰减为指针类型,实现一种与语言其余部分不同的传递引用语义。 丑陋。

回顾(其他人已经说过这个),签名

 void foo(char a[]); // asking for trouble 

被毫不客气地纠缠在一起

 void foo(char *a); 

…所有这些都是为了与古代C代码兼容。 由于您不是在编写古老的C代码,因此不应该使用这个“function”。

但是,您可以干净地传递对数组的引用 。 C ++要求知道数组的大小:

 void foo( char (&a)[ 50 ] ); 

现在a不能在函数内修改(编辑:它的内容当然可以 – 你知道我的意思),并且只能传递正确大小的数组。 对于其他所有内容,传递指针或更高级别的类型。

我听说一个数组相当于一个常量指针

可以这样想,但它们并不等同。

传递给函数时,数组会衰减到指针,这就是函数内部有效的原因。

仅仅因为签名是void foo(char a[])不会成为a数组。

在函数外部,它只是一个数组,你不能在它上面做指针算术。

在C ++中,任何类型为“T of array”的函数参数都被调整为“指向T的指针”。 试试这段代码:

 void foo(char a[]) {} void foo(char* a) {} //error: redefinition 

它们确实是同一个function。

那么,为什么我们可以将数组参数作为指针参数传递给函数? 不是因为数组等效于常量指针,而是因为数组类型可以隐式转换为指针类型的右值。 还要注意转换的结果是rvalue,这就是为什么你不能将operator ++应用于数组,你只能将这个运算符应用于左值。

我听说一个数组相当于一个常量指针,不能递增,因为它不是一个左值…

几乎。

数组表达式是一个不可修改的左值 ; 它可能不是++--等运算符的操作数,它可能不是赋值表达式的目标。 这与常量指针(即,声明为T * const的指针)不同。

数组表达式将替换为指针表达式,其值是数组的第一个元素的地址, 除非数组表达式是sizeof或一元&运算符的操作数,或者数组表达式是用于的字符串文字在声明中初始化另一个数组。

当您使用数组参数调用函数时,例如

 int a[N]; ... foo(a); 

表达式 a从类型“N-element array of int ”转换为“指向int指针”,此指针值是传递给foo ; 因此,相应的函数原型应该是

 void foo (int *arr) {...} 

注意,在函数参数声明的上下文中, T a[]T a[N]T *a相同; 在所有三种情况下, a被声明为指向T的指针。 在函数foo ,参数arr是一个指针表达式,它一个可修改的左值,因此它可以被赋值给并且可能是++--运算符的操作数。

请记住,所有这些转换都在数组表达式上 ; 也就是说,数组标识符或引用内存中数组对象的其他表达式。 不转换数组对象(保存数组值的内存块)。

将数组a []传递给函数时,它会将“a”(地址)的值传递给函数。 所以你可以将它用作函数中的指针。 如果在函数中声明一个数组,’a’是常量,因为你不能在内存中更改它的地址。