这将给出一个正确的输出,即使我没有分配内存并且已经在主内部声明了指向结构二的指针
struct one
{
char x;
int y;
};
struct two
{
char a;
struct one * ONE;
};
main()
{
struct two *TWO;
scanf("%d",&TWO->ONE->y);
printf("%d\n",TWO->ONE->y);
}
但是当我在main之外的结构之后声明一个指向2的指针时,我会得到分段错误,但为什么我之前没有得到分段错误
struct one
{
char x;
int y;
};
struct two
{
char a;
struct one * ONE;
}*TWO;
main()
{
scanf("%d",&TWO->ONE->y);
printf("%d\n",TWO->ONE->y);
}
答案 0 :(得分:3)
在这两种情况下,TWO
是指针,指向struct two
类型的对象。
在案例1中,指针是狂野的,可以指向任何地方。
在案例2中,指针为NULL
,因为它是全局的。
但在这两种情况下,指针都指向有效 struct two
对象。您在scanf
中的代码将此指针视为引用有效对象。这导致了不确定的行为。
答案 1 :(得分:2)
因为你正在做的是未定义的行为。有时它似乎有效。这并不意味着你应该这样做: - )
最可能的解释是如何初始化变量。当堆栈指针递减时,自动变量(在堆栈上)将获得堆栈上发生的任何垃圾。
函数外部的变量(如第二种情况)总是初始化为零(指针类型的空指针)。
这是你们两种情况之间的基本区别,但正如我所说,第一种情况纯属偶然。
答案 2 :(得分:1)
当声明全局指针时,它将被初始化为零,因此生成的地址将是您的系统可能读取或不可读的小数字。
声明自动指针时,其初始值可能更有趣。在这种情况下,无论运行时库在调用main()之前在堆栈上的那个点上留下什么,或者可能是编译器生成的堆栈帧设置代码中的剩余值。它有可能是一个保存的堆栈指针或帧指针,如果与小偏移一起使用,它是一个有效的指针。
所以无论如何,未初始化的指针确实有一些东西,一个值导致错误,而另一个值,现在,在你的系统上,没有。
那是,因为分段错误是操作系统的一种机制,而不是C语言。
故障是一种基于块的机制,可以为自己和其他程序分配一定数量的页面 - 每个页面都有几个K--它可以保护自己和其他程序的页面,同时允许程序自由统治。您必须偏离块上下文或尝试编写只读页面(即使您的页面)以生成错误。简单地打破语言规则并不一定足够。操作系统很高兴让你的程序行为不端,并且由于它的狂野引用而行为奇怪,只要它只读取和写入(或clobbers)本身。