C语言里面的void类型本质和NULL

C语言里面的void类型本质和NULL

void类型本质

编程语言类型:
(1)编程语言分两种:强类型语言和弱类型语言(比如PHP…n它就是弱类型语言);强类型语言中所有的变量都有自己固定的类型,这个类型有固定的内存占用,有固定的解析方法;而弱类型语言中没有类型的概念,所有变量全都是一个类型(一般都是字符串的),程序在用的时候再根据需要来处理变量。

(2)c语言就是典型的强类型语言,c语言中所有的变量都有明确的类型;因为c语言中的一个变量都要对应内存中的一段内存,编译器需要这个变量的类型来确定这个变量占用内存的字节数和这一段内存的解析方法。

数据类型的本质含义:
(1)数据类型的本质就决定变量的内存占用数,和内存的解析方法。

(2)所以得出结论:c语言中变量必须有确定的数据类型,如果一个变量没有确定的类型(就是所谓的无类型)会导致编译器无法给这个变量分配内存,也无法解析这个变量对应的内存,因此得出结论不可能有没有类型的变量。

(3)但是c语言中可以有没有类型的内存;在内存还没有和具体的变量相绑定之前,内存就可以没有类型。实际上纯粹的内存就是没有类型的,内存只是因为和具体的变量相关联后才有了确定的类型(其实内存自己本身是不知道的,但是我们编译器知道,我们程序在使用这个内存时知道所以会按照类型的含义去进行内存的读和写)。

void类型的本质:
(1)void类型的正确的含义是:不知道类型,不确定类型,还没确定类型。

(2)比如说:void a;它定义了一个void类型的变量,含义就是说a是一个变量,而且a肯定有确定的类型,只是目前我还不知道a的类型,还不确定,所以标记为void。

为什么需要void类型:
(1)什么情况下需要void类型呢?其实就是在描述一段还没有具体使用的内存时需要使用类
型。

(2)void的一个典型应用,想必大多数读者都看到过,就是malloc的返回值;我们知道malloc向系统堆管理器申请一段内存给当前程序使用,malloc返回的是一个指针,这个指针指向申请的那段内存。malloc刚申请的这段内存尚未用来存储数据,malloc函数也无法预知这段内存将来被存放什么类型的数据,所以malloc无法返回具体类型的指针,解决方法就是返回一个void *类型,告诉外部我返回的是一段干净的内存空间,尚未确定类型。所以我们在这个malloc函数之后可以给这段内存读写任意类型的数据。下面是malloc函数的原型:

   #include <stdlib.h>

   void *malloc(size_t size);

(3)void *类型的指针指向的内存是尚未确定类型的,因此我们后续可以使用强制类型转换强行将其转换为各种类型;这就是void类型的最终归宿,就是被强制类型转换成一个具体类型。

(4)void 类型使用时一般都是用void *,而不是仅仅使用void。

NULL

NULL在C/C++中的标准定义:
(1)NULL不是C语言关键字,本质上是一个宏定义。
(2)NULL的标准定义:

  #ifdef _cplusplus            // 条件编译
   #define NULL 0
   #else
   #define NULL (void *)0        // 这里对应C语言的情况
   #endif

解释:C++的编译环境中,编译器预先定义了一个宏_cplusplus,程序中可以用条件编译来判断当前的编译环境是C++的还是C的。NULL的本质解析:NULL的本质是0,但是这个0不是当一个数字解析,而是当一个内存地址来解析的,这个0其实是0x00000000,代表内存的0地址。(void *)0这个整体表达式表示一个指针,这个指针变量本身占4字节,地址在哪里取决于指针变量本身,但是这个指针变量的值是0,也就是说这个指针变量指向0地址(实际是0地址开始的一段内存)。

从指针角度理解NULL的本质:
(1)int *p; p是一个函数内的局部变量,则p的值是随机的,也就是说p是一个野指针。

(2)int *p = NULL; p是一个局部变量,分配在栈上的地址是由编译器决定的,我们不必关心,但是p的值是(void *)0,实际就是0,意思是指针p指向内存的0地址处。这时候p就不是野指针了。

(3)为什么要让一个野指针指向内存地址0处?主要是因为在大部分的CPU中,内存的0地址处都不是可以随便访问的(一般都是操作系统严密管控区域,所以应用程序不能随便访问)。所以野指针指向了这个区域可以保证野指针不会造成误伤。如果程序无意识的解引用指向0地址处的野指针则会触发段错误。这样就可以提示你帮助你找到程序中的错误。

为什么需要NULL:
(1)第一个作用就是让野指针指向0地址处安全。
(2)第二个作用就是一个特殊标记。按照标准的指针使用步骤是:

int *p = NULL;        // 定义p时立即初始化为NULL
p = xx;
if (NULL != p)
{
    
    
        *p  // 在确认p不等于NULL的情况下才去解引用p
}
p = NULL    

注意:一般比较一个指针和NULL是否相等不写成if (p == NULL),而写成if (NULL == p)。原因是第一种写法中如果不小心把 == 写成了=,则编译器不会报错,但是程序的意思完全不一样了;而第二种写法如果不小心把 == 写成了 = 则编译器会发现并报错。

注意不要混用NULL与’\0’:
(1)’\0’ 和 ‘0’ 和 0 和 NULL几个区分开。
(2)’\0’是一个转义字符,他对应的ASCII编码值是0,本质就是0。
(3)'0’是一个字符,他对应的ASCII编码值是48,本质是48。
(4)0是一个数字,他就是0,本质就是0。
(4)NULL是一个表达式,是强制类型转换为void *类型的0,本质是0.

总结:’\0’用法是C语言字符串的结尾标志,一般用来比较字符串中的字符以判断字符串有没有到头;'0’是字符0,对应0这个字符的ASCII编码,一般用来获取0的ASCII码值;0是数字,一般用来比较一个int类型的数字是否等于0;NULL是一个表达式,一般用来比较指针是否是一个野指针。

猜你喜欢

转载自blog.csdn.net/weixin_45905650/article/details/108393652
今日推荐