关于字符读取,过滤回车的问题 | 清空缓冲区 、cin、scanf。

1. fflush()失效问题:fflush(stdin)是未定义行为,该函数用于输出流,即fflush(stdout) 。 用rewind(stdin)代替刷新输入缓冲区。
2. 参考文章:https://blog.csdn.net/qq_40843865/article/details/81072212
3.关于C++的清空缓冲区的方法:https://www.cnblogs.com/youngforever/articles/3125860.html

清空缓冲区

C++清空缓冲区:

法一:以下语句在 cin 输入之前调用,用于清理输入时,残留在输入缓冲区的字符。

cin.clear()  // 是用来更改cin的状态标示符的。
cin.sync()   // 是用来清除缓存区的数据流的。

法二:

cin.ignore( numeric_limits<streamsize>::max(), '\n' );
//cin.ignore(1024, '\n'),通常把第一个参数设置得足够大,这样实际上总是只有第二个参数'\n'起作用,
//这一句就是把回车(包括回车)之前的所以字符从输入缓冲(流)中清除出去。
C语言清空(输入)缓冲区:
  • rewind(stdin); 仅windows下生效
  • while((getchar())!=EOF); 清除所有内容
  • setbuf(stdin, NULL); 关闭缓冲区
对于 _getch() 无回显有效
//控制台清空缓冲区 
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));

在循环中读取单个字符时,需要考虑过滤回车的问题。
例如:我们循环5次,分别被输入 h e l l o. 预期输出也是这5个字母。

	while (1)
	{
		ch1 = getchar();		//无回显,控制台
		printf("ch1 = %d , ch1 = %c\n", ch1, ch1);

然而结果却与预期不符,应为我们没有考虑过滤每次输入后的回车符。
在这里插入图片描述
这里有几种过滤回车的方法。(回车符本质是一个字符,使用一个变量将其接收即可)

法一:额外接收一个字符,去除残留在输入缓冲区的 \n

缺点,必须严格按照一个输入一个回车,一旦多敲一个回车,ch1将不能收到正常的结果。

		ch1 = getchar();
		getchar();	// 过滤回车

在这里插入图片描述
解决方案:使用多个候选变量,一个候选变量存储输入的字符时,另一个为回车。

		ch1 = getchar();	// 候选变量1
		ch2 = getchar();	// 候选变量2
		if (ch1 != '\n' || ch2 != '\n')	// 任意一个候选变量得到字符
		{
			if (ch1 == '\n')	// 确保ch1得到字符
			{
				ch1 = ch2;
			}
			// 注意这的输出,代表的是永远可以确定ch1为有效输入字符
			printf("ch1 = %d , ch1 = %c\n", ch1, ch1);
		}

在这里插入图片描述
注意:因为getchar() 一次只能得到一个字符,因此我们一次输入多个的时候,与预期不符。这里可以使用while替代if判断,只要有正确的输入,我们就替换到ch1使用。

		ch1 = getchar();
		ch2 = getchar();
		while (ch1 != '\n' || ch2 != '\n')	// 任意一个得到字符
		{
			if (ch1 == '\n')
			{
				swap(ch1, ch2);
			}
			printf("ch1 = %d , ch1 = %c\n", ch1, ch1);
			// ... ch1使用过后置为 '\n'
			ch1 = '\n';
		}

在这里插入图片描述

法二:清空缓冲区

在输入前清空缓冲区内残留的数据

		ch1 = getchar();
		scanf("%*[^\n]"); scanf("%*c");
		//while ((c = getchar()) != '\n' && c != EOF); // 等价
		//rewind(stdin); 			// 刷新输入缓冲区,仅windows下生效
		//setbuf(stdin, NULL);		// 关闭输入缓冲区

在这里插入图片描述
缺点是无法一次输入多个。

法三:使用scanf输入

scanf支持 %*c 过滤字符。缺点:同样不能多输入一个回车,否则会混乱。

	while (1)
	{
		scanf("%c%*c", &ch1);
		printf("ch1 = %d , ch1 = %c\n", ch1, ch1);
	}

在这里插入图片描述
解决方案:读取非回车字符(scnaf支持使用[]选择字符集合)

	while (1)
	{
		scanf("%[^\n]c", &ch1);	// 只接收非回车字符
		getchar();		// 过滤回车
		printf("ch1 = %d , ch1 = %c\n", ch1, ch1);
	}

在这里插入图片描述
改进:检查scanf读取到了字符,再进行输出。

	while (1)
	{
		if (scanf("%[^\n]c", &ch1) > 0)
		{
			printf("ch1 = %d , ch1 = %c\n", ch1, ch1);
		}
		getchar();
		
	}

在这里插入图片描述
缺点是不支持连续输入。

法四:输入到字符串中,每次取一个。

	char str[100];
	while (1)
	{
		scanf("%s", str);
		int n = strlen(str);
		for (int i = 0; i < n; ++i) 
		{
			printf("ch1 = %d , ch1 = %c\n", str[i], str[i]);
		}
	}
scanf("%c", &ch1);	// 将回车存到ch1中
ch1 = getchar();	
rewind(stdin);			// 刷新输入缓冲区
setbuf(stdin, NULL);		// 关闭输入缓冲区
scanf("%*[^\n]"); scanf("%*c");		// %* 可以过滤字符,该语句可以清空缓冲区中所有字符
while ((c = getchar()) != '\n' && c != EOF);	// 同理,清除换冲过去所有字符

在这里插入图片描述



/// C++
// 1.
	// cin.clear();
	// cin.sync();
// 2.
	//cin.ignore( numeric_limits<streamsize>::max(), '\n' );
	// cin.ignore(1024, '\n'),通常把第一个参数设置得足够大,这样实际上总是只有第二个参数'\n'起作用,
						//所以这一句就是把回车(包括回车)之前的所以字符从输入缓冲(流)中清除出去。
// 3.对于 _getch() 无回显有效
	//控制台清空缓冲区 FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
scanf输入缓冲区问题是指在使用scanf函数进行输入时,输入缓冲区中可能会残留上一次输入的换行符\n,导致下一次输入不符合预期。例如,当我们输入完1 2后按下回车键,输入缓冲区里存放着1 2 \n。第一次scanf读走1给a,2给b,中间的空格丢弃,此时第一句scanf已经读完。但是缓冲区里还留着一个\n,当第二次scanf读入时,首先检查缓冲区,发现缓冲区里还有\n,而且正好匹配%c,于是直接读走\n给c。这就是典型的scanf缓冲区问题。 为了解决scanf输入缓冲区问题,可以使用以下方法: 1. 使用fflush(stdin)命令强行刷新输入缓冲,丢弃输入缓冲中的数据。这个方法可以清除缓冲区中的换行符等残留数据,确保输入的正确性。 2. 使用getchar()函数吃掉前面的回车确认符。在执行读取字符操作之前,使用getchar()读取并丢弃缓冲区中的回车符,确保下一次输入的正确性。 3. 使用rewind(stdin)清除标准输入的按键缓冲区。rewind函数是把指定流的读写指针重新指向开头,可以清除输入缓冲区中的残留数据。 通过使用上述方法,可以有效地解决scanf输入缓冲区问题,确保输入的准确性和一致性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [scanf缓冲区问题](https://blog.csdn.net/qq_45908718/article/details/117394732)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我叫RT

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

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

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

打赏作者

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

抵扣说明:

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

余额充值