【问题标题】:Unexpected results with array and array as argument [duplicate]数组和数组作为参数的意外结果[重复]
【发布时间】:2021-09-07 15:39:20
【问题描述】:

请原谅我这个可能很愚蠢的问题。考虑一下:

int foo(int* arr) {
    std::cout << arr << "(" << sizeof(arr) << ")";
}

int main()
{
    int x[] = {0, 1, 2, 3, 4};
    foo(x);
    std::cout << " " << x << "(" << sizeof(x) << ")";
}

Output: 0x7c43ee9b1450(8) 0x7c43ee9b1450(20) - 地址相同,大小不同。

我的理解是函数参数是特定于数组第一个元素的地址,所以大小为8字节,main中的变量也应该如此;那么函数外部变量的大小怎么代表整个数组(4 字节 int times 5 个元素 = 20)?我怎么可能从函数内部确定一个数组实际上有多大?

【问题讨论】:

  • 里面mainsizeof(x)是数组的大小;在他的其他函数中,sizeof(arr) 是指针的大小。
  • arr 是一个指向数组第一项的指针,所以你得到一个指针的大小。 x 是一个数组,所以你得到一个数组的大小(一个项目的大小乘以数组中的项目数)。
  • int[5] 类型的数组很容易衰减为 int* 类型。这就是你在这里看到的。
  • "相同地址,不同大小" ...想象一下激光笔指向飞机与指向飞机飞行员——地址相同,大小不同 :-)

标签: c++


【解决方案1】:

这是因为函数内外的类型不一样。

如果你确保函数内部和外部的类型相同,你应该得到相同的结果。

int foo(int (&arr)[5])
{
     std::cout << arr << "(" << sizeof(arr) << ")";
     return 0;
}

问题是数组decay 直接变成了指针。因此,如果将数组传递给函数,它将很容易转换为指针。这就是这里发生的事情。

int foo(int* arr)
    //  ^^^^    Notice this is not an array.
    //          It is simply a pointer to an integer
    //          The array has decayed into a pointer to the
    //          first element in the array.
{
     std::cout << arr << "(" << sizeof(arr) << ")";
     return 0;
}

我怎么可能从函数内部确定一个数组实际上有多大?

这实际上是 C 的一个真正问题。在 C 中,他们通过让您将数组的大小作为第二个参数传递来解决这个问题:

 int foo(int* arr, std::size_t size);

然后从 main 调用它:

     foo(arr, sizeof(arr)/sizeof(arr[0])); // This always works as it done
                                           // at compile time and not runtime

在 C++ 中,我们通常不使用 C 数组,但更喜欢 std::vectorstd::array,因为大小很容易检索。通常我们使用容器类型C,因为它们是容器的duck types

 template<typename C>
 int foo(C& container)
 {
       std::cout << "(" <<container.size() << ")";
       return container.size();
 }

【讨论】:

  • 感谢您向我澄清!毕竟这很明显,我只是尽我所能来解决这个指针的问题。
【解决方案2】:

当传递这样的数组时,您会丢失所有大小信息。 所以被调用的函数在数组大小方面是盲目的。

在 C++ 中,使用 std::array(固定大小的数组)和 std::vector(改变大小的数组)更有意义。当您将它们传递给函数时,您的意图会更加清晰。您的代码中的错误和内存访问问题将会减少。

希望模板版本不会吓到你。 矢量变体更简单,但在运行时可能会使用更多内存。

#include <array>
#include <vector>
#include <iostream>

template<size_t N>
size_t foo(const std::array<int,N>& arr) 
{
    for (const auto n : arr) std::cout << n << " ";
    std::cout << "(" << arr.size() << ")" << std::endl;
    return arr.size();
}

size_t foo(const std::vector<int>& arr)
{
    for (const auto n : arr) std::cout << n << " ";
    std::cout << "(" << arr.size() << ")" << std::endl;
    return arr.size();
}

int main()
{
    std::array<int,5> x{ 0, 1, 2, 3, 4 };
    std::vector<int> y{ 0, 1, 2, 3, 4 };

    auto size_x = foo(x);
    auto size_y = foo(y);
}

【讨论】:

  • 现代 C++中我们也可以使用std::span
  • 这也是一种选择:)
猜你喜欢
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-25
  • 1970-01-01
  • 2016-02-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多