RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 924642
Accepted
ampawd
ampawd
Asked:2020-12-24 05:04:36 +0000 UTC2020-12-24 05:04:36 +0000 UTC 2020-12-24 05:04:36 +0000 UTC

指向数组的指针的微妙之处

  • 772

众所周知,如果没有运算符,sizeof则可以计算数组元素的个数,例如,像这样:

int arr[10];
size_t size = *(&arr + 1) - arr;

在哪里

arr是指向第一个元素的指针

&arr有一个指向整个数组的指针

&arr + 1在我们的数组之后有一个指向下一块内存的指针

*(&arr + 1)是数组最后一个元素之后的元素的地址。

因此,指针的差异给出了它们之间的元素数量。

问题:

  1. 这不会*(&arr + 1)导致UB?

  2. 如何&arr有指向整个数组的指针?它是由标准定义的吗?

c++
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    AnT stands with Russia
    2020-12-24T06:24:36Z2020-12-24T06:24:36Z

    *(&arr + 1)可以写成(&arr)[1]或1[&arr]。正是以这种“更有趣”的形式,这个问题在讨论中定期出现。

    在 C++ 中,这个问题没有正式的答案。该话题一度被积极讨论,但仍停留在“草拟”状态:

    http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232

    尚未看到对这个问题给出明确答案的尝试。也就是说,直到现在,在 C++ 语言中,对于是否有可能做到这一点的老问题还没有答案

    int arr[10];
    
    for (int *p = &arr[0]; p != &arr[10]; ++p) // `&arr[10]` - UB или нет?
      ...;
    
    for (int *p = arr; p != 1[&arr]; ++p) // `1[&arr]` - UB или нет?
      ...;
    

    至少第一种选择的形式合法性问题自豌豆之王时代就已为人所知,但尚未提供合理的答案。

    在 C 语言中,已经尝试通过声明相邻的运算符&并*在计算表达式之前相互“消灭”彼此来解决其中的一些情况。这使该选项合法化&arr[10]

    &arr[10]  <=>  &*(arr + 10)   <=>  arr + 10 - нет UB
    

    但这并没有正式使变体1[&arr](您的变体)合法化。在这个变体中,我们有

     (int *) *(&arr + 1)
       ^     ^^^^^^^^^^^ 
       |     выражение, результат которого имеет тип `int [10]`
       |
       стандартное неявное преобразование массива к указателю 
    

    与 C 语言声明相邻&和*“消灭”彼此的方式相同,有必要*声明相邻的“隐式数组到指针转换”和运算符“折叠”为简单的指针转换,即 认为这个表达式等价

     (int *) (&arr + 1)
    

    然而,这还没有完成。也就是说,在 C 中,您的版本正式生成未定义的行为。

    在 C++ 语言中,一切都还悬而未决(并且长期以来一直悬而未决)。

    • 8
  2. Andrey Sv
    2020-12-24T06:15:51Z2020-12-24T06:15:51Z

    按照标准,& 运算符获取操作数的地址,并将其实际转换为一个元素的数组。

    出于指针算术 ([expr.add]) 和比较 ([expr.rel], [expr.eq]) 的目的,不是以这种方式获取地址的数组元素的对象被认为属于数组有一个类型为 T 的元素。

    更简单的地址算术。在这种情况下,数组元素是一个由十个整数元素组成的数组。因此,递增指针将移动到数组中的下一个元素。在那之后,只剩下一个指向下一个元素的第一个元素的指针(对不起重言式)并得到它们的区别。命名*(&arr + 1)将给出一个指向下一个数组的第一个元素的指针int arr[10];,但实际上指针将保持不变,只是类型int*。

    指针和它指向的东西是两个不同的东西。在内存中的位置无关紧要,指针可以随心所欲地递增。在这种情况下,工作使用通常的数字,它是一个指针:

    int arr[10];
    auto sp = &arr;
    sp++;
    sp++;
    sp++;
    sp++;
    //size_t size = *(&arr + 1) - arr;
    size_t size = (int*)sp - arr; // По сути тоже самое
    

    按照标准,一切都很好。它不会导致任何 UB。是的,这一切都在标准中定义。

    为了更好地演示,我们可以采用更简单的类型:

    int a;
    int *pa = &a;
    int *pb = pa + 1;
    size_t s = pb - pa;
    

    如果 P 和 Q 分别指向同一个数组对象 x 的元素 x[i] 和 x[j],则表达式 P - Q 的值为 i - j。

    在这种情况下,我们得到数组的维度,它将等于一。如果您需要获取类型的维度,则可以执行以下操作:

    size_t s = (char*)pb - (char*)pa;
    

    但最好不要重新发明轮子并使用 sizeof。

    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5