如何在C ++中使用getline命令? [英] How to use the getline command in c++?

查看:86
本文介绍了如何在C ++中使用getline命令?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将cout命令转换为c ++中的getline命令.

I'm trying to turn a cout command into a getline command in c++.

这是我要更改的代码....

This is my code that I'm trying to changes....

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; 
    }

我正在尝试将以下行:cin >> employees[count].name;和此行:cin >> employees[count].title;更改为getlines.有人可以帮忙吗?

I'm trying to change this line: cin >> employees[count].name; and this line: cin >> employees[count].title; into getlines. Can anyone help?

谢谢

推荐答案

C ++中cin.getline()的冲洗问题

当您想从C ++中的输入流中删除多余的字符时,通常是因为您混合了格式化和未格式化的输入方法.格式化的方法将在流中保留换行符,而未格式化的方法将使用它并成功终止,但是完全无法执行您想要的操作.

Flushing Problems with cin.getline() in C++

When you want to remove extraneous characters from an input stream in C++, it's usually because you mixed formatted and unformatted input methods. The formatted method would leave a newline in the stream and the unformatted method would consume it and terminate successfully, but fail completely to do what you wanted.

    #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";
 }

这个问题通常源于另一个问题,即在程序终止之前如何暂停程序.仅在流中没有剩余字符时,才使用cin.get().您抛出cin >> foo的那一刻;在代码中,解决方案突然失败.您需要先清除流中的所有剩余字符,然后它才能再次工作.

Often this question stems from another question, which is how to pause a program before it terminates. Using cin.get() works only when there are no characters left in the stream. The instant you throw a cin>> foo; in the code, suddenly the solution fails. You need to clear out any leftover characters from the stream before it'll work again.

那么您如何解决该问题?好消息是,除非您想变得挑剔,否则就像循环一样简单: C ++语法(切换纯文本)

So how do you fix the problem? The good news is that unless you want to get picky, it's as simple as a loop: C++ Syntax (Toggle Plain Text)

    #include <istream>  
 void ignore_line ( std::istream& in ) { 
  char ch;
        while ( in.get ( ch ) && ch != '\n' );
 } 

此循环仅读取字符,直到读取文件结尾或换行符.通常假定C ++中的交互式输入是面向行的,并且保证在读取换行符后具有干净的缓冲区.虽然这是不正确的(输入不必是面向行的),但它的分布范围很广,因此可以出于此线程的目的而假定它.

This loop simply reads characters until end-of-file or a newline is read. It's generally assumed that interactive input in C++ is line-oriented and you're guaranteed to have a clean buffer after reading a newline. While that's not true (input doesn't have to be line-oriented), it's wide spread enough that we can assume it for the purposes of this thread.

那么这种方法有什么问题呢?没有.实际上,除非您想深入研究并解决细微的问题,否则这几乎是一样的.但是在我们研究问题之前,这里有一个替代解决方案,它以不同的方式完成相同的事情:

So what's wrong with this approach? Nothing. In fact, this is about as good as it gets unless you want to dig down and fix the subtle problems. But before we look at the problems, here's an alternative solution that does the same thing in a different way:

    #include <ios>
    #include <istream>
    #include <limits>   
void ignore_line ( std::istream& in ) {   
in.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
 } 

std :: istream的ignore成员函数将读取并丢弃最多N个字符或直到分隔符为止.在上面的示例中,N由流大小数据类型的最大值表示,定界符为换行符.仅需一个较大的值(通常为80),它同样可以很好地工作:in.ignore中的C ++语法(切换纯文本)(80,'\ n');但是,streamsize数据类型更可能是流使用的缓冲区大小的准确表示,并且更有可能一直工作.这是我推荐的解决方案.

The ignore member function of std::istream will read and discard up to N characters or until a delimiter. In the above example, N is represented by the largest value of the streamsize data type, and the delimiter is a newline. It works equally well with just a large value (80 is common): C++ Syntax (Toggle Plain Text) in.ignore ( 80, '\n' ); However, the streamsize data type is more likely to be an accurate representation of the size of the buffer that the stream is using, and it's more likely to work all of the time. This is the solution that I recommend.

那么这怎么了?有两个值得注意的问题.第一个很容易修复,并且源于istream不太灵活的事实. istream实际上是basic_istream的typedef.如果您想让广泛的流与ignore_line一起使用,那么您对istream就是SOL.因此,诀窍是使用basic_istream<>代替:

