为什么不能按值将数组传递给函数呢?

时间:2022-10-24 21:04:46

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

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

8 个解决方案

#1


51  

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

#2


25  

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

这里还有另一种观点:在c中没有一个单独的类型“array”,相反,T[N]对于每个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 N is deduced for you -- but this just means that you can create a whole family of distinct, different functions, 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”)。

#3


4  

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

#4


3  

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.

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

#5


1  

You are passing 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 types in 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规范中的类型列表。数组不是原始类型,而是由指针和操作符组合而成的。(它不会让我再放一个链接,但构造在“数组类型派生”下进行描述。)

#6


1  

Summery:

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

Example 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:

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. &(required-lvalue):左值- - >右值
  3. Array Decay: new pointer (temporary) points to (by value) array address
  4. 数组衰减:新的指针(临时)指向(值)数组地址

readmore:

readmore:

Rvalue

右值

Array Decay

数组衰变

#7


0  

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::vector you can actually pass array-like objects to functions by value.

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

#8


0  

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.

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

#1


51  

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

#2


25  

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

这里还有另一种观点:在c中没有一个单独的类型“array”,相反,T[N]对于每个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 N is deduced for you -- but this just means that you can create a whole family of distinct, different functions, 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”)。

#3


4  

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

#4


3  

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.

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

#5


1  

You are passing 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 types in 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规范中的类型列表。数组不是原始类型,而是由指针和操作符组合而成的。(它不会让我再放一个链接,但构造在“数组类型派生”下进行描述。)

#6


1  

Summery:

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

Example 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:

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. &(required-lvalue):左值- - >右值
  3. Array Decay: new pointer (temporary) points to (by value) array address
  4. 数组衰减:新的指针(临时)指向(值)数组地址

readmore:

readmore:

Rvalue

右值

Array Decay

数组衰变

#7


0  

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::vector you can actually pass array-like objects to functions by value.

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

#8


0  

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.

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