【问题标题】:Why do these expressions not work with this code?为什么这些表达式不适用于此代码?
【发布时间】:2022-01-14 03:12:24
【问题描述】:

这纯粹是基于理论,但我有这个代码:

int i = 3, k[] = {2, 4, 6, 8, 10, 12}, *x = &i, *y = k;
double d = 1.5;
struct point_tag {
 int x, y;
 char *name;
} pt[] = {{200, 40, "begin"}, {300, 100, "end"}}, *pp = pt;

还有这两个表达式:

pt[i--].y+50 在运行时导致未定义的行为

*(*pp.name+2) 无法编译

我只想知道为什么上面的不能运行,为什么下面的不能编译,尽管*((*pp).name+2) 可以。

【问题讨论】:

  • 了解运算符优先级(.*)。
  • “在运行时导致未定义的行为”如果您不知道原因,您如何知道它会导致未定义的行为?
  • 基本上:不要编写奇怪和不必要的复杂代码,也不会出现奇怪的错误。没有理由您应该在访问数组的位置执行i--,而只需使用 for 循环。没有理由你应该进行指针解引用和算术运算,只需使用可读且无错误的[] 运算符。
  • 下次请出示minimal reproducible example,大家会轻松很多。

标签: c linux


【解决方案1】:

pt[i--].y+50 在运行时导致未定义的行为

数组pt 的大小为2,因为您添加了两个初始化项。这导致有效的索引值为 0 和 1。i 的初始值为 3。您只需越界访问数组。

*(*pp.name+2) 无法编译

运算符优先于.,优先于*

【讨论】:

    【解决方案2】:

    您将数组 pt 声明为具有 2 个元素。变量i由值3初始化

    int i = 3,...;
    

    所以这个表达式带有下标运算符

    pt[i--].y+50 
    

    访问数组之外​​的内存,因为数组的有效索引范围是[0, 2)

    至于这个表达

    *(*pp.name+2)
    

    那么就和表达式一样

    *(*( pp.name ) + 2 )
    

    由于变量pp 是一个指针,你不能应用点运算符。

    你至少需要写

    *( ( *pp ).name+2)
    

    【讨论】:

      【解决方案3】:

      pt[i--].y+50 在运行时导致未定义的行为

      i 存储值 3 并且您只有一个两个插槽数组。由于您没有在数组的定义中的括号中指定长度,因此初始化程序指示数组的大小,并且初始化程序只有两个单元格。您只能访问索引01,其余的是未定义的行为。 (3 是远离阵列的两个插槽)。

      *(*pp.name+2) 无法编译

      这是正常的。字段选择比指针解引用具有更高的优先级,因此它被解释为*((*(pp.name))+2),其中pp.name 无效,因为pp 是一个指针,而不是struct。顺便说一句,(*pp) 是一个struct,所以(*pp).name 可以正常编译。

      我只想知道为什么上面的不能运行,为什么下面的不能编译,尽管*((*pp).name+2) 可以。

      这会编译,因为*ppstruct,所以字段访问器工作(*pp).name 是指向char 的指针,所以(*pp).name + 2(和等效的pp->name + 2)也是指针(一个指向pp->name的第三个字符的指针,*((*pp).name + 2)是指向的字符(在字段名的第三个位置)

      最后,我建议你,如果你想结束对指针的理解而不是讨厌它们,你可以从更简单的表达式开始,使用 ->[] 运算符(它们可以简化指针表达式,由于运算符优先级,看起来很不自然)并且只要您首先了解基础知识,事情就会变得复杂。

      【讨论】:

        猜你喜欢
        • 2015-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-08
        相关资源
        最近更新 更多