C 文件复制.doc_第1页
C 文件复制.doc_第2页
C 文件复制.doc_第3页
C 文件复制.doc_第4页
C 文件复制.doc_第5页
免费预览已结束,剩余1页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C 文件复制借助于getchar 与putchar 函数,可以在不了解其它输入输出知识的情况下编写出数量惊人的有用的代码。最简单的例子就是把输入一次一个字符地复制到输出,其基本思想如下:读一个字符while (该字符不是文件结束指示符)输出刚读入的字符读下一个字符将上述基本思想转换为C语言程序为:#include /* copy input to output; 1st version */main()int c;c = getchar();while (c != EOF) putchar(c);c = getchar();其中,关系运算符!=表示“不等于”。字符在键盘、屏幕或其它的任何地方无论以什么形式表现,它在机器内部都是以位模式存储的。char 类型专门用于存储这种字符型数据,当然任何整型(int)也可以用于存储字符型数据。因为某些潜在的重要原因,我们在此使用int类型。这里需要解决如何区分文件中有效数据与输入结束符的问题。C语言采取的解决方法是:在没有输入时,getchar 函数将返回一个特殊值,这个特殊值与任何实际字符都不同。这个值称为EOF(end of file,文件结束)。我们在声明变量c 的时候,必须让它大到足以存放getchar函数返回的任何值。这里之所以不把c声明成char类型,是因为它必须足够大,除了能存储任何可能的字符外还要能存储文件结束符EOF。因此,我们将c声明成int类型。EOF 定义在头文件中,是个整型数,其具体数值是什么并不重要,只要它与任何char类型的值都不相同即可。这里使用符号常量,可以确保程序不需要依赖于其对应的任何特定的数值。对于经验比较丰富的C 语言程序员,可以把这个字符复制程序编写得更精炼一些。在C语言中,类似于c = getchar()之类的赋值操作是一个表达式,并且具有一个值,即赋值后左边变量保存的值。也就是说,赋值可以作为更大的表达式的一部分出现。如果将为c赋值的操作放在while循环语句的测试部分中,上述字符复制程序便可以改写成下列形式:#include /* copy input to output; 2nd version */main()int c;while (c = getchar() != EOF)putchar(c);在该程序中,while 循环语句首先读一个字符并将其赋值给c,然后测试该字符是否为文件结束标志。如果该字符不是文件结束标志,则执行while语句体,并打印该字符。随后重复执行while语句。当到达输入的结尾位置时,while循环语句终止执行,从而整个main函数执行结束。以上这段程序将输入集中化,getchar函数在程序中只出现了一次,这样就缩短了程序,整个程序看起来更紧凑。习惯这种风格后,读者就会发现按照这种方式编写的程序更易阅读。我们经常会看到这种风格。(不过,如果我们过多地使用这种类型的复杂语句,编写的程序可能会很难理解,应尽量避免这种情况。)对 while语句的条件部分来说,赋值表达式两边的圆括号不能省略。不等于运算符!=的优先级比赋值运算符=的优先级要高,这样,在不使用圆括号的情况下关系测试!=将在赋值=操作之前执行。因此语句c = getchar() != EOF等价于语句c = (getchar() != EOF)该语句执行后,c的值将被置为0 或1(取决于调用getchar函数时是否碰到文件结束标志),这并不是我们所希望的结果(更详细的内容,请参见第2 章的相关部分)。练习 1-6 验证表达式getchar() != EOF的值是0还是1。练习 1-7 编写一个打印EOF值的程序。1.5.2. 字符计数下列程序用于对字符进行计数,它与上面的复制程序类似。#include /* count characters in input; 1st version */main()long nc;nc = 0;while (getchar() != EOF)+nc;printf(%ldn, nc);其中,语句+nc;引入了一个新的运算符+,其功能是执行加1 操作。可以用语句nc = nc + 1 代替它,但语句+nc 更精炼一些,且通常效率也更高。与该运算符相应的是自减运算符-。+与-这两个运算符既可以作为前缀运算符(如+nc),也可以作为后缀运算符(如nc+)。我们在第2 章中将看到,这两种形式在表达式中具有不同的值,但+nc与nc+都使nc的值增加1。目前,我们只使用前缀形式。该字符计数程序使用long类型的变量存放计数值,而没有使用int类型的变量。long整型数(长整型)至少要占用32 位存储单元。在某些机器上int与long类型的长度相同,但在一些机器上,int类型的值可能只有16 位存储单元的长度(最大值为32767),这样,相当小的输入都可能使int类型的计数变量溢出。转换说明%ld告诉printf函数其对应的参数是long整型。使用double(双精度浮点数)类型可以处理更大的数字。我们在这里不使用while 循环语句,而用for循环语句来展示编写此循环的另一种方法:#include /* count characters in input; 2nd version */main()double nc;for (nc = 0; gechar() != EOF; +nc);printf(%.0fn, nc);对于float与double类型。printf函数都使用%f进行说明。%.0f强制不打印小数点和小数部分,因此小数_部分的位数为0。在该程序段中,for 循环语句的循环体是空的,这是因为所有工作都在测试(条件)部分与增加步长部分完成了。但C语言的语法规则要求for循环语句必须有一个循环体,因此用单独的分号代替。单独的分号称为空语句,它正好能满足for 语句的这一要求。把它单独放在一行是为了更加醒目。在结束讨论字符计数程序之前,我们考虑以下情况:如果输入中不包含字符,那么,在第一次调用getchar 函数的叫候,while 语句或for 语句中的条件测试从一开始就为假,程序的执行结果将为0,这也是正确的结果。这一点很重要。whi1e 语句与for 语句的优点之一就是在执行循环体之前就对条件进行测试,如果条件不满足,则不执行循环体,这就可能出现循环体一次都不执行的情况。在出现0 长度的输入时,程序的处理应该灵活一些,在出现边界条件时,while语句与for语句有助于确保程序执行合理的操作。1.5.3. 行计数接下来的这个程序用于统计输入中的行数。我们在上面提到过,标准库保证输入文本流以行序列的形式出现,每一行均以换行符结束。因此,统计行数等价于统计换行符的个数。#include /* count lines in input */main()int c, nl;nl = 0;while (c = getchar() != EOF)if (c = n)+nl;printf(%dn, nl);在该程序中,while循环语句的循环体是一个if语句,它控制自增语句+nl。if语句先测试圆括号中的条件,如果该条件为真,则执行其后的语句(或括在花括号中的一组语句)。这里再次用缩进方式表明语句之间的控制关系。双等于号=是C语言中表示“等于”关系的运算符(类似于Pascal中的单等于号=及Fortran中的.EQ.)。由于C 语言将单等于号=作为赋值运算符,因此使用双等于号=表示相等的逻辑关系,以示区分。这里提醒注意,在表示“等于”逻辑关系的时候(应该用=),C语言初学者有时会错误地写成单等于号=。在第2 章我们将看到,即使这样误用了,其结果通常仍然是合法的表达式,因此系统不会给出警告信息。单引号中的字符表示一个整型值,该值等于此字符在机器字符集中对应的数值,我们称之为字符常量。但是,它只不过是小的整型数的另一种写法而已。例如,A是一个字符常量;在ASCII字符集中其值为65(即字符A的内部表示值为65)。当然,用A要比用65 好,因为。A的意义更清楚,且与特定的字符集无关。字符串常量中使用的转义字符序列也是合法的字符常量,比如,n代表换行符的值,在ASCII字符集中其值为10。我们应当注意到,n是单个字符,在表达式中它不过是一个整型数而已;而n是一个仅包含一个字符的字符串常量。有关字符串与字符之间的关系,我们将在第2 章进一步讨论。练习 1-8 编写一个统计空格、制表符与换行符个数的程序。练习 1-9 编写一个将输入复制到输出的程序,并将其中连续的多个空格用一个空格代替。练习 1-10 编写一个将输入复制到输出的程序,并将其中的制表符替换为t,把回退符替换为b,把反斜杠替按为。这样可以将制表符和回退符以可见的方式显示出来。1.5.4. 单词计数我们将介绍的第4 个实用程序用于统计行数、单词数与字符数。这里对单词的定义比较宽松,它是任何其中不包含空格、制表符或换行符的字符序列。下面这段程序是UNIX 系统中wc程序的骨干部分:#include #define IN 1 /* inside a word */#define OUT 0 /* outside a word */* count lines, words, and characters in input */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 (state = OUT) state = IN;+nw;printf(%d %d %dn, nl, nw, nc);程序执行时,每当遇到单词的第一个字符,它就作为一个新单词加以统计。state 变量记录程序当前是否正位于一个单词之中,它的初值是“不在单词中”,即初值被赋为OUT。我们在这里使用了符号常量IN与OUT,而没有使用其对应的数值1 与0,这样程序更易读。在_较小的程序中,这种做法也许看不出有什么优势,但在较大的程序中,如果从一开始就这样做,因此而增加的一点工作量与提高程序可读性带来的好处相比是值得的。读者也会发现,如果程序中的幻数都以符号常量的形式出现,对程序进行大量修改就会相对容易得多。下列语句nl = nw = nc = 0;将把其中的3个变量nl、nw与nc都设置为0。这种用法很常见,但要注意这样一个事实:在兼有值与赋值两种功能的表达式中,赋值结合次序是由右至左。所以上面这条语句等同于n1 = (nw = (nc = 0);运算符|代表OR(逻辑或),所以下列语句if (c = | c= n | c = t)的意义是“如果c 是空格,或c 是换行符,或c 是制表符”(前面讲过,转义字符序列t 是制表符的可见表示形式)。相应地,运算符&代表AND(逻辑与),它仅比|高一个优先级。由&或|连接的表达式由左至右求值,并保证在求值过程中只要能够判断最终的结果为真或假,求值就立即终止。如果c 是空格,则没有必要再测试它是否为换行符或制表符,这样就不必执行后面两个测试。在这里,这一点并不特别重要,但在某些更复杂的情况下这样做就有必要了,不久我们将会看到这种例子。这段程序中还包括一个else部分,它指定当if语句中的条件部分为假时所要执

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论