目录
语句和表达式的概念
if语句的多种语法结构
注释的便捷方法(环境vs)
if语句执行的过程
逻辑与&& 逻辑或|| 运算关系的顺序
else的匹配原则
C语言有没有布尔类型
C99标准
sizeof(bool)的值为多少?
_Bool原码
BOOL、TRUE、FALSE
sizeof(BOOL)的值为多少?
BOOL与bool的区别
“零值”的比较
1.bool变量与“零值”比较
2.float、double变量与“零值”比较 - (这里以double为例)
3.指针变量与"零值"比较
语句和表达式的概念
C语言中由一个分号;隔开的就是一条语句
printf("Hello!\n");
1+2;
C语言中,用各种操作符把变量连接起来,形成有意义的式子,就叫做表达式
1+2
if语句的多种语法结构
1.if语句
if(表达式) 语句;
2.if - else语句
if(表达式) 语句1; else 语句2;
3.if - else if - else语句
//多分支 if(表达式1) 语句1; else if(表达式2) 语句2; else 语句3;
注释的便捷方法(环境vs)
1.先按ctrl + k,再按ctrl + c
2.采用if(0)注释 -- 不推荐
同时我们还可以从上面得出一个结论:非0为真,0为假
if语句执行的过程
#include<stdio.h>
int main()
{
int flag = 1;
if (flag == 1)
printf("hello world\n");
return 0;
}
#include<stdio.h>
int isEmpty()
{
printf("某种数据结构是否为空!\n");
return 1;
}
int main()
{
if ((isEmpty()) == 1)
printf("yes\n");
return 0;
}
1.先执行()中的表达式或者函数,得到真假结果
2.条件 判定功能
3.进行 分支功能
逻辑与&& 逻辑或|| 运算关系的顺序
总结:从左到右。
else的匹配原则
我们来看看下面的代码运行结果是啥?
相信我们很多人看到这里,由于x等于0,而不等于10,所以来到else打印hello yesterday!但其结果其实是什么也不打印,这里是因为else是与离他最近的if匹配的,由于x不等于10,所以里面的if-else语句没有执行,所以也就不会打印啦。我们来验证一下,在与if(x==0)后面加一个与之匹配的else语句。
总结:以后写if_else时,建议带上{ },这样不仅不容易出粗,而且代码的可观性也比较好。
再来看一个代码
#include<stdio.h>
int main()
{
int flag = 0;
if (flag == 1);
{
printf("why you can see me?\n");
}
return 0;
}
C语言有没有布尔类型
bool 类型只有两个值:true 和 false。上面我们写的if()语句中非0为真,0为假,是因为C语言没有提供bool类型,而且我们也知道if()只有是条件表达式为真我们才执行,所以我们一般都写if(1),而不写if(true)。
当我们写if(true)或者定义bool类型的变量时,编译器也提示出来为定义的标识符,说明编译器不认识它们,证明C没有提供bool类型。
C99标准
但其实C语言时是有bool类型的,只不过我们编译器目前采用的是C89 or C90的标准,而在C99中引入了_Bool类型,它是一个类型,不过在新增头文件stdbool.h中,被重新用宏写成了bool,为了保证C/C++兼容性。引入头文件stdbool.h,程序就没有错误了。
sizeof(bool)的值为多少?
在 C 语言标准中,bool 类型是由 stdbool.h 头文件引入的。bool 通常被定义为枚举类型,其中 false 的值为 0,true 的值为 1。因此,sizeof(bool) 的值在 C 语言标准中并没有规定。 一般情况下,sizeof(bool) 的大小应该是 1 字节,因为 bool 类型只需要存储一个二进制位(0 或 1)来表示 true 或 false。但是,具体的实现方式可能会因编译器和操作系统的不同而有所不同。
_Bool原码
BOOL、TRUE、FALSE
#include<stdio.h>
#include<windows.h>
int main()
{
BOOL x = TRUE;
x = FALSE;
}
这里的BOOL实际上是一个重命名 - typedef int BOOL; 这里我们可以证明一下
sizeof(BOOL)的值为多少?
BOOL与bool的区别
我将BOOL转到定义后,发现开头有这么一串注释,这样他们的区别就很明显了。
由上面的图片可以得到,BOOL是微软帮我们设计的,我们只能在微软的对应的开发工具才能使用BOOL,BOOL是微软的标准(不推荐,可移植性较差),而bool是通用的。
总结:
1.优先使用C90,就是我们之前用的非0为真,0为假。
2.一定要使用bool类型,优先使用bool,不推荐BOOL(可移植性较差)。
“零值”的比较
1.bool变量与“零值”比较
#include <stdbool.h>
#include <windows.h>
int main()
{
int pass = 0; //0表示假,C90,我们习惯用int表示bool
//bool pass = false; //C99写法一:
if (pass == 0) { //理论上可行,但此时的pass是应该被当做bool看待的,== 用来进行整数比较,不推荐
//TODO
}写法二:
if (pass == false) { //不推荐,尽管在C99中也可行
//TODO
}写法三:
//1.先执行()中的表达式,得到真假结果(true or false,逻辑结果) - 而这里的pass本身就是逻辑结果
//2.条件 判定功能
//3.进行 分支功能
if (pass) { //推荐 - 直挂的反应出来了,flag是"bool"
//TODO
}
system("pause");
return 0;
}
结论:bool类型,直接判定,不用操作符进行和特定值比较。
2.float、double变量与“零值”比较 - (这里以double为例)
我们接下来看这个代码,后面的注释是我们预测的输出。
#include <stdio.h>
int main()
{
double x = 1.0;
double y = 0.1;
printf("%.50f\n", x - 0.9);//0.1
printf("%.50f\n", y);//0.1
if ((x - 0.9) == y) {
printf("you can see me!\n");//输出you can see me!
}
else {
printf("you can not see me!\n");
}
return 0;
}
但是当我们运行这个代码的时候,结果令我们大失所望呀。
为什么呢?
这里我们将数值3.1打印50的精度,结果出现了一大堆意外的数字。
这是因为浮点数在内存中存储,并不想我们想的,是完整存储的,在十进制转化成为二进制,是有可能有精度损失的。 注意这里的损失,不是一味的减少了,还有可能增多。浮点数本身存储的时候,在计算不尽的时候,会“四舍五入”或者其他策略。所以上面才会输出you can not see me!
那么两个浮点数该如何比较呢? - 应该进行范围精度比较
在 C 语言中,由于浮点数的精度问题,不能直接使用等于号(==)判断两个浮点数是否相等。通常使用以下方法来比较两个浮点数的大小关系:
1.定义一个比较精度值 EPS,例如 1e-6,代表可接受的最小误差范围;
2.判断两个数之差(绝对值)是否小于等于精度值 EPS;
了解fabs函数
在 C 语言中,fabs 函数属于 math.h 头文件,因此在使用该函数前需要先包含 math.h 头文件。该函数返回一个 double 类型的值,可以用于计算浮点数的绝对值。
当我们去改进程序后,我么发现就可以比较两个浮点数了。
两个精度定义
我们发现我们定义1e-6(也就是0.000001),可能有时候设置的误差范围比较大导致判断错误,那么我们一个具体怎么设置这个值呢,那么此时C语言就提供了两个精度:
#include //使用下面两个精度,需要包含该头文件
DBL_EPSILON //double 最小精度
FLT_EPSILON //float 最小精度
转到定义后
XXX_EPSILON是最小误差,是:XXX_EPSILON+n不等于n的最小的正数。 EPSILON这个单词翻译过来是'ε'的意思,数学上,就是极小的正数 。
请问我们这样写会有问题嘛? - 问题是:要不要相等
XXX_EPSILON是最小误差,是:XXX_EPSILON+n不等于n的最小的正数。 XXX_EPSILON+n不等于n的最小的正数: 有很多数字+n都可以不等于n,但是XXX_EPSILON是最小的,但是, XXX_EPSILON依旧是引起不等的一员。 换句话说:fabs(x) <= DBL_EPSILON(确认x是否是0的逻辑),如果=,就说明x本身,已经能够引起其他和他+和-的数据本身的变化了,这个不符合0的概念。
现在我们来回归主题:float、double变量与“零值”比较
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <windows.h>
int main()
{
double x = 0.00000000000000000000001;
//if (fabs(x-0.0) < DBL_EPSILON){ //写法1
//if (fabs(x) < DBL_EPSILON){ //写法2
if (x > -DBL_EPSILON && x < DBL_EPSILON) { //写法3
printf("you can see me!\n");
}
else {
printf("you can not see me!\n");
}
system("pause");
return 0;
}
总结:在 C 语言中,由于浮点数在计算机中存储的方式和精度限制的原因,不能直接使用等于号来判断两个浮点数是否相等,也不能直接判断浮点数是否等于 0.0,如果我们要比较,就需要形成一个极小的精度EPS,然后将这个数与0.0的差值的绝对值进行比较,这样我们才能判断float、double变量与“零值”的比较。
3.指针变量与"零值"比较
常识补充:对NULL, '\0', 0的整体理解
1.NULL、'\0'和0是C语言中常用的三个表示“0”的值。
2.它们的类型是不同的。
1. NULL:通常被定义为一个值为0的宏,表示指针不指向任何有效的内存地址。在大多数情况下,一个指针的值为NULL表示其未被初始化或者指向了无效的内存地址,NULL是'0'被强制转换成指针类型的值。
2. '\0':是一个字符常量,表示字符数组的结束符。在C语言中,字符串是由字符数组组成的,每个字符串的结尾都必须以'\0'字符作为结束标志,告诉程序字符串的长度。
3. 0:是整数常量的一种,表示数值0。在C语言中,用0来表示逻辑假,非0的值表示逻辑真。
4.强制类型转化的理解
总结:强制类型转化没有改变内存中的数据,只是改变了它的类型。
接下来看下面的写法哪个好
#include<stdio.h>
int main()
{
int* p = NULL;
if (p == 0)
{
//写法一
}
if (p)
{
//写法二
}
if (NULL == p)
{
//写法三
}
return 0;
}
写法一:尽管NULL的值和0一样,但是意义不同,写法一容易让人认为p是整形变量
写法二:让人认为p是bool变量
写法三:很容易让人认识到这是指针相关的判断