传递给函数的数组参数不是常量指针吗?

8

考虑以下代码:

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[]);

2
阅读comp.lang.c FAQ的第6节。 - Keith Thompson
6个回答

13

当您将数组作为函数参数传递时,它会被降级为指针。
因此,在函数体内增加的是指针而不是数组。


特别是,这就好像你声明了char *temp = a;然后增加了temp - Mahmoud Al-Qudsi

11

这是从C语言继承而来的一个相当不幸的特性,名称非常难听叫做“衰减”(decay)。因为C曾经不允许通过值传递复合类型,所以他们决定允许程序员将数组指定为函数参数类型,但只是表面上看起来是这样。数组类型会退化为指针类型,实现了一种与语言其他部分不同的引用传递语义。丑陋。

总的来说(其他人已经说过了),函数签名:

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

被毫不客气地搞砸成

void foo(char *a);

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

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

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

现在,在该函数内部无法修改a(编辑:当然可以修改其内容 ——你知道我的意思),只能传递正确大小的数组。对于其他所有情况,请传递指针或更高级的类型。


4
我听说数组等同于常量指针。
你可以这样想,但它们并不相同。
当传递给函数时,数组会衰变为指针,这就是为什么在函数内部它是有效的。
仅仅因为签名是 void foo(char a[]) 并不代表 a 是一个数组。
在函数外部,它只是一个数组,你不能对其进行指针运算。

3

在C++中,任何类型为“T数组”的函数参数都会被调整为“指向T的指针”。尝试运行以下代码:

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

它们确实是相同的功能。

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


1
当你将数组a[]传递给函数时,它会将'a'的值,即一个地址,传递到函数中。因此,在函数中你可以将其作为指针使用。如果你在函数中声明一个数组,'a'是常量,因为你无法改变它在内存中的地址。

1
我听说数组相当于一个常量指针,不能递增,因为它不是 lvalue(左值)...
几乎是这样。
数组表达式是一个不可修改的 lvalue;它不能作为 ++-- 等运算符的操作数,并且不能成为赋值表达式的目标。这并不等同于常量指针(即声明为 T * const 的指针)。
数组表达式将被替换为一个指针表达式,其值是数组的第一个元素的地址,除非该数组表达式是 sizeof 或一元 & 运算符的操作数,或者当该数组表达式是用于初始化另一个声明中的数组的字符串字面量时。
当您使用数组参数调用函数时,例如:
int a[N];
...
foo(a);

表达式 a 从类型为“N个元素的int数组”转换为“指向int的指针”,并且该指针值是传递给foo的内容;因此,相应的函数原型应为

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

请注意,在函数参数声明的上下文中,T a[]T a[N]T *a 相同;在这三种情况下,a 被声明为指向 T 的指针。在函数 foo 中,参数 arr 是一个指针表达式,它是可修改的左值,因此可以被赋值,并且可以是 ++-- 运算符的操作数。
请记住,所有这些转换都是在数组表达式上进行的;也就是说,数组标识符或其他引用内存中数组对象的表达式。数组对象(保存数组值的一块内存)不会被转换。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接