我正在尝试将cout命令转换为c ++中的getline命令.
这是我试图改变的代码....
for (int count=0; count < numberOfEmployees; count++)
{
cout << "Name: ";
cin >> employees[count].name;
cout << "Title: ";
cin >> employees[count].title;
cout << "SSNum: ";
cin >> employees[count].SSNum;
cout << "Salary: ";
cin >> employees[count].Salary;
cout << "Withholding Exemptions: ";
cin >> employees[count].Withholding_Exemptions;
}
Run Code Online (Sandbox Code Playgroud)
我正试图改变这一行:cin >> employees[count].name;这一行:cin >> employees[count].title;进入getlines.有人可以帮忙吗?
谢谢
当您想要在C++中从输入流中删除无关字符时,通常是因为您混合了格式化和未格式化的输入方法.格式化的方法将在流中留下换行符,未格式化的方法将使用它并成功终止,但完全无法完成您想要的操作.
#include <iostream>
int main() {
std::cout<<"Enter the letter A: ";
std::cin.get();
std::cout<<"Enter the letter B: ";
std::cin.get();
std::cout<<"Too late, you can't type anymore\n";
}
Run Code Online (Sandbox Code Playgroud)
这个问题通常源于另一个问题,即如何在程序终止之前暂停程序.使用cin.get()仅在流中没有剩余字符时才有效.你扔一个cin >> foo的瞬间; 在代码中,突然解决方案失败了.您需要在流再次运行之前清除流中剩余的任何字符.
那么你如何解决这个问题呢?好消息是除非你想挑剔,否则它就像循环一样简单:C++语法(切换纯文本)
#include <istream>
void ignore_line ( std::istream& in ) {
char ch;
while ( in.get ( ch ) && ch != '\n' );
}
Run Code Online (Sandbox Code Playgroud)
此循环只读取字符,直到文件结束或读取换行符.通常假设C++中的交互式输入是面向行的,并且在读取换行符后保证有一个干净的缓冲区.虽然这不是真的(输入不必是面向行的),但它的广泛传播使我们可以为此线程的目的而假设它.
那么这种方法有什么问题呢?没有.事实上,除非你想深入挖掘并修复微妙的问题,否则这个问题就好了.但在我们研究问题之前,这里有一个替代解决方案,以不同的方式做同样的事情:
#include <ios>
#include <istream>
#include <limits>
void ignore_line ( std::istream& in ) {
in.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
}
Run Code Online (Sandbox Code Playgroud)
std :: istream的ignore成员函数将读取并丢弃最多N个字符或直到分隔符.在上面的示例中,N由streamize数据类型的最大值表示,分隔符是换行符.只有很大的值(80是常见的)它同样适用:C++语法(切换纯文本)in.ignore(80,'\n'); 但是,streamize数据类型更可能是流正在使用的缓冲区大小的准确表示,并且它更有可能一直工作.这是我推荐的解决方案.
那有什么不对呢?有两个值得注意的问题.第一个很容易解决,它源于istream不是很灵活的事实.istream实际上是basic_istream的typedef.如果你想要一个宽流来使用ignore_line,你就是使用istream的SOL.所以诀窍是使用basic_istream <>代替:
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in ) {
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
}
Run Code Online (Sandbox Code Playgroud)
现在,ignore_line是一个模板函数,它将从第一个参数派生流包含的字符类型.您可以传递派生自或专门化basic_istream的任何流,问题就消失了.而不仅仅是'\n',在文字上使用widen是一个好主意,以便在必要时将其正确转换为更宽的类型.好,易于.
第二个问题更难.更加困难.这更难,因为标准的iostream似乎在每一个转折点都阻挡了你的方式,缺乏便携性或不受欢迎的功能.事实上,完全解决问题是不可能的.问题是行为根据流的内容而不同.例如:
#include <iostream>
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in ) {
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
}
int main() {
std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin.clear();
ignore_line ( std::cin );
std::cout<<"All done.\n";
}
Run Code Online (Sandbox Code Playgroud)
运行此程序三次:
输入:"asdf"输出:程序在没有您输入的情况下完成.
输入:只需按Enter输入:程序等待您再次按Enter键.
输入:信号EOF输出:程序等待您再次按Enter键.
问题是流是空的.如果立即按Enter键,则会在流上添加换行符并由cin.get使用.与信号EOF一样.此时,流中没有任何内容,cin.ignore会停止所有内容,直到您输入更多字符.这是因为cin.ignore是一个阻塞读取.如果没有什么可读的,它会等待.
我们希望它做的不是阻止这三种情况中的任何一种.好消息是iostream库支持一些可能的解决方案.坏消息是这些都是死路一条.这是两个常见的:
同步成员函数istream类支持名为sync的成员函数.为什么它具有这样的功能正在争论中,因为没有人能够就它应该做什么达成一致.甚至Bjarne Stroustrup本人也错误地声明它丢弃了流中的所有字符:
#include <iostream>
int main() {
std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin.clear();
std::cin.sync();
std::cout<<"All done.\n";
}
Run Code Online (Sandbox Code Playgroud)
当它工作时,它工作得很漂亮.坏消息是C++标准不需要同步来做丢弃无关字符的任何事情.该解决方案是不可移植的.
in_avail成员函数下一步是查看istream的流缓冲区的in_avail成员函数.乍一看,这个成员函数看起来会告诉你流中有多少个字符,如果它返回0,你可以避免调用ignore:
#include <iostream>
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in ) {
if ( in.rdbuf()->in_avail() > 0 )
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
}
int main() {
std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin.clear();
ignore_line ( std::cin );
std::cout<<"All done.\n";
}
Run Code Online (Sandbox Code Playgroud)
与同步一样,当它工作时,它工作得很好.但是再一次,该标准提出了一个问题,即不要求in_avail为您提供流中字符的准确表示.实际上,一些流行的实现具有严格符合的in_avail,它总是返回0.不是非常有用.现在我们必须发挥创意.
回调成员函数
#include <iostream>
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
void ignore_line
( std::basic_istream<CharT>& in ) {
if ( !in.putback ( in.widen ( '\n' ) ) )
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) ); else
in.ignore(); }
int main()
{ std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin.clear();
ignore_line ( std::cin );
std::cout<<"All done.\n";
}
Run Code Online (Sandbox Code Playgroud)
这看起来很有希望,因为乍一看,似乎你可以尝试推回换行符.如果操作失败,则最后读取的字符不是换行符,您可以自由调用ignore而不会阻塞.如果操作成功,则返回换行符,您可以使用单个字符ignore将其删除.
可悲的是,它不起作用.回归并不是要求做任何可预测的事情,这引发了为什么它甚至可用的问题.
但实际上,回归实际上让我们接近一个看似合理的解决方案,大部分时间都可以工作.我们可以通过使用流缓冲区的sungetc成员函数来保证最后读取的字符被放回,而不是依赖于putback是否失败.诀窍是取消最后一个字符,然后再次读取它并针对换行符进行测试:
#include <iostream>
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in ) {
if ( in.rdbuf()->sungetc() != std::char_traits<CharT>::eof()
&& in.get() != in.widen ( '\n' ) ) {
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
}
}
int main() {
std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin.clear();
ignore_line ( std::cin );
std::cout<<"All done.\n";
}
Run Code Online (Sandbox Code Playgroud)
我们使用sungetc而不是istream的unget的原因是因为unget返回了流,但是sungetc返回被推回的字符或EOF.通过这种方式,我们可以更轻松地判断功能是否失败.
如果sungetc失败,则以下之一将成立:
1)流处于错误状态.2)没有任何角色可以取消.3)流不支持ungetting字符.
如果sungetc成功,将始终有一个字符来读取和测试换行符.如果该字符与换行符匹配,那么最后读取的字符也是换行符,我们不需要调用ignore.如果字符不匹配,则表示尚未读取整行,我们可以安全地调用ignore而不会阻塞.
如果流处于错误状态,那就是调用代码必须处理的内容.如果没有要忘记的字符,那么这正是该解决方案正确设计的正确处理方式.但是,如果流不支持ungetting字符,那就是一个问题.ignore_line函数将始终无法丢弃字符,因此对于那些不支持ungetting字符的实现,我们可以添加一个强制忽略的标志.知道有多少字符被忽略有时很有用,所以让我们添加它,我们有最终的解决方案:
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
std::streamsize ignore_line ( std::basic_istream<CharT>& in, bool always_discard = false ) {
std::streamsize nread = 0;
if ( always_discard || ( in.rdbuf()->sungetc() != std::char_traits<CharT>::eof()
&& in.get() != in.widen ( '\n' ) ) )
{
// The stream is good, and we haven't
// read a full line yet, so clear it out
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
nread = in.gcount(); }
return nread;
}
Run Code Online (Sandbox Code Playgroud)
为了更好的衡量,我还将包括一个调用ignore_line的操纵器以及一个使用ignore_line来暂停程序的操纵器.这样未洗过的群众就可以停止使用系统("PAUSE"); 和getch();:
class ignoreline {
bool _always_discard;
mutable std::streamsize _nread;
public:
ignoreline ( bool always_discard = false )
: _always_discard ( always_discard ), _nread ( 0 ) {}
std::streamsize gcount() const { return _nread;
}
template <typename CharT>
friend std::basic_istream<CharT>& operator>> ( std::basic_istream<CharT>& in, const ignoreline& manip )
{
manip._nread = ignore_line ( in, manip._always_discard );
return in;
}
};
class pause {
ignoreline _ignore;
public:
pause ( bool always_discard = false ) : _ignore ( always_discard ) {}
std::streamsize gcount()
const { return _ignore.gcount();
}
template <typename CharT>
friend std::basic_istream<CharT>& operator>> ( std::basic_istream<CharT>& in, const pause& manip )
{
if ( !( in>> manip._ignore ) )
in.clear();
std::cout<<"Press Enter to continue . . .";
return in.ignore();
}
};
Run Code Online (Sandbox Code Playgroud)
现在所有三种情况都表现相同:
int main()
{ std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin>> ignoreline();
std::cout<<"All done.\n";
std::cin>> pause();
}
Run Code Online (Sandbox Code Playgroud)
故事的寓意是:它从来没有像看起来那么简单,编写可以实现你想要的可移植代码是非常困难的,而iostream库是一个巨大的混乱.
注意:如果你是一个初学者忘记了一切,只是明白有一个冲洗问题,并使用cin