C语言学习----缓冲区&结束键盘输入

本文详细解释了C语言中的缓冲区概念,区分了完全缓冲和行缓冲输入,并介绍了如何使用EOF标志在程序中检测键盘输入结束。还讨论了文件、流和键盘输入在C语言中的处理方式,以及如何处理文件结尾和使用Ctrl+Z作为信号。
摘要由CSDN通过智能技术生成

缓冲区&结束键盘输入

本文摘自C Primer Pluse 中文版
🐬我觉得关于缓冲区的概念是很重要的~~ 所以侧重记录了下来~ 一起学习叭🌱

缓冲区

先来看看这个程序

#include <stdio.h>
int main(void)
{
    char ch;
    while ((ch = getchar()) != '#')
    putchar(ch);
    return 0;
}

如果在老式系统运行上述程序,你输入文本时可能显示如下:
HHeelllloo, tthheerree…II wwoouulldd[enter]
lliikkee aa #
以上行为是个例外。像这样回显用户输入的字符后立即重复打印该字符是属于无缓冲(或直接)输入,即正在等待的程序可立即使用输入的字符。

对于该例,大部分系统在用户按下Enter键之前不会重复打印刚输入的字符,这种输入形式属于缓冲输入用户输入的字符被收集并储存在一个被称为缓冲区(buffer)的临时存储区,按下Enter键后,程序才可使用用户输入的字符。图8.1比较了这两种输入。
在这里插入图片描述

🌿缓冲分为两类:完全缓冲I/O和行缓冲I/O。

完全缓冲输入指的是当缓冲区被填满时才刷新缓冲区(内容被发送至目的地),通常出现在文件输入中。缓冲区的大小取决于系统,常见的大小是 512 字节和 4096字节。

行缓冲I/O指的是在出现换行符时刷新缓冲区。键盘输入通常是行缓冲输入,所以在按下Enter键后才刷新缓冲区

🌴那么,使用缓冲输入还是无缓冲输入?ANSI C(标准C库)和后续的C标准都规定输入是缓冲的,不过最初K&R把这个决定权交给了编译器的编写者。读者可以运行echo.c程序观察输出的情况,了解所用的输出类型。

我们大多数系统都是有缓冲输入的

结束键盘输入

#include <stdio.h>
int main(void)
{
    char ch;
    while ((ch = getchar()) != '#')
    putchar(ch);
    return 0;
}

在上述程序中,只要输入的字符中不含#,那么程序在读到#时才会结束。但是, #也是一个普通的字符,有时不可避免要用到。应该用一个在文本中用不到的字符来标记输入完成,这样的字符不会无意间出现在输入中,在你不希望结束程序的时候终止程序。C 的确提供了这样的字符,不过在此之前,先来了解一下C处理文件的方式。

文件、流和键盘输入

文件(file)是存储器中储存信息的区域。通常,文件都保存在某种永久存储器中(如,硬盘、U盘或DVD等)。毫无疑问,文件对于计算机系统相当重要。例如,你编写的C程序就保存在文件中,用来编译C程序的程序也保存在文件中。后者说明,某些程序需要访问指定的文件。当编译储存在名为 echo.c 文件中的程序时,编译器打开echo.c文件并读取其中的内容。当编译器处理完后,会关闭该文件。 其他程序,例如文字处理器,不仅要打开、读取和关闭文件,还要把数据写入文件。

C 是一门强大、灵活的语言,有许多用于打开、读取、写入和关闭文件的库函数。从较低层面上,C可以使用主机操作系统的基本文件工具直接处理文件,这些直接调用操作系统的函数被称为底层 I/O (low-level I/O)。由于计算机系统各不相同,所以不可能为普通的底层I/O函数创建标准库,ANSI C也不打算这样做。然而从较高层面上,C还可以通过标准I/O包 (standard I/O package)来处理文件。这涉及创建用于处理文件的标准模型和一套标准I/O函数。在这一层面上,具体的C实现负责处理不同系统的差异,以便用户使用统一的界面。

🌳上面讨论的差异指的是什么?例如,不同的系统储存文件的方式不同。有些系统把文件的内容储存在一处,而文件相关的信息储存在另一处;有些系统在文件中创建一份文件描述。在处理文件方面,有些系统使用单个换行符标记行末尾,而其他系统可能使用回车符和换行符的组合来表示行末尾。有些系统用最小字节来衡量文件的大小,有些系统则以字节块的大小来衡量。

