2010-02-06 105 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