🍊字符输入输出
2021-1-19
| 2023-8-2
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
Property
 

单字符I/O

字符输入/输出函数:getchar()putchar() ,这两个函数通常定义在 stdio.h头文件中。
 
getchar()函数不带任何参数,它从输入队列中返回下一个字符:
putchar()函数打印它的参数
这些函数只处理字符,比更通用的scanf()printf()函数更快、更简洁。而且 getchar()putchar()不需要转换说明,因为它们只处理字符。
 

ctype.h系列的字符函数

 ctype.h头文件中的字符测试函数:
函数名
如果是下列参数,返回值为真
isalnum
字母或数字
isalpha
字母
isblank
标椎的空白字符(空格 水平制表符)
iscntrl
控制字符 ctrl+B
isdigit
数字
isgraph
除空格之外的任意可打印字符
islower
小写字母
isprint
可打印字符
ispunct
标点符号 (除空格或字母数字字符以外的任意可打印的字符)
isspace
空白字符(空格,换行 ,换页, 回车, 垂直制表符 ,水平制表符)
isupper
大写字母
isxdigit
十六进制数字符
 
ctype.h头文件中的字符映射函数:
函数名
行为
tolower
如果参数是大写字符,该函数返回小写字符;否则返回原始参数
toupper
如果参数是小写字符,该函数返回大写字符;否则返回原始参数
 

缓冲区

为什么要有缓冲区?
notion image
首先,把若干字符作为一个块进行传输比逐个发送这些字符节约时间。其次,如果用户打错字符,可以直接通过键盘修正错误。当最后按下Enter键时,传输的是正确的输入。
 
缓冲分为两类:完全缓冲I/O和行缓冲I/O。
  • 完全缓冲输入指的是当缓冲区被填满时才刷新缓冲区(内容被发送至目的地),通常出现在文件输入中。缓冲区的大小取决于系统,常见的大小是 512 字节和 4096字节。
  • 行缓冲I/O指的是在出现换行符时刷新缓冲区。键盘输入通常是行缓冲输入,所以在按下Enter键后才刷新缓冲区。
 
虽然缓冲输入好处很多,但是某些交互式程序也需要无缓冲输入。例如,在游戏中,你希望按下一个键就执行相应的指令。因此,缓冲输入和无缓冲输入都有用武之地。那么,使用缓冲输入还是无缓冲输入?
ANSI C和后续的C标准都规定输入是缓冲的,不过最初K&R把这个决定权交给了编译器的编写者。
ANSI C决定把缓冲输入作为标准的原因是:一些计算机不允许无缓冲输入。许多IBM PC兼容机的编译器都为支持无缓冲输入提供一系列特殊的函数,其原型都在conio.h头文件中。这些函数包括用于回显无缓冲输入的getche()函数和用于无回显无缓冲输入的getch()函数(回显输入意味着用户输入的字符直接显示在屏幕上,无回显输入意味着击键后对应的字符不显示)。UNIX系统使用另一种不同的方式控制缓冲。在UNIX系统中,可以使用ioctl()函数(该函数属于UNIX库,但是不属于C标准)指定待输入的类型,然后用getchar()执行相应的操作。在ANSI C中,用setbuf()setvbuf()函数控制缓冲,但是受限于一些系统的内部设置,这些函数可能不起作用。总之,ANSI没有提供调用无缓冲输入的标准方式,这意味着是否能进行无缓冲输入取决于计算机系统。
 
 

结束键盘输入

文件、流和键盘输入

文件(file)是存储器中储存信息的区域。通常,文件都保存在某种永久存储器中(如,硬盘等)。编写的C程序就保存在文件中,用来编译C程序的程序也保存在文件中。后者说明,某些程序需要访问指定的文件。当编译储存在名为 echo.c 文件中的程序时,编译器打开echo.c文件并读取其中的内容。当编译器处理完后,会关闭该文件。其他程序,例如文字处理器,不仅要打开、读取和关闭文件,还要把数据写入文件。
C 是一门强大、灵活的语言,有许多用于打开、读取、写入和关闭文件的库函数。从较低层面上,C可以使用主机操作系统的基本文件工具直接处理文件,这些直接调用操作系统的函数被称为底层 I/O。由于计算机系统各不相同,所以不可能为普通的底层I/O函数创建标准库,ANSI C也不打算这样做。然而从较高层面上,C还可以通过标准I/O包来处理文件。这涉及创建用于处理文件的标准模型和一套标准I/O函数。在这一层面上,具体的C实现负责处理不同系统的差异,以便用户使用统一的界面。
不同的系统储存文件的方式不同。有些系统把文件的内容储存在一处,而文件相关的信息储存在另一处;有些系统在文件中创建一份文件描述。在处理文件方面,有些系统使用单个换行符标记行末尾,而其他系统可能使用回车符和换行符的组合来表示行末尾。有些系统用最小字节来衡量文件的大小,有些系统则以字节块的大小来衡量。
如果使用标准 I/O 包,就不用考虑这些差异。因此,可以用 if (ch ==)检查换行符。即使系统实际用的是回车符和换行符的组合来标记行末尾,I/O函数会在两种表示法之间相互转换。
从概念上看,C程序处理的是流而不是直接处理文件。
流(stream)是一个实际输入或输出映射的理想化数据流。这意味着不同属性和不同种类的输入,由属性更统一的流来表示。于是,打开文件的过程就是把流与文件相关联,而且读写都通过流来完成。stdin流表示键盘输入,stdout流表示屏幕输出getchar()putchar()printf()scanf()函数都是标准I/O包的成员,处理这两个流。
 
可以用处理文件的方式来处理键盘输入。例如,程序读文件时要能检测文件的末尾才知道应在何处停止。因此,C 的输入函数内置了文件结尾检测器。既然可以把键盘输入视为文件,那么也应该能使用文件结尾检测器结束键盘输入。
 

文件结尾

计算机操作系统要以某种方式判断文件的开始和结束。检测文件结尾的一种方法是,在文件末尾放一个特殊的字符标记文件结尾。CP/M、IBMDOS和MS-DOS的文本文件曾经用过这种方法。如今,这些操作系统可以使用内嵌的Ctrl+Z字符来标记文件结尾。这曾经是操作系统使用的唯一标记,不过现在有一些其他的选择,例如记录文件的大小。所以现代的文本文件不一定有嵌入的Ctrl+Z,但是如果有,该操作系统会将其视为一个文件结尾标记。
notion image
 
操作系统使用的另一种方法是储存文件大小的信息。如果文件有3000字节,程序在读到3000字节时便达到文件的末尾。MS-DOS 及其相关系统使用这种方法处理二进制文件,因为用这种方法可以在文件中储存所有的字符,包括Ctrl+Z。新版的DOS也使用这种方法处理文本文件。UNIX使用这种方法处理所有的文件。
 
无论操作系统实际使用何种方法检测文件结尾,在C语言中,用getchar()读取文件检测到文件结尾时将返回一个特殊的值,即EOF(end of file)scanf()函数检测到文件结尾时也返回EOF。通常, EOF定义在stdio.h文件中:
为什么是-1?因为getchar()函数的返回值通常都介于0~127,这些值对应标准字符集。但是,如果系统能识别扩展字符集,该函数的返回值可能在0~255之间。无论哪种情况,-1都不对应任何字符,所以,该值可用于标记文件结尾。
某些系统也许把EOF定义为-1以外的值,但是定义的值一定与输入字符所产生的返回值不同。如果包含stdio.h文件,并使用EOF符号,就不必担心EOF值不同的问题。
 
getchar()的返回值和EOF作比较,如果两值不同,就说明没有到达文件结尾:
 
使用该程序进行键盘输入,要设法输入EOF字符。
在大多数UNIX和Linux系统中,在一行开始处按下Ctrl+D会传输文件结尾信号。许多微型计算机系统都把一行开始处的Ctrl+Z识别为文件结尾信号,一些系统把任意位置的Ctrl+Z解释成文件结尾信号。
每次按下Enter键,系统便会处理缓冲区中储存的字符,并在下一行打印该输入行的副本。这个过程一直持续到以UNIX风格模拟文件结尾(按下Ctrl+D)。在PC中,要按下Ctrl+Z。
 
 

