2012-02-26 17 views
2

林創建綴問題解算器,它在最後的崩潰而循環到完成最後部分的方程。綴方程解算器C++ while循環堆

我稱之爲主最後while循環來解決什麼留在堆棧上,它掛在那兒,如果我從棧中彈出最後一個元素,將退出循環,並返回錯誤的答案。

// 
// 
// 
// 
// 
#include <iostream> 
#include<stack> 
#include<string> 
#include <ctype.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <sstream> 
using namespace std; 
#define size 30 
int count=0; 
int count2=0; 
int total=0; 
stack<string> prob; 
char equ[size]; 
char temp[10]; 
string oper; 
string k; 
char t[10]; 
int j=0; 
char y; 


    int solve(int f,int s, char o) 
    { 
    cout<<"f="<<f<<endl; 
    cout<<"s="<<s<<endl; 
    cout<<"o="<<o<<endl; 
    int a; 
    if (o== '*')//checks the operand stack for operator 
    { 
    cout << f << "*" << s << endl; 
    a= f*s; 
    } 
    if (o == '/')//checks the operand stack for operator 
    { 
    cout << f << "/" << s << endl; 
    if(s==0) 
    { 
     cout<<"Cant divide by 0"<<endl; 
    } 
    else 
     a= f/s; 
    } 
    if (o == '+')//checks the operand stack for operator 
    { 
    cout << f << "+" << s << endl; 
    a= f+s; 
    } 
    if (o == '-')//checks the operand stack for operator 
    { 
    cout << f << "-" << s << endl; 
    a= f-s; 
    } 
    return a; 
} 



int covnum() 
{ 
    int l,c; 
    k=prob.top(); 
    for(int i=0;k[i]!='\n';i++)t[i]=k[i]; 
    return l=atoi(t); 
} 


char covchar() 
{ 
    k=prob.top(); 
    for(int i=0;k[i]!='\n';i++)t[i]=k[i]; 
    return t[0]; 
} 


void tostring(int a) 
{ 
    stringstream out; 
    out << a; 
    oper = out.str(); 
} 


void charstack(char op) 
{ 
    oper=op; 
    prob.push(oper); 
} 


void numstack(char n[]) 
{ 
    oper=n; 
    prob.push(oper); 
} 

void setprob() 
{ 
    int f,s; 
    char o; 
    char t; 
    int a; 
    int i; 
    t=covchar(); 
    if(ispunct(t)) 
    { 
    if(t=='(') 
    { 
     prob.pop(); 
    } 
    if(t==')') 
    { 
     prob.pop(); 
    } 
    else if(t=='+'||'-') 
    { 
     y=t; 
     prob.pop(); 
    } 
    else if(t=='/'||'*') 
    { 
     y=t; 
     prob.pop(); 
    } 
    } 
    cout<<"y="<<y<<endl; 
    i=covnum(); 
    cout<<"i="<<i<<endl; 
    s=i; 
    prob.pop(); 
    t=covchar(); 
    cout<<"t="<<t<<endl; 
    if(ispunct(t)) 
    { 
    o=t; 
    prob.pop(); 
    } 
    i=covnum(); 
    cout<<"i="<<i<<endl; 
    f=i; 
    prob.pop(); 
    t=covchar(); 
    if (t=='('||')') 
    { 
    prob.pop(); 
    } 
    a=solve(f,s, o); 
    tostring(a); 
    prob.push(oper); 
    cout<<"A="<<prob.top()<<endl; 
} 


