4.2 基本数据类型
基本数据类型最主要的特点是其值不可以再分解为其他类型。也就是说基本数据类型是自我说明的。
4.2.1 整数类型
在C语言中,整型数据即为整数,是不包含小数部分的数值型数据,以二进制形式进行存储。
1.整型数据的分类
整型数据的一般分类如图4-1所示。
图4-1 整数类型
整型数据的类型说明以及取值范围如表4-2所示。
表4-2 整型数据的类型说明以及取值范围
2.整型数据在内存中的存放形式
数据在计算机内存中是以二进制的形式存储的,1个二进制数称为1位(bit),它是计算机存储中最小的单位。由于使用位来做单位太小,所以实际生活中计算机大多采用字节来处理信息单位,1个字节由8个二进制数组成。字节在计算机中是一个可寻址的信息单位,也就是说计算机中每一个字节信息都有一个地址,这个地址也只能存取一个字节的信息量,但是字节中位的数目却可以任意。
假如定义一个整型变量:
int a; a=11;
十进制数11转换为二进制数为1100,那么它在计算机中的存放形式,如图4-2所示。
图4-2 int型变量存放形式
实际上,在计算机中数值一律使用补码来存储。正数的补码与原码相同,而原码是对数字的二进制的定点表示方法,只不过通过最高位的数字来表示正负,0为正,1为负,所以这一位被称为符号位,这就是为什么10的补码符号位是0了。
负数的补码在符号位用1表示,其余位为此数原码的绝对值按位取反后加1。
例如,对-11求补码的运算,如图4-3所示。
图4-3 求-11码
这样就可以得到-11补码,也就是-11计算机中的存储形式。可以发现,最终结果的符号位为1,表示为负,正好符合-11负数本质。
提示
并不是所有的整型数据符号位为1就表示负,例如无符号整型数据由于没有符号,所以省去了符号位,虽然最高位可能为1,但不表示负数。
各种无符号整型数据所占的内存空间字节数与相应的有符号类型量相同。但由于省去了符号位,故不能表示负数,如图4-4所示。
图4-4 无符号存放形式
例如:整数13在内存中实际存放的情况,如图4-5所示。
图4-5 整型数据的存放形式
3.整型变量的溢出
由于每种数据类型所占的字节可能不同,那么当一个取值范围较大的数据类型转换为一个取值范围较小的数据类型时,可能就会出现数据溢出的情况。
【例4-1】定义两个int型变量a和b,a赋值为2147483647,计算a+1的值,将结果赋给b,输出b的值。(源代码\ch04\4-1)
运行上述程序,结果如图4-6所示。
图4-6 整型变量的溢出
【代码解析】
本例演示了整型变量的溢出情况。首先定义两个整型变量a和b,并对其进行初始化。输出后发现b的结果并不是2147483648,而是-2147483648。这是因为在计算时结果超过了最大值,进位时将符号位进为1,此时用字节表示的话32位全是1,由于符号位是1,所以结果为-2147483648,输出结果的内存表示,如图4-7所示。
图4-7 溢出
提示
在内存中,位数从右向左,由0开始计数。
【例4-2】编写程序,定义一个无符号整型变量i,初始化为0x100000000,然后使用格式控制参数%u(不带符号的十进制整数输出格式)输出a的十进制无符号整数的形式。(源代码\ch04\4-2)
#include <stdio.h> int main() { unsigned int i = 0x100000000; // 定义无符号整型变量 printf("无符号整型变量i=%d\n",i); // 使用格式控制参数%u输出i return 0; }
运行上述程序,结果如图4-8所示。
图4-8 整型变量的溢出
【代码解析】
在本例中变量i为无符号int类型,在内存中占有4个字节,也就是拥有32位的二进制数,它的最大取值为0xFFFFFFFF,但本例中的变量i的值为0x100000000,它是0xFFFFFFFF+1后得到的,也就是说i的赋值已经溢出,会向最高位进一位为1,是第33位,被截去,剩下的32位都是0,所以a的值为0。
4.2.2 字符类型
字符型数据表示单个字符,不能是字符串。在内存中是以ASCII码值的形式存储的,一个字符占有1个字节。
注意:
(1)字符型数据只能用单引号括起来,不能用双引号或其他括号。
(2)字符可以是字符集中任意字符,但数字被定义为字符型之后就不能参与数值运算。如'5'和5是不同的。'5'是字符型数据,不能参与运算。
例如,一个字符变量:
char a= 'x';
其中“x”的ASCII码为120(十进制),120的二进制数为1111000,由于1个字节占8位,所以用0将空位补全,则字符变量a在内存中存放形式,如图4-9所示。
图4-9 变量a在内存中的存放形式
提示
在C语言中,整型变量与字符型变量之间可以相互转换,在赋值时可对字符型变量赋以整型值,对整型变量赋以字符值,输出时亦然。
【例4-3】编写程序,定义字符型变量a、b、c和d,然后分别对其进行初始化,最后对应输出它们的整型数据。(源代码\ch04\4-3)
运行上述程序,结果如图4-10所示。
图4-10 字符型变量
【代码解析】
本例用于演示字符型变量在内存中的存储方式。首先定义四个字符型变量a、b、c和d,初始化值为‘Y’‘y’‘>’‘9’,通过输出函数printf,将四个字符型数据与其相应的整型数据输出,通过这段代码可以发现字符型变量在内存中是将字符的ASCII码值存储到内存单元中的,它们之间能够相互转换。
4.2.3 实型
C的实型数据主要有float类型(32位)和double类型(64位)两种。实型变量又称为浮点型变量,它是由整数部分和小数部分组成的。
1.实型数据的分类
实型变量用于存储实型数值的变量,根据精度可分为单精度类型、双精度类型以及长双精度类型3种,如图4-11所示。
图4-11 浮点型数据的分类
浮点型数据的类型说明以及取值范围,如表4-3所示。
表4-3 浮点型数据的类型说明以及取值范围
提示
要尽量避免一个很大的数与一个很小的数相加或相减,否则就会“丢失”小的数。
2.浮点型数据在内存中的存放形式
一个浮点型数据一般在内存中占4个字节(32位)。与整型数据的存储方式不同,浮点型数据在内存中的存放形式遵循IEEE754标准,它在内存中的存储由数符、阶码、尾数组成。浮点型数据的精度由尾数的位数决定,float型数据为23位,double型数据为52位。
以float型数据为例,它在内存中的表示形式,如图4-12所示。
图4-12 float型数据在内存中的表示
由于浮点数的表现形式一般为:
R=M*2e
其中R(Real)表示实数,M(Mantissa)表示尾数,e(Exponent)表示阶码,所以float型数据的表现形式就可以分为三部分,如图4-13所示。
图4-13 float型数据在内存中的表现形式
其中数符也就是前面介绍过的符号位,0为正1为负;阶码e实际上是移码E(取值0~255)的表示,根据IEEE标准的规定,算法为e=E-127(float型),而double型为e=E-1023。其中e若为正则表示浮点数向左移动e位,e若为负则表示浮点数向右移动e位;尾数M表示浮点数据的有效数字位。
例如,求出float型数据125.5在内存中的存储形式。
125.5转换为二进制数为1111101.1,将它写成指数形式为:1.111101*26,则说明e为6,所以E=e+127=6+127=133,而133转换为二进制为10000101,剩下1.111101去掉整数部分为111101,由于尾数是23位,所以将空位补0,则float型数据125.5在内存中的存储形式,如图4-14所示。
图4-14 float型125.5在内存中的表示
double型数据计算方式与float型数据相似,这里不再赘述。
3.有效数字
有效数字说的是精度,一般是说一个近似数四舍五入到哪一位,就说明这个数字精确到哪一位,比如float型能可靠表示6位十进制数,多于6位以后的数就不可靠了,而double型能可靠表示15位十进制数,15位以后的数也就不可靠了。取值范围是能表示的最小值和能表示的最大值之间的一个数域,超出这个数域的值根本就不能表示了,就像char型能表示-128~+127的数,小于-128和大于+127的数就不能表示了。有效数字肯定都是取值范围之内的数。
通常在Microsoft Visual C++ 6.0开发工具中使用格式控制参数%f输出的float型数据一般包含6个小数位,这是因为编译器和计算机环境有关,所以并非所有的数字都是有效数字。
例如,输出float型数字3.1415926,代码如下:
float f=3.1415926; printf("%f",f);
此时输出结果并非3.1415926,而是3.141593。所以若是对两个浮点型数据进行比较,那么只需要对这两个数之间的差值进行判断,若是差值在给定范围中,则可以认为两数相等。
例如,比较浮点型数据123.123与123.124大小,它们之间的差值为0.001,此时可以认为两数大小相等。
4.2.4 布尔类型
在C语言中,使用整型int来表示真假。在输入时:使用非零值表示真,零值表示假。在输出时:真的结果是1,假的结果是0。这里所说的“输入”表示在一个需要布尔值的地方(也就是其他类型转化为布尔类型时),比如if条件判断中的条件;“输出”表示程序的逻辑表达式返回的结果(也就是布尔类型转化为其他类型时),比如“a==b”的返回结果只有0和1两种可能。
C语言中的布尔类型只有在编译器支持C99的情况下才能正常使用。另外,C99为了让C和C++兼容,增加了一个头文件“stdbool.h”。里面定义了bool、true、false,让我们可以像C++一样的定义布尔类型。
布尔类型只有两个值false和true。布尔类型通常用来判断条件是否成立,如果变量值为0就为false,否则就为true。
1.自己定义的“仿布尔型”
在C99标准被支持之前,C语言常常自己模仿定义布尔型,方式有很多种,常见的有下面两种方法,例如:
第一种方法:
#define TRUE 1 #define FALSE 0
第二种方法:
enum bool { false, true };
2.bool类型的使用
使用bool来定义布尔型变量。bool类型长度为1,只能取值范围为0或1。将任意非零值赋值给bool类型,都会先转换为1,表示真。将零值赋值给bool类型,结果为0,表示假。
【例4-4】编写程序,使用bool来定义布尔型变量。bool类型长度为1,取值范围为0或1。(源代码\ch04\4-4)
运行上述程序,结果如图4-15所示。
图4-15 bool类型
【代码解析】
本例用于演示布尔类型的使用。首先定义一个布尔类型的变量a,通过scanf()函数输入一个值,而布尔类型的变量非零即为真,所以输入-2,最后输出的是1,并通过sizeof()函数测出布尔类型的变量的长度为1。
提示
bool在C语言里是占用1字节,而bool是int类型,int类型的大小是视具体环境而定的。