数组参数是否传递给函数而不是常量指针?
考虑一下代码:
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’是常量,因为你不能在内存中更改它的地址。