The C Programming Language(第 2 版) 笔记 / 1 介绍 / 1.5 字符输入/输出 / 1.5.1 文件复制

目录、参考文献


1.5 字符输入/输出

接下来我们看一组与字符型数据处理有关的程序
许多程序只不过是这里所讨论的程序原型的扩充版本而已
标准库提供的输入/输出模型非常简单
无论文本从何处输入,输出到何处,其输入/输出都是按照字符流的方式处理
文本流是由多行字符构成的字符序列,而每行字符则由 0 个或多个字符组成,行末是一个换行符
标准库负责使每个输入/输出流都能够遵守这一模型

使用标准库的 C 语言程序员不必关心在程序之外这些行是如何表示的
标准库提供了一次读/写一个字符的函数,其中最简单的是 getcharputchar 两个函数
每次调用时,getchar 函数从文本流中读入下一个输入字符,并将其作为结果值返回
也就是说,在执行语句 c = getchar() 之后,变量 c 中将包含输入流中的下一个字符
这种字符通常是通过键盘输入的

每次调用 putchar 函数时将打印一个字符
例如,语句 putchar() 将把整型变量 c 的内容以字符的形式打印出来,通常是显示在屏幕上
putcharprintf 这两个函数可以交替调用,输出的次序与调用的次序一致

1.5.1 文件复制

借助于 getcharputchar 函数,可以在不了解其它输入/输出知识的情况下编写出数量惊人的有用的代码
最简单的例子就是把输入一次一个字符地复制到输出,其基本思想如下:

读一个字符
while (该字符不是文件结束指示符) 
    输出刚读入的字符
    读下一个字符

将上述基本思想转换为 C 语言程序为:

#include <stdio.h>

/* copy input to output; 1st version */ 
main() 
{ 
    int c; 
    c = getchar(); 
    while (c != EOF) { 
        putchar(c); 
        c = getchar(); 
    } 
}

关系运算符 != 表示 “ 不等于 ”

[vagrant@node01 1.5]$ gcc -o test01 test01.c
[vagrant@node01 1.5]$ ls
test01  test01.c
[vagrant@node01 1.5]$ ./test01
aa
aa
abc
abc

getchar() 在没有字符时会阻塞等待键盘输入
等待键盘输入时,控制流会传递给 shell
此时输入的字符是被 shell 接收的,也是被 shell 镜像打印出来的,让用户可以看到自己输入了什么
shell 的操作是以行为单位的(所以叫命令行)
即当输入回车键时,shell 会将这一行的输入(包括回车)以及执行权通过异常控制流传递回 C 程序
C 程序会重新执行 getchar() 函数的第一条指令
这次能够获取到字符不会再阻塞,循环打印,直到这一行的字符打印完了(包括回车)将再次阻塞并将执行权传递给 shell

在 shell 中输入 Ctrl + d 时等价于输入 EOF

char 类型专门用于存储字符型数据,任何整型 int 也可以用于存储字符型数据
因为某些潜在的重要原因,我们在此使用 int 类型

这里需要解决如何区分文件中有效数据与输入结束符的问题
C 语言采取的解决方法是:在没有输入时,getchar 函数将返回一个特殊值,这个特殊值与任何实际字符都不同
这个值称为 EOF(end of file,文件结束)
我们在声明变量 c 的时候,必须让它大到足以存放 getchar 函数返回的任何值
这里之所以不把 c 声明成 char 类型,是因为它必须足够大
除了能存储任何可能的字符外还要能存储文件结束符 EOF,因此,我们将 c 声明成 int 类型
EOF 定义在头文件 <stdio.h> 中,是个整型数
其具体数值是什么并不重要,只要它与任何 char 类型的值都不相同即可
这里使用符号常量,可以确保程序不需要依赖于其对应的任何特定的数值

对于经验比较丰富的 C 语言程序员,可以把这个字符复制程序编写得更精炼一些
在 C 语言中,类似于 c = getchar() 之类的赋值操作是一个表达式,并且具有一个值(即:赋值后左边变量保存的值)
程序可改写为:

#include <stdio.h>

/* copy input to output; 2nd version */ 
main() 
{ 
    int c; 
    while ((c = getchar()) != EOF) 
        putchar(c); 
}
[vagrant@node01 1.5]$ gcc -o test02 test02.c
[vagrant@node01 1.5]$ ls
test01  test01.c  test02  test02.c
[vagrant@node01 1.5]$ ./test02
aa
aa
abc
abc

赋值表达式两边的圆括号不能省略
因为不等于运算符 != 的优先级比赋值运算符 = 的优先级要高
在不使用圆括号的情况下关系测试 != 将在赋值 = 操作之前执行
即:语句 c = getchar() != EOF 等价于语句 c = (getchar() != EOF)
该语句执行后 c 的值将被置为 01(取决于调用 getchar 函数时是否碰到文件结束标志)

打印 EOF 看看:

#include <stdio.h>

/* copy input to output; 2nd version */ 
main() 
{
    putchar(EOF);
    putchar('\n');
}
[vagrant@node01 1.5]$ gcc -o test03 test03.c
[vagrant@node01 1.5]$ ./test03
�

目录、参考文献

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值