C语言之基础部分一(数据类型)
前言
本部分可以说涵盖c语言础部分各个方位知识点,同时加上做题时相关知识点。
有的知识点部分一笔概过,对于本人容易出错的地方会着重讲解。
读者遇到不懂的知识点可以去查找相关资料
1、数据类型分类
2、基本类型分类
2.1、整形
比如0,-12,255,1,32767等等这些都是整型数据。
整型数据中是不允许出现小数点和其它特殊符号的。
int a;
a=1.2;//实质a为1
printf(“%d”,a)//输出1
即,给整形赋值浮点型,整形只会保留整数部分
2.1.1、有符号数和无符号数
对于有符号数,以最高位(左边第一位)作为符号位,
最高位是0表示的数据是正数,最高位是1表示的数据是负数
整数10二进制形式: 0 0 0 0 1 0 1 0
整数-10二进制形式: 1 0 0 0 1 0 1 0
对于无符号整数,因为表述的都是非负数,一个字节中的8位全部用来存储数据,不再设置符号位
整数10二进制形式: 0 0 0 0 1 0 1 0
整数138二进制形式: 1 0 0 0 1 0 1 0
2.1.2、变量溢出
对于有符号的char变量,127加上1等于多少?-128减去1又等于多少?
对于无符号的char变量,255加1等于多少?0减去1等于多少?
把一个有符号的-16赋给一个无符号的char变量又等于多少?
把129赋给有符号的char变量又等于多少?
如果你非常清楚,下面的这部分你就不要看了;
如果你不清楚,恭喜你,读完下面的内容将彻底明白。
首先,要明白无符号和有符号的表示。
无符号8位全部表示数,所以能表示2的8次方个数256(0-255);
有符号的字符,第一个位表示符号位0表示正,1表示负所以只有7位表示数,所以按道理正数和负数各能表示2的7次方个数(128个),共能表示256个数,但是负数和正数的表示方法不同,正数:最高位为0,剩下7位是多少就是多少,如01101110 实际就是1101110=206;而负数:最高位为1,剩下取反加1,如11101110所以是是-0010010=-18,这么一来1000 0000 和 0000 0000这两个就不是一个意思了:前者先取出表示数的(符号位不管)低7位000 0000取反后111 1111,加上1后1000 0000,实际上表示的是这是一个负数,负数的绝对值大小为1000 0000即128,所以表示-128,所以,以0开头的可以表示0到+127这128个数,一1开头的表示-1到-128这128个数,而加法、减法的本质都是一样,就是在原来的码上加个1,11101110(-18)加上1等于11101111(-17),可见和正数的加法没有区别,明白了这些就不难解决文中开头提出的问题了。
有符合127(0111 1111)加上1,码变成1000 0000这刚好是有符号时-128的码,再加1变成-127,可见有符号数的加法是0 1 2 ... 126 127 -128 -127...0
同理-128减去1等于127
无符号255的码1111 1111 加上1后变成了0000 0000溢出了进的1到了CPU寄存器,所以是0。
0(0000 0000)减去1码变成(1111 1111)刚好是无符号255的码。
-16的码付给无符号的,码不边只是表示方法不一样而已。129同理
最大正值加1一般会得到一个负值;类似的最小负值减1一般会得到最大正值。
2.2、字符型
字符型是整型数据中的一种,它存储的是单个的字符,
存储方式是按照ASCII码的编码方式,每个字符占一个字节,8位。
使用单引号’’把字符引起来,用以和变量、其他数据类型区别。比如:’A’,’5’,’m’,’$’,’;’等等。
比如有这样5个字符:'H'、'e'、'l'、'l'、'o',他们在内存中存储的形式如下的图表所示。
01001000 01100101 01101100 01101100 01101111
H e l l o
字符型的输出,既可以使用字符的形式输出字符,即采用“%c”格式控制符,还可以使用采用的其他整数输出方式。比如:
char c = ‘A’;
printf(“%c,%u”,c,c);
输出结果是:A,65
此处65是字符‘A’的ASCII码。
字符的家族中,控制符是无法通过正常的字符形式表示,比如常用的回车、换行、退格等等,需要使用特殊的字符形式来表示他们,这种特殊字符称为转义符,常见几种如下
2.3、浮点型
C语言中除了整型外,另外一种数据类型就是浮点型,浮点型可以表示有小数部分的数据。
浮点型包含三种数据类型,分别是单精度的float类型,双精度的double类型,和长双精度long double类型。
参与运算的表达式中存在double类型,或者说,参与运算的表达式不是完全由整型组成的,在没有明确的类型转换标识的情况下(将在下一小节中讲解),表达式的数据类型就是double类型。例如:
1 + 1.5 + 1.23456789 /*表达式运算结果是double类型*/
1 + 1.5 /*表达式运算结果是double类型*/
1 + 2.0 /*表达式运算结果是double类型*/
1 + 2 /*表达式运算结果是int类型*/
2.3.1、一般形式
如1.23 123.0 0.123 -.60等
2.3.2、指数形式
如下所示(‘e’或者‘E’都可以)
2.0e3 表示2000.0
1.23e-2 表示0.0123
.123e2 表示12.3
1.e-3 表示0.001
对于指数形式,有以下两点要求:
(1)字母e前面必须要有数字
(2) 字母e的后面必须是整数
3、类型转换
计算过程中,如果遇到不同的数据类型参与运算该怎么办,是终止程序还是转换类型后继续运算。
编译器采取第二种方式,如果能够转换成功,程序继续运算,如果转换失败,程序报错同时终止运行。
数据类型有两种转换方式,分别隐式转换和显式转换。
3.1、数据赋值两种情况
3.1.1、占字节较大的数据赋值给占字节较小的数据
例如
int a = 2147483648;
printf("%d",a);
这样赋值后,输出变量a的值并非预期的2147483648,而是-2147483648,原因是2147483648超出了int类型能够装载最大值,数据产生了溢出。如果换一种输出格式控制符,代码如下所示:
printf("%u",a);
输出的结果就是变量a的值,原因是%u是按照无符号整型输出的数据,而无符号整型的数据范围上限大于2147483648这个值。
例子:
unsigned short a = 256;
char b = a;
printf("%d",b);
这样赋值后,输出变量b的值并非预期的256,而是0,原因是256超出了char类型能够装载最大值,b只截取了a的低8位的数据,如下:
3.1.2、占字节较小的数据赋值给占字节较大的数据
情况一:
当字节较大数是无符号数时,转换时新扩充的位被填充成0
char b = 10;
unsigned short a = b;
printf("%u",a);
这样赋值后,变量a中输出的值是10,原因如下:
情况二:
当字节较大数是有符号数时,转换时新扩充的位被填充成符号位
char b = 255;
short a = b;
printf("%d",a);
这样赋值后,变量a输出的值是-1,变量a扩充的高8位,根据变量b的最高位1都被填充成了1,所以数值由正数变成了负数,因为变量a的最高位符号位是1,至于为什么16个1表示的是-1,涉及到二进制数的原码和补码问题,这里先不深究。转换图示如下:
3.2、隐式转换
C语言中设定了不同数据参与运算时的转换规则,编译器会在悄无声息中进行数据类型的转换,进而计算出最终结果,这就是隐式转换。
一句话终结,低精度类型向高精度类型(默认)
3.2.1、典型例子
int i;
i = 2 + 'A';
先计算“=”号右边的表达式,字符型和整型混合运算,按照数据类型转换先后顺序,把字符型转换为int类型65,然后求和得67,最后把67赋值给变量i。
double d;
d = 2 + 'A' + 1.5F;
先计算“=”号右边的表达式,字符型、整型和单精度float类型混合运算,因为有浮点型参与运算,“=”右边表达式的结果一定是double类型,按照数据类型转换顺序,把字符型转换为类型65.0,2转换为2.0,1.5F转换为1.5,最后把双精度浮点数68.5赋值给变量d。
3.2.2、逆向转换
上述情况都是有低精度类型向高精度类型的转换,如果逆向转换,可能会出现丢失数据的危险,编译器会以警告的形式给出提示。
例如:
int i;
i = 1.2;
浮点数1.2舍弃小数位后,把整数部分1赋值给变量i。如果i=1.9,运算后变量i的值依然是1,而不是2。
注 意:把浮点数转换为整数,直接舍弃小数位。
3.3、显式转换
隐式类型转换编译器是会产生警告的,提示程序存在潜在的隐患。如果非常明确的希望转换数据类型,这就需要用到显式类型转换了。
显式转换格式如下所示:
(类型名称) 变量或者常量
或者
(类型名称) (表达式)
4、计算机如何识数——数制
数据在计算机里是以二进制形式的数表示的,在实际程序中,许多系统程序需要直接对二进制位的数据操作,还有不少硬件设备与计算机通信都是通过一组二进制数控制和反映硬件的状态。
在表示一个数时,二进制形式位数多,八进制和十六进制比二进制书写方便些,他们都是计算机中计算常用的数制。
4.1、二进制
二进制是逢二进一的数制,目前的计算机全部都是采用二进制系统。
0和1是二进制数字符号,运算规则简单,操作方便,因为每一位数都可以用任何具有两个稳定状态的元件表示,所以二进制易于用电子方式实现。
4.1.1、二进制运算规则
加法:0+0=0,0+1=1,1+0=1,1+1=10
减法:0-0=0,1-0=1,1-1=0,10-1=1
乘法:0×0=0,0×1=0,1×0=0,1×1=1
除法:0÷1=0,1÷1=1
例如,(1100)2 + (0111)2计算如下:
1100
+ 0111
10011
4.1.2. 二进制转换为十进制
十进制是逢十进一,由数字符号0,1,2,3,4,5,6,7,8,9组成,可以这样分析十进制数:
(1234)10 = 1 * 103 + 2 * 102 + 3 * 101 + 4 * 100 = 1000 + 200 +30 + 4 =(1234)10
采用同样的方式转换二进制到十进制。
(1101)2 = 1 * 23 + 1 * 22 + 0 * 21 + 1 * 20 = 8 + 4 + 0 + 1 = (13)10
(10.01)2 = 1 * 21 + 0 * 20 + 0 * 2-1 + 1 * 2-2 = 2 + 0 + 0 + 0.25 = (2.25)10
4.1.3、十进制转换二进制
⑴ 十进制整数转换为二进制
方法是除以2取余,逆序排列,以(89)10为例,如下。
89 ÷ 2 余1
44 ÷ 2 余0
22 ÷ 2 余0
11 ÷ 2 余1
5 ÷ 2 余1
2 ÷ 2 余0
1 余1
(89)10 = (1011001)2
(5)10 = (101)2
(2)10 = (10)2
⑵ 十进制小数的转换为二进制
方法是乘以2取整,顺序排列,以(0.625)10为例,如下。
0.625 * 2 = 1.25 取整1
0.25 * 2 = 0.5 取整0
0.5 * 2 = 1 取整1
(0.625)10 = (0.101)2
(0.25)10 = (0.01)2
(0.5)10 = (0.1)2
4.2、八进制
八进制是逢八进一的数制,采用0~7八个数字组成。八进制比二进制书写方便,也常用于计算机计算。
需要注意的是,C语言中,八进制数以数字0开头,比如04,017等等。
4.2.1、 八进制转换为十进制
和二进制转换为十进制的原理相同,
如:(64)8= 6 * 81 + 4 * 80 = 48 + 4 =(52)10
4.2.2、 二进制转换为八进制
整数部份从最低有效位开始,以3位二进制数一组,最高有效位不足3位时以0补齐,每一组均可转换成一个八进制的值,转换结果就是八进制的整数。
小数部份从最高有效位开始,以3位一组,最低有效位不足3位时以0补齐,每一组均可转换成一个八进制的值,转换结果就是八进制的小数。
例如:(11001111.01111)2 = (011 001 111.011 110)2 = (317.36)8
4.3、十六进制
十六进制就是逢十六进一的数制,采用0~9和A~F十六个数字组成(A代表10,F代表15),也常用于计算机计算。
4.3.1、十六进制转换为十进制
和二进制转换为十进制的原理相同,如:
(2FA)16 = 2 * 162 + F * 161 + A * 160= 512 + 240 + 10 =(762)10
4.3.2、二进制转换为十六进制
与二进制转换为八进制相似,只是转换为十六进制时,以4位二进制数为一组,每一组转换为一个十六进制的值。由高到低。
例如:
(11001111.01111)2 = (1100 1111.0111 1000)2= (CF.78)16
5、ASCII码
ASCII码很多,这里仅仅说一些比较重要常用的内容,感兴趣的童鞋可以自己百度查找。
NULL 十进制是0。
本部分记住
字符0~9,A~Z,a~zASCII码
字符 十六进制 十进制
0 —— 30 —— 48
A —— 41 —— 65
a —— 61 —— 97
起始字符ASCII知晓,其他字符自行相减