第八章 - DDL-Killer/The-road-of-Linxu-Group2024 GitHub Wiki

  • 单引号中的字符代表的是 字符的 ASCII 码值

优先级:赋值<逻辑<关系<算术

单字符I/O:getchar() 和 putchar()

ch = getchar()
putchar(ch)

缓冲区

  • 回显用户输入的字符后立即重复打印该字符是属于无缓冲输入
  • 大部分系统在用户按下Enter键之前不会重复打印,这种输入形式属于缓存输入
  • 用户输入的字符被收集并储存在一个被称为缓冲区的临时存储区,按下Enter键之后,程序才可使用用户输入的字符
  • 存在的意义:
    1. 把若干字符作为作为一个块进行传输比逐个发送这些字符节约时间(时间效率)
    2. 用户如果打错字符,直接通过键盘修正错误(人机交互)
  • 虽然缓冲输入的好处有很多,但是某些交互式程序也需要无缓冲输入
  • 缓冲分为两类:完全缓冲I/O行缓冲I/O
    1. 完全缓冲输入指的是当缓冲区被填满时才刷新缓冲区(内容被发送到目的地)
    2. 行缓冲指的是在出现换行符时刷新缓冲区——键盘输入,所以按下Enter键之后才会刷新缓冲区
  • ANSI C决定把缓冲输入作为标准的原因是:一些计算机不允许无缓冲输出
  • 回显输入和无回显输入
    1. 回显输入意味着用户输入的字符直接显示在屏幕
    2. 无回显输入意味着击键后对应的字符不显示

结束键盘输入

文件、流和键盘输入

  • 文件(file)是存储器中储存信息的区域

c语言是一门强大、灵活的语言:

  1. 从较低层面上,C可以使用主机操作系统的基本文件工具直接处理文件,这些直接调用操作系统的函数被称为底层I/O
  2. 从较高层面上,C可以使用标准I/O函数来处理文件,具体的C负责处理不同系统的差异,以便用户使用统一的界面

  • 从概念上看,C程序处理的是流而不是直接处理文件
  • 是一种实际输入或输出映射的理想化数据流,这意味着不同属性和不同种类的输入,由属性更统一的流来表示
    eg:打开文件的过程就是把流和文件相关联,而且读写都通过流来完成

文件结尾

  • 计算机操作系统要以某种方式判断文件的开始和结束
  • 常见的办法是在文件末尾放一个特殊字符标记文件结尾 ^z
  • 另一种方法是储存文件大小的信息
  • 在C语言中,用getchar()读取文件检测到文件结尾时会返回一个特殊的值,即EOF(end of file)
  • scanf()函数检测到文件结尾时也返回EOF

EOF

  • 通常,EOF定义在。stdio.h文件里
    #define EOF (-1)
  • -1的原因是因为getchar()函数的返回值通常都介于0~127,拓展为0~255
  • 无论为哪种, -1 都不对应任何字符

理解EOF是一个值,标志着检测到文件结尾,并不是在文件中找得到的符号

  • EOF的检测:
    1. 文件大小:对比当前位置和文件的总大小,知道是否已经到达文件的末尾
    2. 读取函数的返回值:一些函数读取到文件末尾的时候,会返回一个特定的标志来表示EOF
    3. 流式处理:文件通常通过流的方式处理,文件流会包含一个EOF标志位.当到达流的末尾,流会设置EOF状态
  • 硬件中的EOF:
    1. 文件系统的元数据:文件系统中的文件有明确的大小信息(即字节数),存储在文件的元数据中,在硬件上,文件数据会以块或扇区为单位存储,当读取操作到达最后一个块或扇区的末尾时,操作系统通过文件元数据计算出文件是否已经读完
    2. I/O缓冲区管理:当数据从硬件存储设备(如硬盘、SSD)读取到内存中时,数据通常会经过一个缓冲区。操作系统或硬件控制器负责管理这些缓冲区,并控制数据的读取过程。当缓冲区的数据已经被耗尽且没有更多数据可以填充缓冲区时,硬件或操作系统就会通知程序EOF到达
    3. 硬盘控制器和总线协议:在硬盘或其他存储设备的硬件控制器中,文件的结束是通过总线协议(SATA/NVMe)和文件系统协议来进行协调的,存储设备读取文件时,控制器会根据传递的命令和数据块的数量来判断是否已经到达文件末尾,文件结束的逻辑是在文件系统级别通过元数据读取操作管理的
  • 如何使用EOF?
    eg:把getchar()的返回值和EOF作比较
  • 绝大部分系统都有办法通过键盘模拟文件结尾条件
  • 在大多数的UNIX和Linux系统,按下Ctrl+Z传递文件结尾信号,在PC中,一般为Ctrl+D

