2010-02-06 74 views
1

我正在创建一个简单的CLI计算器工具作为练习。我需要确保n1和n2是数字才能使这些功能正常工作;因此,我希望在遇到预定的非数字值时使程序退出。验证数字用户输入

任何人都可以给我一些方向吗?

此外,如果任何人可以提供任何一般的提示,如何我可以做得更好,我将不胜感激。我只是在学习C++。

谢谢!

完整的代码包含在下面。

#include <iostream> 
#include <new> 

using namespace std; 

double factorial(double n) { return(n <= 1) ? 1 : n * factorial(n - 1); } 

double add(double n1, double n2) { return(n1 + n2); } 

double subtract(double n1, double n2) { return(n1 - n2); } 

double multiply(double n1, double n2) { return(n1 * n2); } 

double divide(double n1, double n2) { return(n1/n2); } 

int modulo(int n1, int n2) { return(n1 % n2); } 

double power(double n1, double n2) { 
    double n = n1; 
    for(int i = 1 ; i < n2 ; i++) { 
     n *= n1; 
    } 
    return(n); 
} 

void print_problem(double n1, double n2, char operatr) { 
    cout<<n1<<flush; 
    if(operatr != '!') { 
     cout<<" "<<operatr<<" "<<n2<<flush; 
    } else { 
     cout<<operatr<<flush; 
    } 
    cout<<" = "<<flush; 
} 

int main(void) { 

double* n1, * n2, * result = NULL; 
char* operatr = NULL; 

n1 = new (nothrow) double; 
n2 = new (nothrow) double; 
result = new (nothrow) double; 
operatr = new (nothrow) char; 

if(n1 == NULL || n2 == NULL || operatr == NULL || result == NULL) { 
    cerr<<"\nMemory allocation failure.\n"<<endl; 
} else { 

    cout<<"\nTo use this calculator, type an expression\n\tex: 3*7 or 7! or \nThen press the return key.\nAvailable operations: (+, -, *, /, %, ^, !)\n"<<endl; 

    do {  
     cout<<"calculator>> "<<flush;  
     cin>>*n1; 

     cin>>*operatr; 

     if(*operatr == '!') { 
      print_problem(*n1, *n2, *operatr); 
      cout<<factorial(*n1)<<endl; 
     } else { 

      cin>>*n2; 

      switch(*operatr) { 
       case '+': 
        print_problem(*n1, *n2, *operatr); 
        cout<<add(*n1, *n2)<<endl; 
        break; 
       case '-': 
        print_problem(*n1, *n2, *operatr); 
        cout<<subtract(*n1, *n2)<<endl; 
        break; 
       case '*': 
        print_problem(*n1, *n2, *operatr); 
        cout<<multiply(*n1, *n2)<<endl; 
        break; 
       case '/': 
        if(*n2 > 0) { 
         print_problem(*n1, *n2, *operatr); 
         cout<<divide(*n1, *n2)<<endl; 
        } else { 
         print_problem(*n1, *n2, *operatr); 
         cout<<" cannot be computed."<<endl; 
        } 
        break; 
       case '%': 
        if(*n1 >= 0 && *n2 >= 1) { 
         print_problem(*n1, *n2, *operatr); 
         cout<<modulo(*n1, *n2)<<endl; 
        } else { 
         print_problem(*n1, *n2, *operatr); 
         cout<<" cannot be computed."<<endl; 
        } 
        break; 
       case '^': 
        print_problem(*n1, *n2, *operatr); 
        cout<<power(*n1, *n2)<<endl; 
        break; 
       default: 
        cout<<"Invalid Operator"<<endl; 
      } 
     } 
    } while(true); 
    delete n1, n2, operatr, result; 
} 
return(0); 
} 
+1

是否有一个原因是您正在创建变量而不是仅仅将它们放在堆栈上?你的代码不再安全;它屈服于例外,并且更难以阅读。 – GManNickG 2010-02-06 01:51:28

+0

相关问题:http://stackoverflow.com/questions/2156467/how-can-i-check-if-a-number-double-type-stored-as-a-string-is-a-valid-double- nu/2156534#2156534 – Manuel 2010-02-06 06:47:05

回答

1

不需要Boost或编写自己的模板或强制自己使用异常与错误代码。 cin独自做你想要的一切。

您可以测试if (cin)if (! cin)来确定成功或失败。一次失败(例如,数字输入中的字母)将使cin停止接受更多输入。然后拨打cin.clear()清除错误并重新开始输入,从任何引起错误的文本开始。此外,您可以请求某个流在转换错误时抛出异常:cin.exceptions(ios::failbit)