如果使用标准 I/O 包,就不用考虑这些差异。因此,可以用 if (ch ==‘\n’)检查换行符。即使系统实际用的是回车符和换行符的组合来标记行末尾,I/O函数会在两种表示法之间相互转换。

也就是说C的I/O包能够 使得不同的系统(虽然对于文件存储处理不同)最终呈现表达的结果也是一样的

🌺从概念上看,C程序处理的是流而不是直接处理文件。

流(stream)是一个实际输入或输出映射的理想化数据流。 这意味着不同属性和不同种类的输入,由属性更统一的流来表示。 于是,打开文件的过程就是把流与文件相关联,而且读写都通过流来完成。

着重理解C把输入和输出设备视为存储设备上的普通文件,尤其是把键盘和显示设备视为每个C程序自动打开的 文件 stdin流表示键盘输入,stdout流表示屏幕输出。getchar()、putchar()、printf()和scanf()函数都是标准I/O包的成员,处理这两个流。

☘️以上讨论的内容说明,可以用处理文件的方式来处理键盘输入。 例如,程序读文件时要能检测文件的末尾才知道应在何处停止。因此,C 的输入函数内置了文件结尾检测器。既然可以把键盘输入视为文件,那么也应该能使用文件结尾检测器结束键盘输入。

文件结尾

计算机操作系统要以某种方式判断文件的开始和结束。检测文件结尾的一种方法是,在文件末尾放一个特殊的字符标记文件结尾。 如今,这些操作系统可以使用内嵌的Ctrl+Z字符来标记文件结尾。这曾经是操作系统使用的唯一标记,不过现在有一些其他的选择,例如记录文件的大小。所以现代的文本文件不一定有嵌入的Ctrl+Z,但是如果有,该操作系统会将其视为一个文件结尾标记。

操作系统使用的另一种方法是储存文件大小的信息。如果文件有3000字节,程序在读到3000字节时便达到文件的末尾。MS-DOS 及其相关系统使用这种方法处理二进制文件,因为用这种方法可以在文件中储存所有的字符,包括Ctrl+Z。新版的DOS也使用这种方法处理文本文件。UNIX使用这种方法
处理所有的文件。

🐋无论操作系统实际使用何种方法检测文件结尾,在C语言中,用getchar()读取文件检测到文件结尾时将返回一个特殊的值,即EOF(end of file的缩写)。scanf()函数检测到文件结尾时也返回EOF。通常, EOF定义在stdio.h文件中:

#define EOF (-1)

为什么是-1?因为getchar()函数的返回值通常都介于0~127,这些值对应标准字符集。但是,如果系统能识别扩展字符集,该函数的返回值可能在0~255之间。无论哪种情况,-1都不对应任何字符,所以,该值可用于标记文件结尾。

某些系统也许把EOF定义为-1以外的值,但是定义的值一定与输入字符所产生的返回值不同。如果包含stdio.h文件,并使用EOF符号,就不必担心EOF值不同的问题。这里关键要理解EOF是一个值,标志着检测到文件结尾,并不是在文件中找得到的符号。

🤔那么,如何在程序中使用EOF?把getchar()的返回值和EOF作比较。如果两值不同,就说明没有到达文件结尾。也就是说,可以使用下面这样的表达式:

while ((ch = getchar()) != EOF)

❗️注意下面几点。

1️⃣不用定义EOF,因为stdio.h中已经定义过了。

2️⃣不用担心EOF的实际值,因为EOF在stdio.h中用#define预处理指令定义,可直接使用,不必再编写代码假定EOF为某值。

3️⃣getchar()函数实际返回值的类型是int,所以它可以读取EOF字符。由于getchar()函数的返回类型是int,如果把getchar()的返回值赋给char类型的变量,一些编译器会警告可能丢失数据。

使用该程序进行键盘输入,要设法输入EOF字符。不能只输入字符EOF,也不能只输入-1(输入-1会传送两个字符:一个连字符和一个数字1)。正确的方法是,必须找出当前系统的要求。例如,在大多数UNIX和Linux系统中,在一行开始处按下Ctrl+D会传输文件结尾信号。许多微型计算机系统都把一行开始处的Ctrl+Z识别为文件结尾信号,一些系统把任意位置的Ctrl+Z解释成文件结尾信号。

每次按下Enter键,系统便会处理缓冲区中储存的字符,并在下一行打印该输入行的副本。这个过程一直持续到以UNIX风格模拟文件结尾(按下Ctrl+D)。在PC中,要按下Ctrl+Z。

🌈ok,完结~(●’◡’●) 看到这里 点个赞叭 (●’◡’●)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~光~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值