簡體   English   中英

為什么我的程序使用std :: vector創建堆棧崩潰?

[英]Why does my program that creates a stack using std::vector crash?

我正在為我的數據結構類創建自己的堆棧。 對於我們的任務,我們使用賦值將實時中綴方程轉換為后綴方程。
我以為我的計划:
接受了輸入
確定它是數字還是數字(操作數)
打印出來
確定輸入是否為運算符(+, - ,/,*)
根據堆棧優先級添加堆棧或打印輸出

相反,它會按預期打印出操作數,但是當我進入運算符時出現此錯誤

>.../dorun.sh line 33: 4136 Segmentation fault     <core dumped> sh "$<SHFILE>"


#include <vector>
using namespace std;

class DishWell{  
public:  
    char ReturnEnd(){  
        return Well.back();  
    }  
    void Push(char x){  
        Well.push_back(x);  
    }  
    void Pop(){  
        Well.pop_back();  
    }  
    bool IsEmpty(){  
        return Well.empty();  
    }  
private:  
    vector<char> Well;  
};   
#include <iostream>  
bool Precidence(char Input, char Stack){  
    int InputPrecidence,StackPrecidence;  
    switch (Input){  
        case '*':  
            InputPrecidence = 4;  
            break;
        case '/':
            InputPrecidence = 4;  
            break;  
        case '+':  
            InputPrecidence = 3;  
            break;  
        case '-':  
            InputPrecidence = 3;  
            break;  
        case '(':  
            InputPrecidence = 2;  
            break;  
        default:  
            InputPrecidence = 0;  
    }  
    switch (Stack){  
        case '*':  
            StackPrecidence = 4;  
            break;  
        case '/':  
            StackPrecidence = 4;  
            break;  
        case '+':  
            StackPrecidence = 3;  
            break;  
        case '-':  
            StackPrecidence = 3;  
            break;  
        case '(':  
            StackPrecidence = 2;  
            break;  
        default:  
            StackPrecidence = 0;  
    }  
    if(InputPrecidence>StackPrecidence) return true;  
    else return false;  
}  
int main(int argc, char** argv) {  
    DishWell DishTray;  
    char Input;  
    bool InputFlag;  
    InputFlag = true;  
    while(InputFlag){  
        cin>>Input;  
        if((((Input>='a'&&Input<='z')||(Input>='A'&&Input<='Z'))|| (Input>='0'&&Input<='9')))//If Digit or Number  
            cout<<Input;  
        if((Input=='*'||Input=='/'||Input=='+'||Input=='-')){//if operand  
            if(Precidence(Input,DishTray.ReturnEnd()))  
                DishTray.Push(Input);  
            else if(!Precidence(Input,DishTray.ReturnEnd()))  
                cout<<Input;  
        }  
        else if(!((((Input>='a'&&Input<='z')||(Input>='A'&&Input<='Z'))||    (Input>='0'&&Input<='9')))||((Input=='*'||Input=='/'||Input=='+'||Input=='-')))//if not digit/numer or operand  
            InputFlag = false;  
    }  
    while(!DishTray.IsEmpty()){  
        cout<<DishTray.ReturnEnd();  
        DishTray.Pop();  
    }  
    return 0; 

我知道,我的代碼很長,但我很感激幫助。 特別是效率或未來編碼的任何時候。

再次感謝

PS Zemoudeh博士,這是你的學生Macaire

我將擴展Rup的答案來回答你沒有問過的問題,但更重要的是: 我怎樣才能找到我的程序崩潰的位置?

一種方法是在整個程序中放置std::coutprintf語句。 在每個函數的開頭寫一個聲明,“function x enter”,最后說“function x exit”。 運行你的程序,當它崩潰時,你會看到它所處的功能。此時,你可以添加行來打印每個變量的內容,以找出出錯的地方。

另一種方法是使用調試器,如gdb

首先,使用-g開關編譯程序以啟用調試信息。

linux@linux-ubuntu:~/t$ g++ prog.cpp -o prog -g

接下來,告訴調試器gdb運行您的程序。

linux@linux-ubuntu:~/t$ gdb ./prog

在gdb提示符下,鍵入run以啟動程序。 我輸入4*(3+2)並且程序at prog.cpp:7 ,這是行return Well.back();

(gdb) run
Starting program: /home/linux/t/prog 
4*(3+2)
4
Program received signal SIGSEGV, Segmentation fault.
0x08048d0b in DishWell::ReturnEnd (this=0xbffff460) at prog.cpp:7
7           return Well.back();  

對於更復雜的程序,您通常需要列出當前正在調用的所有函數。 您可以使用bt獲取該信息,“backtrace”的縮寫。 在下面的回溯中,您會看到函數main (#1)正在調用函數DishWell::ReturnEnd (#0)。 #0是當前函數,因為函數形成堆棧,其中當前函數是堆棧的頂部(偏移量0是頂部)。

(gdb) bt
#0  0x08048d0b in DishWell::ReturnEnd (this=0xbffff460) at prog.cpp:7
#1  0x08048b35 in main (argc=1, argv=0xbffff534) at prog.cpp:75
(gdb) 

只有這兩個命令( runbt ),你已經解決了80%的問題:找到程序崩潰的地方。 如果你在這里停止閱讀,你應該能夠通過添加print語句或斷言來解決問題,看看Well的狀態是什么以及為什么back()會破壞你的程序。 但是讓我們再使用gdb ......

您可以鍵入list以查看該行周圍的源代碼,以獲得更多上下文,而無需離開調試器。

(gdb) list
2   using namespace std;
3   
4   class DishWell{  
5   public:  
6       char ReturnEnd(){  
7           return Well.back();  
8       }  
9       void Push(char x){  
10          Well.push_back(x);  
11      }  
(gdb) 

gdb可以打印變量和簡單表達式。 打印Well的值對新手來說沒什么用處,因為它是一個復雜的數據結構,而不是一個簡單的變量。 但我們可以告訴gdb在該變量上調用一個方法......

(gdb) print Well.size()
$2 = 0
(gdb) print Well.empty()
$3 = true

啊哈, Well是空的,你已經back() 當我們查看std::vector一些好的文檔時 ,我們看到你調用了未定義的行為,在這種情況下是一個程序崩潰。

現在看一下你的程序,並試着找出為什么當你的程序不期望它是空的時候, Well是空的。 如果您喜歡gdb ,請閱讀它上面的一些教程,並學習如何設置斷點或單步操作。

錯誤發生在您的while(InputFlag)循環中:

    if((Input=='*'||Input=='/'||Input=='+'||Input=='-')){//if operand  
        if(Precidence(Input,DishTray.ReturnEnd()))  

問題是第一次通過你在一個空向量上調用DishTray.ReturnEnd() 在調用Precidence並正確操作之前,您需要檢查向量是否為空,如果向量為空,則需要從ReturnEnd()返回0值。 這一切都說我無法真正看到你在這里嘗試做什么,因為你將操作數直接傳遞到輸出而沒有以任何方式將它們引用到堆棧 - 這真的是算法的正確實現嗎?

但是你真的需要學習如何自己調試這個。 您應該真正閱讀dorun.sh以了解它是如何編譯代碼的,您應該了解如何使用gdbdbx或您系統上的任何調試器來自行解決這個問題。 如果它是gdb,你可能想要類似的東西

 g++ -g mystack.cpp -o mystack
 gdb mystack
 run
 <enter input, e.g. 2+3+4+5>
 bt

如果我理解正確,你的任務就是實現Shunting-yard算法

因為,它是一個數據結構賦值,如果我是你,我不會使用std::vector 因為,通常是不允許的。 您應該使用char stack[STACK_SIZE]實現ADT,或使用鏈接列表方法動態實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM