当函数具有特定大小的数组参数时,为什么将其替换为指针?


71

鉴于以下程序,

#include <iostream>

using namespace std;

void foo( char a[100] )
{
    cout << "foo() " << sizeof( a ) << endl;
}

int main()
{
    char bar[100] = { 0 };
    cout << "main() " << sizeof( bar ) << endl;
    foo( bar );
    return 0;
}

输出

main() 100
foo() 4
  1. 为什么将数组作为指向第一个元素的指针传递?
  2. 它是C的遗产吗?
  3. 标准怎么说?
  4. 为什么严格的C ++类型安全性下降了?

在这些情况下,我总是使用std :: array,避免必须处理此类问题,并且也可以使用std算法
paulm 2014年

2
什么严格的类型安全?谁承诺严格的类型安全性?C ++中没有这样的东西。
n。代词

TL; DR提供以下答案:数组在传递给函数时成为指针,因此当检查其大小时,得到的只是指针的大小。如果仅使用C语言,我只能建议您预先计算要从数组中取出的任何大小作为另一个参数。
超级猫


Answers:


85

是的,它是从C继承的。函数:

void foo ( char a[100] );

将参数调整为指针,因此变为:

void foo ( char * a );

如果要保留数组类型,则应传递对数组的引用:

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

C ++ '03 8.3.5 / 3:

...使用以下规则确定函数的类型。每个参数的类型由其自己的decl-specifier-seq和声明符确定。在确定每个参数的类型之后,将类型为“ T的数组”或“返回T的函数”的任何参数分别调整为“指向T的指针”或“返回T的函数指针”...。

解释语法:

在Google中检查“左右”规则;我在这里找到了一个描述。

它将大致应用于以下示例:

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

从标识符“ a”开始

'a'是一个

向右移动-我们找到一个,)因此我们反方向寻找(。当我们向左移动时,我们经过&

“ a”是参考

&到达开口处之后,我们(再次反转并向右看。现在我们看到[100]

'a'是对100数组的引用

然后我们再次反转方向,直到到达char

'a'是对100个字符的数组的引用


1
后者的缺点是将数组大小硬接线到函数签名中。功能模板可以避免这种情况。
2009年

4
值得一提的是,使用std :: vector可以巧妙地避免所有与传递数组有关的问题。
markh44 2009年

5
这可以归结为C / C ++中的纯数组参数是一个虚构的事实-它们实际上是指针。应该尽可能避免使用数组参数-它们实际上只是使事情变得混乱。
Michael Burr,2009年

2
只是一个小巧的选择:函数参数不会衰减到指针。它被调整为指针。如果函数参数是指针,则用作函数参数的数组名称可能会衰减为指针。
juanchopanza 2015年

1
布拉沃解释规则,因为该链接现在是一个404
gsamaras

16

是。在C和C ++中,不能将数组传递给函数。就是那样子。

您为什么仍要进行纯数组?你看着boost/ std::tr1::array/std::arraystd::vector

但是请注意,您可以将对任意长度数组的引用传递给函数模板。从我的头顶上:

template< std::size_t N >
void f(char (&arr)[N])
{
  std::cout << sizeof(arr) << '\n';
}

6
但是您可以传递“对数组的引用”。
理查德·科登,2009年

@Richard:在您发表评论时,我只是添加了此内容。:)
2009年

6
通过引用传递给数组并不限于“功能模板”。您可以通过引用非模板函数来传递数组。使用函数模板的优点是可以推导数组索引,从而可以为不同大小的数组类型调用函数。
理查德·科登,2009年

4
@CsTamas,是的,在C中用于传递数组和对象的规则不同。当作为参数传递时,结构实际上是按值复制的。数组被视为指向其第一个元素的指针。(C中的数组和指针是非常相互关联的。它们不是同一回事,但出于参数传递的目的,它们是相同的)
Tyler McHenry,2009年

1
现在有std :: array。
Trevor Hickey

0

C / C ++术语中有一个宏伟的词,用于静态数组和函数指针-衰减。考虑以下代码:

int intArray[] = {1, 3, 5, 7, 11}; // static array of 5 ints
//...
void f(int a[]) {
  // ...
}
// ...
f(intArray); // only pointer to the first array element is passed
int length = sizeof intArray/sizeof(int); // calculate intArray elements quantity (equals 5)
int ptrToIntSize = sizeof(*intArray); // calculate int * size on your system

4
和?充其量,这间接表明发生什么。OP正在询问为什么要以这种方式设置语言。另外,当您真正要动态分配的内容时,“静态数组”是一个令人困惑的术语。从技术上讲,您显示的数组具有extern链接,而不是static。我不确定这里的函数指针与什么有关?
underscore_d
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.