【问题标题】:array length using pointers [duplicate]使用指针的数组长度[重复]
【发布时间】:2013-07-30 11:28:45
【问题描述】:

可以使用*(&arr+1)-arr 计算数组长度,然后简化为(&arr)[1]-arr,进一步简化为1[&arr]-arr

但是,当在与内存分配不同的函数中计算长度时,会计算出错误的结果。

例如,

#include <iostream> 
#define ARRAY_SIZE(arr) (1[&arr]-arr)      
using namespace std;

void func(int *arr)
{
    cout<<ARRAY_SIZE(arr)<<endl;
}

int main()
{
    int arr[]={1,2,3,4,5};
    cout<<ARRAY_SIZE(arr)<<endl;
    func(arr);
}

这给出了输出:

5
8

是什么导致了这种奇怪的行为?

【问题讨论】:

  • 如果您了解*(&amp;arr+1)-arr 技巧的工作原理,这并不奇怪。
  • “数组不是指针”有帮助吗?
  • 是您发布的实际代码的输出,还是使用char * 而不是int * 的一些类似代码的输出?
  • “进一步简化” ??!!
  • 我真的很好奇人们在学习 C++ 时会发现这种计算数组大小的愚蠢方法。

标签: c++ arrays pointers pass-by-reference


【解决方案1】:

可以使用 *(&arr+1)-arr 计算数组长度

仅当 arr 实际上是一个数组时。在func 中,arr 是一个指针,因此这会取消引用内存中的随机字以给出未定义的行为。

仅给定一个指向数组第一个元素的指针,就无法判断数组的大小。您可以通过引用传递数组:

template <size_t N>
void func(int (&arr)[N]) {
    cout<<ARRAY_SIZE(arr)<<endl;
    cout<<N<<endl;               // equivalent, and less weird
}

使用相同的技术,我们可以重新实现ARRAY_SIZE,而无需借助预处理器或任何奇怪的指针算法:

template <size_t N>
size_t ARRAY_SIZE(int (&arr)[N]) {
    return N;
}

【讨论】:

  • 在 C++11 中,我会让第二个使用模板 T 作为类型,并使其 constexpr 启动。 C++03 可以得到同样的效果(一个只对数组起作用的常量表达式),但是需要一些sizeoftrickery
  • @DaveS 在 C++11 中,您将使用 std::array 代替
  • 实际上,如果arr 是一个指针,那么你从表达式*(&amp;arr+1)-arr 得到的不是它的大小而是未定义的行为。 OP 得到了 8 的结果,这对于 int* 的大小来说似乎是一个合理的值,但实际上这仅仅是巧合。如果代码在没有优化的情况下编译并在 x86 上运行,这很可能是结果,因为表达式 *(&amp;arr + 1) 必须选择调用者保存的 EBP。
  • @AndreyChernyakhovskiy:你是对的;我并没有认真考虑过这种废话会对指针造成什么影响。
【解决方案2】:

main() 中,编译器知道arr 是一个大小为5 * sizeof(int) 的数组。在func() 中,所有编译器都知道arr 是一个指向内存块的指针——它不知道数组有多大,甚至不知道它是一个数组(它可能只是分配的一块内存例如通过malloc())。

【讨论】:

    【解决方案3】:

    当您将数组传递给函数时,它会衰减为指针,并且会丢失有关其大小的信息。 func 可以取任意大小的数组,那么如何确定大小呢?您必须将数组的大小作为额外参数传递,或者使用诸如 std::vector 或 (C++11) std::array 之类的数据结构来跟踪它们的大小。

    【讨论】:

      猜你喜欢
      • 2013-03-01
      • 2020-03-04
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多