Почему моя программа, которая создает стек с помощью std :: vector, вылетает? - PullRequest
2 голосов
/ 17 января 2011

Я создаю свой собственный стек для своего класса структур данных. Для нашего задания мы используем это задание для преобразования инфиксного уравнения реального времени в постфиксное уравнение.
Я думал, что моя программа:
взял ввод
определяет, была ли это цифра или число (операнд)
распечатывает
определяет, является ли ввод оператором (+, -, /, *)
добавляет в стек или распечатывает, в зависимости от приоритета стека

Вместо этого он печатает операнды, как и ожидалось, но я получаю эту ошибку при вводе оператора

>.../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; 

Мой код очень длинный, я знаю, но я ценю помощь. Особенно в любое время для эффективности или будущего кодирования.

Еще раз спасибо

P.S. Доктор Земудех, это ваш ученик Макэйр

Ответы [ 3 ]

6 голосов
/ 17 января 2011

Я расширю ответ Рупа, чтобы ответить на вопрос, который вы не задавали, но он важнее: Как узнать, где происходит сбой моей программы?

Один из способов - поместить в вашу программу операторы std::cout или printf. Поставьте оператор в начале каждой функции, говоря «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) 

Используя только эти 2 команды (run, bt), вы решили 80% проблемы: найти место, где произошла ошибка вашей программы. Если вы перестали читать здесь, вы сможете решить эту проблему, добавив операторы печати или утверждения, чтобы увидеть, каково состояние 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, прочитайте некоторые учебники и узнайте, как делать такие вещи, как установка точек останова или один шаг.

2 голосов
/ 17 января 2011

Ошибка в вашем while(InputFlag) цикле:

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

Проблема в том, что в первый раз вы вызываете DishTray.ReturnEnd() для пустого вектора.Вам нужно проверить, является ли вектор пустым, перед вызовом Precidence и действовать соответствующим образом, или вернуть значение 0 из ReturnEnd(), если вектор пуст, или что-то еще.Все это говорит о том, что я на самом деле не вижу, что вы пытаетесь сделать здесь, поскольку вы опускаете операнды напрямую через выход, не ссылаясь ни на что из стека, - действительно ли это правильная реализация алгоритма?

Но вам действительно нужно научиться отлаживать это для себя.Вы действительно должны прочитать dorun.sh, чтобы увидеть, как он компилирует код, и вы должны узнать, как использовать gdb или dbx или любой другой отладчик, который у вас есть в вашей системе, чтобы понять это для себя.Если это GDB, вы, вероятно, хотите что-то вроде

 g++ -g mystack.cpp -o mystack
 gdb mystack
 run
 <enter input, e.g. 2+3+4+5>
 bt
1 голос
/ 17 января 2011

Если я правильно вас понимаю, ваше задание касается реализации алгоритма маневрового двора .

Поскольку это присвоение структуры данных, на вашем месте я бы не использовал std::vector. Потому что это обычно не разрешается. Вы должны реализовать ADT с char stack[STACK_SIZE] или динамически с подходом со списком ссылок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...