码迷,mamicode.com
首页 > 其他好文 > 详细

空指针(NULL)那些事?

时间:2016-08-12 20:11:12      阅读:93      评论:0      收藏:0      [点我收藏+]

标签:

我们常常被告知,使用指针前需要判断是否为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。综上,使用空指针并不一定会发生问题,关键是怎么用。遇到问题得理性分析,不要想当然。纸上学来终觉浅,绝知此事要躬行。

关于程序设计基石与实践更多讨论与交流,敬请关注本博客和新浪微博songzi_tea

空指针(NULL)那些事?

标签:

原文地址:http://blog.csdn.net/songzitea/article/details/52177279

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!