So what's wrong with this? There are two notable problems. The first is easy to fix, and it stems from the fact that istream isn't very flexible. istream is actually a typedef for basic_istream. If you want a wide stream to work with ignore_line, you're SOL with istream. So the trick is to use basic_istream<> instead:

    #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' ) ); 
}

现在ignore_line是一个模板函数,它将从第一个参数派生流包含的字符类型.您可以传递任何源自basic_istream或专门针对basic_istream的流,问题就不存在了.不只是'\ n',而是在文字上使用widen是一个好主意,这样在必要时可以将其正确地转换为更广泛的类型.很好,很容易.

Now ignore_line is a template function that will derive the type of characters that the stream contains from the first argument. You can pass any stream that derives from or specializes basic_istream, and the problem is gone. Instead of just '\n', it's a good idea to use widen on the literal so that it will be properly converted to a wider type if necessary. Nice and easy.

第二个问题更加困难.难得多.这比较困难,因为标准iostream似乎在缺乏便携性或不良功能的情况下随时都会阻碍您的前进.实际上,不可能完全解决该问题.问题是行为取决于流的内容而不同.例如:

The second problem is harder. Much harder. It's harder because standard iostreams seem to block your way at every turn with lack of portability or undesired features. In fact, it's impossible to completely fix the problem. The problem is that the behavior is different depending on the contents of the stream. For example:

    #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"; 
} 

运行此程序三次:

输入:"asdf"输出:该程序无需您的任何输入即可完成.

Input: "asdf" Output: The program finishes without any more input from you.

输入:只需按Enter键输出:程序等待您再次按Enter键.

Input: Just hit Enter Output: The program waits for you to hit Enter one more time.

输入:信号EOF输出:程序等待您再次按下Enter键.

Input: Signal EOF Output: The program waits for you to hit Enter one more time.

问题是流为空.如果您立即按Enter键,则会在流上放置换行符,并由cin.get使用.同样,用信号通知EOF.到那时,流中什么都没有了,cin.ignore会停止所有操作,直到您键入更多字符为止.这是因为cin.ignore是阻止读取.如果没有什么可阅读的,它将等待.

The problem is that the stream is empty. If you hit Enter immediately, a newline is placed on the stream and consumed by cin.get. Likewise with signaling EOF. At that point there's nothing left in the stream and cin.ignore stops everything until you type more characters. This is because cin.ignore is a blocking read. If there's nothing to read, it waits.

对于这三种情况,我们都希望它不会阻塞.好消息是iostream库支持某些可能的解决方案.坏消息是这些都是死胡同.这是两个常见的:

What we'd like it to do is not block for any of those three cases. The good news is that the iostream library supports some possible solutions. The bad news is that these are dead ends. Here are two common ones:

sync成员函数istream类支持一个称为sync的成员函数.它为何具有这样的功能尚在争论中,因为没有人能就应该做什么做达成共识.甚至Bjarne Stroustrup本人也错误地声明它会丢弃流中的所有字符:

The sync member function The istream class supports a member function called sync. Why it has such a function is under debate, because nobody can agree on what it should be doing. Even Bjarne Stroustrup himself incorrectly stated that it discards all characters in the stream:

  #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"; 
} 

此方法有效时,效果很好.坏消息是C ++标准不需要同步就可以执行任何操作,例如丢弃多余的字符.此解决方案不可移植.

When this works, it works beautifully. The bad news is that the C++ standard doesn't require sync to do anything like discarding extraneous characters. This solution is non-portable.

in_avail成员函数下一步是查看istream流缓冲区的in_avail成员函数.乍看起来,该成员函数将告诉您流中有多少个字符,如果返回0,则可以避免调用ignore:

The in_avail member function The next step is to look at the in_avail member function of istream's stream buffer. At first glance it looks like this member function will tell you how many characters are in the stream, and if it returns 0, you can refrain from calling 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";
 }

与同步一样,当它起作用时,效果很好.但是,该标准再次通过说不需要in_avail来为您提供流中字符的准确表示而一堵墙.实际上,某些流行的实现具有严格符合的in_avail,该in_avail始终返回0.不是很有用.现在我们必须要有创造力.

