【问题标题】:Accessing structure elements using pointers使用指针访问结构元素
【发布时间】:2011-06-04 12:35:12
【问题描述】:

当以下程序没有崩溃时,我感到很惊讶。

typedef struct _x {
  int a;
  char b;
  int c;
} x;

main() {
  x *ptr = 0;
  char *d = &ptr->b;
}

据我了解,-> 运算符的优先级高于 & 运算符。因此,当我们尝试取消引用 NULL 指针 tr 时,我预计程序会在下面的语句中崩溃。

char *d = &ptr->b; 

但是&ptr->b 语句的计算结果是一个有效的地址。有人可以解释我错在哪里吗?

【问题讨论】:

  • 这有点类似于 offsetof 宏。

标签: c pointers structure


【解决方案1】:

您的期望是没有根据的。当您取消引用空指针时,C 程序不一定会“崩溃”。当您尝试做类似的事情时,C 程序会表现出所谓的未定义行为。未定义的行为可以以许多不同的方式表现出来。它可能导致崩溃。或者它可以产生一些甚至类似于“工作”程序的东西。后者显然是在你的情况下发生的。

但无论如何,您的程序的行为是未定义的。不,它不会像您错误地认为的那样产生“有效地址”。对应于内存中不存在对象的位置的数字地址是无效的(当然,空指针值除外)。

【讨论】:

    【解决方案2】:

    您的代码没有崩溃的原因是您实际上并没有取消引用指针。注意表达式

    &ptr->b
    

    实际上并没有尝试加载ptrptr->b 的内容。相反,它只是将其所在位置的地址存储在内存中。你最终会得到一个指针,指向ptr 指向的对象的b 字段应该在哪里。这将是地址 0 之后的几个字节,因此取消引用您刚刚创建的指针将导致段错误。

    【讨论】:

      【解决方案3】:

      &ptr->b == sizeof(int),表示_x_x之后_x.a(类型为int)相对于地址*((x*)0)的偏移量。 4 的偏移量(32 位架构的典型值)保存在 d 指针中。您必须访问 d 才能获得 seg-fault。

      【讨论】:

        【解决方案4】:

        计算地址不需要访问内存。 &ptr->b 的意思是“给我ptr 指向的结构的b 字段的地址。”这样做不需要查看该内存位置中可能存储的任何内容。

        考虑索引数组而不是结构可能会有所帮助。 C 将ptr[5] 定义为等价于*(ptr + 5),这意味着&(ptr[5])&(*(ptr + 5)) 相同。现在很容易看到&* “取消”并留下(ptr + 5),这仅涉及指针增量,而不是从内存中加载。

        C 使这有点模糊,因为它区分了左值和右值。也就是说,涉及记忆的表达式在表达式左侧的处理方式与在右侧的处理方式不同。给定像x = y;这样的语句,C编译器将从y的地址加载一个值,并将其存储在x的地址中。这就是区别:y 是隐式取消引用,但 x 不是。

        【讨论】:

          猜你喜欢
          • 2020-11-05
          • 1970-01-01
          • 2023-02-16
          • 2013-06-11
          • 1970-01-01
          • 2017-01-04
          • 2013-05-26
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多