所以,你可以这样做:

for (;;) try { 
    double lhs, rhs; 
    char oper; 
    cin.exceptions(0); // handle errors with "if (! cin)" 
    cin >> lhs >> oper; // attempt to do "the normal thing" 
    if (! cin) { // something went wrong, cin is in error mode 
     string command; // did user enter command instead of problem? 
     cin.clear(); // tell cin it's again OK to return data, 
     cin >> command; // get the command, 
     if (command == "quit") break; // handle it. 
     else cin.setstate(ios::failbit); // if command was invalid, 
              // tell cin to return to error mode 
    } 
    cin.exceptions(ios::failbit); // now errors jump directly to "catch" 
     // note that enabling exceptions works retroactively 
     // if cin was in error mode, the above line jumps immediately to catch 
    if (oper != '!') cin >> rhs; 
    // do stuff 
} catch (ios::failure &) { 
    cin.clear(); 
    cin.ignore(INT_MAX, '\n'); // skip the rest of the line and continue 
} 

这意味着作为误差输入输出流处理的演示。您可以选择使用例外或手动测试或两者兼而有之。

3

你想要做的是读取一行输入或字符串,然后尝试将该行转换为数字形式。 Boost将其包装在lexical_cast中,但你根本不需要这个。我已经回答了一个类似于您的问题两次,herehere。阅读这些帖子了解发生了什么。

下面是最终的结果:

template <typename T> 
T lexical_cast(const std::string& s) 
{ 
    std::stringstream ss(s); 

    T result; 
    if ((ss >> result).fail() || !(ss >> std::ws).eof()) 
    { 
     throw std::bad_cast(); 
    } 

    return result; 
} 

使用它,我在这些职位如何概括:

int main(void) 
{ 
    std::string s; 
    std::cin >> s; 

    try 
    { 
     int i = lexical_cast<int>(s); 

     /* ... */ 
    } 
    catch(...) 
    { 
     /* ... */ 
     // conversion failed 
    } 
} 

这使用了异常。你可以让这个无抛出像链接上面概述,通过捕捉bad_cast例外:

template <typename T> 
bool lexical_cast(const std::string& s, T& t) 
{ 
    try 
    { 
     t = lexical_cast<T>(s); 

     return true; 
    } 
    catch (const std::bad_cast& e) 
    { 
     return false; 
    } 
} 

int main(void) 
{ 
    std::string s; 
    std::cin >> s; 

    int i; 
    if (!lexical_cast(s, i)) 
    { 
     std::cout << "Bad cast." << std::endl; 
    } 
} 

这有利于使Boost的lexical_cast没有抛,但如果你自己实现它,没有理由浪费时间投掷并捕捉异常。实现它们在对方的条款,其中扔版本使用无抛出版本:

// doesn't throw, only returns true or false indicating success 
template <typename T> 
const bool lexical_cast(const std::string& s, T& result) 
{ 
    std::stringstream ss(s); 

    return (ss >> result).fail() || !(ss >> std::ws).eof(); 
} 

// throws 
template <typename T> 
T lexical_cast(const std::string& s) 
{ 
    T result; 
    if (!lexical_cast(s, result)) 
    { 
     throw std::bad_cast("bad lexical cast"); 
    } 

    return result; 
} 

还有更多的麻烦在您的代码:你new荷兰国际集团的一切!这是有原因的吗?考虑你的代码的任何部分是否会抛出一个异常:现在你跳出主体并泄露所有东西。如果你堆叠分配你的变量,它们将被保证破坏。

+0

很难做到一刀切。对于计算器程序,您希望接受像“1 + 1”这样的输入。 'cin >> temp_string'使这很困难。一旦遇到信件,不应该像“123nan”一样输入,不要早贪心? – Potatoswatter 2010-02-08 21:25:32

-2

也许很多C++的人会讨厌我,但即使C++拥有所有这些新的闪亮字符串,我仍然尽量保持C++字符串的清晰感,在这种情况下,最简单也相当可观干净的事情是要坚持以良好的醇” C:

if (sscanf(input, "%d", &integer) != 1) { 
// failure to read number 
} 
// happily continue and process 
+0

亵渎是没有必要的。 – GManNickG 2010-02-08 21:39:51

+0

哈哈,有人似乎亲自采取这一点。 抱歉,fan字,GMan。思想在程序员的网站上是有效的。 – ypnos 2010-02-10 06:45:08