【问题标题】:Why does * need to be put before (&a) to subtract a (a is an array)?为什么要在 (&a) 之前加上 * 来减去 a(a 是数组)?
【发布时间】:2020-08-16 23:38:38
【问题描述】:

我正在学习如何查找数组的长度,但我对这个解决方案感到困惑。我试图在网上找到解释,但似乎没有。

int arr[5] = {5, 8, 1, 3, 6};
   int len = *(&arr + 1) - arr;
   cout << "The length of the array is: " << len;

【问题讨论】:

  • 我很困惑为什么这段代码会不断出现。有一种很好且易于理解的方法来获取数组的大小:sizeof(array)/sizeof(*array)。这既简单又干净。相反,即使是 C++ 专家也不清楚上面显示的代码是否合法。
  • 那个解决方案也不错。只是我想了解两者。
  • 最佳解决方案是std::size(arr) (en.cppreference.com/w/cpp/iterator/size)。无需担心额外的知识,它会按预期工作。

标签: c++ pointers


【解决方案1】:

数组的内存地址和第一个元素的内存地址是一样的,当你对一个指针进行加减时,都是通过它所指向的类型的大小来完成的,所以:

  • arr 指的是int&amp;arr 指的是int[5]
  • &amp;arr+1 以五个整数的大小递增内存地址。
  • 如果您执行(&amp;arr+1)-arr,则会出现编译错误,因为它们是不同的类型。
  • 如果你做(&amp;arr+1)-&amp;arr你得到1,因为内存地址的偏移量与int[5]的大小相同。
  • 因此,当您执行*(&amp;arr+1) 时,您将获得相同的内存地址但指向int 而不是int[5]。现在你不会得到一个编译错误,因为两个指针都指向int,并且你得到的内存地址的偏移量是int的大小,而不是int[5]。 内存地址和类型有时很难解释,我希望我说清楚了。在这里,您可以运行一些代码来查看提到的一些概念:
   int arr[5] = {5, 8, 1, 3, 6};
   int len = *(&arr + 1) - arr;
   
   cout << "arr: " << arr << endl;
   cout << "arr + 1: " << arr+1 << endl;
   cout << "&arr: " << &arr << endl;
   cout << "&arr + 1: " << &arr+1 << endl;
   cout << "*(&arr + 1): " << *(&arr+1) << endl;
   
   // cout << "&arr + 1 - arr: " << &arr+1-arr << endl;
   // error: invalid operands of types ‘int (*)[5]’ and ‘int [5]’ to binary ‘operator-’

   cout << "The length of the array is: " << len;

【讨论】:

  • 您好,谢谢您的回答。这对我帮助很大。但我只想问你是从哪里学来的?有没有关于此类内容的书籍或视频?
  • 恐怕我没有什么特别推荐的...我从大学教授那里学到了这种东西,我不知道在哪里可以找到它的书面或视频,我'对不起。
  • &arr 是一个指向 int[5] 的指针(这意味着 int(*)[5]),所以当你取消引用它时,你会得到类型 int[5],我认为这是隐式转换的使用算术运算符时指向 int 指针。 @S.M. 的回答解释它。另外,如果您想了解更多信息,可以查找有关指针运算和算术的信息。
【解决方案2】:

数组arr的类型是int[5]&amp;arr的类型是int(*)[5](&amp;arr + 1) 增加了sizeof(int[5]) 上的数组地址,因为它是通过指针算法的规则完成的,即计算数组之后的地址。 *(&amp;arr + 1)int[5],紧跟在 arr 之后的数组,arr[5] 将放置在其中。减法的两个参数衰减到int*。指向 int 的指针相减得到 5。

这可能被认为是未定义的行为,因为属于不同对象存储的指针的减法未定义。带有指向未分配内存的指针(如(&amp;arr + 1))的表达式的结果也是未定义的。

【讨论】:

  • "未定义指针订阅" - 你的意思是什么?
  • 我相信这是一个已知的语言缺陷,这是否是 UB 是模棱两可的。前段时间我问了一个类似的问题:Dereferencing one past the end pointer to array type.
  • 订阅 - 这是自动更正导致的打印错误。
  • 好的,更新为不属于同一个数组的指针。
  • @FrançoisAndrieux • 这是语言中一个有趣的蜘蛛网角。在我看来(因为我不再是语言律师),它似乎是 UB。
【解决方案3】:

首先,获取数组大小的传统方法是sizeof a/sizeof *a。 C++11 增加了std::extent&lt;decltype(a)&gt;::value。当然,没有办法仅从指向它的指针获取数组的大小,如

void f(int x[]) {/* no size here */}

由于数组不是- 的合适操作数,因此右侧操作数会发生数组到指针的转换,从而产生int*。两个操作数都必须是这种类型,这样减法才能产生多个ints。 &amp;arr 当然是指向 array 的指针(int(*)[5] 类型,它传达大小),因此&amp;arr+1 也是如此。添加*(或等效地写(&amp;arr)[1])会生成一个左值,该左值应该是指“arr 之后的下一个数组”,它本身会衰减为与- 一起使用的指针。

但是,正如索引形式所表明的那样,这涉及到引用一个不存在的数组,因此是未定义的行为

【讨论】:

    猜你喜欢
    • 2016-09-19
    • 2019-03-18
    • 1970-01-01
    • 2012-02-13
    • 2014-03-29
    • 1970-01-01
    • 2012-10-19
    • 2016-02-25
    • 1970-01-01
    相关资源
    最近更新 更多