As with sync, when this works, it works great. But once again, the standard raises a wall by saying that in_avail isn't required to give you an accurate representation of the characters in the stream. In fact, some popular implementations have a strictly conforming in_avail that always returns 0. Not very useful. Now we have to get creative.

回退成员函数

 #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";
 } 

这看起来很有希望,因为乍一看,您似乎可以尝试退回换行符.如果操作失败,则最后读取的字符不是换行符,您可以自由调用ignore而不会阻塞.如果操作成功,则换行符将返回,您可以使用单个字符忽略将其删除.

This looks very promising because at first glance, it seems that you can attempt to push back a newline. If the operation fails, the last read character wasn't a newline and you're free to call ignore without blocking. If the operation succeeds, the newline is back and you can remove it with a single character ignore.

可悲的是,它不起作用.不需要回退来进行任何可预见的操作,这引发了为什么它甚至可用的问题.

Sadly, it doesn't work. putback isn't not required to do any of this predictably, which raises the question of why it's even available.

但是回退实际上使我们接近了一种似乎在大多数情况下都可行的解决方案.可以依靠流缓冲区的sungetc成员函数来保证最后读取的字符被放回,而不是依赖于放回失败或不失败.技巧是获取最后一个字符,然后再次阅读并针对换行符进行测试:

But putback actually takes us close to a solution that seems plausible enough to work most of the time. Instead of relying on putback to fail or not, we can guarantee that the last read character is put back by using the sungetc member function of the stream's buffer. The trick is to unget the last character, then read it again and test it against a newline:

  #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";
 }

之所以使用sungetc而不是istream的unget的原因是因为unget返回了流,但是sungetc返回了被推回的字符或EOF.这样,我们可以更轻松地判断函数是否失败.

The reason we use sungetc instead of istream's unget is because unget returns the stream, but sungetc returns either the character that was pushed back, or EOF. This way we can tell if the function failed or not more easily.

如果sungetc失败,则满足以下条件之一:

If sungetc fails, one of the following will be true:

1)流处于错误状态. 2)没有要删除的字符. 3)流不支持取消字符.

1) The stream is in an error state. 2) There are no characters to unget. 3) The stream doesn't support ungetting characters.

如果sungetc成功,将始终有一个字符要读取并针对换行符进行测试.如果该字符与换行符匹配,则最后读取的字符也是换行符,我们不需要调用ignore.如果字符不匹配,则说明未读整行,我们可以安全地调用ignore而不会阻塞.

If sungetc succeeds, there will always be a character to read and test against the newline. If that character matches a newline, then the last read character was also a newline and we don't need to call ignore. If the character doesn't match, then a full line hasn't been read and we can safely call ignore without blocking.

如果流处于错误状态,则调用代码必须处理该问题.如果没有要解开的字符,那么这正是此解决方案旨在正确处理的内容.但是,如果流不支持删除字符,那就是一个问题. ignore_line函数将始终无法丢弃字符,因此对于那些不支持获取字符的实现,我们可以添加一个标志来强制忽略.有时也要知道有多少个字符也被忽略了,所以让我们也添加它,便得到了最终的解决方案:

If the stream is in an error state, that's something the calling code has to deal with. If there are no characters to unget, then that's precisely what this solution is designed to properly handle. But, if the stream doesn't support ungetting characters, that's an issue. The ignore_line function will always fail to discard characters, so for those implementations that don't support ungetting characters, we can add a flag that forces an ignore. It's sometimes useful to know how many characters were ignored as well, so let's add that too and we have the final solution:

   #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; 
}

出于很好的考虑,我还将包括一个调用ignore_line的操纵器,以及一个使用ignore_line暂停程序的操纵器.这样,未清洗的物料就可以停止使用系统("PAUSE");和getch();:

Just for good measure, I'll also include a manipulator that calls ignore_line and also a manipulator that uses ignore_line to pause the program. That way the unwashed masses can stop using system ( "PAUSE" ); and 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();  
 } 
}; 

现在,所有三种情况的行为都相同:

Now all three cases behave identically:

     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();
 } 

这个故事的寓意是:它从未像看起来那样简单,编写可完成所需功能的可移植代码非常困难,并且iostream库非常混乱.

And the moral of the story is: It's never as simple as it seems, writing portable code that does what you want is extremely difficult, and the iostream library is a huge mess.

注意:如果您是初学者,请忘记所有内容,只是了解有冲洗问题并使用cin

这篇关于如何在C ++中使用getline命令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