栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

第5讲 - C语言关键字(5)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

第5讲 - C语言关键字(5)

接着上一节课,我们再讲两道题目

#include
int main()
{
	int i = -20;
	unsigned int j = 10;
	printf("%dn", i + j);
	printf("%un", i + j);
	return 0;
}

请问两个式子打印的结果是什么?

答:遇到这种题目,我们首先要将i和j的二进位制补码表示出来,用他们的二进位制补码相加减得到我们要的结果

整型i的源码是1000000000000000  0000000000010100

对应的反码是1111111111111111  1111111111101011

对应的补码是1111111111111111  1111111111101100

j是无符号数,无符号数没有原反补码的概念,所以对应的源码就是存在内存中的补码

j的源码是0000000000000000  0000000000001010(补码)

i和j的补码对应相加得到 1111111111111111  1111111111110110

printf("%dn", i + j);表示我们打印的是整型,对应的就是signed int,是有符号整型,有两种方法计算对应的值,第一种方法就是求出我们i和j的补码相加的结果对应的源码(不再赘述)第二种方法非常简单,因为我们使用的是有符号整型,那么我们可以直接跳过内部计算的细节,-20+10=-10

注意由补码求源码有两种方法,第一种:和源码求补码的步骤一样,按位取反+1,第二种方法,和源码求补码的步骤相反,也就是先-1,再按位取反,两种方法记忆一种即可。

第二个式子:

我们的第一个式子打印的是有符号整型,第二个式子打印的是无符号整型,我们前面计算的i和j的补码相加之前的所有步骤都不变,变得是如何看待i和j的补码相加的结果,也就是1111111111111111  1111111111110110

既然是无符号整数,那么所有位数都是数值位,直接当做二进位制数字进行计算

如图,我们计算的二进位制序列对应的数字就是4294967286,是一个非常大的数字 ,进行运行检测

 结果相同

总结:类型决定了如何看待内存中二进位制序列   

第二题:

int main()
{
	unsigned int i;
	for ( i = 9; i >= 0; i--)
	{
		printf("%un", i);

	}
	return 0;
}

这段代码运行的结果是什么?

答:死循环

为什么会死循环呢?

答:for循环内部的计算步骤是这样的:i=9,满足i>=0;i--,直到减到0,0满足i>=0,0-1的结果就相当于0+(-1),-1对应的二进位制补码是11111111111111111111111111111111,0的补码就是0,0+ -1对应的二进位制补码结果就是-1的二进位制的补码,因为我们的i是无符号整型,所以这串代码的全部位数都是数值位,所以i就变成了2^32-1,因为2^32-1大于0,一直相减的结果就始终大于0,所以就死循环。

接下来,我们讲一下c语言中的bool

问题1:c语言中有没有bool类型

答:c89 c90没有bool类型,c99中引入_Bool类型,_Bool类型的头文件是#include

在没有头文件的时候,我们引用bool类型,可以发现,出现错误

 当我们引用了头文件#include再进行调用

 

可以发现,bool类型只占一个字节 我们转到bool类型的定义

 可以发现,boll类型中定义真为1假为0

理论上,表示真假,一个字节就足够了,不过要取决于编译器,vs2013认为是一个字节

我们切换一个大写的试试

 我们可以发现,使用大写依旧没问题(不过要加windows的头文件),那么大小写究竟有什么差异呢

我们转到BOOL的定义

 可以看到,这个BOOL类型是由微软研发的

我们进行运行,可以发现,打印了四个字节

我们查看定义,可以发现 

这个BOOL相当于整型,占四个字节

需要注意的是,优先使用小写的bool,因为大写的BOOL只在微软旗下的产品才可用

bool类型和0进行比较

int main()
{
	int flag = 0;
	if (flag == 0)
	{
		printf("1n");
	}
	if (flag == false);
	{
		printf("2n");
	}
	if (!flag)
	{
		printf("3n");
	}
	return 0;


}

上面那三种方法最好

第一种,不合适,原因是flag==0和int x==0,这两种看起来没什么区别,语义不明

第二种我们也不推荐,因为我们第二种必须有c99平台支持,必须有头文件,没有头文件的情况下,是编译不过去的

更推荐的是第三种,我们介绍一下if语句的执行步骤

1:先执行()中的表达式和步骤or或函数,得到真假结果

2:条件  判定功能

3:进行  分支功能

我们这里的真假true 和false ,这是逻辑结果,直观的反映了flag是bool类型

接下来,我们介绍一些浮点型的特性

int main()
{
	double f = 3.6;
	return 0;
}

这里的3.6默认的就是double类型的,而不是float类型的

当我们想用float类型的变量存储3.6时,可以在3.6后面加上f

