2.2 常量及常量的应用
在程序运行过程中其值不变的量叫做常量。常量在程序中主要作用是为变量赋值、构成表达式等,是数据在C语言中重要的组成形式。常量可分为整型常量、实型常量、浮点常量、字符常量等,不同的数据类型的常量有不同的书写规则。学习常量时,要注意其书写的形式及使用特点。
2.2.1 整型常量
整型数分为有符号和无符号两种。整型常量就是整常数,也具有有无符号之分。在C语言中,使用的整常数有八进制、十六进制和十进制三种。
1.十进制整常数
十进制整常数没有前缀,其数码为0~9。以下各数是合法的十进制整常数:
237,-568,65535,1627;
以下各数不是合法的十进制整常数:
023(不能有前导0),23D(含有非十进制数码)
在程序中是根据前缀来区分各种进制数的。因此在书写常数时不要把前缀弄错造成结果不正确。十进制可以表示带符号的数据。
2.八进制整常数
八进制整常数以0开头,即以0作为八进制数的前缀。数码取值为0~7。八进制数通常是无符号数。以下各数是合法的八进制数:
015(十进制为13),0101(十进制为65),0177777(十进制为65535)
以下各数不是合法的八进制数:
256(无前缀0),03A2(包含了非八进制数码),-0127(出现了负号)
注意
八进制整数是以0开头(不是英文字母O而是数字0)的数,在数学领域内0123和123表示两个值相同的整数,而在C语言中,0123表示八进制的123,它的十进制值是:1×82+2×81+3×80=64+16+3=83。但当程序的输出结果为八进制数时,前面的0消失。
在八进制中不允许出现8和9。
3.十六进制整常数
十六进制整常数的前缀为0X或0x。其数码取值为0~9,A~F或a~f(数据不区分大小写)。以下各数是合法的十六进制整常数:
0X2A(十进制为42),0XA0(十进制为160),0XFFFF(十进制为65535)
以下各数不是合法的十六进制整常数:
5A(无前缀0X),0X3H(含有非十六进制数码)
注意
大于9时可依次用a,b,c,d,e,f表示10,11,12,13,14,15;在程序中出现的十六进制数一定要以0x开头,但当程序输出结果为十六进制时,前面的0x消失。
在16位字长的机器上,基本整型的长度也为16位,因此表示的数的范围也是有限的。十进制无符号整常数的范围为0~65535,有符号数为-32768~+32767。八进制无符号数的表示范围为0~0177777。十六进制无符号数的表示范围为0X0~0XFFFF或0x0~0xFFFF。如果使用的数超过了上述范围,就需要加上后缀。
4.长整型常数的后缀表示
长整型数是用后缀“L”或“I”来表示的。例如三种不同数制的长整型常数如下。
十进制长整常数:
158L(十进制为158),358000L(十进制为358000)
八进制长整常数:
012L(十进制为10),077L(十进制为63),0200000L(十进制为65 536)
十六进制长整常数:
0X15L(十进制为21),0XA5L(十进制为165),0X10000L(十进制为65 536)
注意
长整数158L和基本整常数158在数值上并无区别。但158L因为是长整型量,C编译系统将为它分配4个字节的存储空间。而158因为是基本整型,只分配2个字节的存储空间。因此在运算和输出格式上要予以注意,避免出错。
5.无符号数的后缀表示
整常数的无符号型数是用后缀“U”或“u”来表示的。例如358u,0x38Au,0235Lu均为无符号数。前缀后缀可同时使用以表示各种类型的数。如0XA5Lu表示十六进制无符号长整数A5,其十进制为165。
代码2.3输出了常量1000和32 768。
代码2.3 常量的输出:fiIe3.c
#include "stdio.h" main() { int x; /*变量声明语句*/ long y; x=1000; /*将常量1000放到整型变量中存放*/ y=32768; /*将常量32 768放到长整型变量中存放*/ printf("\n x=%d\t",x); printf("y=%ld\n",y); /*分别输出整型变量和长整型变量*/ }
屏幕输出:
1000 32768
请大家思考:
◆ 若x和y均定义为Iong型,程序运行结果如何?
◆ 若x和y均定义为int型,程序运行结果如何?
2.2.2 实型常量
实型也称为浮点型,实型常量也称为实数或者浮点数。在C语言用的实型常量中,实数只采用十进制。它有两种形式:十进制小数形式和指数形式。
1.十进制小数形式
由数码0~ 9和小数点组成。
例如:0.0,3.14,0.618,.618,10.0和123.都是合法的小数表示形式,要求必须有小数点,并且小数点的前面或者后面必须有数字。
2.指数形式
由十进制数构成基数,加阶码标志“e”或“E”以及阶码组成(如图2.4所示)。用于表示数学中由基数*10阶码次幂的科学计数法。
图2.4 指数形式的十进制数构成
指数表示的常量在书写的时候,一定要注意:
◆ 字母E(或e)前可以是小数或整数,如果是纯小数,则可以将小数点之前的0省略,但是E(e)之前必须有数字。例如E2、e是不合法的指数形式。
◆ 字母E(或e)后必须为整数,不能出现小数的情况。例如1e2.5、1.2E8.9是不合法的指数形式。
一个实数有多种指数的表示形式,如果字母E(或e)前的基数表示为小数点前有且仅有一个数字,则称之为“规范化的指数形式”,其一般形式为:
m E n(m为十进制数,n为十进制整数)
其值为m*10n。
如:
2.1E5(等于2.1*105) 3.7E-2(等于3.7*10-2) 0.5E7(等于0.5*107) -2.8E-2(等于-2.8*10-2)
以下不是合法的实数:
345(无小数点) E7(阶码标志E之前无数字) -5(无阶码标志) 53.-E3(负号位置不对) 2.7E(无阶码)
标准C语言默认实型常量的数据类型为doubIe型,同样也允许浮点数后缀“f”或“F”即表示该数为fIoat型浮点数。若十进制整型数加上后缀“f”或“F”,则可变成实数,例如22f和22.是等价的。代码2.4说明了这种情况。
代码2.4 实数常量的表示:fiIe4.c
main(){ printf("%f\n ",22.); /*输出实型常量22.*/ printf("%f\n ",356f); /*单精度实型常量356f*/ }
程序运行的结果为:
22.000000 356.000000 /*默认的输出方式*/
2.2.3 字符常量
字符型数据在内存中是以字符的ASCII码形式存放的。字符型常量可以表示所有的字符,包括键盘上不可输入的字符和控制字符。字符常量的表示形式主要有普通的字符常量和转义字符两种表示形式。
1.普通字符常量
普通的字符常量是用单引号括起来的一个字符,例如'a'、'b'、'='、'+'、'?'都是合法字符常量。在C语言中,字符常量有以下特点:
◆ 字符常量只能用单引号括起来,不能用双引号或其他括号。
◆ 字符常量只能是单个字符,不能是多个字符。
◆ 字符可以是字符集中任意字符。但数字被定义为字符型之后就不能参与数值运算。如'5'和5是不同的,'5'是字符常量,不能参与数值运算。
2.转义字符
转义字符是一种特殊的字符常量。转义字符以反斜线“\”开头,后跟一个或几个字符。转义字符具有特定的含义,不同于字符原有的意义,所以称为“转义”字符。例如在前面各例题printf函数的格式串中用到的“\n”就是一个转义字符,其意义是“回车换行”。转义字符主要用来表示下列几种情况下的字符:
◆ 普通字符无法表示的字符。例如‘\\’,‘\’,等等,用普通的字符常量表示容易引起歧义。
◆ 用一般字符不便于表示的控制代码。例如回车、制表符等。
◆ 无法输入的字符。例如‘≥’、‘∩’,等等。
表2.2中的\ddd和\xhh正是为此而提出的。其中ddd和hh分别为八进制和十六进制的ASCII代码。如\101表示字母’A’,’\102’表示字母’B’,’\134’表示反斜线,’\XOA’表示换行等。
表2.2 常用的转义字符及其含义
代码2.5是一个转义字符的使用实例。
代码2.5 转义字符的使用:fiIe5.c
#include "stdio.h" main(){ int a,b,c; /*变量a,b,c*/ a=5; b=6; c=7; printf(" ab c\tde\n"); /*字符a,b,c及转义字符的输出*/ printf("hijk\tL\bM\n"); /*输出转义字符*/ printf("%d\t%d\t%d\n",a,b,c); /*输出整型数据a,b,c;*/ }
程序运行的结果为:
ab c de hijk M 5 6 7
程序在第一个输出语句中首先输出两个空格后输出字符'a'和'b'以及空格和字符'c'之后就是'\t'制表键,所以跳过一个输出区,一般每个输出区有8列,从第9列输出字符'd'和'e';接着是“\n”,于是跳到下一行行首输出下一行的内容。下一行开始输出字符'h'、'i'、'j'和'k'后'\t'跳到下一个输出区,输出字符'L',但下一转义字符'\b'又使得退回一格,所以在字符'L'位置输出字符'M',接着是'\n',则转到下一行行首,输出三个变量a,b,c的值5,6,7,中间间隔为'\t'制表键。从上面的例子中可以看出,要想使输出的结果美观大方,可以使用转义字符。
2.2.4 字符串常量
字符串常量是指用一对双引号括起来的若干个字符组成的序列。如"heIIo c","cworId@163.com","PROGRAME"和"Aa"等都是字符串常量。双引号中字符个数可以为0个、1个或多个,例如""、"a"等。若字符为空格,则为空格串,例如" "。
字符串常量在内存中存储时每一个字符占用一个字节。为了程序设计需要,在字符串的末尾要存储一个结束符,C语言规定结束符为字符'\0',字符'\0'是指ASCII码为0的字符,这个字符除了作为结束符没有其他意义。字符串必须有一个结束符,如果没有结束符,程序在输出时就不知到何处停止。字符串的双引号内的字符可以为普通的字符或转义字符。在使用中要注意字符串中转义字符的书写形式。例如下面的两个字符串:
"the current path is c:\tc>"和"please press the key "y" or "n""
在程序中应写成:
"the current path is c:\\tc>"和"please press the key \"y\" or \"n\""
字符串常量和字符常量是不同的量。它们之间主要有以下区别:
◆ 字符常量由单引号括起来,字符串常量由双引号括起来。
◆ 字符常量只能是单个字符,字符串常量则可以含一个或多个字符。
◆ 可以把一个字符常量赋予一个字符变量,但不能把一个字符串常量赋予一个字符变量。在C语言中没有相应的字符串变量。但是可以用一个字符数组来存放一个字符串常量,在数组一章内将予以介绍。
◆ 字符常量占一个字节的内存空间,字符串常量占的内存字节数等于字符串中的字符数加1。增加的一个字节中存放字符"\0" (ASCII码为0),这是字符串结束的标志。
例如字符串"heIIo c" 在内存中所占的字节为:
字符常量'A'和字符串常量"A"虽然都只有一个字符,但在内存中的情况是不同的。
'A'在内存中占一个字节,可表示为:
"A"在内存中占二个字节,应表示为:
2.2.5 常量使用时的错误分析
开始使用常量的时候,不可避免会产生一些简单的常见错误。当遇见错误时,要仔细分析出错的原因,找出解决方法。常量主要的作用是为变量赋值,所以一定要注意书写的形式要正确。接下来便分析各常量使用不成功的实例及其解决方法。代码2.6是一个错误书写常量的例子。
代码2.6 常量的错误书写形式:fiIe6.c
#include <stdio.h> main() { int m,n; char c; m=0238; /*错误代码*/ n=0x5aL; /*错误代码*/ c="a"; printf("%d,%d",m,n); }
编译时错误提示:
Illegal octal digit in function main Non-portable pointer assignment in function main
整型常量的表示形式有十进制、八进制、十六进制三种,使用时一定要注意这三种常量的书写形式。上例的错误很明显,对变量m赋值常量的书写形式为八进制,组成数字非法,使用时改正即可。对变量n赋值常量的书写形式为十六进制的长整型,而变量n为普通整型,提出警告错误,使用时引起注意。
C语言中无字符串变量,对字符串无法赋值,所以对变量c的赋值是错误的。代码2.7是一个错误的对符号常量赋值的例子。
代码2.7 对符号常量错误赋值:fiIe7.c
#define Rate 10.5 /*宏常量定义*/ main() /*利用常量计算数据的值*/ { float pay; pay=35*Rate*5; /*计算*/ printf("\n pay %f\n",pay); Rate=11; /*错误代码*/ pay=35*Rate*5; printf("\n new pay %f\n",pay);}
编译时错误提示:
Lvalue required in function main
符号常量在程序中不可被重新赋值,否则程序出错。对于语句“Rate=11;”的书写是错误的,使用时要使用其他的方案来解决这个问题,不可直接更改常量的值。
在程序中要注意有些符号是要成对出现的,这一点是初学者最容易忽视的问题了。代码2.8是一个符号不配对的例子。
代码2.8 忽略符号成对出现:fiIe8.c
#include "stdio.h" #define PI 3.14 main() { double radius; scanf("%f",&radius); /*input the radius/* printf("print the area in screen\n"); printf("the area is %f,PI*radius*radius); }
编译时错误:
Unexpected end of file in comment started on line Compound statement missing ) in function main
根据给出的编译提示,本程序存在两处错误,但是这两处错误需要用心寻找原因。首先一处是程序中第二行的注释/*与*/应该为成对出现的,而后面的结束符书写有错误。这一点是初学者不易发现的错误,而编译系统也不能准确地分析出,它会把以后的程序语句处理成注释部分。第二个错误是丢失了第二个输出语句的右双引号,这样编译系统会把以后的部分处理成串,导致找不到主函数的右花括号。