空指针(NULL)那些事?
Posted 松子茶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了空指针(NULL)那些事?相关的知识,希望对你有一定的参考价值。
我们常常被告知,使用指针前需要判断是否为NULL;如果是NULL而你去使用它就会出问题。真相果真是这样吗?
首先,看看这段程序执行后,有问题吗?
#include<iostream>
#include<cstdlib>
using namespace std;
class Test1
private:
int a;
public:
void f()
cout<<"Test1: Core or not ? "<<endl;
;
int main()
Test1 *p = NULL;
p->f();//会core吗?会出大事吗?
return 0;
这里,p是一个空指针,通过这个空指针,我们访问了函数f。没core,没问题,成功输出了 Test1: Core or not ?
发生了什么事?空指针也能用?
如果我们把f稍作修改,程序其他地方不做任何变动:
void f()
cout<<"Test1: Core or not ? "<<a<<endl;//access a
那么程序运行后分分钟core掉了。
有没有感觉了?嗯,相信有了。我们继续往下看:
#include<iostream>
#include<cstdlib>
using namespace std;
static int global = 1;
class Test2
private:
int a;
public:
void f()
cout<<"Test1: Core or not ? "<<global<<endl;//access global
;
int main()
Test2 *p = NULL;
p->f();//会core吗?会出大事吗?
return 0;
也没问题。
嗯,你可能已经知道了真相。通过空指针访问东西,只要那个东西是确实存在的,就不会有问题。怎么理解“确实存在”?它是一个实体,看得见,摸得着。这得说到C++程序中对象的内存布局。
在C++中,成员函数、静态变量是独立于对象存放的;而普通的数据成员是和对象相关的。
Test1 obj1;
Test1 obj2;
obj1和obj2是共用函数f的,函数f对obj1和obj2是相同的,内存中只有一份实体;而obj1和obj2有自己的实体a。
然而,注意到Test1 *p = NULL;仅仅是声明式,而非定义式。这时候,没有定义任何的对象出来,通过p如何访问a呢?哪来的a呢?a在内存里并不存在。因此,访问a必定core。
而函数f呢?它是独立于对象存放的,自然没问题。一般说来,f位于程序的代码段,而全局变量一般位于BSS段或者DATA段(这个比较复杂,和该全局变量是否初始化以及初始化为0还是非0有关)。而当我们定义对象时,才为该对象分配内存,才有数据成员a的存在:
#include<iostream>
#include<cstdlib>
using namespace std;
static int global1 = 1; //DATA段
static int global2; //BSS段
class Test3
private:
int a;
public:
void f()
cout<<"Test1: Core or not ? "<<endl;
;
Test3 obj3; //DATA段 (调用默认构造函数进行初始化)
int main()
Test3 obj1; //stack段。定义obj1,这时候自然为a分配内存了
Test3 *obj2 = new Test3();//heap段,也为a分配内存了。
Test3 *p;//只是声明,没有定义。没有对象,也没有a。
return 0;
我们知道,C++中,类的非静态成员函数会被编译器改写:
void Test::f()
被改写为类似于void Test__f(Test *const this)
而
Test *p = NULL;
p->f();
将被编译器改写为
Test *p = NULL;
Test__f(p);
因此Test::f中带有一个值为NULL的this指针(p),如果通过这个空指针p读写数据,就会崩溃。否则,安然无事。那么,this指针可以操纵哪些东西呢?哦,类的非静态数据成员。而类的静态数据成员,全局变量等,是不会通过this指针访问的,因此,上例中,访问a崩溃,访问global则安全。
最后,我们看一个问题。
class Test4
public:
void f()
cout<<&(*this)<<endl; // 有问题吗?
;
int main()
Test4 *p = NULL;
p->f();
return 0;
没问题。&(*this)就是this,值和p相等。因此上面会输出0。综上,使用空指针并不一定会发生问题,关键是怎么用。遇到问题得理性分析,不要想当然。纸上学来终觉浅,绝知此事要躬行。
以上是关于空指针(NULL)那些事?的主要内容,如果未能解决你的问题,请参考以下文章
动态内存管理那些事:malloccallocreallocfree