C Primer Plus 第8章(字符输入输出和输入验证)

目录

  • 1. 单字符I/O:getchar() 和 putchar()
  • 2. 缓冲区
  • 3. 结束键盘输入
    • 3.1 文件、流和键盘输入
    • 3.2 文件结尾
  • 4. 重定向和文件
    • 4.1 UNIX、Linux 和 DOS 重定向
      • 4.1.1 重定向输入
      • 4.1.2 重定向输出
      • 4.1.3 组合重定向
  • 5. 创建更友好的用户界面
    • 5.1 使用缓冲输入
    • 5.2 混合数值和字符输入

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

char c;
while((c = getchar()) != '#')
{
    putchar(c);
}

2. 缓冲区

  • 回显用户输入的字符后立即重复打印该字符是属于无缓冲(或直接)输入,即正在等待的程序可立即使用输入的字符
  • 在按下 ENTER 键之前不会重复打印刚输入的字符,这种输入形式属于缓冲输入
  • 用户输入的字符被收集并存储在一个被称为缓冲区(buffer)的临时存储区,按下 ENTER 键后,程序才可使用用户输入的字符
  • 使用缓冲区的原因
    • 把若干字符作为一个块进行传输比逐个发送这些字符节约时间
    • 如果用户打错字符,可以直接通过键盘修正错误;当按下 ENTER 键时,传输的是正确的输入
  • 缓冲分为两类
    • 完全缓冲I/O
      • 当缓冲区被填满时才刷新缓冲区(内容被发送至目的地),通常出现在文件输入中
      • 常见大小是512和4096字节
    • 行缓冲I/O
      • 在出现换行符时刷新缓冲区
      • 键盘输入通常是行缓冲输入,所以按下 ENTER 键后才刷新缓冲区

3. 结束键盘输入

3.1 文件、流和键盘输入

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

  • 通常文件都保存在某种永久存储器中(硬盘、U盘或DVD等)

  • C有许多用于打开、读取、写入和关闭文件的库函数

    • 从较低层面上,C可以使用主机操作系统的基本文件工具直接处理文件,这些直接调用操作系统的函数被称为底层I/O(low-level I/O)
    • 从较高层面上,C还可以通过**标准I/O包(standard I/O package)**来处理文件;这涉及创建用于处理文件的标准模型和一套标准I/O函数;在这一层面上,具体的C实现负责处理不同系统的差异(不同的系统存储文件的方式不同),以便用户使用统一的界面
  • 可以用 if (c == ‘\n’) 检查换行符,即使系统实际用的是回车和换行符的组合来标记行末尾,I/O函数会在这两种表示方法之间相互转换

  • 从概念上看,C程序处理的是(stream)而不是直接处理文件

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

3.2 文件结尾

  • 计算机操作系统要以某种方式判断文件的开始和结束

  • 检测文件结尾的方法:

    • 在文件末尾放一个特殊的字符标记文件结尾,CTRL + Z 会被视为一个文件结尾标记
    • 存储文件大小的信息,用这种方法可以在文件中存储所有的字符,包括 CTRL + Z
  • 在C语言中,用 getchar() 读取文件检测到文件结尾时将返回一个特殊的值,即 EOF(end of file)

    • scanf() 函数检测到文件结尾时也返回 EOF

    • 通常,EOF 定义在 stdio.h 文件中

    #define EOF (-1)
    
    • 定义为 -1 的原因:getchar() 函数的返回值通常都介于 0~127 ,这些值对应标准字符集;如果系统能识别扩展字符集,该函数的返回值可能为 0~255;无论哪种情况,-1 都不对应任何字符,所以,该值可以用于标记文件结尾
  • 在大多数 UNIX 和 Linux 系统中,在一行开始处按下 CTRL + D 会传输文件结尾信号

  • 其他系统中,在一行开始处或任意处按下 CTRL + Z 会传输文件结尾信号

4. 重定向和文件

  • 程序可以通过两种方式使用文件
    • 显式使用特定的函数打开文件、关闭文件、读取文件、写入文件
    • 设计能与键盘和屏幕互动的程序,通过不同的渠道重定向输入至文件和从文件输出
      • 把 stdin 流重新赋给文件
      • 继续使用 getchar() 函数从输入流中获取数据,但是不关心从流的什么位置获取数据

4.1 UNIX、Linux 和 DOS 重定向

  • 重定向输入让程序使用文件而不是键盘来输入
  • 重定向输出让程序输出至文件而不是屏幕

4.1.1 重定向输入

  • 文本文件(text file)是内含文本的文件,其中存储的数据是我们可识别的字符

    • 文件内容可以是文本或者C程序

    • 内含机器语言指令的文件(存储可执行程序的文件)不是文本文件

    ./ABC < words
    // 名为 ABC.exe 的可执行文件
    // 名为 words 的文本文件
    
  • 符号 < 是 UNIX 和 DOS / Windows 的重定向运算符

    • 该运算符使文件与 stdin 流相关联,把文件中的内容导入程序
    • 程序本身并不知道(不关心)输入的内容是来自文件还是键盘,它只直到这是需要导入的字符流,所以它读取这些内容并把字符逐个打印在屏幕上,直至读到文件结尾

4.1.2 重定向输出

./ABC > words
// 名为 ABC.exe 的可执行文件
// 名为 words 的文本文件
  • 符号 > 也是重定向运算符
    • 创建新的文本文件,然后把程序的输出重定向至该文件中
    • 重定向把 stdout 流从显示设备赋给文本文件
      • 如果已经有同名文件,通常会擦除该文件的内容,然后替换新的内容

4.1.3 组合重定向

./ABC < words > new_words
// 等效于
./ABC > new_words < words
  • 通过程序将文本文件转存到另一个文本文件中
  • 组合重定向的原则:
    • 重定向运算符连接一个可执行程序(包括标准操作系统命令)和一个数据文件,不能用于连接一个数据文件和另一个数据文件,也不能用于连接一个程序和另一个程序
    • 使用重定向u运算符不能读取多个文件的输入,也不能把输出定向至多个文件
    • 通常,文件名和运算符之间的空格不是必须的,除非是偶尔在命令行提示模式中使用的有特殊含义的字符

5. 创建更友好的用户界面

5.1 使用缓冲输入

int i = 0;
printf("i = %d\n", i);
while(getchar() != 'y')
{
    printf("i = %d\n", ++i);
}

// 优化

int i = 0;
printf("i = %d\n", i);
while (getchar() != 'y')
{
    printf("i = %d\n", ++i);
    while (getchar() != '\n')
    {
        continue;
    }
}

// 优化

int i = 0;
char c = ' ';
printf("i = %d\n", i);
while ((c = getchar()) != 'y')
{
    if (c == 'n')
    {
        printf("i = %d\n", ++i);
    }else
    {
        printf("Error\n");
    }
    
    while (getchar() != '\n')
    {
        continue;
    }
}

5.2 混合数值和字符输入

  • getchar() 和 scanf() 都可以处理输入,但是不能混用
    • getchar() :读取每个字符,包括空格、制表符和换行符
    • scanf() :在读取时会跳过空格、制表符和换行符
int length = 0;
int width = 0;
char c = ' ';


while ((c = getchar()) != EOF)
{
    if (c == '\n')
    {
        continue;
    }
    scanf("%d %d", &length, &width);
    for (int i = 1; i <= length; i++)
    {
        for (int j = 1; j <= width; j++)
        {
            putchar(c);
        }
        putchar('\n');
    }
}

你可能感兴趣的:(C语言,c语言)