- if else 语法
- 什么是语句
- 什么是表达式
- 基本语法
- 真与假
- bool变量与“零值”进行比较
- float变量与“零值”进行比较
- 指针变量与”零值“进行比较
- else到底与哪个if配对呢?
- if语句后面的分号
C语言中由一个分号;隔开的就是一条语句。
printf("hello world!n");//这是一条语句
1 + 2;//这是另一条语句
什么是表达式
C语言中,用各种操作符把变量连起来,形成有意义的句子,就叫做表达式。(非官方)
操作符:+, -, *, /, %, <, >, =, ==, ......
int a = b + c;//这就是一条表达式基本语法
//demo1
if(表达式)
语句;
//demo2双分支
if(表达式)
语句1;
else
语句2;
//demo3多分支
if(表达式1)
语句1;
else if(表达式2)
语句2;
else
语句3;
//demo4嵌套
if(表达式1){
if(表达式2)
语句1;
else
语句2;
}
else if(表达式3){
...
}
else{
...
}
真与假
bool变量与“零值”进行比较C语言中,0表示假,非0表示真。
切记,假只能是0,而真是0之外的所有数字,比如-1、-2、1、2、1.5、3.4等等等等
首先深入理解bool
C语言有没有bool类型?
c99之前是没有的,也就是c89、c90(主要)没有,大部分的书也是认为没有的。
但是在c99引入了_Bool类型,新增在头文件stdbool.h中,被重新用宏写成了bool,为了保证C/C++的兼容性。
可以看到bool类型的大小是1个字节,其实原因很简单,因为bool类型就是用来表示真和假的,只需要用1个bit就可以了,不过这个问题还是要看编译器的理解。
这是Microsoft自己搞的一套BOOL值,是微软定义的专属类型,其它平台是不支持的。
一个好的代码,一定是跨平台强的,所以不推荐使用微软的BOOL值,事实证明在Linux中(centos 7)中,BOOL会报错
事实证明,bool类型在vs和linux下都是1个字节大小,可编译通过,而BOOL在vs下是4个字节,在Linux下编译不通过,会报错。
以上是C语言c99标准下的bool类型。
而在c89、c90标准下,虽然没有bool类型,但是一般习惯自定义flag
#includeint main() { int flag = 0;//假 习惯用int表示bool,因为0一般认为是整形,所以左值的类型一般也设为整形 !flag//真 return 0; }
在表示真假情况时,我们优先使用c89、c90下的自定义flag,而若非得使用bool类型,推荐使用c99,摒弃微软。
前面说了这么多bool类型,现在正式开始与0比较
先介绍一下if语句的执行顺序
- 先执行括号内的语句,得出结果
- 根据结果来判断真假
- 根据真假来选择分支
#includefloat变量与“零值”进行比较int main() { int flag = 0; //c89、c90 //bool flag = false;//c99 //demo if(flag == 0){//理论上可行,但是这里的flag虽然是int,但是意义上认为是bool,而0是int,所以不建议比较 ... } //demo if(flag == false){//虽然在c99下完全可行,但是在逻辑上麻烦 ... } //demo if(flag){//非常推荐,由于bool本身的意义就表示真假,所以直接用bool判断真假,不需要比较再得出真假 ... } return 0; }
首先说明一点:浮点数的存储和整形的存储(二进制补码)是完全不同的规则!!!
再说明一点:由于float与double仅有精度的区别,而默认的浮点数是double类型,为了简便,这里使用double举例
可以看到,浮点数存储在内存中是有精度的损失的(值可能变大,也可能变小),所以是不能够用浮点数来进行比较的,因为存储在内存中的浮点数的大小和我们想象的大小有可能是不同的。
那么浮点数应该如何比较呢?这里就得用损失精度的方式比较了,也就是规定一个精度,两个数的差在该精度范围内,就认为相等。
#include#include //fabs的头文件 int main() { double d1 = 0.1; double d2 = 0.1000000000000001; if((d1 - d2) < 精度 && (d2 - d1) < -精度){ printf("认为两数相等n"); } //上面写的太冗余,改进成如下 if(fabs(d1 - d2) < 精度){//fabs是浮点数求绝对值 printf("认为俩数相等n"); } return 0; }
但是就有了一个问题,精度从何而来呢?
方法一:自定义,一般用宏定义
方法二:用系统精度(暂时推荐)
#include#include #include #include //使用精度的头文件 //FLT_EPSILON float最小精度 //DBL_EPSILON double最小精度 int main() { double d1 = 1.0; double d2 = 0.9; //demo1 if(fabs((d1 - d2) - 0.1) < DBL_EPSILON){ printf("相等n"); } else{ printf("不相等n"); } //demo2 if(d1 - d2 == 0.1){ printf("相等n"); } else{ printf("不相等n"); } system("pause"); return 0; }
查看一下系统精度的定义
XXX_EPSILON是最小误差,是:XXX_EPSILON+n不等于n的最小的正数。
EPSILON这个单词翻译过来是 ε ε ε的意思,数学上,就是极小的正数 ----来自百度
前面铺垫了这么多,现在正式进入与”零值“比较
#include#include #include #include int main() { double d = 0.00000000000000000001; //demo1 if(d - 0.0 > - DBL_EPSILON && d - 0.0 < DBL_EPSILON){ ... } //demo2 if(d - 0.0 > - DBL_EPSILON && d - 0.0 < DBL_EPSILON){ ... } //demo3 if(fabs(d - 0.0) < DBL_EPSILON){ ... } //demo4 if(fabs(d) < DBL_EPSILON){ ... } //这一看,傻子都知道是demo4最好了 return 0; }
还有一个问题,在其它的书籍或者博客当中,很容易看到在比较的时候它们使用的是<=或者>=而不是使用<或者>,但是我推荐使用<或者>。
个人看法:
XXX_EPSILON是最小误差,是:XXX_EPSILON+n不等于n的最小的正数。
XXX_EPSILON+n不等于n的最小的正数:有很多数字+n都可以不等于n,而XXX_EPSILON是最小的,但是,XXX_EPSILON依旧是引起不等的一员。
换句话说fabs(d) <= DBL_EPSILON(确认d是否是0的逻辑),如果=,就说明=本身,已经能够引起其它和它+、-的数据本身的变化了,这个不符合0的概念。
所以我认为在进行比较的时候不带=
指针变量与”零值“进行比较int* p = NULL; //demo1 if(p == 0) if(p != 0) //不推荐,因为p和0是不同类型的,而且最重要的是当只看见这一句话,没看见上下文时,极易认为p是一个整形 //demo2 if(p) if(!p)//不推荐,因为该写法极易认为p是bool变量 //demo3 if(p == NULL) if(p != NULL)//推荐,但还有更好的写法 //demo4 if(NULL == p) if(NULL != p)//该写法容易检测出是否少写了=
补充:
else到底与哪个if配对呢?对于0、' '、NULL这三者来说,在值上,在内存中是一模一样的,都是0
至于为什么写成这样的原因是:由于操作符两侧的操作数,是同类型的情况下,容易区分变量的类型以及意义
比如p != NULL,可以一眼看出p是个非空指针
c != ' ',可以一眼看出字符c不是' '
可以总结出四个字:就近原则,else默认与距离最近的if语句配对
if语句后面的分号可以看到在if后加了;使得后面的语句无论if判断条件是真还是假,都会输出。
是因为;是语句的结束标志,单独写一个;意味着空语句,上面的写法改成如下会更好理解
大家知道,if后只跟一条语句是可以不写{}的,而这时填写了;就意味着if的内部是空语句。



