Нужно создать двусвязный список и проделать с ним некоторые действия - a) Добавить новый элемент в начало, b) Убрать первый элемент, c) Добавить новый элемент в конец, d) Убрать последний элемент. Синтаксических ошибок не выявлено, компилируется но в ходе работы крашется. Подозреваю что накосячил с передачей данных в методы класса. (Новичок, качество кода сам знаю что говно). Прошу указать на ошибки с возможным решением, заранее спасибо.
Visual Studio выдает это: Поток 0x1f20 завершился с кодом 0 (0x0). HEAP[LAB_1_AiStrD.exe]: Invalid address specified to RtlValidateHeap( 01290000, 012AC5F8 ) LAB_1_AiStrD.exe вызвал срабатывание точки останова.
Вот нужный кусок кода: main.cpp
#include <iostream>
#include "List.h"
typedef unsigned int uint;
using namespace std;
int* createArray(int*& array, uint num);
int* fillArray(int*& array, uint num);
void printArray(int* array, uint num);
void deleteArray(int* array);
int* addNewElement(int*& array, uint num, int newData);
int* deleteLastElement(int*& array, uint num);
List fillDeque(List deQue, uint num);
int main()
{
setlocale(LC_ALL, "rus");
uint num;
int t, actType;
startPoint:
cout << "Выберите действие: \n 1. Работа с динамическим массивом \n 2. Работа с двухсвязным списком \n";
cout << " 3. Перевод из инфиксной формы в постфиксную (обратная польская нотация)\n";
cin >> actType;
switch (actType)
{
case (1):
{
cout << "Ввдите целое положительное число для определения длины массива..." << endl;
std::cin >> num;
if ((num >= 1) && (num <= 4294967295))
{
int* array = NULL;
createArray(array, num);
fillArray(array, num);
cout << "Динамический массив успешно создан и заполнен случайными данными!" << endl;
cout << "Для продолжения выберите дейстие\n a. Добавить новый элемент в конец. \n b. Убрать последний элемент" << endl;
char mode;
std::cin >> mode;
if ((mode == 97) || (mode == 65)) // 97 is a, 65 is A
{
cout << "Данные в массиве: " << endl;
printArray(array, num);
int newData = (rand() % 100);
array = addNewElement(array, num, newData);
cout << "Новый сгенерированный элемент " << newData << " был добавлен в конец динамического массива" << endl;
cout << "Данные в массиве: " << endl;
printArray(array, num+1);
}
else if ((mode == 98) || (mode == 66)) // 98 is b, 66 is B
{
cout << "Данные в массиве: " << endl;
printArray(array, num);
uint Last_Elm = array[sizeof(array) / sizeof(array[0])]; // копируем значение последнего элемента для вывода
array = deleteLastElement(array, num);
cout << "Последний элемент " << array[Last_Elm] << " был удален из динамического массива" << endl;
cout << "Данные в массиве: " << endl;
printArray(array, num-1);
}
else
{
cout << endl << "Ошибка! " << endl;
}
}
else
{
cout << endl << "Ошибка! " << endl;
}
cout << "\n Хотите продолжить? да - 1; нет - 0" << endl;
std::cin >> t;
if (t == 1)
{
std::system("cls");
goto startPoint;
}
break;
}
case (2):
{
cout << "Ввдите целое положительное число для определения длины списка..." << endl;
cin >> num;
if (num >= 1)
{
List deQue; //Объявляем переменную, тип которой есть список
deQue = fillDeque(deQue, num); //Добавляем в список элементы
cout << "Данные в списке. Вывод сначала списка: " << endl;
deQue.ShowStart(); //Отображаем список на экране
char listmode;
cout << "Выберите действие: \n a. Добавить новый элемент в начало. \n b. Убрать первый элемент.\n";
cout << " c. Добавить новый элемент в конец.\n d. Убрать последний элемент. \n";
cin >> listmode;
switch (listmode)
{
case ('a'): //Добавить новый элемент в начало
{
cout << "Данные в списке. Вывод сначала списка: " << endl;
deQue.ShowStart();
deQue.AddFirst(rand() % 100);
cout << "Новый сгенерированный элемент ";
deQue.ShowFirst();
cout << " был добавлен в начало списка\n";
cout << "Данные в списке. Вывод сначала списка: " << endl;
deQue.ShowStart();
}
case ('b'): //Убрать первый элемент
{
cout << "Данные в списке. Вывод сначала списка: " << endl;
deQue.ShowStart();
deQue.DeleteFirst(1); // ?? what is argument ??
cout << "Первый элемент был удален\n";
cout << "Данные в списке. Вывод сначала списка: " << endl;
deQue.ShowStart();
}
case ('c'): //Добавить новый элемент в конец
{
cout << "Данные в списке. Вывод с конца списка: " << endl;
deQue.ShowEnd();
deQue.AddLast(rand() % 100);
cout << "Новый сгенерированный элемент ";
deQue.ShowLast();
cout << " был добавлен в конец списка\n";
cout << "Данные в списке. Вывод с конца списка: " << endl;
deQue.ShowEnd();
}
case ('d'): //Убрать последний элемент
{
cout << "Данные в списке. Вывод с конца списка: " << endl;
deQue.ShowEnd();
deQue.DeleteLast(1); // ?? what is argument ??
cout << "Последний элемент был удален\n";
cout << "Данные в списке. Вывод с конца списка: " << endl;
deQue.ShowEnd();
}
default:
{
cout << "\n Хотите продолжить? да - 1; нет - 0" << endl;
cin >> t;
if (t == 1)
{
std::system("cls");
goto startPoint;
}
else break;
}
}
return 0;
}
else
{
cout << endl << "Ошибка! " << endl;
}
cout << "\n Хотите продолжить? да - 1; нет - 0" << endl;
std::cin >> t;
if (t == 1)
{
std::system("cls");
goto startPoint;
}
break;
}
case (3):
{
// МЕСТО ДЛЯ ПОЛЬСКОЙ ОБРАТНОЙ чего-то там....
}
default:
{
cout << "\n Хотите продолжить? да - 1; нет - 0" << endl;
std::cin >> t;
if (t == 1)
{
std::system("cls");
goto startPoint;
}
else break;
}
}
return 0;
}
array.cpp
#include <iostream>
typedef unsigned int uint;
using namespace std;
int* createArray(int*& array, uint num)
{
array = new int[num];
return array;
}
int* fillArray(int*& array, uint num)
{
for (uint i = 0; i < num; i++)
{
array[i] = rand() % 100 + 1;
}
return array;
}
void printArray(int* array, uint num)
{
for (uint i = 0; i < num; i++)
{
cout << array[i] << "\t";
}
cout << endl;
}
void deleteArray(int* array)
{
delete[] array;
}
int* addNewElement(int*& array, uint num, int newData)
{
int *temp = NULL;
uint numTemp = num + 1;
temp = createArray(temp, numTemp); // создаем временный массив
for (uint i = 0; i < num; i++) temp[i] = array[i]; // копируем данные со старого массива
temp[numTemp-1] = newData; // добавляем новый элемент в конец нового массива
deleteArray(array);
return temp;
}
int* deleteLastElement(int*& array, uint num)
{
int* temp = NULL;
int numTemp = num - 1;
temp = createArray(temp, numTemp);
for (int i = 0; i < numTemp; i++) temp[i] = array[i]; // копируем данные со старого массива
deleteArray(array); // удаляем старый массив
return temp;
}
List.h
#pragma once
// #pragma once препроцессорная директива, разработанная для контроля за тем
// чтобы конкретный исходный файл при компиляции подключался строго один раз
struct Node //Структура, являющаяся звеном списка
{
int x; //Значение x будет передаваться в список
Node* Next, * Prev; //Указатели на адреса следующего и предыдущего элементов списка
};
class List //Создание типа данных "Список"
{
Node* Head, * Tail; //Указатели на адреса начала списка и его конца
public:
List() :Head(NULL), Tail(NULL) {}; //Инициализируем адреса как пустые
~List(); //Прототип деструктора
void ShowStart(); //Прототип функции отображения списка на экране сначала
void ShowEnd(); //Прототип функции отображения списка на экране с конца
void ShowLast();
void ShowFirst();
void AddLast(int x); //Прототип функции добавления элементов в конец списка
void AddFirst(int x); //Прототип функции добавления элементов в начало списка
void DeleteFirst(int x); //Прототип функции удаления элементов сначала списка
void DeleteLast(int x); //Прототип функции удаления элементов с конца списка
void DeleteAllList(int x); //Прототип функции удаления всего списка
};
List.cpp
#include <iostream>
#include <stdlib.h>
#include "List.h"
using namespace std;
/* Деструктор — это функция-член, которая вызывается автоматически,
когда объект выходит из области действия или явно уничтожается вызовом Delete */
List::~List() //Деструктор
{
while (Head) //Пока по адресу на начало списка что-то есть
{
Tail = Head->Next; //Резервная копия адреса следующего звена списка
delete Head; //Очистка памяти от первого звена
Head = Tail; //Смена адреса начала на адрес следующего элемента
}
}
void List::AddLast(int x)
{
Node* temp = new Node; //Выделение памяти под новый элемент структуры
temp->Next = NULL; //Указываем, что изначально по следующему адресу пусто
temp->x = x; //Записываем значение в структуру
if (Head != NULL) //Если список не пуст
{
temp->Prev = Tail; //Указываем адрес на предыдущий элемент в соотв. поле
Tail->Next = temp; //Указываем адрес следующего за хвостом элемента
Tail = temp; //Меняем адрес хвоста
}
else //Если список пустой
{
temp->Prev = NULL; //Предыдущий элемент указывает в пустоту
Head = Tail = temp; //Голова=Хвост=тот элемент, что сейчас добавили
}
}
void List::AddFirst(int x)
{
Node* temp = new Node; //Выделение памяти под новый элемент структуры
temp->Prev = NULL; //Указываем, что изначально по следующему адресу начало списка
temp->x = x; //Записываем значение в структуру
if (Head != NULL) //Если список не пуст
{
temp->Next = Head; //Указываем адрес на следующий элемент в соотв. поле
Head->Prev = temp; //Указываем адрес педыдущего за началом элемента
Head = temp; //Меняем адрес начала
}
else //Если список пустой
{
temp->Next = NULL; //Cледующий элемент указывает в пустоту
Head = Tail = temp; //Голова=Хвост=тот элемент, что сейчас добавили
}
}
void List::DeleteFirst(int x)
{
//Если удаляем первый элемент, то могут быть такие варианты
//В списке есть только первый, в списке есть несколько элементов
//Поэтому разбиваем логику выполнения
if ((x == 1) and (Head->Next)) //Если удаляем первый, но есть и другие, то
{
Node* temp = Head; //Указываем, что нам нужно начало списка
Head = Head->Next; //Сдвигаем начало на следующий за началом элемент
Head->Prev = NULL; //Делаем так, чтоб предыдущий началу элемент был пустым
delete temp; //Удаляем удаляемое начало
return;
}
else if ((x == 1) and (Head == Tail)) //Если удаляем первый, но в списке только 1 элемент
{
Head->Next = NULL; //обнуляем все что нужно
Head = NULL;
delete Head; //Удаляем указатель на начало
return;
}
}
void List::DeleteLast(int x)
{
//удаляемый элемент является последним элементом списка
Node* temp = Tail; //Указываем, что нам нужен хвост
Tail = Tail->Prev; //Отодвигаем хвост немного назад
Tail->Next = NULL; //Обозначаем, что впереди за хвостом пусто
delete temp; //Очищаем память от бывшего хвоста
}
void List::DeleteAllList(int x)
{
while (Head != NULL) // пока не указываем на хвост
{
Node* temp = Head; // создаем временный элемент
Head = Head->Next; // присваиваем ему указатель на следующий
delete temp; // и удаляем его
}
Head = NULL;
Tail = NULL;
}
void List::ShowStart()
{
//ВЫВОДИМ СПИСОК С НАЧАЛА
Node* temp = Head; //Временно указываем на адрес первого элемента
while (temp != NULL) //Пока не встретим пустое значение
{
cout << temp->x << " "; //Выводим каждое считанное значение на экран
temp = temp->Next; //Смена адреса на адрес следующего элемента
}
cout << "\n";
}
void List::ShowEnd()
{
//ВЫВОДИМ СПИСОК С КОНЦА
Node* temp = Tail; //Временный указатель на адрес последнего элемента
while (temp != NULL) //Пока не встретится пустое значение
{
cout << temp->x << " "; //Выводить значение на экран
temp = temp->Prev; //Указываем, что нужен адрес предыдущего элемента
}
cout << "\n";
}
void List::ShowLast()
{
Node* temp = Tail; //Временный указатель на адрес последнего элемента
cout << temp->x; //Выводить значение на экран
delete temp;
}
void List::ShowFirst()
{
Node* temp = Head; //Временный указатель на адрес последнего элемента
cout << temp->x; //Выводить значение на экран
delete temp;
}
fillDeque.cpp
#include <iostream>
#include "List.h"
typedef unsigned int uint;
using namespace std;
List fillDeque(List deQue, uint num)
{
for (uint i = 0; i < num; i++)
{
deQue.AddLast(rand() % 100 + 1);
}
return deQue;
}
Начнем отсюда:
void List::AddLast(int x)
{
Node* temp = new Node;
temp->Next = NULL;
temp->x = x;
if (Head != NULL)
Tail->Next = temp;
Tail = temp;
//...
Когда вы добавляете второй элемент, то выполняется Head != NULL
. На что будут указывать Tail->prev
, Tail->next
и Head->next
после выполнения кода в условии?..
А теперь вам наверное понятно, что невозможно кратко рассказать о всех ваших ошибках и как их исправить. Лучше погуглите, посмотрите как реализуются двусвязные списки, и перепишите код, как только все поймете...
Проблема была в методе ShowFirst()
, строчка delete temp
void List::ShowFirst()
{
Node* temp = Head; //Временный указатель на адрес последнего элемента
cout << temp->x; //Выводить значение на экран
// delete temp; // не надо удалить
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
У меня есть код, с двумя вариантами, первый который работает с оператором afirst и второй который работает с оператором a->first для меня разницы...
Пытаюсь использовать коннектер MySQL и C++ среда : Windows 10 Code::Blocks 1712 MySQL 8