如何在c ++中使用getline命令?

Gve*_*222 6 c++ getline

我正在尝试将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.有人可以帮忙吗?

谢谢

Roh*_*ews 9

在C++中使用cin.getline()解决问题

当您想要在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


Ken*_*nde 1

看一下getline原型,您会发现需要两件事:

  1. 一个istream东西
  2. 用于获取结果的字符串
  3. (可选)“新行”分隔符(默认为'\n'.

在您的情况下,分隔符似乎可能是默认的:'\n'; 如果没有,您可以指定分隔每个值的字符(可能是空格' '或其他字符)。流cin将是您的istream对象,并且 的每个属性employees[count]将用作第二个参数。总而言之,getline(cin, employees[count].name);应该做到这一点。