如何在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命令? 的相关文章

  • 使用链表进行堆排序

    我想知道是否有人曾经使用链表进行堆排序 如果他们可以提供代码 我已经能够使用数组进行堆排序 但尝试在链表中进行排序似乎不切实际 而且在你知道的地方很痛苦 我必须为我正在做的项目实现链接列表 任何帮助将不胜感激 我也用C 答案是 你不想在链表
  • 静态构造函数和 BeforeFieldInit?

    如果类型没有静态构造函数 则将执行字段初始值设定项 就在使用该类型之前 或者在某个时间点突发奇想 运行时 为什么这段代码 void Main start Dump Test EchoAndReturn Hello end Dump clas
  • 关于逻辑/算法的想法以及如何防止线程写入 Sql Server 中的竞争

    我有以下逻辑 public void InQueueTable DataTable Table int incomingRows Table Rows Count if incomingRows gt RowsThreshold async
  • EntityHydrate 任务失败

    我最近安装了 Visual Studio 11 Beta 和 Visual Studio 2010 之后 我无法在 Visual Studio 2010 中构建依赖于 PostSharp 的项目 因此我卸载了 Visual Studio 1
  • 防止控制台应用程序中的内存工作集最小化?

    我想防止控制台应用程序中的内存工作集最小化 在Windows应用程序中 我可以这样做覆盖 SC MINIMIZE 消息 http support microsoft com kb 293215 en us fr 1 但是 如何在控制台应用程
  • 用于在标头更改时重新编译的简单 C 项目的示例 makefile

    有谁有完整的 makefile 可以执行以下操作 如果 HEADER 文件发生更改 则重建项目 cpp 文件在 makefile 中列出 头文件未在 makefile 中列出 头文件允许与 cpp 文件具有不同的名称 部分cpp文件没有头文
  • 为什么这个 makefile 在“make clean”上执行目标

    这是我当前的 makefile CXX g CXXFLAGS Wall O3 LDFLAGS TARGET testcpp SRCS main cpp object cpp foo cpp OBJS SRCS cpp o DEPS SRCS
  • if constexpr 中的 not-constexpr 变量 – clang 与 GCC

    struct A constexpr operator bool const return true int main auto f auto v if constexpr v A a f a clang 6 接受该代码 GCC 8 拒绝它
  • Linux 上的 RTLD_LOCAL 和dynamic_cast

    我们有一个由应用程序中的一些共享库构成的插件 我们需要在应用程序运行时更新它 出于性能原因 我们在卸载旧插件之前加载并开始使用新插件 并且只有当所有线程都使用旧插件完成后 我们才卸载它 由于新插件和旧插件的库具有相同的符号 我们dlopen
  • 条件类型定义

    如果我有一小段这样的代码 template
  • 如何在多线程应用程序中安全地填充数据并 Refresh() DataGridView?

    我的应用程序有一个 DataGridView 对象和一个 MousePos 类型的列表 MousePos 是一个自定义类 它保存鼠标 X Y 坐标 类型为 Point 和该位置的运行计数 我有一个线程 System Timers Timer
  • SQLAPI++ 的免费替代品? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否有任何免费 也许是开源 的替代品SQLAPI http www sqlapi com 这个库看起来
  • ASP.NET Core 中间件与过滤器

    在阅读了 ASP NET Core 中间件之后 我对何时应该使用过滤器以及何时应该使用中间件感到困惑 因为它们似乎实现了相同的目标 什么时候应该使用中间件而不是过滤器 9频道有一个关于此的视频 ASP NET 怪物 91 中间件与过滤器 h
  • 当Model和ViewModel一模一样的时候怎么办?

    我想知道什么是最佳实践 我被告知要始终创建 ViewModel 并且永远不要使用核心模型类将数据传递到视图 这就说得通了 让我把事情分开 但什么是Model 和ViewModel一模一样 我应该重新创建另一个类还是只是使用它 我觉得我应该重
  • Xamarin Forms Binding - 访问父属性

    我无法访问页面的 ViewModel 属性以便将其绑定到 IsVisible 属性 如果我不设置 BindingContext 我只能绑定它 有没有办法可以在设置 BindingContext 的同时访问页面的 viewmodel root
  • 构建 C# MVC 5 站点时项目之间的处理器架构不匹配

    我收到的错误如下 2017 年 4 月 20 日构建 13 23 38 C Windows Microsoft NET Framework v4 0 30319 Microsoft Common targets 1605 5 警告 MSB3
  • winform c# 中的弹出窗口

    我正在开发一个需要弹出窗口的项目 但问题是我还希望能够通过表单设计器在此弹出窗口中添加文本框等 所以基本上我有一个按钮 当您单击它时 它将打开我在表单设计器中设计的另一个窗口 我一直在谷歌搜索 但还没有找到我需要的东西 所以我希望你们能帮助
  • ContentDialog Windows 10 Mobile XAML - 全屏 - 填充

    我在项目中放置了一个 ContentDialog 用于 Windows 10 上的登录弹出窗口 当我在移动设备上运行此项目时 ContentDialog 未全屏显示 并且该元素周围有最小的填充 在键盘上可见 例如在焦点元素文本框上 键盘和内
  • 如何为有时异步的操作创建和实现接口

    假设我有数百个类 它们使用 计算 方法实现公共接口 一些类将执行异步 例如读取文件 而实现相同接口的其他类将执行同步代码 例如将两个数字相加 为了维护和性能 对此进行编码的好方法是什么 到目前为止我读到的帖子总是建议将异步 等待方法冒泡给调
  • 如何在 ASP.NET Core 中注入泛型的依赖关系

    我有以下存储库类 public class TestRepository Repository

随机推荐