重定向和文件

  • 在标准情况下,C程序使用标准I/O包查找标准输入作为输入源(stdin流)
  • 程序可以通过两种方式使用文件:
    1. 显式使用特定的函数打开文件、关闭文件、读取文件、写入文件
    2. 设计能与键盘和屏幕互动的程序,通过不同的渠道重定向输入至文件和从文件输出(把stdin流重新赋给文件)

stdio.h

  • 标准I/O包,stdin是其中的一个标准输入流,通常与用户的键盘输入相关联

stdin是什么?

  • stdin是一个已经打开的文件指针,指向标准输入流
  • 标准输入流通常与终端或控制台连接,程序可以通过stdin来获取用户输入
  • stdin是由操作系统自动管理的
  • C语言标准库的三个标准流:
    1. stdin:标准输入,通常是键盘
    2. stdout:标准输出,通常是终端
    3. stderr:标准错误输出,通常也输出终端
  • 使用:
    eg:scanf() 是一个常用的函数,用于从标准输入读取格式化数据。它从 stdin 读取数据,并根据格式化字符串解析输入的值。
  • 重定向:通过命令行,可以将文件或其他数据源作为stdin输入,而不是键盘输入
  • stdin是缓冲流,这意味着它在后台可能会缓冲一部分输入,直到你按下回车键,数据才会传递给程序

UNIX、Linux和DOS重定向

UNIX(运行命令行模式)、Linux(ditto)和Window命令行提示都能重定向输入、输出

一、重定向输入

  • 文本文件是内含文本的文件,其中储存的数据是我们可以识别的字符
  • 内含机器语言指令的文件(储存可执行程序的文件)不是文本文件
  • <符号 (右导左) 是UNIX和DOX/Windows的重定向运算符,该运算符使文本文件与stdin流相关联
    eg:echoof < words 该运算符使words文件与stdin流相关联,把word文件中的内容导入echoof程序
  • 在C语言的标准I/O库中,文件I/O设备通过文件指针(FILE *)来表示,无论是操作系统中的普通文件,还是终端、键盘等输入输出设备,都可以通过类似的方式进行处理
  • 文件和设备的抽象:C语言把文件和设备统一抽象为“流”是一种灵活的设计,因为这样可以让程序以相同的方式来处理不同类型的输入输出来源:
    1. 文件流:C语言使用标准的I/O函数来处理磁盘文件,这些文件以二进制或文本模式打开并处理
    2. 标准输入/输出流:三个标准流不是磁盘文件,但是与用户的输入设备或输出设备连接,使用函数进行交互
    3. 设备文件:很多硬件设备被抽象为文件,通常处于/dev目录下,通过open()``read()``write()等系统调用与这些设备进行通信
  • I/O设备和文件的统一操作:
    1. fopen():用于打开文件或设备。可以指定读、写、追加、二进制等模式
    2. fread()fwrite():用于读取和写入数据。无论是从磁盘文件还是I/O设备
    3. fclose():关闭文件或设备
    4. fseek()ftell():用于在文件或设备中移动指针并获取当前位置
  • 设备文件的种类
    1. 字符设备文件:字符设备允许一次一个字节的读取或写入。字符设备文件通常可以用cat或其他字符操作程序访问
    2. 块设备文件:块设备一次读写一个数据块,通常用于存储设备。程序可以通过随机访问的方式读取或写入数据块
      这些设备文件本质上都通过统一的文件接口(FILE *)访问

二、重定向输出

  • >符号 (左输右)
    eg:echoof>mywords 创建一个名为myword的新文件,然后把echoof输出重定向至该文件
  • 重定向把stdout从显示设备赋给文件
  • 如果文件名相同,通常会擦除该文件的内容,然后替换新的内容

三、组合重定向

  • 重定向运算符连接一个可执行程序(包括标准操作系统命令)和一个数据文件
  • 重定向运算符不能连接一个数据文件和另一个数据文件,也不能连接一个程序和另一个程序
  • 使用重定向运算符不能读取多个文件的输入,也不能把输出定向至多个文件
  • 通常,文件名和运算符直接的空格不是必须的

四、注释

  • 重定位让你能使用键盘输入程序文件,要完成这一任务,程序要测试文件的末尾
  • 重定向是一个命令行概念,因为我们要在命令行输入特殊的符号发出指令
  • 如果不使用命令行环境,也可以使用重定向
    eg:MVSD默认设置是把可执行文件放在项目文件夹的子文件夹,称为Debug,文件名和项目名基本相同,文件的拓展名为.exe

创建更友好的用户界面

使用缓存输入

混合数值和字符输入

  • getchar()读取每个字符,包括空格、制表符和换行符
  • scanf()在读取数字时会跳过空格、制表符和换行符

输入验证

分析程序

  • 程序遵循模块化的编程思想,使用独立函数(模块)来验证输入和管理显示
  • 输入由字符组成,scanf()可以把输入转成整数值或浮点值
  • 使用转换说明限制了可接受输入的字符类型,而getchar()和使用%c的scanf()接受所有字符

菜单浏览