使用指针访问结构元素

时间:2011-01-06 08:26:07

标签: c pointers structure

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

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评估为有效地址。有人可以解释我错在哪里吗?

4 个答案:

答案 0 :(得分:5)

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

但无论如何,你的程序的行为是未定义的。不,它不会产生一个“有效地址”,因为你似乎错误地相信。与没有对象存在的内存中的位置对应的数字地址无效(当然,除了空指针值之外)。

答案 1 :(得分:4)

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

&ptr->b

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

答案 2 :(得分:2)

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

答案 3 :(得分:2)

计算地址不需要访问内存。 &ptr->b表示“向我提供b指向的ptr字段的地址”。这样做不需要查看可能存储在该内存位置的任何内容。

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

C使它略微混浊,因为它区分左值和左值。也就是说,表达式的表达式在表达式的左侧与右侧的表达式区别对待。给定x = y;之类的语句,C编译器将从y的地址加载一个值,并将其存储在x的地址中。这是区别:y被隐式取消引用,但x不是。