IO函数分类

输入函数分为缓冲输入和无缓冲输入,无缓冲输入在用户输入完之后立即打印字符,缓冲输入是在用户输入某个特定值之前系统是不会打印的。

缓冲区Buffer

  • 无缓冲输入,程序立即使用输入内容。
  • 缓冲输入,用户输入的字符被收集到一个称为缓冲区的临时存储区,按下enter程序才会使用用户输入的字符。

缓冲区给用户提供了在键盘上修改错误的机会,但是有时候在一些交互的程序中我们也会需要无缓冲输入。

缓冲的分类

缓冲分为完全缓冲IO和行缓冲IO,完全缓冲指缓冲区被填满才会刷新(读取),行缓冲指按下 enter 猜刷新缓冲区。在C语言中一般是行缓冲,文件读取会用到完全缓冲。

底层IO(low-level IO)和标准高级IO

操作系统提供的IO函数称为底层IO,各个操作系统的文件存储方式,回车符和换行符号的表示不一样等等,所以底层IO不会写在库里。C语言只支持标准高级IO。

CPU的指令集不同,也就是说汇编语言完全不一样。为其中一种架构写的程序,如果要移植到另一种架构上,基本上要全部重写。C语言跨平台是指C语言的编译器和它的标准库使得同一段C语言代码可以被编译成各种CPU指令集上的指令,并且执行结果相同。标准高级IO就是这样的一个高级标准库。

使用标准IO编译器会把if(x == '\n')编译出符合系统的代码

文件结尾

为什么 IO 要涉及到文件呢?因为处理输入输出和处理文件的读写是一致的,文件结束通常会有两种机制,一种是在文件末尾放入一个特殊标志,二是记录文件大小。在C语言中无论系统怎么实现文件结尾,iO 函数例如getchar遇到文件结尾时还是会返回一个特殊的值 EOF,标志着读取到了文件结尾。

  1. # define EOF -1

为什么是-1,因为通常getchar的返回值介于 0 到 127 的 ascll 码,不对应任何一个字符。绝大部分系统都能通过键盘来模拟文件结尾,ctrl + d/z 。

重定向

程序本身并不知道(或关心)输入是来自文件而不是来自键盘。C将文件和 I/O 设备置于相同的地位,所以现在这个文件就是 I/O 设备。

  1. # include<stdio.h>
  2. int main()
  3. {
  4. int ch;
  5. while((ch=getchar())!=EOF){
  6. putchar(ch);
  7. }
  8. return 0;
  9. }

在UNIX,Linux/Windows 中,< 和 > 以及 >> 代表重定向,下面是使用示例:

  1. //test是test.c编译出的可执行文件
  2. ./test>work
  3. ./test<work
  • 重定向不能读取多个或者向多个文件输出
  • 只能一个可执行文件和一个数据文件
  • ./test < work1 > work2重定向不在乎顺序
  • 运算符用累加的方法将数据输出到指定的文件上,不会覆盖已有的数据

getchar/putcahr

两个函数只操作一个单个的字符,getchar 会读取每一个字符包括空格,回车,制表,而 scanf 则会跳过这些字符。

puts

puts (字符数组) 其作用是将一个字符串(以’\0’结束的字符序列)输出到终端。将字符串结束标志 ‘\0’ 转换成 ‘\n’ , 即输出完字符串后换行。

字节流

我们使用键盘输入 is 42 时,在我们眼中有字符有数字,实际上在程序眼中是一个字节流,第一个字节是 i 的字符编码,第二个是 s 的字符编码, 第三个是空格的字符编码。虽然我们输入的都是字符但是我们可以转换成整数或者浮点数,例如scanf的%d连续读取两个字符 4 和 2 ,再转换成相应的整数。

简言之,输入由字符组成,使用 scanf 和 getchar 会接受所有的字符,而使用转换说明 %d 或者 %f 则限制流可接受输入的字符类型。