字符输入/输出和输入验证 DAY19


前言


`

一、单字符I/O

getchar()和putchar()每一次只能处理一个字符。
你可能认为这种方法实在太笨拙了,毕竟与我们的阅读方式相差甚远。但是,这种方法很适合计算机。而且,这是绝大多数文本(即,普通文字)处理程序所用的核心方法。为了帮助读者回忆这些函数的工作方式,请看程序 。该程序获取从键盘输入的字符,并把这些字符发送到屏幕上。程序使用while循环,当读到#字符时停止。

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

在这里插入图片描述

读者可能好奇,为何输入的字符能直接显示在屏幕上?如果用一个特殊字符(如,#)来结束输入,就无法在文本中使用这个字符,是否有更好的方法结束输入?要回答这些问题,首先要了解C程序如何处理键盘输入,尤其是缓冲和标准输入文件的概念。

二、缓冲区

在这里插入图片描述
每一个数都是重复的,像这样回显用户输入的字符后立即重复打印该字符是属于无缓冲(或直接)输入,即正在等待的程序可立即使用输入的字符。

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

在这里插入图片描述

为什么要引入缓冲区?

首先,把若干字符作为一个块进行传输比逐个发送这些字符节约时间。其次,如果用户打错字符,可以直接通过键盘修正错误。当最后按下Enter键时,传输的是正确的输入。

虽然缓冲输入好处很多,但是某些交互式程序也需要无缓冲输入。
例如,在游戏中,你希望按下一个键就执行相应的指令因此,缓冲输入和无缓冲输入都有用武之地。

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

完全缓冲输入指的是当缓冲区被填满时才刷新缓冲区(内容被发送至目的地),通常出现在文件输入中。
缓冲区的大小取决于系统,常见的大小是512字节和4096字节。
行缓冲I/O指的是在出现换行符时刷新缓冲区。键盘输入通常是行缓冲输入,所以在按下Enter键后才刷新缓冲区。

程序使用的缓冲是行缓冲。键盘输入通常是行缓冲输入,所以在按下Enter键后才刷新缓冲区。

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

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

文件结尾

计算机操作系统要以某种方式判断文件的开始和结束。检测文件结尾的一种方法是,在文件末尾放一个特殊的字符标记文件结尾。 检测文件结尾的一种方法是,在文件末尾放一个特殊的字符标记文件结尾。

这个特殊的字符标记一般是:Ctrl+Z。

在下面的程序中,要结束输入,在按下 Ctrl+Z后,程序会就结束。

在这里插入图片描述

补充

getchar()函数

int getchar (void)

getchar()函数的返回类型为 int 整型 参数为 void

此时大家肯定会想,getchar()函数不是用来输入单个字符的吗,为什么返回类型为 int 整型呢 ?
1、getchar其实返回的是字符的ASCII码值(整数)。
2、getchargetchar在读取结束或者失败的时候,会返回EOF。

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

为什么是-1?
因为getchar()函数的返回值通常都介于0~127,这些值对应标准字符集。
但是,如果系统能识别扩展字符集,该函数的返回值可能在0~255之间。
所以无论哪种情况,-1都不对应任何字符,所以,该值可用于标记文件结尾。
某些系统也许把EOF定义为-1以外的值,但是定义的值一定与输入字符所产生的返回值不同。
另外,char型本身就是无符号型

#include <stdio.h>
#include <string.h>
int main()
{
	int ch = 0;  //因为 getchar() 返回类型为 int
	while ((ch = getchar()) != EOF) // 连续输入单个字符
	{
		printf("%c",ch);  // 输出一个字符
		//putchar(ch);    // 此时 printf("%c",ch) 与  putchar(ch)  输出结果一样
  	}
 
	return 0;
}

此时 printf(“%c”,ch) 与 putchar(ch) 输出结果一样

注意几点

  • 不用定义EOF,因为stdio.h中已经定义过了
  • 不用担心EOF的实际值,因为在stdio.h中用#define 预处理指令定义,可以直接使用
  • 变量ch的值从char变成int,因为char类型的变量只能表示0~255的无符号整形,但是EOF的值是-1,还好,getchar()的实际返回值是int.所以他可以读取EOF字符
  • 使用该程序进行键盘输入,要设法输入EOF字符,而不是字符EOF,也不能输入-1(输入-1会传输两个值,一个连字符和一个字符1。)正确的方法是,找到当前系统的需求,许多系统会把一行最开始处的Ctrl + Z作为文件结尾的信号。

我们暂停一会。既然程序能把用户输入的内容拷贝到屏幕上,那么考虑一下该程序还可以做什么。(上面的程序文件名是pp.cpp)

假设以某种方式把一个文件传送给它,然后它把文件中的内容打印在屏幕上,当到达文件结尾发现EOF信号时停止。

或者,假设以某种方式把程序的输出定向到一个文件,然后通过键盘输入数据用pp.cpp 来储存在文件中输入的内容。

假设同时使用这两种方法:把输入从一个文件定向到pp.cpp中,并把输出发送至另一个文件,然后便可以使用pp.cpp来拷贝文件。

重定向和文件

设计能与键盘和屏幕互动的程序,通过不同的渠道重定向输入至文件和从文件输出,换言之,把stdin流重新赋给文件(这时,是用键盘输入,输出给文件而不是屏幕)。继续使用getchar()函数从输入流中获取数据,但它并不关心从流的什么位置获取数据。虽然这种重定向的方法在某些方面有些限制,但是用起来比较简单,而且能让读者熟悉普通的文件处理技术。

重定向输入

我们找到pp.exe的位置

在这里插入图片描述

输入cmd
在这里插入图片描述

cmd是什么?

CMD是Windows操作系统中的命令提示符(Command Prompt)程序,它是一种命令行工具,可以让用户通过键入命令来与计算机进行交互。

CMD是Windows中一个基本的系统组件,它提供了一个简单的方式来执行诸如文件管理、网络管理、系统配置等各种任务。通过命令提示符,用户可以通过简单的命令来执行这些任务,而无需打开图形用户界面(GUI)。
————————————————

原文链接:https://blog.csdn.net/weixin_43783942/article/details/129470999

会出现这个界面
在这里插入图片描述
我们打开pp.exe,程序是可以运行的,输入Ctrl+Z终止程序。

在这里插入图片描述

创建一个pp.txt(文本文件),内容在右侧
在这里插入图片描述
下来把pp.txt的内容导入pp.exe程序

pp.exe<pp.txt

在这里插入图片描述
如果跨文件夹访问要加上文件位置

重定向输出

下来用键盘输入,输出给文件而不是屏幕

在这里插入图片描述
确实是输出到文件里了
在这里插入图片描述

组合重定向

把输入从一个文件pp2.txt定向到 pp.exe中,并把输出发送至另一个文件pp3.txt

没有任何问题

在这里插入图片描述

注意:在一条命令中,输入文件名和输出文件名不能相同。 echo_eof < mywords > mywords…<–错误
原因是> mywords在输入之前已导致原mywords的长度被截断为0.

在UNIX、Linux或Windows/DOS系统中使用两个重定向运算符(<和>)时,要遵循以下原则。

  • 重定向运算符连接一个可执行程序(包括标准操作系统命令)和一个数据文件不能用于连接一个数据文件和另一个数据文件,也不能用于连接一个程序和另一个程序。

  • 使用重定向运算符不能读取多个文件的输入,也不能把输出定向至多个文件。

小试牛刀:文件输出

不使用重定向,因为重定向的可移植性差,用C语言程序直接打开文件。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
	char fname[100];
	FILE* fp;
	int ch;
	printf("Enter the name of the file :");
	scanf("%s", fname);
	fp = fopen(fname, "r");
	if (fp == NULL)
	{
		printf("Failed open the file,bye");
		exit(1);
	}
	while ((ch = getc(fp)) != EOF)
		putchar(ch);
	fclose(fp);
	return 0;
}

我想看看我写的代码,文件名是源.cpp

在这里插入图片描述
非常成功。

创建更友好的用户界面

大部分人偶尔会写一些中看不中用的程序。还好,C提供了大量工具让输入更顺畅,处理过程更顺利。不过,学习这些工具会导致新的问题。本节的目标是,指导读者解决这些问题并创建更友好的用户界面,让交互数据输入更方便,减少错误输入的影响。

使用缓冲输入

缓冲输入用起来比较方便,因为在把输入发送给程序之前,用户可以编辑输入。
但是,在使用输入的字符时,它也会给程序员带来麻烦。前面示例中看到的问题是,缓冲输入要求用户按下Enter键发送输入。这一动作也传送了换行符,程序必须妥善处理这个麻烦的换行符。

我们以一个猜谜程序为例。用户选择一个数字,程序猜用户选中的数字是多少。

我们关注的重点在输入和输出。缓冲区

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int guess = 1;

    printf("Pick an integer from 1 to 100. I will try to guess it.\n");
    printf("Respond with a y if my guess is right and with an n if it's wrong.\n");
    printf("Uh...is your number %d?\n", guess);
    while(getchar()!='y')//scanf('%c',ch)=getchar()
    {
        printf("Well, then, is it %d?\n",++guess);
    }
    printf("I knew I could do it!\n");
    return 0;
}

可以看出,每次输入 n 时,程序打印了两条消息。这是因为输入 n 后,我们还按下了 Enter 进行换行,然后还读取了一个换行符,下一次循环中,getchar() 读取了这个换行符并打印了第二条消息。当我们输入多个字符时也会出现多行消息。

改进
使循环读取并丢弃输入的数据

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int guess = 1;

    printf("Pick an integer from 1 to 100. I will try to guess it.\n");
    printf("Respond with a y if my guess is right and with an n if it's wrong.\n");
    printf("Uh...is your number %d?\n", guess);
    while (getchar() != 'y')//no sir输入1.n
    {
        printf("Well, then, is it %d?\n", ++guess);
        while (getchar() != '\n')//2.o不等于\n继续循环while (getchar() != '\n')直到\n
            continue;
    }
    printf("I knew I could do it!\n");
    return 0;
}

在这里插入图片描述

continue的理解
1.continue本身的性质一直读到末尾
2.书上的意思是他只是一个占位符,

在这里插入图片描述
这的确是解决了换行符的问题。但是,该程序还是会把f被视为n。我们用if语句筛选其他响应.首先,添加一个char类型的变量储存响应:char r ;

修改后的循环如下:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int guess = 1;
    char r;
    printf("Pick an integer from 1 to 100. I will try to guess it.\n");
    printf("Respond with a y if my guess is right and with an n if it's wrong.\n");
    printf("Uh...is your number %d?\n", guess);
    while ((r = getchar()) != 'y')
    {
        if ( r == 'n')
            printf("Well, then, is it %d?\n", ++guess);
        else
            printf("I understand only n or y\n");
        while (getchar() != '\n')
           ;
    }
    printf("I knew I could do it!\n");
    return 0;
}

如果您发现文章有错误请与我留言,感谢

  • 41
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

马职音人

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

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

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

打赏作者

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

抵扣说明:

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

余额充值