1_数据类型

一、引入

1)我们所有要处理的数据文件(视频,图片,音频等文件)
		都是以二进制的形式来保存在内存中的

2)将8bit称为一个字节(byte),并将字节作为最小的可操作单位


我们在保存这些数据的时候,要思考这些数据的属性,比如说这个数据的大小

为了避免一个很大的空间保存一个很小的数据,或者一个很小的空间保存一个很大的数据

那么怎么让操作系统知道开辟多大的空间呢? 
			就涉及到 数据类型

二、C语言数据类型

1、基本类型
	系统分配给基本类型的变量的内存大小是固定的,C语言已经定义好了这个类型
	
	1)整型
		int		4个字节(32bits)
			unsigned int 	取值范围  0 ~ 2^32 - 1
			(signed) int	取值范围  -2^31 ~ 2^31-1
			
		short	2个字节(16bits)
			unsigned short 	取值范围  0 ~ 2^16 -1
			(signed) short  取值范围  -2^15 ~ 2^15-1
			
		long		
				32位机器	4个字节(32bits)
				64位机器	8个字节(64bits)
			
			
		---------------------
			unsigned 无符号
				代表所有的bit位都是数值
			
			signed  有符号
				最高位为符号位(只占1位) + 数值位
					1	-> 负数
					0	-> 正数
		
		================
			当CPU把数据进行运算时,不能直接把变量的数据进行计算
			需要先把数据拷贝到 CPU内部的寄存器(32bits)
			再对寄存器的值进行计算
			
			当变量的数据小于32bits时,
				无符号的数拷贝到寄存器高位补0
				有符号的数拷贝到寄存器高位补符号位
		
	
	2)字符型
		char  	1个字节(8bits)
			unsigned char   取值范围 0 ~ 255
			(signed) char   取值范围 -128 ~ 127
			
			例子:
				char a = 260;
				printf("%d\n", a);		//  4
	
	
	3)浮点型(实型)
	
		float (单精度)	占4个字节(32bits)
			如图所示:(参考图示) 
				31位(最高位)为符号位,占1bit, 1为负数,0为正数 
				30~23bit 为 指数段 ,占8bits  ,指数加上127后 得到二进制数 
				22~0bit 为 尾数段 ,占23bits
			
			例子: 
				float d = 3.14;
			
		double(双精度) 占8个字节(64bits)
			如图所示:(参考图示) 
				63位(最高位)为符号位,占1bit, 1为负数,0为正数 
				62~52bit 为 指数段 ,占11bits  ,指数加上1023后 得到的二进制数 
				51~0bit 为 尾数段 ,占52bits
		
		例子: 
			将十六进制数 0xC1480000 转换成浮点数  
				0xC1480000 
			--》 11000001 01001000 00000000 00000000

			--》 1      10000010   1001000 00000000 00000000
				符号位   指数段       尾数段
				
				
				符号位: 1  --》 负数 
				
				指数段E: 10000010
					1000 0010 --》 130   --》  130-127  --》 3 即实际的指数部分为3
				
				尾数段M: 1001000 00000000 00000000
						这里,在尾数的左边 省略存储了一个1,是以实际的尾数为
							1.10010000000000000000000
				
				把这三个部分的数据单独拎出来后,
				通过指数部分E的值 来调整位数部分M的值
					方法: 
						如果指数E为正数,尾数M的小数点就向右移
						如果指数E为负数,尾数M的小数点就向左移
						小数点的移动位数有指数的绝对值决定
						
				此时 E为3,是一个正数,尾数M的小数点就向右移3位 
					1.10010000000000000000000
				--》1100.10000000000000000000  
				至此,上面就是这个浮点数的二进制形式,然后再去转换成十进制 
					整数部分: 1100   ---》 12 
					小数部分: 10000000000000000000 --》 1 * 2^(-1)  --》 0.5
				==》 12.5 
					由于符号位为1,因此这个浮点数为 -12.5 
					

注意:
	在C语言中,整数的默认的类型为int,浮点数的默认的类型为double


2、构造类型
	C语言允许用户自定义类型
	系统分配给构造类型的变量所占的内存大小 取决于该类型是定义的
	
	数组类型
	结构体类型
	枚举类型
	联合体类型(共用体)

3、指针类型
	
	
4、void空类型
	void 代表在内存中不占内存空间大小
	
	在C语言中,主要有三大作用 
		(1) void 作为函数的返回值,表示函数不返回任何数据    void 函数名
		(2) void 作为函数的参数,表示函数不带任何参数,此时void可省   函数名(void)
		(3) void * 通用指针,在同一个操作系统中,所有指针类型所占的内存大小是一样的

三、变量和常量

