1.3 基本数据类型
1.3.1 整型数据
C语言中用整型数据来表示整数。
(1)整型常量
C语言的整型常量可以有以下三种表示形式。
十进制整型常量:例如123、−45、0、158L、358000L等(1L表示长整型,稍后介绍)。
八进制整型常量:以0开头表示,例如012L、077L、0200000L等。
十六进制整型常量:以0x开头表示,例如0x15L、0xA5(A表示十进制值10,B表示十进制值11,依此类推)、0x10000L等。
长整型数158L和基本整型常量158在数值上并无区别。在TC编译软件中的区别是为长整型常量分配4字节的存储空间,只为基本整型常量分配2字节的存储空间,在VC++6.0编译软件中都分配4字节的存储空间。
无符号数也可用后缀表示,整型常数的无符号数的后缀为“U”或“u”。例如,358u、0x38Au、235Lu均为无符号数。
前缀、后缀可同时使用,以表示各种类型的数。例如,0xA5Lu表示十六进制无符号长整数A5,其十进制为165。
(2)整型变量
①整型变量的基本类型 在C语言中,按照整型变量所占的二进制位数来分类,可分为:
基本型:类型说明符为int,VC中占4字节的内存单元。
短整型:类型说明符为short int或short。所占字节和取值范围均与基本型相同。
长整型:类型说明符为long int或long,在内存中占4字节。
根据整型变量是否带符号位来分类,可以分为带符号类型和无符号类型。带符号类型用关键字signed表示,无符号类型用关键字unsigned表示,如果既不指定为signed,也不指定为unsigned,则隐含为带符号型(signed),因此signed是完全可以省略不写的。而无符号型必须用unsigned指定,用unsigned与上述三种类型匹配可构成:
无符号基本型:类型说明符为unsigned int或unsigned。
无符号短整型:类型说明符为unsigned short。
无符号长整型:类型说明符为unsigned long。
②整型变量的定义与赋值 定义整型变量的语法是:
限定词int变量名表
限定词包括long、short和unsigned、signed,限定词缺省,隐含为signed。在有限定词的情况下,int可以省略。
(3)整型变量的长度和取值范围
在不同的C编译系统中对各类整型变量所占的字节数规定不同,以16位计算机系统上带符号整型数据占16位为例,其存储示意图如图1-2所示。
图1-2 基本整型存储示意图
如果符号位为0,表示是正整数,第1~15位全为1时能表示的最大整数是215-1,即32767。如果符号位为1,表示是负整数,第1~15位全为0时表示的最小整数是-215,即-32768。
可以用同样的方法计算其他整型数的取值范围,表1-1中列出了在Visual C++6.0系统中整数类型的字节长度和取值范围。
表1-1 整数类型的字节长度和取值范围
注:表中带方括号的部分在整型变量定义时可以省略不写,不影响变量的取值范围。
1.3.2 实型数据
C语言中实型数据又称为浮点数,有实型常量和实型变量,主要用于表达和处理实数。
(1)实型常量
在数学中,表示小数有两种方法:一种是小数表示法,另一种是科学计数法。例如126.8和1.268×102。在C语言中也是用这两种形式来表示浮点数,只不过102用1E+2表示。
①十进制小数形式:由数字和小数点组成。书写时,小数点不可以省略。例如1.23、.123、123.、123.0、0.123、0.0等都是合法的实型常量。
②指数形式:由十进制数加上阶码标志e(或E)及阶码(只能为整数,可以带符号)组成。其一般形式为aEn。a为十进制数,n为十进制整数,都不可缺少。例如1.235可以表示为1.235×100、0.1235×101、12.35×10-1等形式,在C语言中可表示为1.235e0、0.1235e1、123.5e-1等形式。如果写成e10、.123e2.5、.e10、e.、e+3都是不合法的指数形式,在字母“e”或“E”的前后以及数字之间不得插入空格。
另外,实型常量的后缀用F(或f)表示单精度型,而后缀用L(或l)表示长精度型。
(2)实型变量
实型数据一般占4字节(32位)的内存空间,并按指数形式存储。实数+2.17189的指数形式是:+0.217189×101=+0.217189E+1,在内存中的存放形式如图1-3所示。
图1-3 实数2.17189在内存中的存放形式
由此可见,小数部分占的位(bit)数越多,数的有效数字越多,精度越高。指数部分占的位数越多,则能表示的数值范围越大。
实型变量有单精度型、双精度型和长双精度型之分,分别用类型名float、double和long double进行定义。C语言中规定了实型变量的字节长度和取值范围,如表1-2所示。
表1-2 实型变量的字节长度和取值范围
由于实型变量是用有限的存储单元进行存储的,因此提供的有效数字是有限的,有效位以外的数字将变得没有意义,由此可能产生一些误差。
1.3.3 字符型数据
C语言可以处理字符型数据。字符型数据包括字符型常量和字符串常量。
(1)字符型常量
C的字符型常量是用一个单引号括起来的一个字符。例如'a'、'B'、'$'、'!'、'5'等都是字符常量(注意:'a'和'A'是不同的字符常量)。
字符值是以ASCII码的形式存放在变量的内存单元之中的。一个字符型变量在内存中占1个字节,只能存放一个字符。因此,在单引号中只能有一个字符,而'ab'是错误的。
例如,对字符变量c1、c2赋予'a'和'b'值:
c1='a'; c2='b';
字符'a'的十进制ASCII码是97,字符b的十进制ASCII码是98。实际上是在c1、c2两个单元内存放的是97和98的二进制代码,如图1-4所示。
图1-4 字符型常量的存储
从这个意义上来说,也可以把字符型数据看成是整型量。C语言允许对整型变量赋以字符值,字符型数据可以像整型数据一样参与四则运算。例如:
'b'-'a'=1
等价于:98-97=1
(2)转义字符
在C语言中除了上述形式上比较直观的字符常量外,还可将退格、换行等非图形字符表示成字符型常量。其方法是使用转义符“\”与一些特殊字符构成转义字符。转义字符主要用来表示那些不便于用一般字符表示的控制字符。常用的转义字符及其含义如表1-3所示。
表1-3 以“\”开头的转义字符及其功能
说明:转义字符的含义是将反斜杠“\”后面的字符转变成为别的意义。例如“\r”中的“r”不代表字符“r”,而作为回车字符。这种扩展方式看上去好像是两个甚至多个字符,实际上代表一个字符。再如“\123”并非三个字符,而是八进制数(123)8(其对应的十进制数为83)所对应的ASCII字符'S';同理,'\xaf '也并非三个字符,而是十六进制数(af)16所对应的ASCII字符。读者可以自己推算其对应的字符并可用C程序验证一下。
【例1-3】转义字符的使用。
/ *源程序1-3.C* / #include <stdio.h> void main() { printf("cr i\tna\07\n"); / *'\07'代表响铃(BEL)* / printf("ab \t\b\bc d"); }
程序运行结果如下(注:└┘代表空格):
cr└┘i└┘└┘└┘└┘na ab└┘└┘└┘└┘c d
(3)字符型变量
字符型变量是用来存放字符常量的,字符型变量在内存中占1个字节存储空间,并且只能存放1个字符常量。
字符型变量的定义格式和书写规则都与整型变量相同。格式为:
char变量名表;
例如:
char c1,c2,c3; c1='a'; / * 是正确的 * / c2='ab'; / * 是错误的,只能存放到1个字符的变量不能存放多个字符 * / c3="a"; / * 是错误的,只能存放到1个字符的变量不能存放字符串 * /
也允许对字符型变量赋以整型值。在输出时,允许把字符型变量按整型量输出,也允许把整型量按字符型量输出。但因为整型量是4字节量,字符量为单字节量,当整型量按字符型量处理时,只有低8位参与处理。
【例1-4】字符型数据的算术运算。
/ *源程序1-4.C* / #include <stdio.h> void main() { char c1,c2,c3; c1='A'+1; / * 将c1赋值为'A'+1* / c2='0'+1; / * 将c2赋值为'0'+1* / c3=122; / * 将c3赋值为整数122* / c1=c1+32; c2=c2+5; printf("%c,%d\n",c1,c1); printf("%c,%d\n",c2,c2); printf("%c,%d\n",c3,c3); }
程序运行结果为:
b,98 6,54 z,122
(4)字符串常量
C语言中规定,字符常量是用单引号括起来的单个字符,而字符串常量则是用一对双引号括起来的字符序列。例如"I love this game. " "hello, China" "a" "500.53$"等都是字符串常量。
在内存中存储一个字符串所占的字节数除了等于这个字符串中的有效字符外,还必须加一个字节存储字符串结束标志'\0'。例如,对于字符串"CHINA",其在内存中实际的存储形式如图1-5所示。
图1-5 内存中的存储形式
注意:尽管'\0'对于一个字符串是必不可少的,但是在书写时却并不需要将之写在字符串的后面,如不写成"CHINA\0",'\0'由C语言编译自动处理。其实在程序中书写的字符串,只要是用双引号括起来的,则系统会自动给这个字符串加上'\0'。
字符串常量和字符常量是不同的。它们之间主要有以下区别:
·字符常量由单引号括起来,字符串常量由双引号括起来。
·字符常量只能是单个字符,字符串常量则可以含0~n个字符。
·可以把一个字符常量赋予一个字符变量,但不能把一个字符串常量赋予一个字符变量。
在C语言中没有相应的字符串变量,但是可以用一个字符数组来存放一个字符串常量。这在后面章节中介绍。
·字符常量占1字节的内存空间。字符串常量所占的内存字节数等于字符串中字节的数量加1。增加的1字节中存放字符串结束的标志'\0'(ASCII码为0)。例如:
'a'在内存中占一个字节,可表示为:
"a"在内存中占两个字节,可表示为:
1.3.4 数据混合运算及数据类型转换
C语言规定,不同类型的数据可以在同一表达式中进行混合运算,但在运算时要进行类型转换。例如,20+'c'+3.5-597.123*'a'是合法的表达式。在进行运算时,不同类型的数据要先转换成同一类型,再进行运算。数据类型的转换方式有两种:一种是自动转换;另一种是强制转换。
(1)类型的自动转换
这种转换由编译系统自动完成,规则如下:
①若参与运算量的类型不同,则先转换成同一类型,然后进行运算。
②转换按数据长度增加的方向进行,以保证精度不降低。例如,int型和long型数据运算时,先把int型转成long型后再进行运算。
③所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再进行运算。
④char型和short型参与运算时,会先转换成int型。
⑤在赋值运算中,赋值运算符两边量的数据类型不同时,赋值运算符右边量的类型将转换为左边量的类型。如果右边量的数据类型长度比左边长,将丢失一部分数据,这样会降低精度,丢失的部分则会进行四舍五入处理。
混合运算的结果一定是表达式中精度最高的数据类型,如图1-6所示。如对于表达式20+'c'+3.5-597.123*'a',其结果一定是double型的。
图1-6 数据的转换规则
【例1-5】读程序,理解不同类型数据的混合运算。
/ *源程序1-5.C* / #include <stdio.h> void main() { double a; a=7/2+2.5; printf("%f\n",a); }
程序的运行结果为:
5.500000
(2)强制类型转换
自动类型转换提供了一种从低级类型向高级类型转换的运算规则,以保证不降低运算结果的精度。强制类型转换机制可以将一个表达式转换成所需要的类型。强制类型转换的一般形式为:
(类型名)(表达式)
【例1-6】读程序,理解类型的强制转换。
/ *源程序1-6.C* / #include <stdio.h> void main() { float x=3.7,y=4.4,z; z=(int)(x+y); / * 这里对(x+y)的结果进行了强制类型转换 * / printf(“x=%f,y=%f,z=%f\n”,x,y,z); }
程序运行结果为:
3.700000,4.400000,8.000000
说明:
①类型名应用()括起。
②强制类型转换只是生成一个中间数据,而原有数据的类型、值均不发生变化。
③注意(int)x+y与(int)(x+y)的区别。