C++ 为什么我们不能按值将数组传递给函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7454990/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:57:57  来源:igfitidea点击:

Why can't we pass arrays to function by value?

c++arraysfunctionarguments

提问by Alcott

Apparently, we can pass complex class instances to functions, but why can't we pass arrays to functions?

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

回答by ?imon Tóth

The origin is historical. The problem is that the rule "arrays decay into pointers, when passed to a function" is simple.

起源是历史性的。问题在于“数组在传递给函数时会衰减为指针”的规则很简单。

Copying arrays would be kind of complicated and not very clear, since the behavior would change for different parameters and different function declarations.

复制数组会有点复杂并且不是很清楚,因为行为会因不同的参数和不同的函数声明而改变。

Note that you can still do an indirect pass by value:

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

struct A { int arr[2]; };
void func(struct A);

回答by Kerrek SB

Here's another perspective: There isn't a single type "array" in C. Rather, T[N]is a a differenttype for every N. So T[1], T[2], etc., are all different types.

这里的另一个透视:没有一个单一类型的“阵列”在C.相反,T[N]是AA不同类型为每个N。所以T[1]T[2]等等,都是不同的类型

In C there's no function overloading, and so the only sensible thing you could have allowed would be a function that takes (or returns) a single type of array:

在 C 中没有函数重载,因此您可以允许的唯一明智的事情是接受(或返回)单一类型数组的函数:

void foo(int a[3]);  // hypothetical

Presumably, that was just considered far less useful than the actual decision to make all arrays decay into a pointer to the first element and require the user to communicate the size by other means. After all, the above could be rewritten as:

据推测,这被认为远不如将所有数组衰减为指向第一个元素的指针并要求用户通过其他方式传达大小的实际决定有用得多。毕竟,上面的可以改写为:

void foo(int * a)
{
  static const unsigned int N = 3;
  /* ... */
}

So there's no loss of expressive power, but a huge gain in generality.

因此,表达能力没有损失,但普遍性有了巨大的提高。

Note that this isn't any different in C++, but template-driven code generation allows you to write a templated function foo(T (&a)[N]), where Nis deduced for you -- but this just means that you can create a whole family of distinct, differentfunctions, one for each value of N.

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

As an extreme case, imagine that you would need two functions print6(const char[6])and print12(const char[12])to say print6("Hello")and print12("Hello World")if you didn't want to decay arrays to pointers, or otherwise you'd have to add an explicit conversion, print_p((const char*)"Hello World").

作为一个极端的例子,假设你需要两个函数print6(const char[6])print12(const char[12])print6("Hello")print12("Hello World"),如果你不想腐烂数组的指针,否则你就必须添加显式转换,print_p((const char*)"Hello World")

回答by Ayub

Answering a very old question, as Question is market with C++ just adding for completion purposes, we can use std::array and pass arrays to functions by value or by reference which gives protection against accessing out of bound indexes:

回答一个非常古老的问题,因为问题是 C++ 的市场,只是为了完成目的而添加,我们可以使用 std::array 并按值或按引用将数组传递给函数,以防止访问越界索引:

below is sample:

以下是示例:

#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);
}

回答by David Schwartz

The reason you can't pass an array by value is because there is no specific way to track an array's size such that the function invocation logic would know how much memory to allocate and what to copy. You can pass a class instance because classes have constructors. Arrays do not.

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

回答by AnT

It was done that way in order to preserve syntactical and semantic compatibility with B language, in which arrays were implemented as physical pointers.

这样做是为了保持与 B 语言的句法和语义兼容性,其中数组被实现为物理指针。

A direct answer to this question is given in Dennis Ritchie's "The Development of the C Language", see the "Critique" section. It says

这个问题的直接答案在 Dennis Ritchie 的“C 语言的发展”中给出,参见“批判”部分。它说

For example, the empty square brackets in the function declaration

例如,函数声明中的空方括号

int f(a) int a[]; { ... }

are a living fossil, a remnant of NB's way of declaring a pointer; ais, in this special case only, interpreted in C as a pointer. The notation survived in part for the sake of compatibility, in part under the rationalization that it would allow programmers to communicate to their readers an intent to pass fa pointer generated from an array, rather than a reference to a single integer. Unfortunately, it serves as much to confuse the learner as to alert the reader.

是活化石,是NB声明指针方式的残余;a仅在这种特殊情况下,在 C 中解释为指针。该符号保留的部分原因是为了兼容性,部分原因是它允许程序员向他们的读者传达传递f从数组生成的指针的意图,而不是对单个整数的引用。不幸的是,它既能混淆学习者,又能提醒读者。