重定向

在默认情况下,C程序使用标准I/O包查找标准输入作为输入源。就是stdin流,它是把数据读入计算机的常用方式。它可以是一个过时的设备,如磁带、穿孔卡或电传打印机,或者是键盘,甚至是一些先进技术,如语音输入。然而,现代计算机非常灵活,可以让它到别处查找输入。尤其是,可以让一个程序从文件中查找输入,而不是从键盘。
 
程序可以通过两种方式使用文件。第 1 种方法是,显式使用特定的函数打开文件、关闭文件、读取文件、写入文件,诸如此类。第2种方法是,设计能与键盘和屏幕互动的程序,通过不同的渠道重定向输入至文件和从文件输出。换言之,把stdin流重新赋给文件。继续使用getchar()函数从输入流中获取数据,但它并不关心从流的什么位置获取数据。虽然这种重定向的方法在某些方面有些限制,但是用起来比较简单。
重定向的一个主要问题与操作系统有关,与C无关。UNIX(运行命令行模式时)、Linux(ditto)和Window命令行都能重定向输入、输出。
重定向输入让程序使用文件而不是键盘来输入,重定向输出让程序输出至文件而不是屏幕。

重定向输入

假设已经编译了test.c 程序,并把可执行版本放入一个名为test(在Windows系统中名test.exe)的文件中。运行该程序,输入可执行文件名:
该程序获取用户从键盘输入的输入。
现在,假设要用该程序处理名为words的文本文件,其中储存的数据是可识别的字符。由于该程序的操作对象是字符,所以要使用文本文件。只需用下面的命令代替上面的命令即可:
notion image
<符号是UNIX和DOS/Windows的重定向运算符。该运算符使文件与stdin流相关联,把文件中的内容导入程序。程序本身并不知道(或不关心)输入的内容是来自文件还是键盘,它只知道这是需要导入的字符流,所以它读取这些内容并把字符逐个打印在屏幕上,直至读到文件结尾。因为C把文件和I/O设备放在一个层面,所以文件就是现在的I/O设备。
 

重定向输出

现在假设要用teset把键盘输入的内容发送到名为mywords的文件中。然后,输入以下命令并开始输入:
>符号是第2个重定向运算符。它创建了一个名为mywords的新文件,然后把test的输出(即你输入字符的副本)重定向至该文件中。重定向把stdout从显示设备(即,显示器)赋给mywords文件。如果已经有一个名为mywords的文件,通常会擦除该文件的内容,然后替换新的内容(但是,许多操作系统有保护现有文件的选项,使其成为只读文件)。所有出现在屏幕的字母都是刚才输入的,其副本储存在文件中。在下一行的开始处按下Ctrl+D(UNIX)或Ctrl+Z(DOS)即可结束该程序。记住在每行的末尾单击Enter键,这样才能把缓冲区的内容发送给程序。
 

组合重定向

现在,假设希望制作一份mywords文件的副本,并命名为savewords。只需输入以下命令即可:
下面的命令也起作用,因为命令与重定向运算符的顺序无关:
注意:在一条命令中,输入文件名和输出文件名不能相同。
 
重定向运算符连接一个可执行程序(包括标准操作系统命令)和一个数据文件,不能用于连接一个数据文件和另一个数据文件,也不能用于连接一个程序和另一个程序。
使用重定向运算符不能读取多个文件的输入,也不能把输出定向至多个文件。
通常,文件名和运算符之间的空格不是必须的,除非是偶尔在UNIX shell、Linux shell或Windows命令行提示模式中使用的有特殊含义的字符。例如test<words
UNIX、Linux或Windows/DOS 还有>>运算符,该运算符可以把数据添加到现有文件的末尾,而 | 运算符能把一个文件的输出连接到另一个文件的输入。
重定向是一个命令行概念,在命令行输入特殊的符号发出指令。如果用不了重定向,可以用程序直接打开文件。
 
  • C
  • 控制语句函数
    目录