为什么我们不能通过数组来传递函数呢?
显然,我们可以将复杂的类实例传递给函数,但为什么我们不能将数组传递给函数呢?
起源是历史的。 问题是规则“数组衰减成指针,当传递给函数”很简单。
复制数组会有点复杂,不太清楚,因为不同的参数和不同的函数声明会改变行为。
请注意,您仍然可以按值进行间接传递:
struct A { int arr[2]; }; void func(struct A);
这里有另外一个观点:在C中没有单一types的“数组”。相反,对于每个N
, T[N]
是不同的types。 所以T[1]
, T[2]
等都是不同的types 。
在C中没有函数重载,所以你可以允许的唯一明智的事情是一个函数,它需要(或返回) 单一types的数组 :
void foo(int a[3]); // hypothetical
据推测,这只是被认为远远没有实际的决定,使所有的arrays衰变成一个指向第一个元素的指针,并要求用户通过其他方式来传递大小。 毕竟,上面的内容可以改写为:
void foo(int * a) { static const unsigned int N = 3; /* ... */ }
所以没有performance力的损失,但总的来说是巨大的收益。
请注意,这在C ++中没有什么不同,但是模板驱动的代码生成允许您编写一个模板函数foo(T (&a)[N])
,其中N
是为您推导出来的,但这只是表示您可以创造一个完整的,不同的function家族,每一个N
值。
作为一个极端的例子,假设你不需要两个函数print6(const char[6])
和print12(const char[12])
来表示print6("Hello")
和print12("Hello World")
想要将数组衰减到指针,否则就不得不添加一个显式转换print_p((const char*)"Hello World")
。
回答一个非常古老的问题,因为问题是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); }
你无法按值传递数组的原因是因为没有具体的方法来跟踪数组的大小,使得函数调用逻辑知道要分配多less内存以及要拷贝什么内存。 你可以传递一个类实例,因为类有构造函数。 arrays不。
您正在传递值:指向数组的指针的值。 请记住,在C中使用方括号表示法只是取消引用指针的简写。 ptr [2]表示*(ptr + 2)。
删除括号会得到一个指向数组的指针,该数组可以通过值传递给一个函数:
int x[2] = {1, 2}; int result; result = DoSomething(x);
请参阅ANSI C规范中的types列表 。 数组不是原始types,而是由指针和运算符组合而成。 (它不会让我把另一个链接,但在“数组types推导”中描述的构造。)
综述:
- 传递数组第一个元素的地址
&a = a = &(a[0])
- 新指针 (新指针, 新地址 ,4字节,在内存中)
- 指向不同types的相同内存位置 。
例1:
void by_value(bool* arr) // pointer_value passed by value { arr[1] = true; arr = NULL; // temporary pointer that points to original array } int main() { bool a[3] = {}; cout << a[1] << endl; // 0 by_value(a); cout << a[1] << endl; // 1 !!! }
地址:
[main] a = 0046FB18 // **Original** &a = 0046FB18 // **Original** [func] arr = 0046FB18 // **Original** &arr = 0046FA44 // TempPTR [func] arr = NULL &arr = 0046FA44 // TempPTR
例2:
void by_value(bool* arr) { cout << &arr << arr; // &arr != arr } int main() { bool a[3] = {}; cout << &a << a; // &a == a == &a[0] by_value(arr); }
地址
Prints: [main] 0046FB18 = 0046FB18 [func] 0046FA44 != 0046FB18
请注意:
- &(required-lvalue):左值 – 右值>右值
- 数组衰减:新指针(临时)指向(按值)数组地址
阅读更多:
右值
数组衰变
这相当于首先制作一个数组的副本,然后将其传递给函数(对于大型数组可能效率非常低)。
除此之外,我会说这是由于历史原因,即一个人不能在C中按值传递数组
我的猜测是,不在C ++中引入传值数组的原因在于,与数组相比,对象被认为是适度的大小。
正如delnan指出的那样,当使用std::vector
,实际上可以通过值将类似数组的对象传递给函数。
实际上, 一个指向数组的指针是通过值传递的 ,在被调用的函数内部使用该指针会给你一种感觉,即数组是通过引用传递的,这是错误的。 尝试更改数组指针中的值以指向您的函数中的另一个数组,您会发现原始数组不受影响,这意味着该数组不被引用传递。