接着上节课的最后,上节课的最后我们讲了浮点型数据和0的比较,接下来,我们写一串代码来实现这个步骤
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<math.h>
#include<float.h>
int main()
{
double a = 0.00000001;
if (fabs(a) < DBL_EPSILON)
{
printf("you can see it a=0 \n");
}
else
{
printf("obbs\n");
}
return 0;
}
其中,头文件#include<math.h>对应的是fabs,fabs是求浮点型数据的绝对值,头文件#include<float.h>对应的是DBL_EPSILON,DBL_EPSILON的意思是系统对应的double类型的精度,我们进行编译
这里没有执行if语句的原因是:double类型的a不够小,我们进行调整一下
#include<stdio.h>
#include<math.h>
#include<float.h>
int main()
{
double a = 0.000000000000000000000000001;
if (fabs(a) < DBL_EPSILON)
{
printf("you can see it a=0 \n");
}
else
{
printf("obbs\n");
}
return 0;
}
我们进行编译,
接下来,我们来分析一个案例
#include<stdio.h>
#include<math.h>
#include<float.h>
int main()
{
double x = 0.000000000000000000000000001;
if (x > -DBL_EPSILON&&x < DBL_EPSILON)
{
printf("you can see it a=0 \n");
}
else
{
printf("obbs\n");
}
return 0;
}
这串代码和上一串代码不同的就是判断条件,这里我们要思考的问题是:判断条件x > -DBL_EPSILON&&x < DBL_EPSILON中的大于和小于能改成大于等于或小于等于吗?
答:不能,解释如下
首先,我们看系统给的精度DBL_EPSILON的定义
总结就是:DBL_EPSILON是最小的值,最小的能让1.0和它的和的结果大于1.0的值
所以假如我们的x等于了这个最小的值,0的定义是任何数加0的结果是它本身,而这个最小的值和1.0相加的结果大于1.0的值,所以这个最小的值就不是0,所以x就不是0,所以条件错误。
总结:不建议写等号
0和‘\0’和NULL的区别
答:首先,数值上相等
int main()
{
printf("%d\n", 0);
printf("%d\n", '\0');
printf("%d\n", NULL);
return 0;
}
编译结果
int a = 0;
char*p = NULL;
=号是操作符,操作符两端的类型必须相等,比如int a;double b;a+b,+是操作符,操作符两端的类型不同,所以产生隐式转化
这里也是相同,p是指针,所以初始化就不要把等号右端换成0,假设我们换成0,我们进行运行
int main()
{
int a = 0;
char*p = 0;
}
可以发现,代码并没有报错:不同的编译器下编译的结果不同
NULL是什么?
我们转到他的定义看看
我们可以发现,NULL的意思就是把0强制类型转化为指针所对应的结果,这里引出了强制类型转化
‘\0’是什么?
答:假如我们不带\
int main()
{
printf("%d\n", 0);
printf("%d\n", '0');
printf("%d\n", NULL);
return 0;
}
我们进行编译
我们可以发现。‘0’对应的结果是48,为什么呢?
答:这里的0是字符0,因为字符0对应的ascii码值为48,所以打印的结果是48
强制类型转化
要理解强制类型转化,首先要理解真正的转化
真正的转化:“123456”--->整型123456,因为第一个是字符串,字符串加上\0一共七个字符,占七个字节,而整型123456无论如何都占4个字节,所以这两个在内存中的存储形式一定不同,所以真正的转化是改变数据在内存中的布局,从而实现改变
“虚假” 的转化:虚假的转化,也就是强制类型转化,例如我们写一串二进位制序列11111111 11111111 11111111 11111111,我们声明他的类型是signed int,我们会把他当成-1,假设我们将其强制类型转化为unsigned int,我们就会把他当成一个很大的数字。总结:强制类型转化并不会改变数据在内存中的存储形式,改变的是数据的类型
许多人可能有疑问:假如我们把一个double类型的数据赋给整型,是不是会改变内存中的数据
答:例如int x=(int)3.14,3.14是double类型的数据,占8个字节,把8个字节的浮点型的数据强制类型转化为四个字节的整型,发生了截断问题,但和我们本身double类型的数据3.14是没有关系的
if——else就近原则
int main()
{
int x = 1;
int y = 0;
if (10 == x)
if (11 == x)
printf("hello 比特");
else
printf("hello world");
return 0;
}
通常的思路:变量x不等于10,所以不进入循环,执行else语句,打印hello world ,我们进行运行
我们可以发现,无结果,原因是什么?
答:因为if else执行的是就近原则,所以else对应的是第二个if,因为第一个if不满足条件,所以不进入下一个if-else语句,所以无结果
如何避免这种错误产生呢?
我们要严格加上花括号,例如
int main()
{
int x = 1;
int y = 0;
if (10 == x)
{
if (11 == x)
{
printf("hello 比特");
}
}
else
{
printf("hello world");
}
return 0;
}
这时候,我们进行运行
成功打印出hello world
如何规避scanf所引起的报错
int main()
{
int a = 0;
scanf("%d", &a);
if (3 == a)
{
printf("3");
}
else
{
printf(".");
}
return 0;
}
我们进行运行
我们要如何规避呢?下面是一种方法
答:
#pragma warning(disable:4996)
我们加上这一行代码,这里的意思是屏蔽或者忽略来自c4996的报错
第二种方法
#define _CRT_SECURE_NO_WARNINGS 1
加上这样一串代码,这是个宏定义,要写在头文件的前面。
switch case语句
首先,switch case语句和if语句都有相同的特点:判断,分支
但也有不同点:if语句能够判断的种类和条件是更丰富的,而switch语句只能判断整型
switch case语句中,case相当于判断部分,break相当于分支部分