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

2024-02-14

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

Thanks


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 的忽略成员函数将读取并丢弃最多 N 个字符或直到分隔符。在上面的例子中,N用streamsize数据类型的最大值表示,分隔符是换行符。它同样适用于较大的值(80 很常见): C++ 语法 (切换纯文本) in.ignore ( 80, '\n' );但是,streamsize 数据类型更有可能准确表示流正在使用的缓冲区的大小,并且它更有可能始终有效。这是我推荐的解决方案。

那么这有什么问题呢?有两个值得注意的问题。第一个很容易修复,这是因为 istream 不太灵活。 istream 实际上是 basic_istream 的 typedef。如果你想要一个宽流与ignore_line一起工作,那么你可以使用istream。所以技巧是使用 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 的流,问题就消失了。最好在文字上使用 Widen,而不是仅仅使用 '\n',以便在必要时将其正确转换为更宽的类型。好,易于。

第二个问题更难。困难得多。这更困难,因为标准 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 ,它总是返回 0。不是很有用。现在我们必须发挥创意。

putback 成员函数

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

这看起来非常有希望,因为乍一看,您似乎可以尝试推回换行符。如果操作失败,则最后读取的字符不是换行符,您可以随意调用忽略而不阻塞。如果操作成功,换行符又回来了,您可以通过单个字符忽略将其删除。

可悲的是,它不起作用。不需要 putback 就可以预见地完成这些操作,这就提出了为什么它可用的问题。

但回溯实际上让我们接近了一个在大多数情况下似乎足够可行的解决方案。我们可以通过使用流缓冲区的 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";
 }

我们使用 sungetc 而不是 istream 的 unget 的原因是因为 unget 返回流,但 sungetc 返回的是被推回的字符,或者 EOF。这样我们就可以更容易地判断函数是否失败。

如果 sungetc 失败,则以下情况之一为真:

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

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

如果流处于错误状态,则调用代码必须处理该情况。如果没有需要删除的字符,那么这正是该解决方案旨在正确处理的问题。但是,如果流不支持取消获取字符,那就是一个问题。 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来暂停程序的操纵器。这样,未清洗的群众就可以停止使用系统(“暂停”);和 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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在c++中使用getline命令? 的相关文章

  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • C# 异步等待澄清?

    我读了here http blog stephencleary com 2012 02 async and await html that 等待检查等待的看看它是否有already完全的 如果 可等待已经完成 那么该方法将继续 运行 同步
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • 无限循环与无限递归。两者都是未定义的吗?

    无副作用的无限循环是未定义的行为 看here https coliru stacked crooked com view id 24e0a58778f67cd4举个例子参考参数 https en cppreference com w cpp
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 方程“a + bx = c + dy”的积分解

    在等式中a bx c dy 所有变量都是整数 a b c and d是已知的 我如何找到整体解决方案x and y 如果我的想法是正确的 将会有无限多个解 由最小公倍数分隔b and d 但我只需要一个解决方案 我可以计算其余的 这是一个例
  • 使用 C# 中的 CsvHelper 将不同文化的 csv 解析为十进制

    C 中 CsvHelper 解析小数的问题 我创建了一个从 byte 而不是文件获取 csv 文件的类 并且它工作正常 public static List
  • 如何定义一个可结构化绑定的对象的概念?

    我想定义一个concept可以检测类型是否T can be 结构化绑定 or not template
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • C 编程:带有数组的函数

    我正在尝试编写一个函数 该函数查找行为 4 列为 4 的二维数组中的最大值 其中二维数组填充有用户输入 我知道我的主要错误是函数中的数组 但我不确定它是什么 如果有人能够找到我出错的地方而不是编写新代码 我将不胜感激 除非我刚去南方 我的尝
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template

随机推荐