C程序设计语言(完美中文版).pdf

上传人:qwe****56 文档编号:70344216 上传时间:2023-01-19 格式:PDF 页数:246 大小:1.78MB
返回 下载 相关 举报
C程序设计语言(完美中文版).pdf_第1页
第1页 / 共246页
C程序设计语言(完美中文版).pdf_第2页
第2页 / 共246页
点击查看更多>>
资源描述

《C程序设计语言(完美中文版).pdf》由会员分享,可在线阅读,更多相关《C程序设计语言(完美中文版).pdf(246页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、本章首先对C语言做简要介绍。目的是通过实际的程序向读者介绍C语言的本质要素,而不是一下子就陷入到具体细节、规则及例外情况中去。因此,在这里我们并不想完整地或很精确地对C语言进行介绍(但所举例子都是正确的)。我们想尽可能快地让读者学会编写有用的程序,因此,重点介绍其基本概念:变量与常量、算术运算、控制流、函数、基本输入输出。本章并不讨论那些编写较大的程序所需要的重要特性,包括指针、结构、大多数运算符、部分控制流语句以及标准库。这样做也有缺陷,其中最大的不足之处是在这里找不到对任何特定语言特性的完整描述,并且,由于太简略,也可能会使读者产生误解。而且,由于所举的例子没有用到C语言的所有特性,故这些

2、例子可能并未达到简明优美的程度。我们已尽力缩小这种差异。另一个不足之处是,本章所讲过的某些内容在后续有关章节还必须重复介绍。我们希望这种重复带给读者的帮助会胜过烦恼。无论如何,经验丰富的程序员应能从本章所介绍的有关材料中推断他们在程序设计中需要的东西。初学者则应编写类似的小程序来充实它。这两种人都可以把本章当作了解后续各章的详细内容的框架。1.1 入门学习新的程序设计语言的最佳途径是编写程序。对于所有语言,编写的第一个程序都是相同的:打印如下单词:hello,world在初学语言时这是一个很大的障碍,要越过这个障碍,首先必须建立程序文本,然后成功地对它进行编译,并装入、运行,最后再看看所产生的

3、输出。只要把这些操作细节掌握了,其他内容就比较容易了。在C语言中,用如下程序打印“hello,world”:#include main()printf(hello,worldn);C第1章基 本 概 念更多免费资源:第 1 页至于如何运行这个程序取决于使用的系统。作为一个特殊的例子,在U N I X操作系统中,必须首先在某个以“.c”作为扩展名的文件中建立起这个程序,如h e l l o.c,然后再用如下命令编译它:cc hello.c如果在输入上述程序时没有出现错误(例如没有漏掉字符或错拼字符),那么编译程序将往下执行并产生一个可执行文件a.o u t。如果输入命令a.out运行a.o u

4、t程序,则系统将打印hello,world在其他操作系统上操作步骤会有所不同,读者可向身边的专家请教。#include 包含有关标准库的信息main()定义名为main的函数,它不接收变元值 main的语句括在花括号中printf(hello,worldn);main函数调用库函数printf可打印字符序列,n代表换行符下面对这个程序本身做一些解释说明。每一个 C程序,不论大小如何,都由函数和变量组成。函数中包含若干用于指定所要做的计算操作的语句,而变量则用于在计算过程中存储有关值。C中的函数类似于F O RT R A N语言中的子程序与函数或 P a s c a l语言中的过程与函数。在本例

5、中,函数的名字为m a i n。一般而言,可以给函数任意命名,但 m a i n是一个特殊的函数名,每一个程序都从名为m a i n的函数的起点开始执行。这意味着每一个程序都必须包含一个 m a i n函数。m a i n函数通常要调用其他函数来协助其完成某些工作,调用的函数有些是程序人员自己编写的,有些则由系统函数库提供。上述程序的第一行#include 用于告诉编译程序在本程序中包含标准输入输出库的有关信息。许多 C源程序的开始处都包含这一行。我们将在第7章和附录B 中对标准库进行详细介绍。在函数之间进行数据通信的一种方法是让调用函数向被调用函数提供一串叫做变元的值。函数名后面的一对圆括号

6、用于把这一串变元(变元表)括起来。在本例子中,所定义的m a i n函数不要求任何变元,故用空变元表()表示。函数中的语句用一对花括号 括起来。本例中的m a i n函数只包含一个语句:printf(hello,worldn);当要调用一个函数时,先要给出这个函数的名字,再紧跟用一对圆括号括住的变元表。上面这个语句就是用变元 hello,worldn 来调用函数p r i n t f。p r i n t f是一个用于打印输出的库函数,在本例中,它用于打印用引号括住的字符串。用双引号括住的字符序列叫做字符串或字符串常量,如 hello,worldn就是一个字符串。目前仅使用字符串作为p r i

7、n t f及其他函数的变元。在C语言中,字符序列 n表示换行符,在打印时它用于指示从下一行的左边换行打印。如果在字符串中遗漏了 n(一个值得做的试验),那么输出打印完后没有换行。在 p r i n t f函数的变元中必须用 n引入换行符,如果用程序中的换行来代替 n,如:printf(hello,world更多免费资源:第 2 页);那么C编译器将会产生一个错误信息。p r i n t f函数永远不会自动换行,我们可以多次调用这个函数来分阶段打印一输出行。上面给出的第一个程序也可以写成如下形式:#include main()printf(hello,);printf(world);printf

8、(n);它所产生的输出与前面一样。请注意,n只表示一个字符。诸如 n等换码序列为表示不能打印或不可见字符提供了一种通用可扩充机制。除此之外,C语言提供的换码序列还有:表示制表符的 t,表示回退符的 b,表示双引号的 ,表示反斜杠符本身的 。2.3节将给出换码序列的完整列表。练习1-1 请读者在自己的系统上运行“hello,world”程序。再做个实验,让程序中遗漏一些部分,看看会出现什么错误信息。练习1-2 做个实验,观察一下当p r i n t f函数的变元字符串中包含 c(其中c是上面未列出的某个字符)时会出现什么情况。1.2 变量与算术表达式下面的程序用公式C=(5/9)(F-3 2)打

9、印华氏温度与摄氏温度对照表:0-1720-640460158026100371204814060160711808220093220104240115260126280137更多免费资源:第 3 页300148这个程序本身仍只由一个名为 m a i n的函数的定义组成,它要比前面用于打印“hello,world”的程序长,但并不复杂。这个程序中引入了一些新的概念,包括注解、说明、变量、算术表达式、循环以及格式输出。该程序如下:#include/*对 fahr=0,20,.,300 打印华氏温度与摄氏温度对照表*/main()int fahr,celsius;int lower,upper,st

10、ep;lower=0;/*温度表的下限*/upper=300;/*温度表的上限*/step =20;/*步长*/fahr=lower;while (fahr=upper)celsius=5*(fahr-32)/9;printf(%dt%dn,fahr,celsius);fahr=fahr+step;其中的两行/*对fahr=0,20,.,300 打印华氏温度与摄氏温度对照表*/叫做注解,用于解释该程序是做什么的。夹在/*与*/之间的字符序列在编译时被忽略掉,它们可以在程序中自由地使用,目的是为了使程序更易于理解。注解可以出现在任何空格、制表符或换行符可以出现的地方。在C语言中,所有变量都必须先

11、说明后使用,说明通常放在函数开始处的可执行语句之前。说明用于声明变量的性质,它由一个类型名与若干所要说明的变量组成,例如int fahr,celsius;int lower,upper,step;其中,类型i n t表示所列变量为整数变量,与之相对,f l o a t表示所列变量为浮点变量(浮点数可以有小数部分)。i n t与f l o a t类型的取值范围取决于所使用的机器。对于 i n t类型,通常为1 6位(取值在-32768 +32767之间),也有用3 2位表示的。f l o a t类型一般都是3 2位,它至少有6位有效数字,取值范围一般在1 0-3 81 0+3 8之间。除i n

12、t与f l o a t之外,C语言还提供了其他一些基本数据类型,包括:c h a r字符单字节s h o r t短整数更多免费资源:第 4 页l o n g长整数d o u b l e双精度浮点数这些数据类型对象的大小也取决于机器。另外,还有由这些基本类型组成的数组、结构与联合类型、指向这些类型的指针类型以及返回这些类型的函数,我们将在后面适当的章节再分别介绍它们。上面温度转换程序计算以4个赋值语句lower=0;upper=300;step =20;fahr=lower;开始,用于为变量设置初值。各个语句均以分号结束。温度转换表中的每一行均以相同的方式计算,故可以用循环语句来重复产生各行输出

13、,每行重复一次。这就是w h i l e循环语句的用途:while (fahr=upper).w h i l e循环语句的执行步骤如下:首先测试圆括号中的条件。如果条件为真(f a h r小于等于u p p e r),则执行循环体(括在花括号中的三个语句)。然后再重新测试该条件,如果为真,则再次执行该循环体。当该条件测试为假(f a h r大于u p p e r)时,循环结束,继续执行跟在该循环语句之后的下一个语句。在本程序中,循环语句后再没有其他语句,因此整个程序终止执行。w h i l e语句的循环体可以是用花括号括住的一个或多个语句(如上面的温度转换程序),也可以是不用花括号括住的单个语

14、句,例如:while (i j)i=2*i;在这两种情况下,我们总是把由w h i l e控制的语句向里缩入一个制表位(在书中以四个空格表示),这样就可以很容易地看出循环语句中包含那些语句。这种缩进方式强化了程序的逻辑结构。尽管C编译程序并不关心程序的具体形式,但使程序在适当位置采用缩进空格的风格对于使程序更易于为人们阅读是很重要的。我们建议每行只写一个语句,并在运算符两边各放一个空格字符以使运算组合更清楚。花括号的位置不太重要,尽管每个人都有他所喜爱的风格。我们从一些比较流行的风格中选择了一种。读者可以选择自己所合适的风格并一直使用它。绝大多数任务都是在循环体中做的。循环体中的赋值语句cel

15、sius=5*(fahr-32)/9;用于求与指定华氏温度所对应的摄氏温度值并将值赋给变量 c e l s i u s。在该语句中,之所以把表达式写成先乘5然后再除以9而不直接写成5/9,是因为在C语言及其他许多语言中,整数除法要进行截取:结果中的小数部分被丢弃。由于 5和9都是整数,5/9相除后所截取得的结果为0,故这样所求得的所有摄氏温度都变成0。这个例子也对p r i n t f函数的工作功能做了更多的介绍。p r i n t f是一个通用输出格式化函数,第7章将对此做详细介绍。该函数的第一个变元是要打印的字符串,其中百分号(%)指示用其他更多免费资源:第 5 页变元(第2、第3个变元)

16、之一对其进行替换,以及打印变元的格式。例如,%d指定一个整数变元,语句printf(%dt%dn,fahr,celsius);用于打印两个整数f a h r与c e l s i u s值并在两者之间空一个制表位(t)。p r i n t f函数第1个变元中的各个%分别对应于第2个、第3个 第n个变元,它们在数目和类型上都必须匹配,否则将出现错误。顺便指出,p r i n t f函数并不是 C语言本身的一部分,C语言本身没有定义输入输出功能。p r i n t f是标准库函数中一个有用的函数,标准库函数一般在 C程序中都可以使用。A N S I标准中定义了p r i n t f函数的行为,从而其

17、性质在使用每一个符合标准的编译程序与库中都是相同的。为了集中讨论C语言本身,在第 7章之前的各章中不再对输入输出做更多的介绍,特别是把格式输入延后到第7章。如果读者想要了解数据输入,请先阅读 7.4节对s c a n f函数的讨论。s c a n f函数类似于p r i n t f函数,只不过它是用于读输入数据而不是写输出数据。上面这个温度转换程序存在着两个问题。比较简单的一个问题是,由于所输出的数不是右对齐的,输出显得不是特别好看。这个问题比较容易解决:只要在 p r i n t f语句的第1个变元的%d中指明打印长度,则打印的数字会在打印区域内右对齐。例如,可以用printf(%3d%6d

18、n,fahr,celsius);打印f a h r与c e l s i u s的值,使得f a h r的值占3个数字宽、c e l s i u s的值占6个数字宽,如下所示:0-1720-64046015802610037另一个较为严重的问题是,由于使用的是整数算术运算,故所求得的摄氏温度不很精确,例如,与0 F 对应的精确的摄氏温度为-1 7.8,而不是-1 7。为了得到更精确的答案,应该用浮点算术运算来代替上面的整数算术运算。这就要求对程序做适当修改。下面给出这个程序的第2个版本:#include/*对fahr=0,20,.,300打印华氏温度与摄氏温度对照表;浮点数版本*/main()f

19、loat fahr,celsius;int lower,upper,step;lower=0;/*温度表的下限*/upper=300;/*温度表的上限*/step =20;/*步长*/更多免费资源:第 6 页fahr=lower;while (fahr=upper)celsius=(5.0/9.0)*(fahr-32.0);printf(%3.0f%6.1fn,fahr,celsius);fahr=fahr+step;这个版本与前一个版本基本相同,只是把 f a h r与c e l s i u s说明成f l o a t浮点类型,转换公式的表达也更自然。在前一个版本中,之所以不用5/9是因为按

20、整数除法它们相除截取的结果为 0。然而,在此版本中5.0/9.0是两个浮点数相除,不需要截取。如果某个算术运算符的运算分量均为整数类型,那么就执行整数运算。然而,如果某个算术运算符有一个浮点运算分量和一个整数运算分量,那么这个整数运算分量在开始运算之前会被转换成浮点类型。例如,对于表达式 fahr-3 2,3 2在运算过程中将被自动转换成浮点数再参与运算。不过,在写浮点常量时最好还是把它写成带小数点,即使该浮点常量取的是整数值,因为这样可以强调其浮点性质,便于人们阅读。第2章将详细介绍把整型数转换成浮点数的规则。现在请注意,赋值语句fahr=lower;与条件测试while(fahr=uppe

21、r)也都是以自然的方式执行在运算之前先把i n t转换成f l o a t。p r i n t f中的转换说明%3.0 f表明要打印的浮点数(即 f a h r)至少占3个字符宽,不带小数点与小数部分。%6.1 f表示另一个要打印的数(c e l s i u s)至少有6个字符宽,包括小数点和小数点后 1位数字。输出类似于如下形式:0-17.820-6.7404.4在格式说明中可以省去宽度(%与小数点之间的数)与精度(小数点与字母f之间的数)。例如,%6 f的意思是要打印的数至少有 6个字符宽;%.2 f说明要打印的数在小数点后有两位小数,但整个数的宽度不受限制;%f的意思仅仅是要打印的数为浮

22、点数。%d打印十进制整数%6 d打印十进制整数,至少6个字符宽%f打印浮点数%6 f打印浮点数,至少6个字符宽%.2 f打印浮点数,小数点后有两位小数%6.2 f打印浮点数,至少6个字符宽,小数点后有两位小数此外,p r i n t f函数还可以识别如下格式说明:表示八进制数的%o、表示十六进制数的%x、表示字符的%c、表示字符串的%s以及表示百分号%本身的%。更多免费资源:第 7 页练习1-3修改温度转换程序,使之在转换表之上打印一个标题。练习1-4编写一个用于打印摄氏与华氏温度对照表的程序。1.3 for语句对于一个特定任务,可以用多种方法来编写程序。下面是前面讲述的温度转换程序的一个变种

23、:#include/*打印华氏与摄氏温度对照表*/main()int fahr;for(fahr=0;fahr=300;fahr=fahr+20)printf(%3d#%6.1fn,fahr,(5.0/9.0)*(fahr-32);这个版本与前一个版本执行的结果相同,但看起来有些不同。一个主要的变化是它删去了大部分变量,只留下了一个 f a h r,其类型为i n t。本来用变量表示的下限、上限与步长都在新引入的f o r语句中作为常量出现,用于求摄氏温度的表达式现在已变成了 p r i n t f函数的第3个变元,而不再是一个独立的赋值语句。这最后一点变化说明了一个通用规则:在所有可以使用某

24、个类型的变量的值的地方,都可以使用该类型的更复杂的表达式。由于 p r i n t f函数的第3个变元必须为与%6.1 f匹配的浮点值,则可以在这里使用任何浮点表达式。f o r语句是一种循环语句,是w h i l e语句的推广。如果将其与前面介绍的 w h i l e语句比较,就会发现其操作要更清楚一些。在圆括号内共包含三个部分,它们之间用分号隔开。第一部分fahr=0是初始化部分,仅在进入循环前执行一次。第二部分是用于控制循环的条件测试部分:fahr=300这个条件要进行求值。如果所求得的值为真,那么就执行循环体(本例循环体中只包含一个p r i n t f函数调用语句)。然后再执行第三部

25、分fahr=fahr+20加步长,并再次对条件求值。一旦求得的条件值为假,那么就终止循环的执行。像 w h i l e语句一样,f o r循环语句的体可以是单个语句,也可以是用花括号括住的一组语句。初始化部分(第一部分)、条件部分(第二部分)与加步长部分(第三部分)均可以是任何表达式。至于在w h i l e与f o r这两个循环语句中使用哪一个,这是随意的,主要看使用哪一个更能清楚地描述问题。f o r语句比较适合描述这样的循环:初值和增量都是单个语句并且是逻辑相关的,因为f o r语句把循环控制语句放在一起,比 w h i l e语句更紧凑。更多免费资源:第 8 页练习1-5 修改温度转换

26、程序,要求以逆序打印温度转换表,即从 3 0 0度到0度。1.4 符号常量在结束对温度转换程序的讨论之前,再来看看符号常量。把 3 0 0、2 0等“幻数”埋在程序中并不是一种好的习惯,这些数几乎没有向以后可能要阅读该程序的人提供什么信息,而且使程序的修改变得困难。处理这种幻数的一种方法是赋予它们有意义的名字。#d e f i n e指令就用于把符号名字(或称为符号常量)定义为一特定的字符串:#define 名字替换文本此后,所有在程序中出现的在#d e f i n e中定义的名字,该名字既没有用引号括起来,也不是其他名字的一部分,都用所对应的替换文本替换。这里的名字与普通变量名有相同的形式:

27、它们都是以字母打头的字母或数字序列。替换文本可以是任何字符序列,而不仅限于数。#include#define LOWER 0 /*表的下限*/#define UPPER 300 /*表的上限*/#define STEP 20 /*步长*/*打印华氏-摄氏温度对照表*/main()int fahr;for (fahr=LOWER;fahr=UPPER;fahr=fahr+STEP)printf(%3d%6.1fn,fahr,(5.0/9.0)*(fahr-32);L O W E R、U P P E R与S T E P等几个量是符号常量,而不是变量,故不需要出现在说明中。符号常量名通常用大写字母拼

28、写,这样就可以很容易与用小写字母拼写的变量名相区别。注意,#d e f i n e指令行的末尾没有分号。1.5 字符输入输出接下来讨论一些与字符数据处理有关的程序。读者将会发现,许多程序只不过是这里所讨论的程序原型的扩充版本。由标准库提供的输入输出模型非常简单。文本的输入输出都是作为字符流处理的,不管它从何处输入、输出到何处。文本流是由一行行字符组成的字符序列,而每一行字符则由 0个或多个字符组成,并后跟一个换行符。标准库有责任使每一输入输出流符合这一模型,使用标准库的C程序员不必担心各字符行在程序外面怎么表示。标准库中有几个函数用于控制一次读写一个字符,其中最简单的是 g e t c h a

29、 r和p u t c h a r这两个函数。g e t c h a r函数在被调用时从文本流中读入下一个输入字符并将其作为结果值返回。即,在执行c=getchar()之后,变量c中包含了输入流中的下一个字符。这种输入字符通常是从键盘输入的。关于从文件更多免费资源:第 9 页输入字符的方法将在第7章讨论。p u t c h a r函数在调用时将打印一个字符。例如,函数putchar(c)用于把整数变量c的内容作为一个字符打印,它通常是显示在屏幕上。p u t c h a r与p r i n t f这两个函数可以交替调用,输出的次序即调用的次序。1.5.1 文件复制借助g e t c h a r与

30、p u t c h a r函数,可以在不掌握其他输入输出知识的情况下编写出许多有用的代码。最简单的程序是一次一个字符地把输入复制到输出,其基本思想如下:读一个字符while(该字符不是文件结束指示符)输出刚读进的字符读下一个字符下面是其C程序:#include /*用于将输入复制到输出的程序;第1个版本*/main()int c;c=getchar();while(c!=EOF)putchar(c);c=getchar();其中的关系运算符!=的意思是“不等于”。像其他许多东西一样,一个字符不论在键盘或屏幕上以什么形式出现,在机器内部都是以位模式存储的。c h a r类型就是专门用于存储这种字

31、符数据的类型,当然任何整数类型也可以用于存储字符数据。由于某种微妙却很重要的理由,此处使用了 i n t类型。需要解决的问题是如何将文件中的有效数据与文件结束标记区分开来。C语言采取的解决方法是,g e t c h a r函数在没有输入时返回一个特殊值,这个特殊值不能与任何实际字符相混淆。这个值叫做E O F(end of file,文件结束)。必须把c说明成一个大到足以存放 g e t c h a r函数可能返回的各种值的类型。之所以不把 c说明成c h a r类型,是因为c必须大到除了能存储任何可能的字符外还要能存储文件结束符E O F。因此,把c说明成i n t类型的。E O F是一个在

32、库中定义的整数,但其具体的数值是什么并不重要,只要知道它与c h a r类型的所有值都不相同就行了。可以通过使用符号常量来保证 E O F在程序中不依赖于特定的数值。对于经验比较丰富的C程序员,可以把字符复制程序编写得更精致些。在 C语言中,诸如更多免费资源:第 10 页c=getchar()之类的赋值操作是一个表达式,因而就有一个值,即赋值后位于=左边变量的值。换言之,赋值可以作为更大的表达式的一部分出现。可以把将字符赋给 c的赋值操作放在w h i l e循环语句的测试部分中,即可以将上面的字符复制程序改写成如下形式:#include /*用于将输入复制到输出的程序;第2 个版本*/mai

33、n()int c;while(c=getchar()!=EOF)putchar(c);在这一程序中,w h i l e循环语句先读一个字符并将其赋给 c,然后测试该字符是否为文件结束标记。如果该字符不是文件结束标记,那么就执行 w h i l e语句体,把该字符打印出来。再重复执行该w h i l e语句。当最后到达输入结束位置时,w h i l e循环语句终止执行,从而整个 m a i n程序执行结束。这个版本的特点是将输入集中处理只调用了一次g e t c h a r函数这样使整个程序的规模有所缩短,所得到的程序更紧凑,从风格上讲,程序更易阅读。读者将会不断地看到这种风格。(然而,如果再往

34、前走,所编写出的程序可能很难理解,我们将对这种趋势进行遏制。)在w h i l e条件中用于括住赋值表达式的圆括号不能省略。不等运算符!=的优先级要比赋值运算符=的优先级高,这就是说,在不使用圆括号时关系测试!=将在赋值=之前执行。故语句c=getchar()!=EOF等价于c=(getchar()!=EOF)这个语句的作用是把c的值置为0或1(取决于g e t c h a r函数在调用执行时所读的数据是否为文件结束标记),这并不是我们所希望的结果。(有关这方面的更多的内容将在第 2章介绍。)练习1-6验证表达式getchar()!=EOF的值是0还是1。练习1-7编写一个用于打印E O F值

35、的程序。1.5.2 字符计数下面这个程序用于对字符计数,与上面的文件复制程序类似:#include /*统计输入的字符数;第1 个版本*/main()long nc;更多免费资源:第 11 页nc=0;while(getchar()!=EOF)+nc;printf(%ldn,nc);其中的语句+nc;引入了一个新的运算符+,其功能是加1。可以用nc=nc+1;来代替它,但+n c比之要更精致,通常效率也更高。与该运算符相对应的还有一个减一运算符-。+与-这两个运算符既可以作为前缀运算符(如+n c),也可以作为后缀运算符(如n c+)。正如第2章将要指出的,这两种形式在表达式中有不同的值,但+

36、n c与n c+都使n c的值加1。我们暂时只使用前缀形式。这个字符计数程序没有用 i n t类型的变量而是用 l o n g类型的变量来存放计数值。l o n g整数(长整数)至少要占用3 2位存储单元。尽管在某些机器上 i n t与l o n g类型的值具有同样大小,但在其他机器上i n t类型的值可能只有1 6位存储单元(最大取值32 767),相当小的输入都可能使i n t类型的计数变量溢出。转换说明%l d用来告诉p r i n t f函数对应的变元是l o n g整数类型。如果使用d o u b l e(双精度浮点数)类型,那么可以统计更多的字符。下面不再用 w h i l e循环

37、语句而用f o r循环语句来说明编写循环的另一种方法:#include /*统计输入的字符数;第2 个版本*/main()double nc;for(nc=0;getchar()!=EOF;+nc);printf(%.0fn,nc);%f可用于f l o a t与d o u b l e类型,%.0 f用于控制不打印小数点和小数部分,因此小数部分为 0。这个f o r循环语句的体是空的,这是因为它的所有工作都在测试(条件)部分与加步长部分做了。但C语言的语法规则要求 f o r循环语句必须有一个体,因此用单独的分号代替。单个分号叫做空语句,它正好能满足f o r语句的这一要求。把它单独放在一行是

38、为了使它显目一点。在结束讨论字符计数程序之前,请观察一下以下情况:如果输入中不包含字符,那么,w h i l e语句或f o r语句中的条件从一开始就为假,g e t c h a r函数一次也不会调用,程序的执行结果为0,这个结果也是正确的。这一点很重要。w h i l e语句与f o r语句的优点之一就是在执行循环体之前就对条件进行测试。如果没有什么事要做,那么就不去做,即使它意味着不执行循环体。程序在出现0长度的输入时应表现得机灵一点。w h i l e语句与f o r语句有助于保证在出现边界条件时做合理的事情。更多免费资源:第 12 页1.5.3 行计数下一个程序用于统计输入的行数。正如

39、上文提到的,标准库保证输入文本流是以行序列的形式出现的,每一行均以换行符结束。因此,统计输入的行数就等价于统计换行符的个数。#include /*统计输入的行数*/main()long c,nl;nl=0;while(c=getchar()!=EOF)if(c=n)+nl;printf(%dn,nl);这个程序中w h i l e循环语句的体是一个i f语句,该i f语句用于控制增值+n l。i f语句执行时首先测试圆括号中的条件,如果该条件为真,那么就执行内嵌在其中的语句(或括在花括号中的一组语句)。这里再次用缩进方式指示哪个语句被哪个语句控制。双等于号=是C语言中表示“等于”的运算符(类似

40、于 P a s c a l中的单等于号=及F O RT R N中的.E Q.)。由于C已用单等于号=作为赋值运算符,故为区别用双等于号=表示相等测试。注意,C语言初学者常常会用=来表示=的意思。正如第 2章所述,即使这样误用了,得到的通常仍是合法的表达式,故系统不会给出警告信息。夹在单引号中的字符表示一个整数值,这个值等于该字符在机器字符集中的数值。它叫做字符常量,尽管它只不过是比较小的整数的另一种写法。例如,A 即字符常量;在A S C I I字符集中其值为6 5(即字符A 的内部表示值为6 5)。当然,用 A 要比用6 5优越,A 的意义清楚,并独立于特定的字符集。字符串常量中使用的换码序