void postfix() 
{ 
    int a=0; 
    char k; 
    for(int i=0;equ[i]!='\0';i++) 
    { 
    if(isdigit(equ[i]))//checks array for number 
    { 
     temp[count]=equ[i]; 
     count++; 
    } 
    if(ispunct(equ[i]))//checks array for operator 
    { 
     if(count>0)//if the int input is done convert it to a string and push to stack 
     { 
     numstack(temp); 
     count=0;//resets the counter 
     } 
     if(equ[i]==')')//if char equals the ')' then set up and solve that bracket 
     { 
     setprob(); 
     i++;//pushes i to the next thing in the array 
     total++; 
     } 
     while(equ[i]==')')//if char equals the ')' then set up and solve that bracket 
     { 
     i++; 
     } 
     if(isdigit(equ[i]))//checks array for number 
     { 
     temp[count]=equ[i]; 
     count++; 
     } 
     if(ispunct(equ[i])) 
     { 
     if(equ[i]==')')//if char equals the ')' then set up and solve that bracket 
     { 
      i++; 
     } 
     charstack(equ[i]); 
     } 
     if(isdigit(equ[i]))//checks array for number 
     { 
     temp[count]=equ[i]; 
     count++; 
     } 
    } 
    } 
} 



int main() 
{ 
    int a=0; 
    char o; 
    int c=0; 

    cout<<"Enter Equation: "; 
    cin>>equ; 
    postfix(); 
    while(!prob.empty()) 
    { 
    setprob(); 
    a=covnum(); 
    cout<<a<<" <=="<<endl; 
    prob.pop(); 
    cout<<prob.top()<<"<top before c"<<endl; 
    c=covnum(); 
    a=solve(c,a,y); 
    } 
    cout<<"Final Awnser"<<a<<endl; 
    system ("PAUSE"); 
    return 0; 
} 
+0

嚴肅的第一個建議:縮進並將代碼分解爲幾個函數......可能在您重寫代碼以便理解時,您也可以找到解決方案。 – paul23 2012-02-26 21:26:31

+0

如上面請縮進我不能讀這個。 – 111111 2012-02-26 21:44:22

+0

這是功課嗎? – 2012-02-26 21:51:38

回答

2

我看到了一些東西,所有可能有助於問題的它不工作:

  • 沒有錯誤或邊界檢查。我意識到這是家庭作業,因此可能會有特定的要求/規範,無需進行某些檢查,但仍需要一些來確保您正確解析輸入。如果你超過了equ/tmp/t的數組大小呢?如果您嘗試彈出/放置它時堆棧是空的呢?
  • 有幾個if語句看起來像else if (t == '+' || '-'),它們很可能不會做你想做的事情。這個表達式實際上總是如此,因爲' - '不是零並且被轉換爲真值。你可能想要else if (t == '+' || t == '-')
  • 據我可以告訴你似乎跳過解析或添加'('到堆棧,這將使你無法正確地評估表達式
  • 你有一個while循環在postfix()中間跳過多個')',但什麼都不做。
  • 您的代碼非常難以遵循。恰當地命名變量和函數並消除大部分全局變量(實際上並不需要大多數全局變量)將有助於大量處理正確的縮進,並在表達式中添加一些空格。
  • 還有其他一些小問題沒有特別值得一提。例如,covchar()和covnum()函數比需要的複雜得多。

多年來我已經寫了幾個postfix解析器,我不能真正關注你正在嘗試做什麼,這並不是說你嘗試的方式是不可能的,但我會建議重新 - 檢查解析表達式所需的基本邏輯,特別是括號的嵌套級別。

+0

感謝所有的幫助,我終於找到了解決方案所需要做的事情。 – user1184034 2012-02-28 20:20:13

3

希望這不是太苛刻,但它看起來像代碼充滿各種問題。我不打算試圖解決所有這些問題,但是,對於初學者來說,你的即時崩潰會涉及訪問總計越界的問題。

實施例:

for(int i=0;k[i]!='\n';i++) 

k是的std :: string的一個實例。 std :: string不是以null結尾的。它跟蹤字符串的長度,所以你應該做這樣的事情,而不是:

for(int i=0;i<k.size();i++) 

這些都是比較簡單的那種錯誤的,但我也看到在整個邏輯一些錯誤。例如,您的標記器(後綴函數)不處理表達式的最後一部分是操作數的情況。我不知道這是允許的條件下,但它的東西中綴解算器應如何處理(我建議重新命名這個功能類似記號化,它是真正令人困惑有一個叫做「後綴」的中綴解算器功能)。

