带有stack / list c ++的EXC_BAD_ACCESS

时间:2018-01-14 14:44:08

标签: c++ exception

我正在研究我的RPN计算器项目。 此时我想将输入计算中的所有数字放在堆栈上,但不幸的是,进程以退出代码11完成,我被卡住了。当我输入例如3,然后输入3 + 3时,就会发生极端情况。 我调试了它,我可以看到问题在于:

if(header!= nullptr) {

在这里:

cell* List::Last() {
    if(header!= nullptr) {
        cell *i;
        for(i = header; i->next != nullptr; i = i->next);
        return i;
    }
    else return nullptr;
}

异常EXC_BAD_ACCESS。我想它与列表中的标题有关,但我不知道为什么。我已经阅读过关于这个例外但它仍然没有帮助我。据我所知,大多数人都使用数组。我会非常感谢任何提示...我的完整代码在这里(它还没有完成,所以似乎有很多无用的方法):

#include <iostream>

using namespace std;
typedef int element;

struct cell
{
    element element;
    cell * next;
};

class List {
protected:
    cell * header;
public:
    List();
    ~List();
    void Insert(element x, cell * p);
    void Delete(cell * p);
    element Retrieve(cell * p);
    cell * Locate(element x);
    cell * First();
    cell * Next(cell * p);
    cell * Previous(cell * p);
    cell * Last();
    void print();
    bool empty() {
        return header == nullptr;
    }
};

List::List() {
    header = nullptr;
}

List::~List() {
    cell *tmp;
    while(header != nullptr) {
        tmp = header;
        header = header->next;
        delete tmp;
    }
}

void List::Insert(element x, cell * p) {
    cell *tmp;
    if (p != nullptr) {
        tmp = p->next;
        p->next = new cell;
        p->next->element = x;
        p->next->next = tmp;
    } else {
        header = new cell;
        header->element = x;
        header->next = nullptr;
    }
}

element List::Retrieve(cell * p) {
    return p->element;
}

void List::Delete(cell *p) {
    cell* tmp;
    tmp=p->next;
    p->next = p->next->next;
    delete tmp;
}

void List::print() {
    for (cell *i = header; i != nullptr; i = i->next) {
        cout << i->element << endl;
    }
}

cell* List::Locate(element x) {
    cell* tmp;
    tmp = header;
    while(tmp->next != nullptr) {
        if(tmp->next->element == x) return tmp;
        tmp = tmp->next;
    }
    return tmp;
}

cell* List::First() {
    return header;
}

cell* List::Last() {
    if(header!= nullptr) {
        cell *i;
        for(i = header; i->next != nullptr; i = i->next);
        return i;
    }
    else return nullptr;
}

cell* List::Next(cell *p) {
    return p->next;
}

cell* List::Previous(cell *p) {
    cell* tmp;
    tmp = header;
    while(tmp->next != p) tmp = tmp->next;
    return tmp;
}

class Stack {
    List * list;
public:
    Stack();
    element top();
    element pop();
    void push(element x);
    bool empty();
    void makenull();
};

Stack::Stack() {
    list = new List();
}

element Stack::top() {
    return this->list->Retrieve(this->list->Last());
}

element Stack::pop() {
    int tmp = this->list->Retrieve(this->list->Last());
    cell* c = this->list->Previous(list->Last());
    this->list->Delete(c);
    return tmp;
}

void Stack::push(element x) {
    this->list->Insert(x, this->list->Last());
}

bool Stack::empty() {
    return this->list->empty();
}

void Stack::makenull() {
    delete list;
}

class RPN {
    Stack *stack;
public:
    RPN();
    int type;
    int result;
    char calculation[];
    int menu();
    int calculate();
    bool isNum(char c);
    bool isOperand(char c);
    void putOnStack();
    void enterCalculation();
    void convertToRPN();
    void convertFromRPN();
};

RPN::RPN() {
    stack = new Stack();
    type = 0;
    result = 0;
}

int RPN::menu() {
    cout << endl << "Choose option:" << endl;
    cout << "1. Convert to RPN" << endl;
    cout << "2. Convert from RPN" << endl;
    cout << "3. RPN calculator" << endl;
    cout << "4. Regular calculator" << endl;
    cout << "5. Finish" << endl;
    cin >> type;

    switch (type) {
        case 1:
            enterCalculation();
            convertFromRPN();
            break;
        case 2:
            enterCalculation();
            convertToRPN();
            break;
        case 3:
            enterCalculation();
            convertFromRPN();
            calculate();
            break;
        case 4:
            enterCalculation();
            calculate();
            break;
        case 5:
            break;
        default:
            cout << "Nie ma takiej opcji!" << endl;
            break;
    }
    return type;
}

bool RPN::isNum(char c) {
    return isdigit(c);
}

bool RPN::isOperand(char c) {
    return c == '+' || c == '-' || c == '/' || c == '*';
}

void RPN::putOnStack() {
    for(int i = 0; i < strlen(calculation); i++)
        if(isNum(calculation[i])) stack->push(calculation[i]);
}

void RPN::enterCalculation() {
    cout << "Type your calculation:" << endl;
    cin >> calculation;
    putOnStack();
}

void RPN::convertToRPN() {

}

void RPN::convertFromRPN() {

}

int RPN::calculate() {

    return result;
}


int main() {
    auto *rpn = new RPN();
    while(rpn->type != 5)
        rpn->menu();
    return 0;
}

2 个答案:

答案 0 :(得分:0)

试试这个:

cell* List::Last() {
   cell *i = header;
   while(i->next != nullptr && i != nullptr)i=i->next;
   return i;
}

答案 1 :(得分:0)

感谢您的帮助。我成功地解决了这个问题。 也许这会对某人有所帮助,我在下面发布我的代码。

#include <iostream>

using namespace std;
typedef string element;

struct cell {
    string element;
    cell * next;
};

class List {
public:
    cell * header;
    List();
    ~List();
    element Retrieve(cell * p);
    cell* Previous(cell * p);
    cell * Last();
    void Insert(const element &x, cell * p);
    void Delete(cell * p);
    bool empty() {
        return header == nullptr;
    }
};

List::List() {
    header = nullptr;
}

List::~List() {
    cell *tmp;
    while(header != nullptr) {
        tmp = header;
        header = header->next;
        delete tmp;
    }
}

element List::Retrieve(cell * p) {
    return p->element;
}

void List::Delete(cell *p) {
    cell* tmp;
    if(p->next == nullptr) {
        cout << "Error! No next element to delete!" << endl;
    } else if(p->next->next == nullptr) {
        delete p->next;
        p->next = nullptr;
    } else {
        tmp = p->next;
        p->next = p->next->next;
        delete tmp;
    }
}

cell* List::Previous(cell *p) {
    if(p == header) {
        cout << "There is no previous element for the header!" << endl;
        return nullptr;
    } else {
        if(header -> next == p) {
            return header;
        } else {
            cell *tmp = header;
            while(tmp->next != p) tmp = tmp->next;
            return tmp;
        }
    }
}

void List::Insert(const element &x, cell * p) {
    cell *tmp;
    if (p != nullptr) {
        if(p -> next == nullptr) {
            p->next = new cell;
            p->next->element = x;
            p->next->next = nullptr;
        } else {
            tmp = p->next;
            p->next = new cell;
            p->next->element = x;
            p->next->next = tmp;
        }
    } else {
        header = new cell;
        header->element = x;
        header->next = nullptr;
    }
}

cell* List::Last() {
    if(header != nullptr) {
        if(header-> next == nullptr) return header;
        else {
            cell *i;
            for(i = header; i->next != nullptr; i = i->next);
            return i;
        }
    }
    else return nullptr;
}

class Stack {
public:
    List * list;
    Stack();
    void push(const element &x);
    void makenull();
    bool empty();
    element pop();
    element top();
};

Stack::Stack() {
    list = new List();
}

void Stack::makenull() {
    this->list->header = nullptr;
}

bool Stack::empty() {
    return this->list->empty();
}

element Stack::top() {
    return this->list->Retrieve(this->list->Last());
}

element Stack::pop() {
    string tmp;
    if(list->Last() == list->header) {
        tmp = this->list->header->element;
        this->list->header = nullptr;
    } else {
        tmp = this->list->Retrieve(this->list->Last());
        cell* c = this->list->Previous(list->Last());
        this->list->Delete(c);
    }
    return tmp;
}

void Stack::push(const element &x) {
    if(this->list->header != nullptr) {
        this->list->Insert(x, this->list->Last());
    } else {
        this->list->header = new cell;
        this->list->header->element = x;
        this->list->header->next = nullptr;
    }
}

class RPN {
public:
    RPN();
    ~RPN();
    Stack *stack;
    int type;
    string calculation;
    int menu();
    string convertToRPN();
    string convertFromRPN();
    double calculateRPN();
    void enterCalculation();
    bool isNum(string s);
    bool isOperator(char c);
    int compareOperators(string op1, string op2);

};

RPN::RPN() {
    stack = new Stack();
    type = 0;
}

RPN::~RPN() {
    delete stack;
}

int RPN::menu() {
    cout << endl << "Choose option:" << endl;
    cout << "1. Convert from RPN" << endl;
    cout << "2. Convert to RPN" << endl;
    cout << "3. RPN calculator" << endl;
    cout << "4. Calculator" << endl;
    cout << "5. Exit" << endl;
    cin >> type;
    cin.ignore();

    switch (type) {
        case 1:
            enterCalculation();
            convertFromRPN();
            break;
        case 2:
            enterCalculation();
            convertToRPN();
            break;
        case 3:
            enterCalculation();
            calculateRPN();
            break;
        case 4:
            enterCalculation();
            calculation = convertToRPN();
            calculateRPN();
            break;
        case 5:
            break;
        default:
            cout << "No such option! Choose a correct one." << endl;
            break;
    }
    return type;
}

bool RPN::isNum(string s) {
    return !s.empty() && std::find_if(s.begin(), s.end(), [](char c) { return !isdigit(c); }) == s.end();
}

bool RPN::isOperator(char c) {
    return (c == '+' || c == '-' || c == '*' || c == '/');
}

int RPN::compareOperators(string op1, string op2) {
    if ((op1[0] == '*' || op1[0] == '/') && (op2[0] == '+' || op2[0] == '-')) return -1;
    else if ((op1[0] == '+' || op1[0] == '-') && (op2[0] == '*' || op2[0] == '/')) return 1;
    return 0;
}

void RPN::enterCalculation() {
    calculation[0] = 0;
    cout << "Input expression:" << endl;
    getline(cin, calculation);
}

string RPN::convertToRPN() {
    auto len = static_cast<int>(calculation.length());
    stack->makenull();
    string RPNcalc;
    RPNcalc.clear();
    int j = 0;
    int par1 = 0;
    int par2 = 0;
    while(isspace(calculation[j])) j++;
    if(!isNum(string(1, calculation[j])) && (calculation[j] != '(')) {
        cout << "Expression incorrect!" << endl;
        string errStr = "err";
        return errStr;
    }
    j = 0;
    while(isspace(calculation[len-1-j])) j++;
    if(!isNum(string(1, calculation[len-1-j])) && (calculation[len-1-j] != ')')) {
        cout << "Expression incorrect!" << endl;
        string errStr = "err";
        return errStr;
    }
    for (int i = 0; i < len; i++) {
        if (isNum(string(1, calculation[i])) || calculation[i] == '.') {
            if(isspace(calculation[i+1])) {
                RPNcalc.push_back(calculation[i]);
                RPNcalc.push_back(' ');
            } else {
                if(isNum(string(1, calculation[i])) && calculation[i+1] != '.' && !isNum(string(1, calculation[i]))) {
                    RPNcalc.push_back(calculation[i]);
                    RPNcalc.push_back(' ');
                } else if(isOperator(calculation[i+1])) {
                    RPNcalc.push_back(calculation[i]);
                    RPNcalc.push_back(' ');
                } else if(calculation[i+1] == ')') {
                    RPNcalc.push_back(calculation[i]);
                    RPNcalc.push_back(' ');
                } else {
                    RPNcalc.push_back(calculation[i]);
                }
            }
        } else if (isOperator(calculation[i])) {
            while(!stack->empty() && stack->top()[0] != '(' && compareOperators(stack->top(), string(1, calculation[i])) <= 0) {
                RPNcalc.push_back(stack->pop()[0]);
                RPNcalc.push_back(' ');
            }
            stack->push(string(1, calculation[i]));
        } else if(calculation[i] == '(') {
            par1++;
            stack->push(string(1, calculation[i]));
        } else if(calculation[i] == ')') {
            par2++;
            while(!stack->empty()) {
                if(stack->top()[0] == '(') {
                    stack->pop();
                    break;
                }
                RPNcalc.push_back(stack->pop()[0]);
                RPNcalc.push_back(' ');
            }
        } else if(isspace(calculation[i])) {

        } else {
            cout << "Expression incorrect!" << endl;
            string errStr = "err";
            return errStr;
        }
    }
    if(par1 != par2) {
        cout << "Expression incorrect!" << endl;
        string errStr = "err";
        return errStr;
    }
    while(!stack->empty()) {
        if(RPNcalc.back() != ' ') RPNcalc.push_back(' ');
        RPNcalc.push_back(stack->top()[0]);
        stack->pop();
    }
    if(type != 4) cout << "RPN expression: " << RPNcalc << endl;
    return RPNcalc;
}

string RPN::convertFromRPN() {
    auto len = static_cast<int>(calculation.length());
    stack->makenull();
    string num;
    string right;
    string left;
    string newExpr;

    int j = 0;
    while(isspace(calculation[j])) j++;
    if(!isNum(string(1, calculation[j]))) {
        cout << "Expression incorrect!" << endl;
        string errStr = "err";
        return errStr;
    }
    j = 0;
    while(isspace(calculation[len-1-j])) j++;
    if(!isOperator(calculation[len-1-j])) {
        cout << "Expression incorrect!" << endl;
        string errStr = "err";
        return errStr;
    }

    for (int i = 0; i < len; i++) {
        if (isOperator(calculation[i])) {
                right = stack->pop();
                left = stack->pop();
                newExpr.clear();
                newExpr += '(';
                newExpr += left;
                newExpr += ' ';
                newExpr += calculation[i];
                newExpr += ' ';
                newExpr += right;
                newExpr += ')';
                stack->push(newExpr);
            } else if (isNum(string(1, calculation[i])) || calculation[i] == '.') {
            if(isspace(calculation[i+1])) {
                num.push_back(calculation[i]);
                stack->push(num);
                num.clear();
            } else num.push_back(calculation[i]);
        } else if(isspace(calculation[i])) {

        } else {
            cout << "Expression incorrect!" << endl;
            string errStr = "err";
            return errStr;
        }
    }
    newExpr = stack->top();
    newExpr.erase(newExpr.begin());
    newExpr.erase(newExpr.end()-1);
    cout << "Infix notation: " << newExpr;
    return newExpr;
}

double RPN::calculateRPN() {
    auto len = static_cast<int>(calculation.length());
    stack->makenull();
    double a = 0;
    double b = 0;
    double result = 0;
    string num;
    num.clear();
    if(isNum(string(1, calculation[len-1]))) {
        cout << "Expression incorrect!" << endl;
        return 0;
    }
    for (int i = 0; i < len; i++) {
        if (isNum(string(1, calculation[i])) || calculation[i] == '.') {
            if(isspace(calculation[i+1])) {
                num.push_back(calculation[i]);
                stack->push(num);
                num.clear();
            } else num.push_back(calculation[i]);
        } else if (isOperator(calculation[i])) {
            a = stod(stack->pop());
            b = stod(stack->pop());
            switch (calculation[i]) {
                case '*':
                    stack->push(to_string(a * b));
                    break;
                case '/':
                    stack->push(to_string(b / a));
                    break;
                case '-':
                    stack->push(to_string(b - a));
                    break;
                case '+':
                    stack->push(to_string(a + b));
                    break;
                default:
                    break;
            }
        } else if(isspace(calculation[i])) {

        } else {
            cout << "Expression incorrect!" << endl;
            return 0;
        }
    }
    result = stod(stack->pop());
    if(!stack->empty()) {
        cout << "Expression incorrect!" << endl;
        return 0;
    }
    cout << "Result: " << result << endl;
    return result;
}

int main() {
    cout << endl << "POSTFIX-INFIX CALCULATOR AND CONVERTER "<< endl;
    auto *rpn = new RPN();
    while(rpn->type != 5)
        rpn->menu();
    return 0;
}