指向类的空指针问题

指向类的空指针异常调用,偶尔能正常运行,系统并未抛出调用栈异常

class A
{
    public:
        void func1()
        {
            printf("call the func1 by 0x%x\n",this);
        };

        int number;
};

int main()
{
    A *pNULL = NULL;

    A TestClass;

    pNULL->func1();  

    TestClass.func1();

    printf("pNULL address 0x%x\n",pNULL);
 
    return 0;
}

上面这段代码运行的时候,会输出

call the func1 by 0x0
call the func1 by 0x5f8dcc2f
pNULL address 0x0

引起上述问题的,其实是类的this指针问题

  1. pNULL作为一个指针,并未指向任何类对象的时候,其持有的this指针为空,但是func1函数在代码段,编译器却认为pNULL->func1是在作func1函数调用,此时等同于外部调用一个类的static 类型的函数
  2. 由于this指针为空,所以如果pNULL不指向任何对象的情况下,如果调用p->number,试图打印一个数据,就会出现调用栈crash,因为number存储在数据段,pNULL必须指向一个实例化的对象才可以找到number的地址,其实是this->number。
call the func1 by 0x0
call the func1 by 0x17e5a75c
pNULL address 0x0
段错误 (核心已转储)

下面解析编译器生成的a.out文件

    60: 00000000000006aa   143 FUNC    GLOBAL DEFAULT   14 main
    61: 000000000000073a    39 FUNC    WEAK   DEFAULT   14 _ZN1A5func1Ev//类的func1函数
    62: 0000000000000762    21 FUNC    WEAK   DEFAULT   14 _ZN1AC1Ev
    63: 0000000000201010     0 OBJECT  GLOBAL HIDDEN    23 __TMC_END__
    64: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
    65: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@@GLIBC_2.2
    66: 0000000000000548     0 FUNC    GLOBAL DEFAULT   11 _init

a.out的符号表印证了我们的结论,finc1在程序加载阶段分配了地址空间(相对于主进程偏移0x000000000000073a),所以调用pNULL->func1并未出错。

需要注意两点

  1. 如果func1函数中调用了number这个成员,仍然会发生段错误
  2. 以这种方式调用类内部的函数,并非推荐的方式,所以我们采取预防措施
        void func1()
        {
            if(NULL == this)
            {
                printf("Error,Call by NULL point\n");
            }
            else
            {
                printf("call the func1 by 0x%x\n",this);
            }
        };

运行修改后的程序会有如下提示:

Error,Call by NULL point

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值