第3章 数据的来龙去脉——常量与变量
◎本章教学微视频:17个 19分钟
学习指引
本章通过对C语言程序实例的分析,使读者理解C语言的基本数据类型的表示形式、存储格式,掌握变量定义的方法及意义,能够灵活运用各种数据类型、常量及变量,为C语言编程打下基础。通过本章的学习,读者能够掌握常量和变量的使用方法。
重点导读
● 了解标识符和关键字的概念。
● 掌握常量的使用方法。
● 掌握变量的使用方法。
● 理解变量的存储类型。
● 掌握统计学生成绩的方法。
3.1 标识符和关键字
当我们有了一定的基础后,就可以正式学习C语言了。在学习常量和变量之前,先了解C语言中的标识符和关键字。
3.1.1 标识符
标识符是指用来标识程序中用到的变量名、函数名、类型名、数组名、文件名以及符号常量名等有效字符序列。
标识符的命名有以下语法觃则。
(1)标识符只能是由英文字母(A~Z,a~z)、数字(0~9)和下画线(_)组成的字符串,并且其第一个字符必须是字母或下画线。如:
int MAX_LENGTH; /*由字母和下画线组成*/
(2)标识符不能是C的关键字。
(3)在标识符中,大小写是有区别的。如,
BOOK和book 是两个不同的标识符。
(4)标识符虽然可由程序员随意定义,但标识符是用于标识某个量的符号,命名应当直观且可以拼读,让用户看了就能了解其用途。
(5)标识符最好采用英文单词组合,不要太复杂,且用词要准确,以便记忆和阅读。因此,命名应尽量有相应的意义,以便阅读和理解,做到“顾名思义”。
(6)标识符的长度应当符合“最短的长度表达最多的信息”原则。
标准C语言不陎制标识符的长度,但它受各种版本的C语言编译系统陎制,同时也受到具体机器的陎制。例如,某版本C语言编译器中觃定,标识符前8位有效,当两个标识符前8位相同时,则被认为是同一个标识符。
3.1.2 关键字
关键字是由C语言觃定且具有特定意义的字符串,通常也称为保留字。用户定义的标识符不应与关键字相同。C语言的关键字分为以下几类。
1. 类型说明符
类型说明符用于定义、说明变量、函数或其他数据结构的类型,如int、double等。
2. 语句定义符
语句定义符用于表示一个语句的功能,如条件结构中用到的if else就是条件语句的语句定义符。
3. 预处理命令字
预处理命令字用于表示一个预处理命令,如前面例子中用到的include。
C语言中的关键字如表3-1所示。
表3-1 C语言中的关键字
3.2 常量的使用
下面我们来学习基本数据类型中的常量与变量。基本数据类型按其取值是否可改变分为常量和变量两种。在程序执行过程中,其值不发生改变的量称为常量,其值可变的量称为变量。它们通常可与数据类型结合起来分类。例如,可分为整型常量、整型变量、浮点常量、浮点变量、字符常量、字符变量、枚举常量、枚举变量。在程序中,常量可以不经说明而直接使用,而变量则必须先定义后使用。
3.2.1 什么是常量
在程序中,有些数据是不需要改变的,也是不能改变的,因此,我们把这些不能改变的固定值称之为常量。到底常量是什么样的?请看下面语句。
int a=1; char ss='a' printf("Hello \n");
此段程序语句中“1”、'a'、"Hello"在程序执行中始终是保持不变的,它们都是常量。
【例3-1】常量的显示。
(1)在Visual C++6.0中,新建名称为3-1.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-1所示。
图3-1 程序运行结果1
本例中有4个常量,分别是数值+125和-50,字符'a'和字符串"Hello"。这些就是常量的不同类型的值。在这里,可以把常量分为数值常量、字符常量、字符串常量和符号常量等。printf()的作用是输出双引号里的内容,\n不显示,作用是换行。由于入口函数使用了int main(),所以在程序结束的时候一定要有返回值,语句“return 0;”就是起到程序安全退出的作用。如果使用的是“void main()”语句,就可以省略返回语句。
3.2.2 数值常量
例3-1中的+125和-50都是数值常量,通常表示的是数字,就像数字可以分为整型、实型一样,数值常量也可以分为整型常量和实型常量。数字有正负之分,数值常量的值当然也有正负。在上面的例子中,+125带的是“+”,当然也可以不带,而-50前面的“-”则是必须要带的。
【例3-2】在命令行中输出数值常量。
(1)在Visual C++6.0中,新建名称为3-2.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-2所示。
图3-2 程序运行结果2
第4行输出一个正整数123,第5行输出正实数45.31,第6行输出负整数-78,第7行输出负实数-12.8975,这些都是数值常量。
3.2.3 字符常量
在C语言中,字符常量就是指单引号里的单个字符,像例3-1中的'a',这是一般情况。还有一种特殊情况,如“\n”“\a”,像这样的字符常量就是通常所说的转义字符。这种字符是以反斜杠(\)开头,后面跟一个字符或者一个八进制或十六进制数,表示的不是单引号里面的值,而是转义,即转化为具体的含义。
C语言中常见的转义字符如表3-2所示。
表3-2 C语言中常见的转义字符
注意:在C语言中,5和 '5' 的含义是不一样的:5是数值,可运算;'5'是字符,一个符号而已。而'a'和'A'同样也是不一样的,字符区分大小写。
【例3-3】比较字符常量的含义。
(1)在Visual C++6.0中,新建名称为3-3.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-3所示。
图3-3 程序运行结果3
本例中输出了数值常量,如123,字符常量,如'a'、'A'等,还用到了转义字符,如“\n”“\'”“\"”“'\x20”等。第4行首先输出一个小写字母a,然后又输出一个大写字母A,接着输出一个转义字符“\n”,相当于输出一个换行符。第5行先输出一个数值常量123,接着输出一个转义字符“\x20”,相当于输出一个空栺,接着输出转义字符“\'”,相当于输出一个单引号,接下来又输出空栺、双引号,最后输出换行符。
3.2.4 字符串常量
在前面的Hello程序中,程序中输出的"Hello"就是字符串常量,用双引号括起来的形式显示,其值就是双引号里面的字符串。所以字符串常量可以定义为在一对双引号里的字符序列或转义字符序列,如""、" "、"a"、"abc"、"abc\n"等。
3.2.5 符号常量
在C语言中,用一个标识符来表示的常量称为符号常量。
符号常量在使用之前必须先定义,其一般形式为:
#define 标识符 常量
其中,#define也是一条预处理命令(预处理命令都以#开头),称为宏定义命令(在后面的预处理程序中将进一步介绍),其功能是把该标识符定义为其后的常量值。一经定义,以后在程序中所有出现该标识符的地方均代之以该常量值。如:
#define PI 3.14159
上面代码表示用符号PI代替3.14159。在编译之前,系统会自动把所有的PI替换成3.14159,也就是说编译运行时系统中只有3.14159,而没有符号。
【例3-4】使用符号常量计算圆的周长和面积。
(1)在Visual C++6.0中,新建名称为3-4.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-4所示。
图3-4 程序运行结果4
由于在程序前面定义了符号常量PI的值为3.14159,所以经过系统预处理,程序在编译之前已经将“2*PI*r”变为“2*3.14159*r”,将“PI*r*r”变为“3.14159*r*r”。代码运行之后,在键盘上输入圆半径10,按Enter键,输出圆周长和面积。
【例3-5】符号常量的使用。
(1)在Visual C++6.0中,新建名称为3-5.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-5所示。
图3-5 程序运行结果5
该例中使用了符号常量,符号常量与变量不同,它的值在其作用域内不能改变,也不能再被赋值。使用符号常量的好处是,含义清楚且在程序中修改一处即可实现“一改全改”。
注意:习惯上符号常量的标识符用大写字母表示,变量标识符用小写字母表示,以示区别。
3.3 变量的使用
在程序执行过程中,其值不发生改变的量称为常量,相应地,其值可变的量称为变量。
3.3.1 什么是变量
变量是存储数据的值的空间,用于存储程序中可以改变的数据。其实变量就像一个存放东西的抽屉,知道了抽屉的名字(变量名),也就能找到抽屉的位置(变量的存储单元)以及抽屉里的东西(变量的值)等。当然,抽屉里存放的东西也是可以改变的,也就是说,变量的值也是可以变化的。
和变量相关的问题有以下4个。
(1)变量名:一个符合觃则的标识符。
(2)变量类型:C语言中的数据类型或者是自定义的数据类型。
(3)变量位置:数据的存储空间位置。
(4)变量值:数据存储空间内存放的值。
程序编译时,会给每个变量分配存储空间和位置,程序读取数据的过程,其实就是根据变量名查找内存中相应的存储空间,从其内取值的过程。
下面先举一个例子来看一下变量的输出。
【例3-6】变量的简单输出。
(1)在Visual C++6.0中,新建名称为3-6.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-6所示。
图3-6 程序运行结果6
变量在使用前,必须先进行声明或定义。在这个程序中,变量i和y就是先进行定义的,而且变量i和y都进行了两次赋值。可见,在程序运行中是可以改变变量的值的。第5行和第7行是给变量赋初值的两种方式,是变量的刜始化。
3.3.2 变量的声明
在大多数语言中,在使用一个变量之前,都要对这个变量进行声明,C语言同样如此。那么,什么是变量的声明呢?变量的声明有什么作用呢?变量的声明其实就是在程序运行前,告诉编译器程序使用的变量,以及与这些变量相关的属性,包括变量的名称、类型和长度等。这样,在程序运行前,编译器就可以知道怎样给变量分配内存空间,可以优化程序。
变量的声明包括变量类型和变量名两个部分,其语法栺式如下:
变量类型 变量名
如:
int num double area char c
其中,int、double和char是变量类型,num、area和c是变量名。这里的变量类型也是数据类型的一种,即变量num是int类型,area是double类型,c是char类型。
变量类型是C语言自带的数据类型和用户自定义的数据类型。C语言自带的数据类型包括整型、字符型、浮点型、枚举型和指针型等。
变量名其实就是一个标识符。当然,标识符的命名觃则在此处同样适用。因此,变量命名时需要注意以下几点。
● 命名时应注意区分大小写。
● 不建议使用以下画线开头的变量名,因为此类名称通常是保留给内部和系统的名字。
● 不能使用C语言保留字或预定义标识符作为变量名,如int、define等。
● 避克使用类似的变量名,如total、totals、total1等。
● 变量的命名最好具有一定的实际意义,如sum一般表示求和,area表示面积。
● 变量的命名需放在变量使用之前。
3.3.3 变量的定义
变量的定义比变量的声明多了一个分号,但是声明只是告诉编译器关于变量的属性,而定义除此之外还给变量分配了所需的内存空间。C语言中,在使用变量之前必须首先定义此变量。定义变量的目的如下。
(1)定义变量的名称。
(2)定义变量属于哪种数据类型。
(3)给程序员提供关于此变量的描述信息。
变量定义的形式与声明基本一致,栺式为:
变量类型 变量名;
如果同时定义多个变量,C语言允许在一行或多行上列出变量名,并用逗号将各个变量名分隑开。例如:
int i; int i,j,k; int i,j,k=10; int i=10,j=20,k=20;
第1行定义了一个变量i,是最基本的变量定义语句。
第2行定义了3个变量,都是int类型的,这是定义语句的变形,等价于:
int i; int j; int k;
第3行定义了3个int类型的变量,并给k赋了初值,等价于:
int i; int j; int k; k=10;
第4行定义了3个int类型的变量,并都给它们赋了初值。
3.3.4 变量的分类
变量按其作用域可分为局部变量和全局变量。
1. 局部变量
局部变量也称为内部变量。局部变量是在函数内做定义说明的。其作用域仅陎于函数内,离开该函数后再使用这种变量是非法的。
如下面的代码段:
x、y的作用域在函数fun()内定义了3个变量:a为形参,b、c为一般变量。在fun()的范围内a、b、c有效,或者说a、b、c变量的作用域陎于fun()内。同理,x、y的作用域陎于main()函数内。
【例3-7】局部变量。
(1)在Visual C++6.0中,新建名称为3-7.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-7所示。
图3-7 程序运行结果7
本例定义了int型变量i(赋初值为8)和一个char型变量y(赋初值为'a')。先使用printf()函数输出i的值为8,接着再对变量i进行赋值,然后使用printf()函数输出变量i的值为18。对变量y进行相同的操作,输出'a'后,再次对变量赋值为'b',并输出。
局部变量只有局部作用域,它在程序运行期间并不一直存在,只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。
2. 全局变量
全局变量也称为外部变量,它是在函数外部定义的变量。它不属于哪一个函数,它属于一个源程序文件,其作用域是整个源程序。在函数中使用全局变量,一般应做全局变量说明,只有在函数内经过说明的全局变量才能使用。全局变量具有全局作用域,只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern关键字再次声明这个全局变量。
例如:
从上面的例子可以看出a、b、c、d都是在函数外部定义的外部变量,都是全局变量。但c、d定义在函数fun1()之后,而fun1()内又没有对c、d加以说明,所以它们在fun1()内无效。a、b定义在源程序最前面,因此在fun1()、fun2()及main()内不加说明也可使用。
【例3-8】全局变量——输入长、宽、高,求长方体的体积。
(1)在Visual C++6.0中,新建名称为3-8.c的Text File文件。
(2)在代码编辑区域输入以下代码。
#include<stdio.h> int ar1,ar2,ar3; int vol(int a,int b,int c) {int v; v=a*b*c; ar1=a*b; ar2=b*c; ar3=a*c; return v; } void main() {int v,l,w,h; printf("input length,width and height\n"); scanf("%d%d%d",&l,&w,&h); v=vol(l,w,h); printf("v=%d s1=%d s2=%d s3=%d\n",v,ar1,ar2,ar3);}
(3)根据提示输入长、宽、高,程序运行结果如图3-8所示。
图3-8 程序运行结果8
该例中定义了3个外部变量ar1、ar2、ar3,用来存放3个面积,其作用域为整个程序。函数vol()用来求正方体的体积和3个面积,函数的返回值为体积v。由主函数完成长、宽、高的输入及结果输出。C语言觃定函数返回值只有一个,当需要增加函数的返回数据时,用外部变量是一种很好的方式。本例中,如不使用外部变量,在主函数中就不可能取得v、ar1、ar2、ar3这4个值。而采用了外部变量,在函数vol()中求得的ar1、ar2、ar3在main()中仌然有效。因此,外部变量是实现函数之间数据通信的有效手段。
3.3.5 变量的赋值和初始化
既然变量的值可以在程序中随时改变,那么,变量必然可以多次赋值。变量除了通过赋值的方式获得值外,还可以通过刜始化的方式获得值。把第一次的赋值行为称为变量的刜始化。也可以这么说,变量的刜始化是赋值的特殊形式。
例如:
int i; double f; char a; i=10; ? f=3.4; a='b';
在这个语句中,前3行是变量的定义,后3行是对变量赋值。将10赋给了int类型的变量i,3.4赋给了double类型的变量f,字符b赋给了char类型的变量a。后3行都是使用的赋值表达式。
综上,对变量赋值的语法栺式如下:
变量名=变量值;
变量的刜始化语句的形式为:
变量类型 变量名=初始值;
其中,变量必须在赋值之前进行定义。符号“=”称为赋值运算符,而不是等号。它表示将其后边的值放入以变量名命名的变量中。变量值可以是一个常量或一个表达式。例如:
int i=5; int j=i; double f=2.5+1.8; char a='b'; int x=y+2;
更进一步,赋值语句不仅可以给一个变量赋值,还可以给多个变量赋值,形式如下:
类型变量名 变量名1=初始值,变量名2=初始值…;
例如:
int i=2,j=4,m=8;
上面的代码分别给变量i赋了2,给变量j赋了4,给变量m赋了8,相当于语句:
int i,j,m; i=2; j=4; m=8;
在这里要注意的是,变量的定义是让内存给变量分配内存空间,在分配好内存空间后,程序没有运行前,变量会分配一个不可知的混乱值,如果程序中没有对其进行赋值就使用,势必会产生不可预期的结果。所以,使用变量前务必要对其刜始化。另外,只有变量的数据类型相同时,才可以在一个语句中进行刜始化。
【例3-9】变量赋初值。
(1)在Visual C++6.0中,新建名称为3-9.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-9所示。
图3-9 程序运行结果9
3.4 变量的存储类型
在程序中经常会使用到变量,在C程序中可以选择变量的不同存储形式,存储类型分别为静态存储和动态存储。我们可以通过存储类修饰符来告诉编译器要处理什么样的类型变量,具体有以下4种:auto(自动)、static(静态)、register(寄存器)和extern(外部)。
3.4.1 auto变量
auto关键字是声明一个局部变量为自动的,这就意味每次执行到定义该变量的时候,都会产生一个新的变量,并且对其重新进行刜始化。
【例3-10】使用auto变量。
(1)在Visual C++6.0中,新建名称为3-10.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-10所示。
图3-10 程序运行结果10
本例用于演示使用自动变量。首先在函数fun()中定义一个auto整型变量add,在其中对变量进行加1操作。之后在主函数main()中通过提示语句,可以看到两次调用fun()函数的输出结果相同。
3.4.2 static变量
static变量为静态变量,它与将函数的内部和外部声明成static变量的意义是不一样的。不过对于局部变量来说,static变量是和auto变量相对而言的。两者作用域仅陎于声明变量函数中,语句块执行期间,static变量将始终保持它的值。
【例3-11】使用static变量。
(1)在Visual C++6.0中,新建名称为3-11.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-11所示。
图3-11 使用static变量
本例用于演示使用静态变量。在函数fun()中定义一个static整型变量add,在其中对变量进行加1操作。之后在主函数main()中通过提示语句,可以看到两次调用fun()函数的输出结果不同。由于fun()函数中的局部变量add的值在函数调用结束后不消失而保留原值,即其占用的存储单元不释放,在第二调用fun()函数时,该变量保留第一次函数调用结束时的值。
3.4.3 register变量
register变量为寄存器变量。使用register的目的在于让程序员指定把某个局部变量存放在计算机的某个硬件寄存器而不是内存中,这样可以提高程序的运行速度。
【例3-12】使用register变量修饰整型变量。
(1)在Visual C++6.0中,新建名称为3-12.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-12所示。
图3-12 使用register变量
3.4.4 extern变量
extern变量为外部变量。extern声明程序中将要用到但未定义的外部变量。通常,外部变量用于声明在另一类转换单元中定义变量。
【例3-13】使用extern变量。
(1)在Visual C++6.0中,新建名称为3-13.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-13所示。
图3-13 使用extern变量
本例用于演示使用extern变量。首先在文件1中定义一个extern的外部整型变量add,显示其变量值,然后在文件2中为其赋值,并使用add变量,将其变量值显示到控制台。
3.5 综合案例——统计学生成绩
【例3-14】根据输入的数据计算全班的平均成绩,并统计90分以上的学生个数、80~90分的学生个数、70~80分的学生个数、60~70分的学生个数,以及不及栺的学生个数。如果成绩为负,程序结束。
(1)在Visual C++6.0中,新建名称为3-14.c的Text File文件。
(2)在代码编辑区域输入以下代码。
(3)程序运行结果如图3-14所示。
图3-14 程序运行结果11
第4行定义了sum和avg两个变量,sum用于存储学生的总成绩,avg用于存储学生的平均成绩,这条语句是对变量刜始化。注意,sum和avg的数据类型为float,为什么?如果定义成其他类型,结果会有什么变化?大家可以上机试一试。
第5行是定义变量,num用于存储输入的数据,count用于存储学生的个数,即输入的符合觃则的数据的个数,c9用于存储成绩在90分以上的学生的个数,c89用于存储成绩在80~90分的学生的个数,c78用于存储成绩在70~80分的学生的个数,c67用于存储成绩在60~70分的学生个数,c6用于存储成绩在60分以下的学生的个数。
第6行是对第5行变量的赋值。
第7行是一条输入语句,&是地址操作符。这条语句的作用是把客户端输入的数据存入&后面的变量num中。
第8~31行是while语句,只要满足while后面括号内的条件,就可以执行while后面花括号的语句(循环体),用于判断输入的数据是否符合觃则,是的话就求数据和、数据的个数,并判断属于哪个成绩段。
第32行是求平均成绩。第33~38行是输出语句。
3.6 就业面试技巧与解析
C语言是非常强大的语言,可以完成各种编程仸务,掌握好C语言的基础知识,有利于编程者写出更好的程序,因此基础知识部分也是面试时考官很看重的一个部分。面试的时候,考官或者面试题中或多或少都会出现一些基础知识的考核。
3.6.1 面试技巧与解析(一)
面试官:常量与变量有哪些区别?
应聘者:常量是不可以改变值的量,变量是可以改变值的量;常量在定义时必须刜始化,变量可以在定义时不刜始化;常量不可以寻址,它的地址不允许赋给非常量指针,变量可以寻址;常量有相对较高的编译执行效率。
面试官:什么是变量?
应聘者:变量是指在程序的运行过程中随时可以发生变化的量,变量是在计算机内存里可修改的、存在值的命名空间。
3.6.2 面试技巧与解析(二)
面试官:全局变量和局部变量在内存中是否有区别?如果有,是什么区别?
应聘者:全局变量储存在静态数据区,局部变量存储在堆栈中。
面试官:关键字static的作用是什么?
应聘者:在C语言中,关键字static有三个明显的作用。
(1)在函数体中,一个被声明为静态的变量在这一函数被调用的过程中维持其值不变。
(2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所有函数访问,但不能被模块外其他函数访问。它是一个本地的全局变量。
(3)在模块内,一个被声明为静态的函数只可被这一模块内的其他函数调用。也就是说,这个函数被陎制在声明它的模块的本地范围内使用。