41、列也是合法的字符常量,故n 表示换行符的值,在A S C I I字符集中其值为1 0。我们应该仔细注意到,n 是单个字符,在表达式中它只不过是一个整数;而另一方面,n 是一个只包含一个字符的字符串常量。有关字符串与字符之间的关系将在第 2章做进一步讨论。练习1-8 编写一个用于统计空格、制表符与换行符个数的程序。练习1-9 编写一个程序,把它的输入复制到输出,并在此过程中将相连的多个空格用一个空格代替。练习1-10 编写一个程序,把它的输入复制到输出,并在此过程中把制表符换成 t、把回退符换成 b、把反斜杠换成。这样可以使得制表符与回退符能以无歧义的方式可见。1.5.4 单词计数我们将要介绍的

42、第四个实用程序用于统计行数、单词数与字符数,这里对单词的定义放得更多免费资源:第 13 页比较宽,它是任何其中不包含空格、制表符或换行符的字符序列。下面这个比较简单的版本是在U N I X系统上实现的完成这一功能的程序 w c:#include#define IN 1 /*在单词内*/#define OUT 0 /*在单词外*/*统计输入的行数、单词数与字符数*/main()int c,nl,nw,nc,state;state=OUT;nl=nw=nc=0;while(c=getchar()!=EOF)+nc;if(c=n)+nl;if(c=|c=n|c=t)state=OUT;else if

