C/C++的空指针,NULL,0和nullptr

一、NULL与0

在C和C++中,NULL和0都可以使用。

C通常使用NULL,C++通常使用0

#include <stdio.h>
int main(void) {
    int *p=NULL;
    int *q=0;
    printf("%d %d",p,q);
    //0 0
    return 0;
}
#include <iostream>
using namespace std;
int main() {
    int *p=NULL;
    int *q=0;
    cout<<p<<" "<<q<<endl;
    //0 0
    return 0;
}

问:NULL到底是什么?

答:NULL是一个宏。

 

问:它的值是多少?

答:C/C++标准规定:它的值是一个空指针常量(null pointer constant),由实现定义。

 

NULL宏是如何定义的?

答:以gcc或clang编译器为例,NULL的定义大致如下(稍有简化):

#if defined(__cplusplus)
# define NULL 0              // C++中使用0作为NULL的值
#else
# define NULL ((void *)0)    // C中使用((void *)0)作为NULL的值
#endif

问:什么样的值才能称之为空指针常量?

答:C语言中常数0和(void*)0都是空指针常量;C++中(暂且忽略C++11)常数0是,而(void*)0 不是

 

问:为什么C中(void*)0是空指针常量,而C++中不是?

答:因为C语言中任何类型的指针都可以(隐式地)转换为void*型,反过来也行。而C++中void*型不能隐式地转换为别的类型指针(例如:int*p = (void*)0;使用C++编译器编译会报错) 

二、nullptr

nullptr是C++独有的,nullptr还是C++的一个关键字。

C++引入nullptr是为了解决NULL为0,判断其是指针还是int类型的歧义

#include <stddef.h>
void foo(int)   {}   // #1
void foo(char*) {}   // #2
int main() {
    foo(NULL); 
    //C++会调用#1,认为NULL是0,是int
}
void foo(int)   {}   // #1
void foo(char*) {}   // #2
int main() {
    foo(nullptr);
    //它会毫无异议地调用#2
}

三、NULL的例题

在C/C++中,NULL的地址均不可访问,也就是不能取出NULL代表的地址上的值

int *p=NULL;
int a=*p;
//error

一个访问NULL地址出错的考题:

解析:main()里的node调用fun()函数,传入参数node,fun()里的node其实是传递指针,int *node=node,前者node是fun()作用域里的指针,后者是main()作用域里的指针。fun()里改变fun()作用域的node的指向,可以输出100。但回到main()时,因为它改变的是指针的指向,而不是指针的值(指针的传递知识:https://blog.csdn.net/sandalphon4869/article/details/88758680),所以改变不可以被传递,即fun()里的fun()作用域的node由于是局部变量被释放,main()里的main()作用域的node其实没有任何改变,还是指向NULL,访问出错。

#include <stdio.h>
void fun(int *node)
{
    int N=100;
    node=&N;
    printf("%d\n",*node);
    //100
}
int main()
{
    int *node=NULL;
    fun(node);
    printf("%d\n",*node);
    //error
    return 0;

}

改变传递的指针的值解决错误: 

解析:改变传递的指针的指向不可以传递改变,而改变传递的指针的值则可以传递改变。

#include <stdio.h>
void fun(int *&node)
{
    int N=100;
    node=&N;
}
int main()
{
    int *node=NULL;
    fun(node);
    printf("%d\n",*node);
    //100 
    return 0;
}

 

使用二级指针解决错误:

解析:int **node是一个二级指针,fun(&node)传递的是node的地址。fun()里**node是&node,即node本身变量名存储的地址,*node是node的指向的地址,让node指向了100,因为*node是改变指针的值,所以改变可以被传递。

#include <stdio.h>
void fun(int **node)
{
    int N=100;
    *node=&N;
}
int main()
{
    int *node=NULL;
    fun(&node);
    printf("%d\n",*node);
    //100
    return 0;
}

使用引用操作符:

解析:引用改变的被传递的参数

#include <stdio.h>
void fun(int *&node)
{
    int N=100;
    node=&N;
}
int main()
{
    int *node=NULL;
    fun(node);
    printf("%d\n",*node);
    //100 
    return 0;
}

参考:

https://www.cnblogs.com/malecrab/p/5569707.html

http://www.cnblogs.com/qingergege/p/6494751.html

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值