1、常量
在程序运行期间 其值不能被改变的量 叫常量
比如:
3,4, 5, 100, …
3 = 5; //error 3是一个常量,其值不能被改变

1)整型常量 
	(1)二进制常量:由0和1组成
		0000 1000  -->  等价于十进制的8
	
	(2)八进制常量:以字符0开头,后面接0个或多个0~7的字符
		格式化输出 %o
			比如: 
					0666, 0777, 01234, ...
	
	(3)十进制常量
		格式化输出 %d 
	
	(4)十六进制常量:以0x或0X开头,后面接0个或多个 0~9 a~f A~F 的字符
		格式化输出 %x 
			比如: 
					0xff
					0x10
	

================
	不同进制之间的转换
		二进制 <==> 八进制 : 1个八进制 对应 3个二进制
			比如:		八进制			二进制 
						0				000
						1				001
						2				010
						...
						6				110
						7				111
					
					
		二进制 <==> 十六进制 :1个十六进制 对应 4个二进制
			比如: 		十六进制		二进制
						0				0000
						1				0001
						2				0010
						...
						9				1001
						a/A 			1010
						...
						f/F				1111


		二进制 转换成 十进制:
			0111   -->    1*2^2 + 1*2^1 + 1*2^0 =  7

		八进制 转换成 十进制: 
			0765   -->    7*8^2 + 6*8^1 + 5*8^0 = 

	结论: 
		1)任何进制 转换成 十进制 都是:直接乘以权值 然后全部相加即可

		2)十进制 转换成 其他R进制: 除R取余法 

		3)任何进制 转换成 非十进制: 
				先把该进制数转换成二进制数,再去转换成对应的其他进制数
			比如: 
				八进制  --》  二进制     ---》  十六进制 
				0777  -->  111 111 111  
					  -->  0001 1111 1111	--> 0x1FF


2)浮点型常量 
	单精度 float 	格式化输出 %f 		(默认输出6位小数)
	双精度 double 	格式化输出 %lf		(默认输出6位小数)

		printf("%.2f\n",b); //小数部分保留2位
		
		printf("%5.2f\n",b);	//整个小数一共占5位(包括小数点),其中小数部分占2位
								向右靠齐,左端补空格
								当实际位数大于约定输出的位数,则按实际位数输出

		printf("%-5.2f\n",b);	//整个小数一共占5位(包括小数点),其中小数部分占2位
								向左靠齐,右端补空格
								当实际位数大于约定输出的位数,则按实际位数输出

								
3)字符常量
	字符常量是 用单引号''引起来的一个或多个字符的序列, 格式化输出 %c 
		比如: 
			'a' ~ 'z'   '0' ~  '9'  'A' ~ 'Z'  .... 
			
		在计算机中,保存一个字符,保存的是它的ASCII码,而不是这个字符本身
	
		查看ASCII码:
			终端上输入指令   man ASCII
	
			OCT 八进制 
			DEC	十进制
			HEX	十六进制
	
			比如: 
				'0'	 ---  48
				'A'	 ---  65
				'a'  ---  97
	
			例子: 
				char a = 'A';
					<==>  char a = 65;
					<==>  char a = 0101;
					<==>  char a = 0x41;
	
	
	(1)普通字符:一般一个字符我们称之为普通字符,可以打印出来,有形状的字符
			比如: 
				'a' ~ 'z'   '0' ~  '9'  'A' ~ 'Z'  .... 
	
	(2)转义字符:一般不可以打印出来的,没有形状,有另外一层含义的字符
			比如: 
				'\n'	换行符
				'\t'	制表符
				'\\'	反斜杠符
				'%%'	百分号符
				...
	
				'\ddd'	:ddd表示1到3位的八进制,打印效果为该数字对应的ASCII码的字符
					
					putchar('\101');	-->   'A'
					
				'\xdd'	:ddd表示1到2位的十六进制,打印效果为该数字对应的ASCII码的字符
	
					putchar('\x41');	-->   'A'
					
					
					
4)字符串常量					
	用双引号""引起来的一串字符		
	字符串常量在内存中保存一定会有一个'\0'结尾,我们称之为终止符(结束符)
			'\0'的ASCII值为 0 
			
		"hello world"
					
		格式化输出 %s 			

2、变量
1)
在程序运行期间 其值能够被改变的量 叫变量

	变量实质上是内存的一个具有特定属性的存储空间,它是用来存储数据的
	这块存储空间中的值 就是变量的值,而且这个值是可以改变的
					
					
变量名
	在定义变量的时候,会在内存中分配空间(空间的大小由数据类型来决定的)
	这个变量名就和这块空间的首地址相关联起来了
	操作系统由变量名就可以访问到这个内存地址的空间
					
					
