C++:cin在Linux和Windows之间的差异帮助

4

我有一个Win32控制台程序,它运行良好。程序从用户那里获取输入并执行一些计算,然后显示输出 - 标准的东西。出于兴趣,我正在尝试让程序在我的Fedora机器上运行,但是当用户输入与我的变量类型不匹配时,我遇到了清除cin的问题。以下是相关代码:

void CParameter::setPrincipal() {
double principal = 0.0;

cout << endl << "Please enter the loan principal: ";
cin >> principal;

while(principal <= 0)
{
    if (cin.fail())
    {
          cin.clear();
          cin.ignore(INT_MAX, '\n');
    }
    else
    {
        cout << endl << "Plese enter a number greater than zero. Please try again." << endl;
        cin >> principal;
    }
}

m_Parameter = principal;

这段代码在Windows中可以正常运行。例如,如果用户尝试输入char数据类型(而不是double),则程序会提示用户出现错误,重置cin,并允许用户重新输入有效值。

当我将此代码移动到Fedora时,它可以编译通过。但是当我运行程序并输入无效的数据类型时,while循环永远不会停止以允许用户更改输入。

我的问题是:在Fedora环境中输入无效数据时,如何清除cin?此外,我应该如何编写此代码,以便在两个环境(Windows和Linux)中都能正常运行?

非常感谢您的帮助!

4个回答

2

我认为cin.ignore会在cin上设置失败标志,这会使它永远停留在最上方的if语句中。INT_MAX是一个非常大的数字 - 你确定所有平台都允许在其上使用cin.ignore吗?


4
好的,我认为 std::numeric_limits<std::streamsize>::max() 可能是更好的选择。 - Johannes Schaub - litb

1

我会转而使用 getline 读取输入,然后使用 stringstream 进行解析:

double principal = 0;
string temp;
while (principal <= 0)
{
    getline(cin, temp);
    istringstream converter(temp);
    if (!(converter>>principal) ||
        !(converter>>std::ws).eof() ||
        principal <= 0)
    {
        cout << "Try again" << endl;
        principal = 0;
    }
}

1

我认为使用格式化输入读取用户响应是一个不好的主意。我会使用getline - 就像这样:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

template <typename T>
bool Read( T & t, istream & is ) {
    string s;
    if ( ! getline( is, s ) ) {
        return false;
    }
    else {
        istringstream ss( s );
        return ss >> t;
    }
}    

int main() {
    while(1) {
        double d;
        if ( ! Read( d, cin ) ) {
            cout << "invalid\n";
        }
        else {
            cout << "You entered " << d << "\n";
        }
    }
}

这适用于Windows - 我目前没有开启我的Linux计算机。


0

我同意Anders Abel和Johannes Schaub的观点;我也认为在出现错误的情况下,不能保证本金不受影响,因此您可以考虑在循环开始时添加principal=0.0;

顺便说一下,我通常使用这个模板函数来执行这种类型的工作:

template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result)
{
    do
    {
        Os<<Prompt.c_str();
        if(Is.fail())
        {
            Is.clear();
            Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        }
        Is>>Result;
        if(Is.fail())
            Os<<FailString.c_str();
    } while(Is.fail());
}

template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString)
{
    InType temp;
    AcquireInput(Os,Is,Prompt,FailString,temp);
    return temp;
}

如果您想避免复制,第一个重载可能更好,如果是内置类型,第二个重载可能更方便。

使用示例:

//1st overload
double aDouble;
AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",aDouble);

//2nd overload (more convenient, in this case and in general with POD)
double aDouble=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n");

在您的情况下,您可以这样更改您的代码:

double principal=0.0;
const char * errMsg="Plese enter a number greater than zero. Please try again.\n";
while(principal<=0.0)
{
    principal=0.0;
    principal=AcquireInput(cout,cin,"Please enter the loan principal: ",errMsg);
    if(principal<=0.0)
        cout<<errMsg;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接