2.4 C语言的数据类型
数据类型是数据的基本属性,描述的是数据的存储格式和运算规则。不同类型的数据内存中所需存储空间的大小是不同的,能够支持的运算、相应的运算规则也是不同的,因而在学习C语言程序时必须准确地掌握和运用数据的数据类型。C语言中的数据类型如表2-9所示。
☆大牛提醒☆
数组类型和结构类型统称为聚合类型,函数的类型指的是函数返回值的类型。当函数没有必要返回一个值时,就需要使用空类型设置返回值的类型。
空类型用于指定没有可用的值,它通常用于表2-10所示的三种情况。
表2-9 C语言中的数据类型
表2-10 空类型可用的情况
2.4.1 整型数据类型
整型数据类型为Integer,例如,0、-12、255、1、32767等都是整型数据,根据数据在程序中是否可以改变数值,可分为整型常量和整型变量;根据有无符号可以分为有符号型和无符号型。有符号型的整数既可以是正数,也可以是负数;无符号型的整数只包含0和正数。
整型数据类型(int)可以用4种修改符的搭配来描述,有符号型(signed)、无符号型(unsigned)、短整型(short)和长整型(long)。如表2-11所示列出了关于标准整数类型的存储大小和值范围。
表2-11 标准整数类型的存储大小和值范围
为了得到某个类型或某个变量的存储大小,用户可以使用sizeof(type)表达式查看对象或类型的存储字节大小。
【例2.4】编写程序,获取整型数据类型的存储大小(源代码\ch02\2.4.txt)。
图2-6 例2.4的程序运行结果
程序运行结果如图2-6所示。
☆大牛提醒☆
在函数printf()中,参数%lu为32位无符号整数。
2.4.2 浮点型数据类型
浮点数的小数点位置是不固定的,可以浮动,C语言中提供了三种不同的浮点格式,分别为:单精度浮点型(float)、双精度浮点数(double)和长双精度浮点型(long double)。
当精度要求不严格时,比如员工的工资,需要保留两位小数,就可以使用float类型;double类型提供了更高的精度,对于绝大多数用户来说已经够用;long double类型支持极高精度的要求,但很少使用。如表2-12所示为浮点型数据类型的存储大小、值范围和精度的细节。
表2-12 浮点型数据类型的存储大小、值范围和精度
【例2.5】编写程序,输出浮点型数据类型占用的存储空间以及它的范围值(源代码\ch02\2.5.txt)。
图2-7 例2.5的程序运行结果
程序运行结果如图2-7所示。
☆大牛提醒☆
%E为以指数形式输出单、双精度实数。
2.4.3 字符型数据类型
在C语言中,字符型是整型数据中的一种,它存储的是单个字符,存储方式是按照ASCII(American Standard Code for Information Interchange,美国信息交换标准码)的编码方式,每个字符占一字节,字符使用单引号“'”引起来,如'A'、'5'、'm'、'$'、';'等。
字符型的输出,既可以使用字符的形式输出字符,即采用%c格式控制符,还可以使用整数输出方式。例如:
char c ='A'; printf("%c,%u",c);
这段代码输出结果是:A,65。此处的65是字符'A'的ASCII码值。
【例2.6】编写程序,实现字符和整数的相互转换输出(源代码\ch02\2.6.txt)。
图2-8 例2.6的程序运行结果
程序运行结果如图2-8所示。从输出结果可以得出,字符型数据是以ACSII码值形式存储的,字符a和整数97是可以相互转换的,整数98是可以与字符b相互转换的。
2.4.4 自定义数据类型
使用typedef可以自定义数据类型,语句由3个部分组成,分别是关键字typedef、原数据类型和新数据类型。具体的应用格式如下:
typedef 原数据类型 新数据类型
一旦定义,其之后的程序中可以使用新数据类型替换掉旧数据类型。
【例2.7】编写程序,利用自定义数据类型实现字符的输出(源代码\ch02\2.7.txt)。
图2-9 例2.7的程序运行结果
程序运行结果如图2-9所示。从输出结果可以看出以上语句的含义是给char取一个别名myChar,之后使用myChar代替char定义字符变量c1,c1就是字符类型。
2.4.5 数据类型的转换
在计算过程中,如果遇到不同的数据类型参与运算就会将数据类型进行转换,C语言编译器转换数据类型的方法有2种,一种是自动转换,一种是强制转换。
1.自动转换
C语言中设定了不同数据参与运算时的转换规则,编译器就会自动进行数据类型的转换,进而计算出最终结果,这就是自动转换。数据类型的自动转换规则如图2-10所示。
C语言编译器在自动转换数据类型时,应遵循以下规则:
(1)如果参与运算量的类型不同,则先转换成同一类型,然后进行运算。
(2)自动转换数据类型按数据长度增加的方向进行,以保证精度不降低。例如整型数据类型和长整型运算时,会先把整型数据类型转成长整型后再进行运算。
(3)所有的浮点运算都是以双精度进行的,即使仅含单精度量运算的表达式,也要先转换成双精度型,再做运算。
(4)字符型和短整型参与运算时,必须先转换成整型数据类型。
图2-10 数据类型的自动转换规则
(5)在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度比左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入。例如:
int i; i=2 + 'A';
计算的规则是先计算“=”号右边的表达式,字符型和整型混合运算按照数据类型转换先后顺序,把字符型转换为int类型65,然后求和得67,最后把67赋值给变量i。
再例如如下语句:
double d; d=2+'A'+1.5F;
计算的规则是先计算“=”号右边的表达式,表达式中有字符型、整型和浮点型3种类型,因为有浮点型参与运算,所以“=”右边表达式的结果是浮点型。按照数据类型转换顺序,把字符型转换为双精度浮点型65.0,2转换为2.0,1.5F转换为1.5,最后把双精度浮点数68.5赋值给变量d。
上述情况都是由低精度类型向高精度类型转换,如果逆向转换,将会出现丢失数据的危险,编译器会以警告的形式给出提示。例如:
int i; i=1.2;
浮点数1.2舍弃小数位后,把整数部分1赋值给变量i。如果i=1.9,运算后变量i的值依然是1,而不是2。
【例2.8】编写程序,利用数据类型的自动转换,从而计算圆的面积(源代码\ch02\2.8.txt)。
程序运行结果如图2-11所示。从运算结果可以看出,虽然PI为浮点型;s,r为整型,但在执行s=r*r*PI语句时,r和PI都转换成双精度浮点型计算,结果也为双精度浮点型。但是由于s为整型,故赋值结果仍为整型,舍去了小数部分,最后输出结果为201。
2.强制转换
当数据类型需要转换时,有时编译器会给出警告,提示程序会存在潜在的隐患,如果非常明确地希望转换数据类型,就需要用到显式类型转换,也就是常说的强制转换。其一般形式为:
(类型说明符) (表达式)
其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。例如:
(float) a 把a转换为实型 (int)(x+y) 把x+y的结果转换为整型
在数据类型需要强制转换时应注意以下问题:
(1)类型说明符和表达式都必须加括号(单个变量可以不加括号),如把(int)(x+y)写成(int)x+y则成了把x转换成int型之后再与y相加了。
(2)无论是强制转换还是自动转换,都只是为了本次运算的需要而对变量的数据长度进行的临时性转换,而不改变数据说明时对该变量定义的类型。
【例2.9】编写程序,实现数据类型的强制转换,从而输出需要的数据类型格式(源代码\ch02\2.9.txt)。
程序运行结果如图2-12所示。从输出结果可以看出,实例中先计算x+y值为8.8,然后赋值给a,因为a为整型,所以自取整数部分8,a=8;接下来b把x+y强制转换为整型;最后10/i是两个整数相除,结果仍为整数2,把2赋给浮点数f;x为浮点型直接输出。
图2-11 例2.8的程序运行结果
图2-12 例2.9的程序运行结果