Получение ошибки «невозможно разыменовать вне итератора deque диапазона» при использовании top () - PullRequest
0 голосов
/ 21 марта 2019

Я создаю простую программу для оценки выражений после исправления, но она не запустится после успешной компиляции из-за «Выражение: не может разыменоваться вне итератора deque диапазона» всякий раз, когда оно достигает назначения переменных операнда в строках 24 & 26. Почему он не будет работать правильно, когда программа достигнет этой точки только после заполнения стека числовыми значениями?

#include <iostream>
#include <stack>
#include <string>
#include <cctype>
using namespace std;

int main() 
{
    stack<int> mystack;
    string answer; 
    int result;
    string done = "Y";
    while (done == "Y" || done == "y") {
        cout << "Please enter the RPN expression to be evaluated: ";
        getline(cin,answer);
        for(int i = 0; i < answer.length(); i++) {

            if(answer[i] == ' ' || answer[i] == ':') { 
                continue;
            } 

            if (isdigit(answer[i]) == false) {
                cout << "Token = " << answer[i];
                int operand2 = mystack.top(); 
                mystack.pop();
                int operand1 = mystack.top(); 
                mystack.pop();

                cout << " Pop " << operand2 << " Pop " << operand1;

                if(answer[i] == '+') { //operation statements
                    result = operand1 + operand2;
                }
                else if(answer[i] == '-') {
                    result = operand1 - operand2;
                }
                else if(answer[i] == '*') {
                    result =  operand1 * operand2;
                }
                else if(answer[i] == '/') {
                    result = operand1 / operand2;
                }

                mystack.push(result); //result returns to stack
                cout << " Push " << result << endl;
            }
            else if(isdigit(answer[i]) == true){
                int operand = 0; 
                while(i < answer.length() && isdigit(answer[i]) == true) {
                    operand = (operand*10) + (answer[i] - '0'); 
                    i++;
                }
                i--;
                mystack.push(operand);
                cout << "Token = " << operand << " Push " << operand << endl;
            }
        }
        cout << "Token = Pop " << mystack.top() << endl << endl;
        mystack.pop();

        cout << "type 'Y' or 'y' to continue or type any other letter to quit: ";
        getline(cin, done);
    }
}

1 Ответ

0 голосов
/ 21 марта 2019

Вот простое решение проблемы. Извините, у меня такое приятное место для моей любимой HP 35 много лет назад, что мне пришлось пойти немного дальше. Эта версия использует целые числа и использует стек строк. Это можно легко преобразовать в удвоения, заменив int на double по всему файлу,

Используется getline () и istringstream для разбора ввода.

Он также использует stringstream для преобразования чисел в строки и обратно.

Вы должны быть осторожны при разборе нескольких слов из каждой строки. Этот код перенаправляет входную строку в ss, объект istringstream, а затем получает токены из этого объекта.

Кроме того, будет напечатан стек, если вы введете «s».

Наконец, вы можете произвольно загрузить стек последовательностью разделенных пробелами чисел или можете вводить числа по одному за раз. Стек используется при вводе оператора.

Удачи.

#include <iostream>
#include <stack>
#include <string>
#include <sstream>

///////////////////////
/// top_and_pop()
/// Save the top value from a stack, and then pop the stack
/// If the stack is empty, return the string "0".
/// If the stack was not empty, return the popped element.
std::string top_and_pop(std::stack<std::string> &stack)
{
  std::string return_string;
  if (stack.empty()) {
    return_string = "0";
    std::cout << "Stack Empty, returning 0" << std::endl;

  } else {
    return_string = stack.top();

    std::cout << "Popping " << return_string << std::endl;
    stack.pop();
  }
  return return_string;
}

//////////////////////
/// is_number
/// Parse number into a int using std::stringstream.
/// If successful, then, the stringstream will be empty.
/// Return: true if the str would successfully parse as a int
bool is_number(const std::string &str)
{
  std::istringstream ss(str);
  int number;
  ss >> number;

  if (!ss.fail() && ss.eof())
    return true;

  ss >> std::ws; // not needed in this program, because we already parsed the
  // input to a single word without whitespace.  Needed for parsing a single line
  // that may contain any set of chars.

  return !ss.fail() && ss.eof();
}

/////////////////////
/// is_operator
/// return false if str is not a single character or if an operator is not found
///  acceptable operators are anyof "+-*/"
bool is_operator(const std::string &str)
{
      return (str.length() == 1 &&
        str.find_first_not_of("+-*/") == std::string::npos);
}

/////////////////////
/// string_to_int
/// convert string to int
/// Check to be sure string can convert to a int before calling
/// if conversion fails, return 0;
int string_to_int(const std::string &str)
{
  std::stringstream stream;
  int number = 0;

  stream << str;
  stream >> number;

  return number;
}

//////////////////////
/// stack_to_string
///
/// print elements of stack
std::string stack_to_string(std::stack<std::string> stack)
{
  std::string return_string;
  while (!stack.empty()) {
    return_string += stack.top() + " ";

    stack.pop();
  }
  return return_string;
}
int main()
{
  std::stack<std::string> mystack;
  std::string input_line;
  bool done = false;  /// flag to indicate that calcualtor is closing
  std::string token_str;
  int operand1, operand2, result;

  std::cout
      << "Please enter an RPN expression.  Expression may consist of any \n"
         "combination of space-separated numbers or operators.\n"
         "Operators may include '+', '-', '*', '/'.  The stack is initialized\n"
         "with an unlimited supply of zeroes.\n\n"
         "Type 's' to print the current stack.\n"
         "To exit, type a 'y'" << std::endl;

  do {
    getline(std::cin, input_line);

    std::stringstream ss(input_line);

    /// loop through all tokens in this input line
    while (ss >> token_str) {
      // Only numbers are allowed on the stack.
      // If the current token is a number, push it on the stack as a string
      if (is_number(token_str)) {
        mystack.push(token_str);
      } else if (is_operator(token_str)) {
        operand2 = (int) string_to_int(top_and_pop(mystack));
        operand1 = (int) string_to_int(top_and_pop(mystack));

        // switch does not accept string as a type, and we checked to ensure
        // it is a single character operand that is handled in the switch
        switch (token_str[0]) {
          case '+':result = operand1 + operand2;
            break;
          case '-':result = operand1 - operand2;
            break;
          case '*':result = operand1 * operand2;
            break;
          case '/':
            if (operand2 == 0) {
              std::cout << "Error: Cannot divide by zero" << std::endl;
              continue;  // don't push result, take new input.
            } else {
              result = operand1 / operand2;
            }
            break;
            // default case not needed as we already checked operator, but
            // for error checking, we include it
          default:std::cout << "Operator not found" << std::endl;
            continue;
        }
        mystack.push(std::to_string(result));
        std::cout << " Push result " << result << " " << std::endl;
      } else if ("Y" == token_str || "y" == token_str) {
        done = true;
      } else if ("stack" == token_str || "s" == token_str) {
        std::cout << "stack: ";
        std::string stack_dump = stack_to_string(mystack);
        std::cout << stack_dump << std::endl;
      } else {
        std::cout << "Invalid input." << std::endl;
      }
    }
  }
  while (!done);
}
...