43、(state=OUT)state=IN;+nw;printf(%d%d%dn,nl,nw,nc);程序在执行时,每当遇到单词的第一个字符,它就作为一个新单词加以统计。s t a t e变量用于记录程序是否正在处理一个单词(是否在一个单词中),它的初值是“不在单词中”,即被赋初值为O U T。我们在这里使用了符号常量 I N与O U T而没有使用其字面值 1与0,主要是因为这可以使程序更可读。在比较小的程序中,这样做也许看不出有什么区别,但在比较大的程序中,如果从一开始就这样做,那么所增加的一点工作量与所提高的程序的明晰性相比是很值得的。读者也会发现,在程序中,如果幻数仅仅出现在符号常量中,那么

44、对程序做大量修改就显得比较容易。语句行nl=nw=nc=0;用于把其中的三个变量n l、nw 与n c都置为0。这种情况并不特殊,但要注意这样一个事实,在兼有值与赋值两种功能的表达式中,赋值结合次序是由右至左。所以上面这个语句也可以写成:nl=(nw=(nc=0);运算符|的意思是O R(或),所以程序行if(c=|c=n|c=t)的意思是“如果c是空格或c是换行符或c是制表符”(回忆一下,换码序列 t 是制表符的可见表更多免费资源:第 14 页示)。与之对应的一个运算符是&,其含义是A N D(与),其优先级只比|高一级。经由&或|连接的表达式由左至右求值,并保证在求值过程中只要已得知真或假

45、,求值就停止。如果 c是一个空格,那么就没有必要再测试它是否为换行符或制表符,故后两个测试无需再进行。在这里这倒不特别重要,但在某些更复杂的情况下这样做就显得很重要,不久我们将会看到这种例子。这个例子中还给出了 e l s e部分,它指定当i f语句中的条件部分为假时所要采取的动作。其一般形式为:if (表达式)语句1else语句2在i f-e l s e的两个语句中有一个并且只有一个被执行。如果表达式的值为真,那么就执行语句1,否则,执行语句2。这两个语句均可以或者是单个语句或者是括在花括号内的语句序列。在单词计数程序中,e l s e之后的语句仍是一个i f语句,这个i f语句用于控制括在

46、花括号中的两个语句。练习1-11你准备怎样测试单词计数程序?如果程序中出现任何错误,那么什么样的输入最有利于发现这些错误?练习1-12 编写一个程序,以每行一个单词的形式打印输入。1.6 数组下面编写一个用来统计各个数字、空白符(空格符、制表符及换行符)以及所有其他字符出现次数的程序。这个程序听起来有点矫揉造作,但有助于在一个程序中对 C语言的几个方面加以讨论。由于所有输入的字符可以分成 1 2个范畴,因此用一个数组比用十个独立的变量来存放各个数字的出现次数要方便一些。下面是这个程序的第 1个版本:#include /*统计各个数字、空白符及其他字符分别出现的次数*/main()int c,i

47、,nwhite,nother;int ndigit10;nwhite=nother=0;for(i=0;i=0&c=9)+ndigitc-0;else if(c=|c=n|c=t)+nwhite;else 更多免费资源:第 15 页+nother;printf(digits=);for(i=0;i=0&c=0&c=9)+ndigitc-0;else if(c=|c=n|c=t)+nwhite;else+nother;在程序中经常会用如下模式来表示多路判定:if(条件1)语句1else if(条件2)语句2else 语句n在这个模式中,各个条件从前往后依次求值,直到满足某个条件,这时执行对应的语

48、句部更多免费资源:第 16 页分,语句执行完成后,整个i f构造完结。(其中的任何语句都可以是括在花括号中的若干个语句。)如果其中没有一个条件满足,那么就执行位于最后一个 e l s e之后的语句(如果有这个语句)。如果没有最后一个e l s e及对应的语句,那么这个 i f构造就不执行任何动作,如同前面的单词计数程序一样。在第一个i f与最后一个e l s e之间可以有0个或多个else if(条件)语句就风格而言,我们建议读者采用缩进格式。如果每一个 i f都比前一个e l s e向里缩进一点,那么对一个比较长的判定序列就有可能越出页面的右边界。第3章将要讨论的s w i t c h语句提

49、供了编写多路分支的另一种手段,它特别适合于表示数个整数或字符表达式是否与一常量集中的某个元素匹配的情况。为便于对比,我们将在 3.4节给出用s w i t c h语句编写的这个程序的另一个版本。练习1-13 编写一个程序,打印其输入的文件中单词长度的直方图。横条的直方图比较容易绘制,竖条直方图则要困难些。练习1-14 编写一个程序,打印其输入的文件中各个字符出现频率的直方图。1.7 函数C语言中的函数类似于 F O RT R A N语言中的子程序或函数,或者 P a s c a l语言中的过程或函数。函数为计算的封装提供了一种简便的方法,在其他地方使用函数时不需要考虑它是如何实现的。在使用正确

50、设计的函数时不需要考虑它是怎么做的,只需要知道它是做什么的就够了。C语言使用了简单、方便、有效的函数,我们将会经常看到一些只定义和调用了一次的短函数,这样使用函数使某些代码段更易于理解。到目前为此,我们所使用的函数(如 p r i n t f、g e t c h a r与p u t c h a r等)都是函数库为我们提供的。现在是我们自己编写一些函数的时候了。由于 C语言没有像F O RT R A N语言那样提供诸如*之类的乘幂运算符,我们可以通过编写一个求乘幂的函数power(m,n)来说明定义函数的方法。power(m,n)函数用于计算整数m的正整数次幂n,即p o w e r(2,5)的

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