为什么我们不能通过值传递数组?

Alc*_*ott 45 c++ arrays arguments function

显然,我们可以将复杂的类实例传递给函数,但为什么我们不能将数组传递给函数呢?

Let*_*_Be 56

起源是历史的.问题是规则"数组在传递给函数时衰减为指针"很简单.

复制数组会有点复杂而且不太清楚,因为不同参数和不同函数声明的行为会发生变化.

请注意,您仍然可以按值进行间接传递:

struct A { int arr[2]; };
void func(struct A);
Run Code Online (Sandbox Code Playgroud)

  • 数组表达式衰减为指针的规则并不特定于函数调用.在C中,衰减发生在除(a)一元`&`address-of运算符的操作数之外的任何上下文中; (b)一元`sizeof`运算符的操作数; 或者(c)初始化器中用于初始化字符数组的字符串文字(`char s [] ="hello";`); 我认为C++中有一两个例外,可能涉及引用.例如,在`int arr [10]; int*p; p = arr;`衰变发生了,但是看不到函数调用. (5认同)
  • 在C++中,您可以将数组传递给每个引用的函数.使用函数模板和非类型模板参数,您甚至可以传递任意长的数组. (3认同)

Ker*_* SB 28

这是另一个视角:C中没有一个类型的"数组".相反,每个类型T[N]都是不同的类型N.所以T[1],T[2]等等,都是不同的类型.

在C中没有函数重载,所以你可以允许的唯一合理的东西是一个接受(或返回)单一类型数组的函数:

void foo(int a[3]);  // hypothetical
Run Code Online (Sandbox Code Playgroud)

据推测,这被认为远没有实际决定使所有数组衰变为指向第一个元素的指针并且要求用户通过其他方式传递大小的实用决策.毕竟,以上内容可以改写为:

void foo(int * a)
{
  static const unsigned int N = 3;
  /* ... */
}
Run Code Online (Sandbox Code Playgroud)

因此,没有表现力的损失,但一般性的巨大收益.

请注意,这在C++中没有任何不同,但模板驱动的代码生成允许您编写模板化函数foo(T (&a)[N]),在N此为您推导出 - 但这只是意味着您可以创建一系列不同的,不同的函数,一个对于每个值N.

作为一个极端的例子,想象一下你需要两个函数print6(const char[6])print12(const char[12])print6("Hello"),print12("Hello World")如果你不想将数组衰减到指针,或者你必须添加一个显式转换,print_p((const char*)"Hello World").


小智 9

回答一个很老的问题,因为Question是C ++的市场,只是出于完成目的而添加,我们可以使用std :: array并将数组按值或引用传递给函数,从而防止访问超出范围的索引:

下面是示例:

#include <iostream>
#include <array>

//pass array by reference
template<size_t N>
void fill_array(std::array<int, N>& arr){
    for(int idx = 0; idx < arr.size(); ++idx)
        arr[idx] = idx*idx;
}

//pass array by value
template<size_t N>
void print_array(std::array<int, N> arr){
    for(int idx = 0; idx < arr.size(); ++idx)
        std::cout << arr[idx] << std::endl;
}

int main()
{
    std::array<int, 5> arr;
    fill_array(arr);
    print_array(arr);
    //use different size
    std::array<int, 10> arr2;
    fill_array(arr2);
    print_array(arr2);
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*rtz 6

您无法按值传递数组的原因是,因为没有特定的方法来跟踪数组的大小,因此函数调用逻辑将知道要分配多少内存以及要复制的内容。您可以传递类实例,因为类具有构造函数。数组没有。

  • 如果将数组声明为a [4],那么您只需知道编译时的大小即可。 (2认同)