gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 12:19:23 25 4
gpt4 key购买 nike

我正在尝试将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;
}

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

谢谢

最佳答案

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

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

那么,您如何解决该问题呢?好消息是,除非您想变得挑剔,否则就像循环一样简单:
C++语法(切换纯文本)
    #include <istream>  
void ignore_line ( std::istream& in ) {
char ch;
while ( in.get ( ch ) && ch != '\n' );
}

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

那么这种方法有什么问题呢?没有什么。实际上,除非您想深入研究并解决细微的问题,否则这几乎是一样的。但是在我们研究问题之前,这里有一个替代解决方案,它以不同的方式执行相同的操作:
    #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数据类型更可能是流使用的缓冲区大小的准确表示,并且更有可能一直工作。这是我推荐的解决方案。

那么,这怎么了?有两个值得注意的问题。第一个很容易修复,并且源于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' ) );
}

现在ignore_line是一个模板函数,它将从第一个参数派生流包含的字符类型。您可以传递任何源自basic_istream或专门针对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";
}

运行此程序三次:

输入:“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";
}

当这种方法起作用时,它可以很好地工作。坏消息是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";
}

与同步一样,当它起作用时,效果很好。但是,该标准再次通过说不需要in_avail来为您提供流中字符的准确表示而一堵墙。实际上,某些流行的实现具有严格符合的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";
}

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

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

但是,退缩实际上使我们接近了一种似乎在大多数情况下都可行的解决方案。我们可以依靠流缓冲区的sungetc成员函数来保证最后读取的字符被放回,而不是依赖于放回失败或不失败。诀窍是获取最后一个字符,然后再次阅读并针对换行符进行测试:
  #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。这样,我们可以很容易地判断函数是否失败。

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

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

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

如果流处于错误状态,则调用代码必须处理该问题。如果没有要解开的字符,那么正是此解决方案旨在正确处理的内容。但是,如果流不支持删除字符,那就是一个问题。 ignore_line函数将始终无法丢弃字符,因此对于那些不支持获取字符的实现,我们可以添加一个标志来强制忽略。有时也要知道有多少个字符也被忽略了,所以让我们也添加它,便得到了最终的解决方案:
   #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暂停程序的操纵器。这样,未清洗的 Material 就可以停止使用系统(“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();
}
};

现在,这三种情况的行为都相同:
     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库则是一团糟。

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

关于c++ - 如何在C++中使用getline命令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9124583/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com