ARM_C高级学习笔记(十一)void类型的本质与NULL

(一)void类型的本质

1.C语言属强类型语言

  1. 编程语言分2种:强类型语言和弱类型语言。 强类型语言中所有的变量都有自己固定的类型,这个类型有固定的内存占用,有固定的解析方法;弱类型语言中没有类型的概念,所有变量全都是一个类型(一般都是字符串的),程序在用的时候再根据需要来处理变量。
  2. C语言就是典型的强类型语言,C语言中所有的变量都有明确的类型。因为C语言中的一个变量都要对应内存中的一段内存,编译器需要这个变量的类型来确定这个变量占用内存的字节数和这一段内存的解析方法。

2.数据类型的本质含义

  1. 数据类型的本质就决定变量的内存占用数,和内存的解析方法。
  2. 所以得出结论:c语言中变量必须有确定的数据类型,如果一个变量没有确定的类型(就是所谓的无类型)会导致编译器无法给这个变量分配内存,也无法解析这个变量对应的内存。因此得出结论不可能有没有类型的变量。
  3. 但是C语言中可以有没有类型的内存。 在内存还没有和具体的变量相绑定之前,内存就可以没有类型。实际上纯粹的内存就是没有类型的,内存只是因为和具体的变量相关联后才有了确定的类型(其实内存自己本身是不知道的,而编译器知道,我们程序在使用这个内存时知道类型所以会按照类型的含义去进行内存的读和写)。

3.void类型的本质

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

4.为什么需要void类型

  1. 什么情况下需要void类型?其实就是在描述一段还没有具体使用的内存时需要使用void类型。
  2. void的一个典型应用案例就是malloc的返回值。我们知道malloc函数向系统堆管理器申请一段内存给当前程序使用,malloc返回的是一个指针,这个指针指向申请的那段内存。malloc刚申请的这段内存尚未用来存储数据,malloc函数也无法预知这段内存将来被存放什么类型的数据,所以malloc无法返回具体类型的指针,解决方法就是返回一个void *类型,告诉外部我返回的是一段干净的内存空间,尚未确定类型。所以我们在malloc之后可以给这段内存读写任意类型的数据。
  3. void *类型的指针指向的内存是尚未确定类型的,因此我们后续可以使用强制类型转换强行将其转为各种类型。这就是void类型的最终归宿,就是被强制类型转换成一个具体类型。**
  4. void类型使用时一般都是用void *,而不是仅仅使用void。

(二)C语言中的NULL

1.NULL在C/C++中的标准定义

  1. NULL不是C语言关键字,本质上是一个宏定义
  2. NULL的标准定义
#ifdef _cplusplus			// 条件编译
#define NULL 0
#else
#define NULL (void *)0		// 这里对应C语言的情况
#endif
  1. 解释:
  • C++的编译环境中,编译器预先定义了一个宏_cplusplus,程序中可以用条件编译来判断当前的编译环境是C++的还是C的。
  • NULL的本质解析:NULL的本质是0,但是这个0不是当一个数字解析,而是当一个内存地址来解析的,这个0其实是0x00000000,代表内存的0地址。(void *)0这个整体表达式表示一个指针,这个指针变量本身占4字节,地址在哪里取决于指针变量本身,但是这个指针变量的值是0,也就是说这个指针变量指向0地址(实际是0地址开始的一段内存)。
  • 简单来说就是NULL赋值给一个指针后,NULL存储的位置取决于被赋值的指针变量,这个指针变量中存储的是0x00000000H(也就是NULL)这个地址,指向的是0x00000000H这个地址处,并且0x00000000H地址处的值是0。

2.为什么需要NULL

  1. 第一个作用就是让野指针指向0地址处安全。
  2. 第二个作用就是一个特殊标记。
  • 按照标准的指针使用步骤是:
int *p = NULL;		// 定义p时立即初始化为NULL
p = xx;
if (NULL != p)      // 在确认p不等于NULL的情况下才去解引用p
{
	*p = xxx; 				
}
p = NULL;			// 用完之后p再次等于NULL
  • 注意:一般比较一个指针和NULL是否相等不写成if (p == NULL),而写成if (NULL == p)。
  • 原因:
    1. 第一种写法中如果不小心把==写成了=,则编译器不会报错,但是程序的意思完全不一样了;(=的话,意思就是NULL赋值给p,不会报错,而if 中的值就是0,条件会永远是不会成立,出错更难查找错误的来源 )
    2. 而第二种写法如果不小心把==写成了=则编译器会发现并报错。(=的话,意思就是p的值赋给一个常量,显然一定会出错)
    3. 总结就是如果代码出错,第二种写法能帮助你查错。

3.注意不要混用NULL与’\0’

  1. ‘\0’ 和 ‘0’ 和 0 和 NULL几个区分开。
  2. '\0’是一个转义字符,他对应的ASCII编码值是0,本质就是0
  3. '0’是一个字符,他对应的ASCII编码值是48,本质是48
  4. 0是一个数字,他就是0,本质就是0
  5. NULL是一个表达式,是强制类型转换为void *类型的0,本质是0.
  6. 总结:
  • ’\0’用法是C语言字符串的结尾标志,一般用来比较字符串中的字符以判断字符串有没有到头;
  • ’0’是字符0,对应0这个字符的ASCII编码,一般用来获取0的ASCII码值;
  • 0是数字,一般用来比较一个int类型的数字是否等于0;
  • NULL是一个表达式,一般用来比较指针是否是一个野指针。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值