This should be taken in the context of the previous part of the article, especially "Embryonic C", which explains how introduction of structtypes in C resulted in rejection of B- and BCPL-style approach to implementing arrays (i.e. as ordinary pointers). C switched to non-pointer array implementation, keeping that legacy B-style semantics in function parameter lists only.

这应该在本文前一部分的上下文中考虑,特别是“胚胎 C”,它解释了struct在 C 中引入类型如何导致拒绝 B 和 BCPL 风格的方法来实现数组(即作为普通指针)。C 切换到非指针数组实现,仅在函数参数列表中保留传统的 B 样式语义。

So, the current variant of array parameter behavior is a result of a compromise: one the one hand, we had to have copyable arrays in structs, on the other hand, we wanted to preserve semantic compatibility with functions written in B, where arrays are always passed "by pointer".

因此,当前数组参数行为的变体是妥协的结果:一方面,我们必须在structs 中有可复制的数组,另一方面,我们希望保持与用 B 编写的函数的语义兼容性,其中数组是总是“通过指针”传递。

回答by Almog

Summery:

总结:

  1. Passing the Address of the array's first element&a = a = &(a[0])
  2. New Pointer(new pointer, new address, 4 bytes, in the memory)
  3. Points to the same memory location, in different type.
  1. 传递数组第一个元素地址&a = a = &(a[0])
  2. New Pointer(新指针,新地址,4字节,内存中)
  3. 指向同一个内存位置类型不同


Example 1:

示例 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 !!! 
}

Addresses:

地址:

[main] 
     a = 0046FB18 // **Original**
     &a = 0046FB18 // **Original**
[func]
     arr = 0046FB18 // **Original**
     &arr = 0046FA44 // TempPTR
[func]
     arr = NULL
     &arr = 0046FA44 // TempPTR


Example 2:

示例 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);
}

Addresses

地址

Prints: 
[main] 0046FB18 = 0046FB18
[func] 0046FA44 != 0046FB18


Please Note:

请注意:

  1. &(required-lvalue):lvalue -to-> rvalue
  2. Array Decay:new pointer (temporary) points to (by value) array address
  1. &(required-lvalue):lvalue -to-> rvalue
  2. Array Decay:新指针(临时)指向(按值)数组地址

readmore:

阅读更多:

Rvalue

Array Decay

右值

阵列衰减

回答by KonradG

You arepassing by value: the value of the pointer to the array. Remember that using square bracket notation in C is simply shorthand for de-referencing a pointer. ptr[2] means *(ptr+2).

正在按值传递:指向数组的指针的值。请记住,在 C 中使用方括号表示法只是取消引用指针的简写。ptr[2] 表示 *(ptr+2)。

Dropping the brackets gets you a pointer to the array, which can be passed by value to a function:

去掉括号会得到一个指向数组的指针,它可以按值传递给函数:

int x[2] = {1, 2};
int result;
result = DoSomething(x);

See the list of typesin the ANSI C spec. Arrays are not primitive types, but constructed from a combination of pointers and operators. (It won't let me put another link, but the construction is described under "Array type derivation".)

请参阅ANSI C 规范中的类型列表。数组不是原始类型,而是由指针和运算符的组合构造而成。(它不会让我放另一个链接,但在“数组类型派生”下描述了构造。)

回答by Andre Holzner

The equivalent of that would be to first make a copy of the array and then pass it to the function (which can be highly inefficient for large arrays).

相当于首先制作数组的副本,然后将其传递给函数(这对于大型数组来说效率非常低)。

Other than that I would say it's for historical reasons, i.e. one could not pass arrays by value in C.

除此之外,我会说这是出于历史原因,即无法在 C 中按值传递数组。

My guess is that the reasoning behind NOT introducing passing arrays by value in C++ was that objects were thought to be moderately sized compared to arrays.

我的猜测是,在 C++ 中不引入按值传递数组的原因是,与数组相比,对象被认为是中等大小。

As pointed out by delnan, when using std::vectoryou can actually pass array-like objects to functions by value.

正如 delnan 所指出的,在使用时,std::vector您实际上可以按值将类数组对象传递给函数。

回答by mrbioeng

actually, a pointer to the array is passed by value, using that pointer inside the called function will give you the feeling that the array is passed by reference which is wrong. try changing the value in the array pointer to point to another array in your function and you will find that the original array was not affected which means that the array is not passed by reference.

实际上,指向数组的指针是按值传递的,在被调用函数中使用该指针会让您感觉数组是按引用传递的,这是错误的。尝试将数组指针中的值更改为指向函数中的另一个数组,您会发现原始数组没有受到影响,这意味着该数组不是通过引用传递的。