CodeInside
@CodeInside

Что за ошибка с памятью и как её решить?

Пишу калькулятор. Хочу решить полученное выражение, используя алгоритм польской инверсии. Для того, чтобы проще было работать с многоразрядными числами и символами в одной сущности - создал класс Autostack. Попрошу сильно не критиковать, ибо это один с моих первых классов (но совет или замечание не помешали б). Суть проблемы после исходников.
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;
}


Ну и исполняемый файл с функцией main (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;
}

Ошибка "heap corruption detected: after normal block (#158) at (адрес)" возникает при каждой попытке закинуть число 20 (5-я итерация; 19-я строка кода). Я так подозреваю, что проблема с динамическим выделением памяти. Можете помочь решить эту проблему, ибо я уже без понять что делать?
  • Вопрос задан
  • 257 просмотров
Пригласить эксперта
Ответы на вопрос 1
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Здесь надо выделять массив, а не переменную
bool* nptr = new bool;
В целом код еле-еле натягивает на троечку. Использование четырёх! стеков там, где можно обойтись двумя. Двойное копирование массивов в push, где можно обойтись одним, не говоря уже про realloc. Копирование массивов при pop, где оно совсем не нужно. Перевыделение памяти на каждый push/pop.
Передача типа строкой вместо bool или enum.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы