2.3 基本类型数据
2.3.1 整型数据
1.整型数据类型标识符
整型数据分为基本整型、短整型、长整型和无符号型4种。
① 基本整型(简称整型):类型标识符为int。
② 短整型:类型标识符为short int或short。
③ 长整型:类型标识符为1ong int或1ong。
④ 无符号型:表示不带符号的整数。
无符号型整数又可分为以下3种。
① 无符号整型:类型标识符为unsigned int。
② 无符号短整型:类型标识符为unsigned short。
③ 无符号长整型:类型标识符为unsigned 1ong。
C语言标准没有具体规定以上各类数据所占的内存字节数,不同C编译系统有不同的规定。表2.2所示为在VC++6.0编译环境中各种整型数据所占的内存字节数和取值范围。
表2.2 整型数据类型所占内存字节数和取值范围
在一个存储单元中存储一个有符号整数时,用最高位表示符号,最高位为0说明是正数,最高位为 1 说明是负数,其余二进制位表示数值,并且以二进制补码的形式表示。如果存储的是一个无符号整数,则所有二进制位都用来表示数值。例如:用两个字节存放一个短整型数时,假设两个字节的所有二进制位全部为1,如果说明为short类型,则它代表的是-1,如果说明为unsigned short类型,则它代表的是65535。
2.整型变量的定义
根据表2.2给出的整型数据类型标识符可以定义相应的整型变量。例如:
int i,j,k; /* 定义变量i,j,k为整型 */ unsigned short n,m; /* 定义变量n,m为无符号短整型 */ long p,l; /* 定义变量p,l为长整型 */
当按上述方法定义变量时,编译系统仅为所定义的变量分配了存储单元,而没有在存储单元中存放任何数据,此时的变量不能正确使用,因为变量中的值无意义。
C语言允许在定义变量的同时,对该变量预先设置初值,也称变量的初始化。例如:
int i1=6; /* 定义i1为整型变量并赋初值6 */
也可以为被定义变量的一部分赋初值,例如:
int i1,i2,i3=10;
定义i1、i2和i3为整型变量,并只对i3初始化,值为10。
如果对几个变量赋以同一个初值,不能写成:
int a=b=c=8;
而应写成:
int a=8,b=8,c=8;
3.整型常量
整型常量简称为整数或整常数。C语言程序中整型常量有以下3种表示形式。
① 十进制整数:按通常习惯的十进制整数形式表示,例如,102、-98、0等。
② 八进制整数:以数字0开头的八进制数符串,数字0是八进制整数的前缀,八进制数符为0~7。八进制数通常是无符号数。例如,025(表示十进制数21)、0400(表示十进制数256)。
③ 十六进制整数:以0x或0X开头的十六进制数符串,0x或0X是十六进制整数的前缀,十六进制数符为0~9和a~f(或A~F),其中a~f(或A~F)对应于十进制数10~15。十六进制数通常是无符号数。例如,0x14(表示十进制数20)、0xFFFF(表示十进制数65535)。
整型数又分为长整型数、短整型数和无符号整型数。长整型数在表示上与其他整型数的区别是加后缀L或l。所谓后缀是指在数字后面加写的字母,如1234L、0X2abL等。无符号数的后缀是U或u,如7543U、0125u等。前缀和后缀可同时使用以表示不同类型、不同进制的整型数。例如,03456LU表示八进制无符号长整型数。
在程序中出现的整数根据前缀来区分各种进制数,根据后缀来区分不同类型,因此在书写常数时不要把前缀和后缀弄错造成结果不正确。
2.3.2 实型数据
1.实型数据类型标识符
实型数据有单精度型和双精度型两种。
● 单精度型:类型标识符为float。
● 双精度型:类型标识符为double。
在VC++6.0中,实型数据占内存大小、取值范围和有效数据位数如表2.3所示。
表2.3 实型数据类型占内存大小、取值范围和有效数据位数
注意:在VC++6.0中,所有的float类型数据在运算中都自动转换成double型数据。
与整型数据的存储方式不同,实型数据是按照规范化的指数形式存储的。所谓规范化的指数形式是指其尾数部分为纯小数,即小数点前整数部分小于1,小数点后的第1位大于0。
2.实型变量的定义
根据表2.3给出的实型数据类型标识符可以定义相应的实型变量,并可在定义时赋初值。例如:
float f,f1=2.5; /* 定义f、f1为单精度实型变量,并为f1赋初值2.5 */ double d; /* 定义d为双精度实型变量 */
3.实型常量
实型常量即实数,又称浮点数。在C语言中实型数只有十进制形式,可以用十进制小数形式或十进制指数形式表示。
(1)十进制小数形式
一般由数字和小数点组成(必须有小数点,但小数点前后的 0 可以省略)。例如, 0.246,.246,246.0,246.,0.0等都是正确的小数表示形式。
(2)十进制指数形式
由尾数、字母e或E及指数部分组成。具体格式如下所示:
尾数e指数部分 或 尾数E指数部分
字母e或E左边部分的尾数可以是“整数部分.小数部分”形式,也可以只有整数部分不含小数点和小数部分,或者只有小数部分前面含有小数点而不含整数部分。指数部分必须为整数,可以是正的,也可以是负的。例如,下面指数形式都是正确的:
135e3 124e-2 -12.12e-5 .135E4 0e0
而下面的指数形式是错误的:
e2 3.5e1.5 .e e5 e
2.3.3 字符型数据
1.字符型数据类型标识符
字符型数据的类型标识符为char,在内存中存储一个字符型数据需要1个字节。
2.字符型变量的定义
使用字符型数据类型标识符char可以定义字符型变量,并可在定义时赋初值,例如:
char c1,c2='A'; /* 定义两个字符型变量c1、c2 ,并给c1赋初值'A' */
3.字符型常量
C语言中,一个字符型常量代表ASCII字符集中的一个字符。在C语言程序中字符型常量有以下两种形式。
① 用一对单引号(即撇号)括起来的单个字符。例如,'b'、'Y'、'9'、'('、'y' 等都是合法的字符型常量。
② 用一对单引号(即撇号)括起来的以一个反斜杠(\)开头的转义字符,形如'\n','\t'等,意思是将反斜杠(\)后面的字符转变成另外的意义。例如,'\n'不代表字母n而是作为换行符。像换行这种非显示字符难以用一般形式的字符表示,所以C语言规定用转义字符这种特殊形式表示。常见的以反斜杠(\)开头的转义字符见表2.4。
表2.4 转义字符表
单引号是字符型常量的定界符。注意,'Y'和'y'是不同的字符型常量。
表2.4中最后两行用ASCII码(八进制数或十六进制数)表示一个字符,即它将字符的ASCII码值转换为对应的字符。例如,'\103'代表字符C,'\012'代表换行,'\376'代表图形字符■。可见,使用表2.4中的表示方法可以表示任何可输出的字母字符、专用字符、图形字符和控制字符。请注意,'\0'或'\000'代表ASCII码为0的控制字符,即“空操作”字符,它可被用在字符串中。
【例2.2】 字符型常量的输出。
程序代码如下:
#include "stdio.h" main( ) { printf("Hello!\thow are you?\nI\'m fine!\n"); printf("This is a cup\b\b\bpen.\n"); printf("A,\101"); }
该程序中3次调用printf( )函数,直接输出双引号内的各个字符。请注意其中的转义字符。第1个printf( )函数先从第一行左端开始输出“Hello!”,然后遇到“\t”,它的作用是跳格,即跳到下一个输出位置,在所用系统中,一个输出区占8列。下一输出位置从第9列开始,故从第9列开始输出“how are you?”。下面遇到“\n”,代表回车换行,返回到下一行最左端(第1列),输出字符“I”,然后遇到“\'”,表示输出“'”,接着输出“m fine”。下面是“\n”,作用是“回车换行”,即光标被移到下一行第一个字符位置。
第2个printf( )函数先输出字符“This is a cup”,后面遇到3个“\b”,“\b”的作用是“退一格”,因此“\b\b\b”的作用是使当前输出位置回退3格到“c”的位置,接着输出“pen.”。最后是“\n”,即“回车换行”。
第3个printf( )函数先输出“A,”,然后遇到“\101”,它的作用是输出ASCII码(八进制数101)所对应的字符,即“A”字符。
程序运行后在显示屏上最后看到的结果是:
Hello! how are you? I'm fine! This is a pen. A,A
注意:第2次调用printf( )函数时,先输出“This is cup”,退3格后再输出“pen.”,“pen.”将取代原来的“cup”。程序执行时在屏幕上看不到“cup”。实际上,屏幕上完全按程序要求输出了全部的字符,只是因为在输出前面的字符后很快又输出后面的字符,在人们还未看清楚之前,新的字符已取代了旧的字符。
4.字符型数据在内存中的存储形式
字符型变量存放一个字符,实际上并不是把该字符本身存放到内存单元中去,而是将该字符的ASCII码(ASCII码对照表见附录C)存放到存储单元中。例如,字符'A'的ASCII码为65,'\n'的ASCII码为10,则程序段:
char c1,c2; c1='A';c2='\n';
执行后,在内存中变量c1和c2的值如图2.3所示。
图2.4 3 字符型数据的存储
因为在内存中,字符数据是以ASCII码的形式存储的,它的存储形式与整数的存储形式类似。因此,在C语言中,字符型数据可以与整型数据混合使用。C语言允许对整型变量赋予字符值,也允许对字符变量赋予整型值。一个字符型数据既可以以字符形式输出,也可以以整数形式输出。以字符形式输出时,需要先将存储单元中的ASCII码转换成相应的字符,然后输出。以整数形式输出时,直接将ASCII码作为整数输出,也可以对字符数据进行算术运算,此时相当于对它们的ASCII码进行算术运算。
【例2.3】 字符型数据的输出。
程序代码如下:
#include "stdio.h" main( ) { char c1; /* 定义c1为字符型变量 */ c1=65; printf("%c,%d\n",c1,c1); /* c1以字符型和整型两种格式输出 */ }
程序运行结果为:
A,65
该程序中c1被定义为字符变量。但在第5行中,将整数65赋给了c1,就是将整数65直接存放到c1的内存单元中。程序的第5行也可用以下语句等价代替:
c1='A';
该语句在执行时,系统首先要将字符'A'转换成其对应的 ASCII 码值 65,然后再存放到cl的内存单元中。二者作用是相同的。第6行将按字符型和整型两种格式输出变量c1的值。其中“%c”是输出字符的格式符。“%d”是输出整数的格式符。有关输出数据的格式符详见第3章。
注意:字符型数据只占一个字节,所以它只能存放0~255范围内的整数。C语言对字符型数据的这种处理增加了程序设计的自由度和灵活性。例如,实现英文字符的大小写转换、数字字符和数字的相互转换等就变得非常方便。
【例2.4】 编写程序实现英文字符的大小写转换。
分析:因为英文字母大小写之间的ASCII码值相差32(参见附录C),即a'-'A'=32,所以很容易通过C语言程序实现英文字符的大小写转换。
程序代码如下:
#include "stdio.h" main( ) { char c1; c1='a'; printf("%c,%c\n",c1,c1-32); }
程序运行结果如下:
a,A
【例2.5】 编写程序实现数字字符和数字的相互转换。
从附录C可以看出,数字字符0的ASCII码值为48,数字字符1~9的ASCII码值为49~57,可以很容易地实现数字字符和数字的相互转换。程序代码如下:
#include "stdio.h" main( ) { char c1,c2; c1='1'; c2=49; printf("%c,%c\n",c1,c2); c1=c1-'0'; c2=c2-'0'; printf("%d,%d\n",c1,c2); }
程序运行结果如下:
1,1 1,1
注意:程序运行后,第1条printf语句输出的是两个字符1,而第2条printf语句输出的则是两个数字1。请大家思考,如果把这两条语句互换位置,结果会是什么?
2.3.4 字符串常量
字符串常量是由一对双引号(" ")括起来的字符序列。双引号是字符串常量的定界符。在组成字符串的字符序列中若有双引号时应使用转义字符“\"”来表示。字符串的长度为字符序列中字符的个数,不包括两边的双引号。
例如:
"It is fine day." /* 长度为15 */ "12345678.09" /* 长度为11 */ "$10000.00" /* 长度为9 */ "" /* 引号中有一个空格,长度为1 */ "" /* 引号中什么也没有,长度为0 */ "a" /* 引号中有一个字符a,长度为1 */
因为字符串长度的不确定性,所以字符串常量在内存中存储时,系统自动在每个字符串常量的尾部加一个字符串结束标志字符“\0”(“\0”是一个ASCII码为0的“空操作”字符,它不引起任何控制动作,也不是一个可显示的字符),以便系统据此判断字符串是否结束。前面已提到,在内存中存储单个字符需要1个字节,因此,长度为n的字符串常量,在内存中要占用n+1个字节的存储空间,前n个字节存储组成字符串的n个字符,最后1个字节存储字符串结束标志“\0”。
例如,"hello"在内存中的存储形式是(字符对应的ASCII码值):
为了能直观理解,以后表示字符时,直接用字符本身表示,则上例表示成:
注意:字符串结束符'\0'是系统自动加上的。在输出一个字符串时,字符串结束符并不输出,例如:
printf("hello");
执行此语句时从左到右一个字符一个字符地输出,直到遇到最后的'\0'字符,表示字符串结束了,停止输出。另外,在书写字符串时也不必加'\0',否则就会画蛇添足。
了解了这一点,就可以理解字符串常量"b"和字符型常量'b'的区别了。
存储字符型常量'b'只需要1个字节:
存储字符串常量"b"需要2个字节:
在C语言中没有专门的字符串变量,如果希望将一个字符串存放在变量中,就要使用字符数组的概念,字符数组中的每一个数组元素存放一个字符。有关字符数组的知识详见第8章。