最重要的是,我給你的建議是讓你的方法的一般變化。

  1. 瞭解調試器。無法強調這一點。在編寫代碼時應該測試代碼,並使用調試器來跟蹤代碼,並確保正確設置狀態變量。

  2. 不要使用任何全局變量來解決這個問題。避免在任何地方傳遞信息可能會很誘人,但是要讓#1更難做到,同時也限制瞭解決方案的普遍性。如果你錯了,那麼通過不傳遞變量節省的時間很容易就會花費你更多的時間。你也可以考慮創建一個類,它將這些東西存儲爲成員變量,你可以避免在類方法中傳遞,但是特別是對於臨時狀態,比如'equ',在你標記它之後甚至不需要它變成必要的標記化功能並廢除它。

  3. 只要你能(理想情況下,當他們第一次定義)初始化變量。我看到很多過時的C風格實踐,您將所有變量聲明在範圍的頂部。試着限制你使用變量的範圍,這會讓你的代碼更安全,更容易得到正確的。它與避免全局性(#2)相關。

  4. 如果可以,則首選替代宏,如果不能,則使用BIG_UGLY_NAMES來區分它們與其他任何事物。使用#define爲'size'創建一個預處理器定義實際上可以防止上面的代碼使用字符串的'size'方法工作。這可以也應該是一個簡單的整型常量,或者更好的是,你可以簡單地使用std :: string作爲'equ'(除了使其不是全局文件範圍外)。

  5. 當你可以時,首選標準C++庫頭。<ctype.h>應該是<cctype>,<stdlib.h>應該是<cstdlib>,而<stdio.h>應該是<stdio>。在同一編譯單元中混合使用.h擴展名和標準頭的非標準頭文件可能會在某些編譯器中導致問題,並且還會錯過一些重要的東西,如命名空間範圍和函數重載。

最後,花點時間解決問題,並且投入一些關心和愛。我意識到這是家庭作業,並且你正處於最後期限之內,但是在現實世界中,你將面臨更嚴格的最後期限,因爲這種編碼是不可接受的。正確命名您的標識符,明確地設置您的代碼的格式,記錄您的功能的作用(不是每一行代碼如何工作,哪些事情在您理解語言的時候實際上不應該做得太晚)。一些編碼TLC將帶你很長的路要走。真的想想如何解決一個問題(如果我們正在採用程序方法,將問題分解爲過程作爲一般工作單元,而不是簡單的整體邏輯版本)。 #2將對此有所幫助。

**示例:而不是一個名爲'postfix'的函數,它使用某個全局輸入字符串並操作某個全局堆棧並部分計算表達式,使其接受輸入字符串並返回單個令牌。現在,這是一個可以在任何地方重複使用的通用功能,並且您還可以將其減少到更容易解決和測試的問題。記下它並將其命名,重點關注使用情況以及接受和返回的內容。例如:

// Tokenize an input string. Returns the individual tokens as 
// a collection of strings. 
std::vector<std::string> tokenize(const std::string& input); 

這純粹是一個例子,它可能會或可能不會對這個特殊問題的最好的一個,但是如果考慮到設計的程序適當的解決辦法,最終的結果是,你應該已經建立你自己是一個經過充分測試,可重複使用的代碼庫,你可以一次又一次地使用它來使所有未來的項目變得更加容易。您還可以更輕鬆地將複雜問題分解成若干更簡單的問題來解決這些問題,從而使所有內容都變得更加簡單,並且整個編碼和測試過程更加順暢。

+1

附加要點:使用'const'而不是'#define'作爲幻數。例如,'#define size 30'行是一個荒謬的想法。 – Gunslinger47 2012-02-27 00:03:24

+0

好點!我會將其添加到答案中。 – stinky472 2012-02-27 00:15:08