2)变量的定义语法:
	数据类型 变量名; 
	数据类型 变量名 = 初始值;
	
		int a;
		
			"数据类型":所有C语言合法的类型都可以的
			“变量名”:符合C语言标识符的命名规则
						由数字、字母、下划线组成,
						不能以数字开头,只能以字母或下划线开头,
						不能与关键字冲突,且区分大小写
					
					abc		12a		sb		int  ab*	c8_9	SB
							 x     			 x 	  x		
					
					
3)变量的访问 (读/写)					
					
	(1)从变量中去读取值
		实际上就是通过变量名找到相应的内存地址,从该地址中去取值 
		这时变量一般是在赋值符号(=)的右边,表示该变量的值,我们称之为右值(rvalue)

	(2)往变量中去写入值
		实际上就是通过变量名找到相应的内存地址,从该地址中去写入值
		这时变量一般是在赋值符号(=)的左边,表示该变量对应的存储空间,称之为左值(lvalue)
					
			例子:
				int a;
				a = 10;		//a作为左值,代表a的那块存储空间,把10写入到这块空间中
				int b = a;	//a作为右值,代表变量a本身的值10,把10写入到b对应的空间中	
					
	我们在定义变量时,给它赋值,称之为初始化
	如果没有给变量赋值,那么这个变量的值是不确定的,未知的
		数据类型 变量名 = 初始值;				

四、整数的存储问题

整数的存储是以二进制的补码形式 存放的

1)正数 
	正数的补码 就是其原码本身  
	
		例子: 
			char a = 13; 
				a --->  0000 1101   -->  13的原码,也是它的补码

			int b = 9;
				b --->  00000000 00000000 00000000 0000 1001  --> 9的原码,也是9的补码


2)负数
	负数的补码是 其绝对值的原码  取反  加1 得到的

		例子: 
			char a = -13;
				|-13|  -->  13  -->  0000 1101		绝对值的原码
									 1111 0010		取反(0变1,1变0)
									 1111 0011		+1  	
										(-13的补码,-13在计算机中的存储形式)

	已知一个负整数的补码,如何去求这个负整数的十进制数? 
		补码还原: (逆运算)
			负数补码 --》 -1  --》 取反 --》绝对值的原码 --》 得到负数

		例子: 
			 1111 1110   
				--->  1111 1101
				--->  0000 0010    2  绝对值的原码 
				--->  -2

			-2在计算机中的存储形式  1111 1110
			254在计算机中的存储形式 1111 1110
			
			-3  --》  3: 0000 0011  -->  1111 1100  -->  1111 1101 
			253  ----> 1111 1101 
			
			.....
				
	结论: 
		一个负整数(-X) 会和一个正整数(2^N - X) 的存储形式是一样的
			(N代表用多少bit位来存储这个数)
			
			
	计算机怎么知道这个数到底代表的是正数还是负数呢?
		%d :以有符号的(32位)整数形式进行输出
		%u :以无符号的(32位)整数形式进行输出

	总结: 
		1)当编译器以有符号(32位)整型输出(%d)时,是以补码还原的方式去解读
		
		2)当编译器以无符号(32位)整型输出(%u)时,就没有符号位概念了
			直接把所有位当作数值位转换成十进制 进行输出
			
		3)当CPU进行数据运算时,直接是以内存中的存放形式进行运算的,即补码形式


	例子:
		1)
			int a = -2;
			printf("%d\n", a);	// -2
			printf("%u\n", a);	// 2^32 - 2
			
			a  	00000000 00000000 00000000 0000 0010	绝对值的原码 2 
				11111111 11111111 11111111 1111 1101	取反 
				11111111 11111111 11111111 1111 1110	+1  
				
				%d : -2
					补码还原  
						-1  --->  取反  --》 绝对值  --》 负数
			
				%u : 2^32 - 2
		
		
		2)
			unsigned int b = -1;
			printf("%d\n", b);		// -1
			printf("%u\n", b);		// 2^32 - 1 
			
				b   00000000 00000000 00000000 0000 0001
					11111111 11111111 11111111 1111 1110
					11111111 11111111 11111111 1111 1111   b的存放形式
	
					%d : -1 
					
					%u :  2^32 - 1


		3) 
			char d = -56;		
			printf("%d\n", d);		// -56
			printf("%u\n", d);		// 2^32-56

				d  	|-56| 	0011 1000
							1100 0111
							1100 1000	d的存放形式

			
				char  -->  int 
					1100 1000									char 
				--> 11111111 11111111 11111111 1100 1000		int 

				%d : 补码还原 
					11111111 11111111 11111111 1100 1000
					11111111 11111111 11111111 1100 0111	-1 
					00000000 00000000 00000000 0011 1000	绝对值的原码 56
					-->  -56

				%u : 2^32 - 56

