何时以及为啥需要在 C++ 中使用 cin.ignore()?
Posted
技术标签:
【中文标题】何时以及为啥需要在 C++ 中使用 cin.ignore()?【英文标题】:When and why do I need to use cin.ignore() in C++?何时以及为什么需要在 C++ 中使用 cin.ignore()? 【发布时间】:2014-10-17 23:34:26 【问题描述】:我用 C++ 编写了一个非常基本的程序,它要求用户输入一个数字,然后输入一个字符串。令我惊讶的是,在运行程序时,它从未停止询问字符串。它只是跳过了它。在对 *** 进行了一些阅读之后,我发现我需要添加一行内容:
cin.ignore(256, '\n');
在获取字符串输入的行之前。添加它可以解决问题并使程序正常工作。我的问题是为什么 C++ 需要这条 cin.ignore()
行,我如何预测何时需要使用 cin.ignore()
?
这是我写的程序:
#include <iostream>
#include <string>
using namespace std;
int main()
double num;
string mystr;
cout << "Please enter a number: " << "\n";
cin >> num;
cout << "Your number is: " << num << "\n";
cin.ignore(256, '\n'); // Why do I need this line?
cout << "Please enter your name: \n";
getline (cin, mystr);
cout << "So your name is " << mystr << "?\n";
cout << "Have a nice day. \n";
【问题讨论】:
这不是您阅读的答案中的解释吗?为什么不在评论中要求澄清?现在我们在这个主题上有另一个副本。叹息。 @LightnessRacesinOrbit 投票以重复关闭? @LightnessRacesinOrbit 抱歉重复了这个问题。 @MattMcNabb:是的,但是 cba 可以找到它。如果我不必这样做会很好。 好的,所以当我运行您的代码而不忽略时,它会跳过第二个 cin>>,大概是因为 endl 仍在流中。但是,当我使用 ignore 运行您的代码时,如果我键入数字字符以外的任何内容,它仍然会跳过第二个 cin>>。如果我输入两个忽略,它会在第二个 cin>> 之前等待第三个输入。谁能解释一下? 【参考方案1】:当您想手动从输入流中丢弃特定数量的字符时。
一个非常常见的用例是使用它来安全地忽略换行符,因为 cin 有时会留下换行符,您必须重复这些换行符才能进入下一行输入。
长话短说,它在处理流输入时为您提供了灵活性。
【讨论】:
感谢您的回复。有没有更有效的方法在 cin 之后使用 getline() ?我是否应该计划在每行之间添加一条忽略线,其中一个 cin 后跟一个 getline()?这对我来说似乎很愚蠢。当你比我有更多的 C++ 经验时,也许它更有意义。 @Raddicus 这真的很愚蠢,特别是因为我们知道'\n'
在 IOStreams 中被解析为空格,而 IOStreams 提供了 std::ws
操纵器,它丢弃了前导空格。您所要做的就是std::getline(std::cin >> ws, mystr)
忽略所有空格和换行符。
@Raddicus:我建议您避免在同一流中混合operator>>
和getline
。例如,对于cin
,只能使用getline
。如果您需要非字符串数据,则使用istringstream
或stoi/stod/etc...
解析从getline
获得的字符串
而不是“有时”,准确描述时间和地点
@0x499602D2 在这种情况下是个好主意,但在其他情况下,空行很重要(例如使用默认值输入),因此仍然需要了解问题【参考方案2】:
忽略正是顾名思义。
它不会“丢弃”你不需要的东西,它会忽略你在调用它时指定的字符数量,直到你指定为断点的字符。
它适用于输入和输出缓冲区。
基本上,对于std::cin
语句,您在调用getline
之前使用ignore,因为当用户使用std::cin
输入内容时,他们按回车键,'\n'
字符进入cin
缓冲区。然后,如果您使用getline
,它将获取换行符而不是您想要的字符串。所以你做一个std::cin.ignore(1000,'\n')
并且应该将缓冲区清除到你想要的字符串。 (放置 1000 是为了跳过指定断点之前的特定数量的字符,在本例中为 \n 换行符。)
【讨论】:
谢谢。像您描述的那样,问为什么 C++ 会在 cin 缓冲区中获取 '\n' 字符的问题是不是太过分了?这是语言的缺陷吗?还是故意这样做是因为它有某种目的? 不完全是缺陷,更像是精确度。从技术上讲,如果换行符没有被读入,那么它就不会读取所有内容。输入缓冲区会忽略空格,因此当您从 std::cin 读取信息时,换行符无关紧要。但是当您谈论 getline 时,它会将整行获取到换行符,并且当换行符是getline 函数首先看到的就是它所得到的一切。 您需要使用numeric_limits<streamsize>::max()
忽略所有字符,而不是1000。
按照标准,.ignore()“提取和丢弃字符”,所以我认为这非常接近于扔掉cplusplus.com/reference/istream/istream/ignore【参考方案3】:
忽略函数用于跳过(丢弃/丢弃)输入流中的字符。忽略文件与文件 istream 相关联。 考虑下面的函数 例如:cin.ignore(120,'/n'); 特定函数跳过下一个 120 个输入字符或跳过字符直到读取换行符。
【讨论】:
【参考方案4】:你想错了。每次使用 cin
或 getline
时,您都会按照逻辑步骤进行思考。前任。先问号码,再问名字。这是思考cin
的错误方式。因此,您遇到了竞争条件,因为您假设每次请求输入时流都是清晰的。
如果您编写程序纯粹是为了输入,您会发现问题:
void main(void)
double num;
string mystr;
cin >> num;
getline(cin, mystr);
cout << "num=" << num << ",mystr=\'" << mystr << "\'" << endl;
在上面,你在想,“首先得到一个数字。”所以你输入123
按回车,你的输出将是num=123,mystr=''
。这是为什么?这是因为在流中有 123\n
并且 123
被解析为 num
变量,而 \n
仍在流中。默认情况下,阅读getline
函数的文档,它将在istream
中查找,直到遇到\n
。在这个例子中,由于\n
在流中,它看起来像是“跳过”了它,但它工作正常。
要使上述操作生效,您必须输入123Hello World
,这将正确输出num=123,mystr='Hello World'
。那,或者你在cin
和getline
之间放置一个cin.ignore
,这样它就会分成你期望的逻辑步骤。
这就是您需要ignore
命令的原因。因为您是以逻辑步骤而不是流形式来考虑它,所以您会遇到竞争条件。
再举一个学校里常见的代码示例:
void main(void)
int age;
string firstName;
string lastName;
cout << "First name: ";
cin >> firstName;
cout << "Last name: ";
cin >> lastName;
cout << "Age: ";
cin >> age;
cout << "Hello " << firstName << " " << lastName << "! You are " << age << " years old!" << endl;
以上似乎是合乎逻辑的步骤。首先询问名字,姓氏,然后是年龄。因此,如果您执行了John
输入,然后是Doe
输入,然后是19
输入,则应用程序将执行每个逻辑步骤。如果您在“流”中想到它,您只需在“名字:”问题上输入John Doe 19
,它也可以正常工作,并且似乎跳过了剩余的问题。要使上述内容按逻辑步骤进行,您需要ignore
处理每个逻辑中断问题的剩余流。
请记住将您的程序输入视为从“流”中读取,而不是按逻辑步骤。每次您调用 cin
时,都会从流中读取它。如果用户输入了错误的输入,这将创建一个相当有缺陷的应用程序。例如,如果您输入的字符应为 cin >> double
,则应用程序将产生看似奇怪的输出。
【讨论】:
【参考方案5】:在 c++ 中使用 scanf(" %[^\n]",str) 比在 cin>> 语句后使用 cin.ignore() 更好。要做到这一点,首先您必须包含 标头。
【讨论】:
不正确。scanf
是 <cstdio>
标头的一部分,不是从用户那里获取输入的惯用 C++ 方式。【参考方案6】:
简答
为什么?因为输入流中仍然存在空格(回车、制表符、空格、换行符)。
什么时候?当您使用某些不会自行忽略前导空格的函数时。默认情况下,Cin 会忽略并删除前导空格,但 getline 不会自行忽略前导空格。
现在有一个详细的答案。
您在控制台中输入的所有内容都是从标准流 stdin 中读取的。当您输入某些内容时,假设您的情况为 256,然后按 Enter,流的内容将变为 256\n
。现在 cin 拾取 256 并将其从流中删除,\n
仍保留在流中。
现在接下来当你输入你的名字时,比如说Raddicus
,流的新内容是\nRaddicus
。
现在问题来了。
当您尝试使用 getline 读取一行时,如果没有提供任何分隔符作为第三个参数,getline 默认读取到换行符并从流中删除换行符。
因此,在调用新行时,getline 从流中读取并丢弃\n
,并导致在 mystr 中读取一个空字符串,这看起来像是跳过了 getline(但不是),因为流中已经有一个换行符,getline 不会提示用于输入,因为它已经读取了它应该读取的内容。
现在,cin.ignore 对此有何帮助?
根据cplusplus.com的忽略文档摘录-
istream& 忽略 (streamsize n = 1, int delim = EOF);
从输入序列中提取字符并丢弃它们,直到 n 个字符已被提取,或者一个比较等于 分隔符。
如果文件结尾是,该函数也会停止提取字符 到达。如果过早地达到这一点(在提取 n 字符或查找分隔符),该函数设置 eofbit 标志。
所以,cin.ignore(256, '\n');
,忽略前 256 个字符或所有字符,直到它遇到分隔符(这里是 \n 在你的情况下),以先到者为准(这里 \n 是第一个字符,所以它忽略直到遇到 \n )。
仅供参考,如果您不确切知道要跳过多少个字符,并且您的唯一目的是清除流以准备使用 getline 或 cin 读取字符串,则应使用 cin.ignore(numeric_limits<streamsize>::max(),'\n')
。
快速解释:它忽略等于流最大大小的字符或直到遇到'\n',无论哪种情况先发生。
【讨论】:
is cin.get() 是否也像 cin.getline() 一样在帐户中使用空格字符?【参考方案7】:正如许多其他用户所指出的那样。这是因为可能有空格或换行符。
考虑以下代码,它会从给定字符串中删除所有重复字符。
#include <bits/stdc++.h>
using namespace std;
int main()
int t;
cin>>t;
cin.ignore(); //Notice that this cin.ignore() is really crucial for any extra whitespace or newline character
while(t--)
vector<int> v(256,0);
string s;
getline(cin,s);
string s2;
for(int i=0;i<s.size();i++)
if (v[s[i]]) continue;
else
s2.push_back(s[i]);
v[s[i]]++;
cout<<s2<<endl;
return 0;
所以,你明白它会忽略那些不需要的输入并完成工作。
【讨论】:
以上是关于何时以及为啥需要在 C++ 中使用 cin.ignore()?的主要内容,如果未能解决你的问题,请参考以下文章