过了几天,小明又找到博主,问之前计算器程序中的NULL指针是什么,虽然杰哥讲过,但没怎么听懂。
既然这样,我们就只好为小明再开一篇文章,探究以下NULL指针。
什么NULL指针?
以下选自某度某科
C语言的NULL指针是什么?
其实C语言的NULL指针和某度某科所说的,是大同小异的,区别很小的,NULL就是一个指向了空值,但是注意,NULL不是直接定义成了一个常量0,而是(void *)0,这是因为任何类型的指针变量赋值NULL时都能够赋值0,我们来看一下定义就明白了
NULL的定义(VS2022)
#define NULL ((void *)0)
这样定义的好处是假设我有一个字符型指针ch,我们需要让他指向内存地址为0的地址时,就可以为他赋值NULL指针,在假设,我们定义一个整形指针变量p,我们也需要让他指向内存地址为0的地址,那么如果NULL单纯是常量0的话,就不能完美让字符型指针ch接收,依次类推,所以,为了兼容所有类型的变量,这里就引入了万能指针的概念,即(void *)指针。
这时候小明就又有疑问了,什么是万能指针(void *)?
那么有关这部分内容我也会出单独一篇文章来阐述,这里篇幅有限,不过多解释。
虽然小明没得到答案,但还是认为吧NULL指针给搞明白比较好,于是问博主能不能以代码案例来讲解
当然可以,案例1
我们有以下代码
#define _crt_secure_no_warnings 1
#include<stdio.h>
void test()
{
printf("Hello world!\n");
}
int main()
{
char a = 'a';
char* ch;
ch = &a;
ch = NULL;
printf("%c\n", ch);
}
这段代码平平无奇,但却能很好的说明,为什么NULL要定义为(void *)
首先,我们打开VS2022,写下以上代码,按“F10”进入VS2022的调试模式,按,F10一直到如图所示
让左侧小箭头指向ch = NULL;这行代码,因为,此时我们检查以下此时ch指向a时的地址是多少。
然后,我们找到VS2022菜单栏中的“调试->窗口->内存->内存1”,如图所示
即可查看每个变量的实时地址,以上操作无误,应是下图所示
然后,我们在“地址”搜索栏中输入“ch”,按回车键,得道此时ch的地址,如下图所示
我们可以发现,此时的ch的指向0x000000B24A0FF620,即a变量的地址。
记录数据,以方便我们一会与NULL指针作比较
接下里,我们继续按“F10”,一直到如图所示
注意:不要按过头了,导致调试结束,从而退出程序,这时候就无法使用内存功能,因为只有在调试模式下才能使用内存模式
重复找内存功能的操作,打开内存1
这次,继续在“地址”搜索栏中输入“ch”,按回车键,得到此时的NULL指针,如图所示
此时,我们居然发现,ch指向0地址,即常量0的地址,若ch为int类型,最终结果也是如此,所以,这也是为什么吧NULL定义为(void *)。
这时候,问题超多的小明又问了一个问题
那NULL指针可以解引用吗?
不可以!!!
因为NULL指针的地址时0x0000000000000000,这也是操作系统的存放0的地址,为了保护系统,所以,NULL指针只可以被指向,而不可以解引用!