[英]When and why do I need to use cin.ignore() in C++?
我用 C++ 编写了一个非常基本的程序,它要求用户输入一个数字,然后输入一个字符串。 令我惊讶的是,在运行程序时,它从未停止请求字符串。 它只是跳过了它。 在对 StackOverflow 进行了一些阅读后,我发现我需要添加一行内容:
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";
}
忽略正是顾名思义。
它不会“丢弃”您不需要的东西,而是会忽略您在调用它时指定的字符数量,直到您指定为断点的字符。
它适用于输入和输出缓冲区。
本质上,对于std::cin
语句,您在执行getline
调用之前使用 ignore ,因为当用户使用std::cin
输入某些内容时,他们按回车键并且'\\n'
字符进入cin
缓冲区。 然后,如果您使用getline
,它会获取换行符而不是您想要的字符串。 所以你做了一个std::cin.ignore(1000,'\\n')
并且应该清除缓冲区直到你想要的字符串。 (将 1000 放在那里是为了在指定的断点之前跳过特定数量的字符,在本例中为 \\n 换行符。)
你正在以错误的方式思考这个问题。 每次使用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
的字符,应用程序将产生一个看似奇怪的输出。
简答
为什么? 因为输入流中仍有空格(回车、制表符、空格、换行符)。
什么时候? 当您使用某些不独立的函数时,会忽略前导空格。 Cin 默认会忽略并删除前导空格,但 getline 不会自行忽略前导空格。
现在详细解答。
您在控制台中输入的所有内容都是从标准流 stdin 中读取的。 当您输入某些内容时,假设您的情况为 256 并按 Enter,流的内容将变为256\\n
。 现在 cin 选取 256 并将其从流中删除, \\n
仍保留在流中。 现在,当您输入您的姓名时,假设为Raddicus
,流的新内容是\\nRaddicus
。
现在问题来了。 当您尝试使用 getline 读取一行时,如果没有提供任何分隔符作为第三个参数,getline 默认读取直到换行符并从流中删除换行符。 因此,在调用新行时,getline 从流中读取并丢弃\\n
并导致在 mystr 中读取一个空字符串,这看起来像 getline 被跳过(但事实并非如此),因为流中已经有一个换行符,getline 不会提示输入输入,因为它已经读取了它应该读取的内容。
现在,cin.ignore 在这里有什么帮助?
根据来自cplusplus.com的忽略文档摘录 -
istream& ignore (streamsize n = 1, int delim = EOF);
从输入序列中提取字符并丢弃它们,直到提取了 n 个字符,或者一个比较等于 delim。
如果到达文件尾,该函数也会停止提取字符。 如果过早地达到了这一点(在提取 n 个字符或找到 delim 之前),该函数将设置 eofbit 标志。
所以, cin.ignore(256, '\\n');
, 忽略前 256 个字符或所有字符,直到遇到分隔符(在您的情况下为 \\n ),以先到者为准(此处 \\n 是第一个字符,因此它会忽略直到遇到 \\n )。
仅供参考,如果您不确切知道要跳过多少个字符,而您的唯一目的是清除流以准备使用 getline 或 cin 读取字符串,您应该使用cin.ignore(numeric_limits<streamsize>::max(),'\\n')
。
快速解释:它忽略等于流的最大大小的字符或直到遇到 '\\n' ,以先发生的情况为准。
当您想手动从输入流中丢弃特定数量的字符时。
一个非常常见的用例是使用它来安全地忽略换行符,因为 cin 有时会留下换行符,您必须转到下一行输入。
长话短说,它在处理流输入时为您提供了灵活性。
忽略功能用于跳过(丢弃/丢弃)输入流中的字符。 忽略文件与文件 istream 相关联。 考虑下面的函数,例如:cin.ignore(120,'/n'); 特定函数跳过下一个 120 个输入字符或跳过这些字符直到读取换行符。
正如许多其他用户所指出的那样。 这是因为可能有空格或换行符。
考虑下面的代码,它从给定的字符串中删除所有重复的字符。
#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++ 中使用 scanf(" %[^\\n]",str) 比在 cin>> 语句之后使用 cin.ignore() 更好。要做到这一点,首先必须包含 < cstdio > 标头。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.