C++排雷:17. 输入整行字符串的getline(空行输出、回车吸收)问题

需求:

  • 输入字符
  • 可选择整行输入和逐字输入两种模式
    问题代码:
#include<iostream>
#include<string>

using namespace std;
int main()

{
	int choice;
	cout << "整行输入请输入1,逐字输入请输入0\n";
	cin >> choice;
	
	if (choice==1)
	{
		string content_str;
		cout << "现在是整行输入模式\n"<<"请整行输入你要输入的内容\n";
		while (getline(cin, content_str))
		{
				cout << content_str << endl;
			//if (content_str.empty())
			//{
			//	break;
			//}
		}
	}
	
	else if(choice==0)
	{
		cout << "现在是逐字输入模式\n" << "请逐字输入你要输入的内容\n";
		char content_str;
		while (cin>>content_str )
		{
			cout << content_str<<endl;
		}
	}
	
	else
	{
		cout << "输入有误\n";
	}

	return 0;
}

我们choice输入1进入整行输入模式,运行结果如下:
在这里插入图片描述
很奇怪,还没有cin,就已经进入了结构体,运行了cout语句了。看来先进入循环后,执行一次再进行条件判断吧?

为了检测,这里把string content_str;

  • 修改为string content_str(“初始值”);
    再运行:
    在这里插入图片描述
    这一结果推翻了之前的推测,现在情况有些难以判断,所以设置断点进行debug:
    在这里插入图片描述进入while之前,初始值正确设置,讲道理,如果不先经过条件判断,直接运行语句的话,直接输出的应该是“初始值”而非空行。
    这里继续下一句,奇怪的事情发生了:
    在这里插入图片描述可以看到,本次并没有提示控制台输入,而是直接进入了结构体,一进去content_str的值就被清空了!
  • 个人认为这个错误是很严重的,如果我想以空行为条件判断,那么在程序一运行时,就直接进入了空行条件结构体了。

很奇怪啊,结构体是在content_str的作用域内的,为什么一进去就清空了呢?我怀疑是getline的作用,使cin直接接受了回车,将回车推到了content_str内,所以输出了空行。

那么回车是从哪里来的呢?分析整个流程:

  • 在确定输入模式的时候,我在控制台敲了1+回车
  • 在conten_str的定义下,输出的“ cout << “现在是整行输入模式\n”<<“请整行输入你要输入的内容\n”; ”当中有两个换行符

先考虑第一个情况,这里把模式1的代码块拿出来单独运行:
在这里插入图片描述果然!空行消失了

问题找到了,那,到底是什么原因,使前面cin输入的1+回车影响到了content_str呢?

原来键盘是输入到缓冲区的,cin 和cin.getline()实际上是从缓冲区读入数据,当缓冲区有内容时,会直接从缓冲区读取,不会要求键盘输入。

  • cin只是在缓存区中,把字符读走,会剩余/n在缓存区中
  • 但是getline对/n极度敏感,导致getline刚开始读入便遇到/n于是停止读入数据。

因此,要在cin与getline之间加入

  • cin.get();
  • 或cin.ignore();
    这样,程序就可以正常运行了,吸收了换行符后,可以加入循环退出语句:
			if (content_str.empty())
			{
				break;
			}

其中cin.get()用来舍弃输入流中不需要的字符 或者舍弃回车。

cin.ignore( a, ch )表示从 cin 中提取并忽略字符。而每抛弃一个字符,它都要进行计数和比较字符:如果计数值达到 a 或者被抛弃的字符是 ch ,则cin.ignore() 函数执行终止;否则,它继续等待。

  • cin.ignore(1024, ‘\n’),通常把第一个参数设置得足够大,这样实际上是为了只有第二个参数 ‘\n’
    起作用,所以这一句就是把回车(包括回车)之前的所以字符从输入缓冲流中清除出去。
  • 如果默认不给参数的话,默认参数为cin.ignore(1, EOF),即把EOF前的1个字符清掉,没有遇到EOF就清掉一个字符然后结束

最后再谈一谈string的输入运算符和getline函数是如何处理空白符的:

  • string的输入运算符自动忽略字符串开头的空白(包括空格符、换行符、制表符),从第一个真正的字符开始,直到遇见下一处空白为止。
  • 如果需要保留输入时的空白符,应用getline函数替代原来的>>运算符,getline从给定的输入流中读入数据,直到换行符为止,此时换行符也被读取进来,但是并不储存在最后的字符串里
C++getline函数默认会读取并丢弃输入的换行符(\n)。这就意味着,当你在使用getline函数读取字符串时,它会读取换行符并将其丢弃,而不会将其包含在读取的字符串。 例如,如果你使用cin来读取一个整数后再使用getline函数读取一个字符串getline函数会读取之前输入的整数后的换行符,并将其丢弃。 然而,如果你想要明确地吸收回车符,可以在调用getline函数之前使用cin.ignore()函数来清除输入的换行符。这样,getline函数就可以读取到正确的输入了。 示例代码如下: cin.ignore(); // 清除输入的换行符 getline(cin, content_str); // 使用getline函数读取字符串 通过在getline函数之前调用cin.ignore函数,你可以确保getline函数正确地读取包括回车符在内的输入内容。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C++排雷17. 输入整行字符串getline空行输出回车吸收问题](https://blog.csdn.net/weixin_44671418/article/details/107064513)[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: 50%"] - *2* [使用cin.get()吸收回车的方法](https://blog.csdn.net/roadtohacker/article/details/103413164)[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: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值