C
C
CodeInside2016-03-16 22:32:40
C++ / C#
CodeInside, 2016-03-16 22:32:40

What is a memory error and how to solve it?

I am writing a calculator. I want to solve the resulting expression using the Polish inversion algorithm. In order to make it easier to work with multi-digit numbers and symbols in one entity, I created the Autostack class. I ask you not to criticize much, because this is one from my first classes (but advice or a remark would not hurt). The essence of the problem after the source.
autostack.h:

#ifndef AUTOSTACK
#define AUTOSTACK
#define last_id c_size+i_size
#include <iostream>
#include <string.h>
using namespace std;

class Autostack
{
  char* _char;
  int* _int;
  bool* is_char;//отображает последовательность чисел и символов в стеке
  short c_size = 0;//количество символов в стеке
  short i_size = 0;//количество чисел в стеке

public:
  void push(char);
  void push(int);
  int top(string&);//возвращает и char, но тип возвращаемого значения записывается в string type
  void pop();
  bool empty();
  unsigned short size();
  ~Autostack();

private:
  void addId(string);
  void dropLastId();
  void dropLastChar();
  void dropLastInt();
};
#endif

autostack.cpp:
#include "Autostack.h"
#include <conio.h>
using namespace std;

void Autostack::push(char ch)
{
  char* ptr = new char[c_size];
  for (short i = 0; i < c_size; i++)
    ptr[i] = _char[i];
  delete[] _char;

  _char = new char[c_size + 1];
  for (short i = 0; i < c_size; i++)
    _char[i] = ptr[i];

  _char[c_size++] = ch;
  delete[] ptr;

  addId("char");
}

void Autostack::push(int val)
{
  int* ptr = new int[i_size];
  for (short i = 0; i < i_size; i++)
    ptr[i] = _int[i];
  delete[] _int;

  _int = new int[i_size + 1];
  for (short i = 0; i < i_size; i++)
    _int[i] = ptr[i];

  _int[i_size++] = val;
  delete[] ptr;

  addId("int");
}

void Autostack::addId(string type)
{
  bool* nptr = new bool;
  for (short i = 0; i < last_id - 1; i++)//-1 так-как только что увелился размер i/c_size
    nptr[i] = is_char[i];
  delete[] is_char;

  is_char = new bool[last_id];
  for (short i = 0; i < last_id - 1; i++)
    is_char[i] = nptr[i];

  (type == "char") ? is_char[last_id - 1] = true : is_char[last_id - 1] = false;
  delete[] nptr;
}

void Autostack::dropLastId()
{
  bool* nptr = new bool[last_id - 1];
  for (short i = 0; i < last_id - 1; i++)
    nptr[i] = is_char[i];
  delete[] is_char;
  is_char = nptr;
}

void Autostack::dropLastChar()
{
  char* nptr = new char[--c_size];
  for (short i = 0; i < c_size - 1; i++)
    nptr[i] = _char[i];
  delete[] _char;
  _char = nptr;
}

void Autostack::dropLastInt()
{
  int* nptr = new int[--i_size];
  for (short i = 0; i < i_size - 1; i++)
    nptr[i] = _int[i];
  delete[] _int;
  _int = nptr;
}

int Autostack::top(string& type)
{
  if (is_char[last_id - 1])
  {
    type = "char";
    return _char[c_size - 1];
  }

  else
  {
    type = "int";
    return _int[i_size - 1];
  }
}

void Autostack::pop()
{
  if (is_char[last_id - 1])
  {
    dropLastId();
    dropLastChar();
  }
  else
  {
    dropLastId();
    dropLastInt();
  }
}

bool Autostack::empty()
{
  if (last_id == 0)
    return true;
  else
    return false;
}

unsigned short Autostack::size()
{
  return last_id;
}

Autostack::~Autostack()
{
  delete[] _char;
  delete[] _int;
}

Well, the executable file with the main function (source.cpp):
#include "Autostack.h"
#include <conio.h>
#include <stack>
using namespace std;

int getNumFromStr(const string, short&);
short getPrior(const char);
bool is_operator(const char ch);

void main()
{
  string exp = "45+12*20-(4+2)";
  Autostack res;//resulted stack
  stack<char> ops;//operators

  for (short i = 0; i < exp.length(); i++)
  {
    if (exp[i] >= 48 && exp[i] <= 57)//если число
      res.push(getNumFromStr(exp, i));//закинуть в результирующий стек (ну и сместить индекс)
    else
      if (exp[i] == '+' || exp[i] == '-' || exp[i] == '*' || exp[i] == '/')
        if (ops.empty() || getPrior(ops.top()) < getPrior(exp[i]))
          ops.push(exp[i]);
        else if(getPrior(ops.top()) >= getPrior(exp[i]))
          while (!(ops.empty()) && getPrior(ops.top()) >= getPrior(exp[i]))
          {
            res.push(ops.top());
            ops.pop();
          }

    if (exp[i] == '(')
      ops.push(exp[i]);

    if (exp[i] == ')')
    {
      char next_push;
      do
      {
        res.push(ops.top());
        ops.pop();
        next_push = ops.top();
      } while (next_push != '(');
      ops.pop();//drop '(' from stack
    }		
  }
  //если вся входная строка разобрана, а в стеке еще остаются знаки операций - извлечение их с стека в результирующий стек
  while (!ops.empty())
  {
    res.push(ops.top());
    ops.pop();
  }


  string type;
  while (!res.empty())
  {
    cout << res.top(type) << ' ';
    res.pop();
  }
  _getch();
}

int getNumFromStr(const string str, short& beg_id)
{
  int ret = 0;
  short dig_count = 0;//количество цифр в считываемом числе
  //считывание dig_count
  for (short i = beg_id; i < str.length() && str[i] >= 48 && str[i] <= 57; i++, dig_count++)
    continue;
  unsigned short factor = pow(10, dig_count - 1);//множитель
  for (short i = beg_id; i < str.length() && str[i] >= 48 && str[i] <= 57; i++, factor /= 10)
    ret += factor*(str[i] - 48);//'str[i] - 48' преобразование с char в значение очередной цифры

  beg_id += dig_count - 1;//-1 потому, что по идее вызов функции будет произведен в цикле последовательного перебора
  //с постфиксной формой инкремента
  //поэтому индекс указывает на последнюю цифру считываемого числа
  return ret;
}

short getPrior(const char ch)
{
  switch (ch)
  {
  case '*':
  case '/': return 3;

  case '+':
  case '-': return 2;

  case '(': return 1;
  }
}

bool is_operator(const char ch)
{
  return
    (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(') ? true : false;
}

The error "heap corruption detected: after normal block (#158) at (address)" occurs every time you try to cast the number 20 (5th iteration; 19th line of code). I suspect that the problem is with dynamic memory allocation. Can you help me solve this problem, because I don't understand what to do anymore?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
R
Rsa97, 2016-03-16
@Rsa97

Here it is necessary to allocate an array, not a variable.
In general, the code barely pulls on a C grade. Using four! stacks where you can get by with two. Double copying arrays in push, where you can get by with one, not to mention realloc. Copying arrays on pop where it's not needed at all. Memory re-allocation for every push/pop.
Passing the type as a string instead of bool or enum.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question