小言_互联网的博客

C语言中,指针在什么情况下为NULL(0)?

318人阅读  评论(0)

问题1:

main函数里面的指针什么时候为NULL?

问题2:

自定义函数或在全局里面的指针什么时候为NULL?

问题3:

指针大小是怎么判断的?

问题4:

结构体内的指针在什么情况下为NULL?

——————————————————————————————

//指向结构体的指针Bitree *t

typedef struct Nd{
    int data;
    struct Nd *left;
    struct Nd *right;
}Bst;

PS:指针大小由操作系统决定,32位系统4个字节,64位8个字节

本次实验为32位gcc编译器————————————————————
在main函数中,
Bst *a;
//表示指向一个Bst结构的指针,指针大小为4个字节
//也就是sizeof(a) = 4;sizeof(*a)=12;sizeof(&a)=4

注意:sizeof()的值是编译器给的,而printf(“%p”),是操作系统给的地址值,所以64位的win7下打印的变量地址还是64位二进制,不受32位编译器影响

//在main函数里面的指针
int main(){
Bst *a;
return 0;}
如果进行if(a){ printf("a不是空树!")}
那么,a还是会输出这个printf,因为a是野指针,如下图依次输出
 				&a
 				a
 				*a
 	野指针就是随机数,可见a指向的地址是00000002
 	反之,如果Bst *a=(Bst*)malloc(sizeof(Bst));
 	再判断也会输出a不是空树 	

||同理,对于main里面p,a,b,c,那一个为NULLtypedef struct nod{
    int data;
    struct nod *l;
    struct nod *r;
}BinaryT;
int main () {
    BinaryT *p=0;||这里p等于'\0',NULL都行
    BinaryT *a;
    BinaryT *b=(BinaryT*)malloc(sizeof(BinaryT));
    BinaryT c[2];

实际上,a是个随机数,不确定为不为0,(本次输出a的地址为00000039,若按整型输出则是3*16+9=57)
故a不为空,b,c均不为空。

作为对比,在自定义函数的情形指针的情况
————————————————
经过测试。。。。。。。
与在main函数情形一致

————————————————————————————————————————————————————————————————————

在全局的情况,全局变量和局部变量的在编译时的不同的处理方式,在程序编译的时候全局变量必须用常量进行初始化,也就是说直接在全局变量的内存地址直接存储变量的值;对于局部变量则在编译的时候不需要这样,编译的时候只需要将局部变量的赋值语句编译成机器代码,在程序运行到这里是在进行局部变量的赋值。

若用g++编译器对该程序进行编译,再碰到这里时,编译器会先把全局变量保存到.bss段中,而且默认值为0,但是会在main函数之前添加一条赋值语句,也就是相当于局部变量进行处理了。

Bitree *a;
||a会直接初始化为0
int main(){
	if(a==NULL){
	printf("a=NULL");
	}
}
但是!!! a指向的内存为NULL了,那么结构体a内的指针是不可访问的,强行访问会运行时出错。

最后通牒!!!
在结构体内指针什么时候为NULL?

1——在main里面
情形一:野指针
int main(){
	Bitree *a;
	if(a->left==NULL){
	printf("NULL");
	}
}
结果:想都不用想,运行时报错!!!
一个随机数当地址,再用这个随机地址去找left和right,简直瞎搞
——————————————————————————————————————————————————
情形2: 分配内存情形
int main(){
	Bitree *a=(Bitree*)malloc(sizeof(Bitree));
	if(a->left==NULL){
	printf("NULL");
	}	
}
运用类比法,相当于在main里面又定义了两个野指针,一个叫a->left,一个叫a->right。因此main里的结构体内指针不为空;

2——在自定义函数或全局情形
void isempty(){
	Bitree *a;
	if(a->left==NULL){
	pritnf("null");
	}
}
结果——类似与main函数,照样运行时报错!!!
若已分配内存(Bitree *a=(Bitree*)malloc(sizeof(Bitree));),则有
	a->left和a->right照样是野指针,不为空

————————————————————————————————————————————————————————————————
全局的情形:
case 1
Bitree *a;

访问a,a是等于NULL的,但如果访问a->left,就是对野指针访问,会运行报错!!!

case 2
Bitree a;
Bitree b[2];

int main(){
	if(a->left==NULL){
	输出NULL
	}
	if(&b[0]->left==NULL){
	输出NULL
	}
}
注意:这两个都是NULL,因为类比如在全局定义了这两个指针,都会自动初始化

总结:访问指针的时候虚拟地址就会向物理地址映射,此时页表会去查看这块地址,而这块地址被存放在只读区,当页表发现地址是无效的,就会反映给操作系统,操作系统就会发送11号信号终止此进程,所以进程异常终止程序崩溃——————————————————————————每次定义一个指针要记得初始化为NULL,否则当做已分配了内存的指针使用!!!


转载:https://blog.csdn.net/weixin_42557786/article/details/102485899
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场