int main()
{
	float f = 3.6f;
	return 0;
}

当不加f时

 我们可以发现,这里说了从double到float截断,原因是什么?

答:float类型占四个字节,3.6是double类型的数据,占8个字节,数据在存储的时候,和变量的类型没有关系,所以我们的double类型的数据存储到float类型的变量中,发生截断。

我们写一串代码,观察产生的现象

int main()
{
	double d = 3.6;
	printf("%.50fn", 3.6);
}

这里的%.50表示小数点后保留50个有效数字,我们进行运行,查看结果

 可以看到答案保留了50位有效数字,但是后面的有效数字中竟然出现了一个1,原因是什么?

答:这里是产生了精度损失,我们可以发现,精度损失既能使我们的数字变大,又能使我们的数字变小,更多细节的话,涉及到浮点型数据在内存中的存储。

接下来,我们看看更多的精度损失的例子

int main()
{
	double x = 1.0;
	double y = 0.1;
	printf("%.50fn", x-0.9);
	printf("%.50fn", y);
	return 0;
}

正常情况下,两个式子打印的结果都应该是0.1,我们进行编译

 我们可以发现,两个式子打印的结果都不是我们预料的结果,这就是精度损失的例子

我们把上面的例子扩展一下

int main()
{
	double x = 1.0;
	double y = 0.1;
	printf("%.50fn", x-0.9);
	printf("%.50fn", y);
	if ((x - 0.9) == 0.1)
	{
		printf("you can se me!");
	}
	else
	{
		printf("oops!");
	}
	return 0;
}

正常情况下,x-0.9的结果应该是0.1,屏幕上应该打印you can se me!我们进行编译

 可以发现,结果是oops,x-0.9的结果并不是0.1

总结:在进行浮点型比较的时候,一定不能用==号

浮点型本身有精度损失,进而导致各种结果可能有细微的差别

那么,两个相同的浮点数又该如何判断和比较

答:

if ((x - y) > -精度 && (x - y) < 精度)
{

}

判断条件如上图代码所示,需要注意的是,这个精度通常是我们自己设置的,非常小的数字,例如

#define EPSILON 0.0000001

所以要满足下列条件:(x - y) > -EPSILON && (x - y) < EPSILON

满足的情况下,可以判断x=y

还有一个更加简洁的写法

if (fabs(x - y) < 精度)
{

}

注意:这里的fabs是浮点数求绝对值的意思,要使用fabs需要用的math.h的头文件

精度除了可以自己设置,也可以采用系统的

DBL_EPSILON
FLT_EPSILON

上面的一个是系统的double类型的精度,下面一个是系统的float类型的精度,注意:使用这两种系统的精度的时候,需要使用头文件#include

下面,我们写一个例子

#include
#define EPS 0.000000001
int main()
{
	double x = 1.0;
	double y = 0.1;
	printf("%.50fn", x-0.9);
	printf("%.50fn", y);
	
	if (fabs((x-0.9)-y) 

注意:使用fabs求浮点型绝对值必须带头文件,我们上次写的if语句是if ((x - 0.9) == 0.1),这种显示是错误,正确的写法就是下面的这种写法,如果我们的写法正确,程序编译应该会打印出you can se me

 可以发现,程序运行成功

我们上面写的是自己设置的精度,接下来,我们使用系统设计的精度

#include
int main()
{
	double x = 1.0;
	double y = 0.1;
	printf("%.50fn", x-0.9);
	printf("%.50fn", y);
	
	if (fabs((x - 0.9) - y) 

注意:在使用系统给的精度DBL_EPSILON时,需要引头文件#include

系统给的精度到底是多大呢?我们转到定义进行查看

 这段绿色的英文是什么意思呢?

答:1.0加很多数字结果都不是1.0,而这个精度是能够和1.0相加之后不是1.0的最小值,很拗口,简而言之就是这个精度是最小的吗,但是这个精度+1.0也比1.0大

我们进行编译

 

上面,我们讲了判断两个浮点性数据相等的办法,接下来,我们来讲一下判断浮点型数据和0相等的办法,我们运用到了类比

if (fabs((x - 0.9) - y) 

这是我们判断两个浮点型相等的条件,也就是x-0.9==y,我们把这里的y换成0即可,也就是

if (fabs(x) 

这就是我们类比后的结果,我们把x-0.9再简化一下,简化为x

if (fabs(x) 

所以判断一个浮点型数据x是否等于0时,需要用浮点型求绝对值的方法求出浮点型数据x的绝对值,用得出来的结果和精度进行比较,这里的精度既可以是我们自己设置的,也可以是系统自带的

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/994366.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号