五、整数之间的赋值问题

在C语言中,允许各个类型的整数之间相互赋值

	char --> int 
	int  --> short 
	unsigned int --> int  
	...
	
赋值规则: 
	1)长的数据类型  --》 短的数据类型 
		int --> short 
		int --> char 
		低字节直接拷贝,高字节全部舍弃 
		
		比如: 
			260  --->  1 0000 0100    --->  char 0000 0100

			
	2) 短的数据类型  --》 长的数据类型
		低字节直接拷贝,高字节要分情况: 
			如果短的数据是无符号的,那么高字节就直接全部补0 
			如果短的数据是有符号的,那么高字节就全部补符号位

		char --> int 
		1100 1010		-->	11111111 11111111 11111111 1100 1010
		
		unsigned char --> int 
		1100 1010		--> 00000000 00000000 00000000 1100 1010
			

	例子:
		1)
		unsigned char d = -56;		
		printf("%d\n", d);	
		printf("%u\n", d);
		
			d  	|-56| 	0011 1000
						1100 0111
						1100 1000	d的存放形式
						
				unsigned char   --->  int  
					1100 1000
				--> 00000000 00000000 00000000 1100 1000

				%d : 符号位为0,为正数, 直接输出  -->  200

				%u : 直接输出  -->  200


		2) 
			char a = 250;
			char d;
			d = a + 8;
			printf("%d\n",d);
			printf("%u\n",d);
					
				a	1111 1010								(char)	
				8	00000000 00000000 00000000 0000 1000	(int)	
					
					a   char -->  int  
						11111111 11111111 11111111 1111 1010
					+	00000000 00000000 00000000 0000 1000	(int)
					  1 00000000 00000000 00000000 0000 0010    a+8  (int)
					
					int --> char 
					
				d   --> 0000 0010	
				
					%d:  char -->  int 
						00000000 00000000 00000000 0000 0010
						符号位为0,为正数,直接输出 --》 2
					
					%u: char -->  int 
						00000000 00000000 00000000 0000 0010
						直接输出 --》 2
						
						
		2) 
			unsigned char a = 250;
			int d = a + 8;
			printf("%d\n",d);
			printf("%u\n",d);				
					
				a	1111 1010   (unsigned char)	
				
					unsigned char  --> int 
				   	1111 1010  
				a	---> 00000000 00000000 00000000 1111 1010
				+8		 00000000 00000000 00000000 0000 1000
						 00000000 00000000 00000001 0000 0010     258
						
				d  	00000000 00000000 00000001 0000 0010 		(int)
					
					%d : 符号位为0,为正数,直接输出 --》258
					
					%u :直接输出 --》258

六、练习

		1) 
			short a = 32767;
			a = a + 1;
			printf("%d\n", a);
			printf("%u\n", a);
			
				a  -->  32767 -->	01111111 11111111		(short)
				
					short --> int 
					a  -->  00000000 00000000 01111111 11111111
					1(int)	00000000 00000000 00000000 00000001
						+	00000000 00000000 10000000 00000000
						
						int --> short 
							--> 10000000 00000000       a
					
					%d :   short --> int 
							11111111 11111111 10000000 00000000  然后进行 补码还原
							11111111 11111111 01111111 11111111  -1
							00000000 00000000 10000000 00000000  取反    绝对值原码32768
						==>  -32768
						
					%u : 	short --> int 
							11111111 11111111 10000000 00000000  直接输出 
						==> 2^32 - 32768
						
		
		2)	unsigned int a = 10;
			int b = -30;
			int w = a + b; 
			
			if( a+b > 5)
			{
				printf("YES\n");
			}
			else 
			{
				printf("栓Q \n");
			}
			
			if( w > 5)
			{
				printf("YES\n");
			}
			else 
			{
				printf("栓Q \n");
			}
					
				a	-->	00000000 00000000 00000000 0000 1010	(unsigned int)
				
				b	-->	-30 
					--> |-30| 	00000000 00000000 00000000 0001 1110
					-->	取反	11111111 11111111 11111111 1110 0001 
					--> +1		11111111 11111111 11111111 1110 0010		(int)
			
				a+b     unsigned int + int   ===>  unsigned int 
						
					a	-->	00000000 00000000 00000000 0000 1010	(unsigned int)
					b	--> 11111111 11111111 11111111 1110 0010		(int)
					a+b --> 11111111 11111111 11111111 1110 1100	(unsigned int)
							a+b的结果为无符号数 

					(1)  a+b > 5    ==>   YES 

				w 		11111111 11111111 11111111 1110 1100	(int)
						w的符号位为1,是一个负数  
						
					(2) w < 5   ==>   栓Q  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RoyLee0826

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值