【问题标题】:When a function has a specific-size array parameter, why is it replaced with a pointer?当函数具有特定大小的数组参数时,为什么用指针替换它?
【发布时间】:2010-11-22 15:05:45
【问题描述】:

给定以下程序,

#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 算法
  • 什么严格的类型安全?谁承诺过严格的类型安全? C++ 中没有这样的东西。
  • TL;DR 以下答案:数组在传递给函数时变成指针,所以当你检查它们的大小时,你得到的只是指针的大小。如果您只使用 C,我只能建议您预先计算要从数组中取出的任何大小作为另一个参数。

标签: c++ arrays standards sizeof function-parameter


【解决方案1】:

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

void foo ( char a[100] );

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

void foo ( char * a );

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

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

C++ '03 8.3.5/3:

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

语法解释:

在谷歌中检查“左右”规则;我找到了它的一个描述here

在这个例子中大概应用如下:

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

从标识符“a”开始

'a' 是一个

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

'a' 是一个参考

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

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

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

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

【讨论】:

  • 后者的缺点是将数组大小硬连接到函数签名中。函数模板可以避免这种情况。
  • 可能值得一提的是,使用 std::vector 将巧妙地避开与传递数组相关的所有问题。
  • 这归结为 C/C++ 中的普通数组参数是虚构的——它们实际上是指针。应尽可能避免使用数组参数——它们真的只会混淆事物。
  • 只是挑剔:函数参数不会衰减为指针。它调整为指针。如果函数参数是指针,则用作函数argument 的数组名称可以衰减 为指针。
  • 感谢您解释规则,因为链接现在是 404。
【解决方案2】:

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

你为什么要做普通数组?你看过boost/std::tr1::array/std::arraystd::vector吗?

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

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

【讨论】:

  • 但是你可以传入“对数组的引用”。
  • @Richard:我只是在您写评论时添加了这个。 :)
  • 通过引用传递数组不限于“函数模板”。您可以通过引用非模板函数来传递数组。使用函数模板的好处是可以推导出数组索引,从而可以为不同大小的数组类型调用函数。
  • @CsTamas,是的,C中传递数组和对象的规则不同。结构体在作为参数传递时实际上是按值复制的。数组被视为指向其第一个元素的指针。 (C 中的数组和指针是非常相互关联的。它们不是一回事,但出于参数传递的目的,它们是相同的)
  • 现在有std::array了。
【解决方案3】:

在用于静态数组和函数指针的 C/C++ 术语中有一个华丽的词 - decay。 考虑以下代码:

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

【讨论】:

  • 然后呢?这充其量只能间接表明发生了什么。 OP 在问 为什么 语言是这样设置的。此外,当您真正的意思是动态分配时,“静态数组”是一个令人困惑的术语。从技术上讲,您显示的数组具有extern 链接,而不是static。而且我不确定函数指针与这里有什么关系?
猜你喜欢
  • 2014-04-05
  • 2011-01-17
  • 2021-10-04
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
  • 2012-08-13
  • 1970-01-01
相关资源
最近更新 更多