Кажется, вставка в связанный список неверно указывает на следующий указатель

0

Я работаю над назначением связанного списка для курса структуры данных. Вставка значений работает нормально, но при попытке распечатать программу вылетает, как только она попадает в вставленное значение. Поэтому, если я использую функцию добавления в инструкции switch в драйвере, попробуйте вставить значение между любым из них, функция отображения будет аварийно завершена, как только она выведет новое значение данных. Я уже давно работаю над этим, и, похоже, не могу обернуться вокруг него. Любые советы высоко ценится.

list.h

// List.h
#ifndef LIST
#define LIST

#include <iostream>
#include <cstdlib>
#include <string>
using namespace std; 

typedef string ElementType;

class List
{
private:
    class Node
    {
    public:
        ElementType data;
        Node * next;

        Node()
            : data(ElementType()), next(NULL)
        { }

        Node(ElementType initData)
            : data(initData), next(NULL)
        { }
    }; // end of Node class

    typedef Node * NodePointer;

public:
    List();
    /* Construct a List object

    Precondition: none.
    Postcondition: An empty List object has been constructed.
    */

    List(const List &source);
    /* Construct a copy of a List object.

    Precondition: None.
    Postcondition: A copy of source has been constructed.
    */

    ~List();
    /* Destroys a List object.

    Precondition:  None.
    Postcondition: Any memory allocated to the List object has been freed.
    */

    const List & operator=(const List &rightSide);
    /* Assign a copy of a List object to the current object.

    Precondition: none
    Postcondition: A copy of rightside has been assigned to this
    object. A constant reference to this list is returned.
    */

    int getSize() const;
    /* Returns the size of the list (number of items in the list)

    Precondition: none
    Postcondition: The return value is the number of items in the list.
    */

    bool empty() const;
    /* Check if this List is empty

    Precondition: none
    Postcondition: The return value is true if this List object is empty;
    otherwise the return value is false.
    */

    void insert(ElementType dataVal, int index);
    /* Insert a value into this List at a given index

    Precondition:  The index is valid (0 <= index <= the list size).
    The first position is index 0, the second position is index 1, etc.
    Postcondition: dataval has been inserted into the list at the position
    determined by index (provided there is room and index is a legal
    position).
    */

    void erase(int index);
    /* Remove the value from this List at a given index.

    Precondition:  The list is not empty and index is valid
    (0 <= index < the list size).
    Postcondition: the element at position index has been
    removed (provided index is a legal position).
    */

    void display(ostream &out) const;
    /* Display the contents of this List

    Precondition:  ostream out is open
    Postcondition: the items in this List have been output to stream out
    */


    int find(ElementType value) const;
    /* Find the first occurrence of a value in this List

    Preconditions:  None
    Postconditions: The return value is the index of the first List item
    that matches value. The first list item has index 0, the second has
    index 1, etc. The return value is -1 if value is not found in the list.
    */


private:
    NodePointer first;
    int mySize;
}; // end of List class

#endif

List.cpp

#include "List.h"
#include <cassert>
// Definition of List constructor
List::List()
: first(0), mySize(0)
{}
// Definition of List copy constructor
List::List(const List &source)
{
    first = 0; 
    if (!source.empty())
    {
        first = new List::Node(source.first->data); 
        List::NodePointer lastPtr = first,
                            origPtr = source.first->next;
        while (origPtr != 0)
        {
            lastPtr->next = new List::Node(origPtr->data);
            lastPtr = lastPtr->next;
            origPtr = origPtr->next;
        }
    }
}
// Definition of List destructor
List::~List()
{
    List::NodePointer currPtr = first,
                    nextPtr;
    while (currPtr != 0)
    {
        nextPtr = currPtr->next; 
        delete currPtr; 
        currPtr = nextPtr; 
    }
}

const List & List::operator=(const List &rightSide)
{
    if (this != &rightSide) // lhs != rhs
    {
        this->~List(); 
        if (rightSide.empty())
            first = 0; 
        else
        {
            first = new List::Node(rightSide.first->data); 
            List::NodePointer lastPtr = first,
                                rhsPtr = rightSide.first->next; 
            while (rhsPtr != 0)
            {
                lastPtr->next = new List::Node(rhsPtr->data); 
                lastPtr = lastPtr->next; 
                rhsPtr = rhsPtr->next; 
            }
        }
    }
    return *this; 
}
// Definition of getSize
int List::getSize() const
{
    return mySize; 
}
// Definition of empty
bool List::empty() const
{
    return (first == 0); 
}
// Definition of insert
void List::insert(ElementType dataVal, int index)
{
    assert(index >= 0 && index <= mySize); 
    List::NodePointer ptr = first; 
    List::NodePointer predPtr = 0; 
    for (int i = 0; i < index; i++)
    {
        predPtr = ptr;
        ptr = ptr->next;
    }
    List::NodePointer newPtr = new Node(dataVal); 
    if (predPtr != 0)
    {
        newPtr->next = predPtr->next; 
        predPtr->next = newPtr; 
    }
    else
    {
        newPtr->next = first;   
        first = newPtr;         //reset first
    }
    delete ptr;                 //return pointer to heap
    mySize++;
}
// Definition of erase
void List::erase(int index)
{
    assert(!empty() && (index >= 0) && (index < mySize)); 
    List::NodePointer ptr = first;
    List::NodePointer predPtr = 0;
    for (int i = 0; i < index; i++)
    {
        predPtr = ptr;
        ptr = ptr->next;
    }
    if (predPtr != 0)
    {
        ptr = predPtr->next; 
        predPtr->next = ptr->next; 
    }
    else
    {
        ptr = first; 
        first = ptr->next; 
    }
    delete ptr;                 //return pointer to heap
    mySize--; 
}
// Definition of display
void List::display(ostream &out) const
{
    List::NodePointer ptr = first; 
    while (ptr != 0)
    {
        out << ptr->data << endl; 
        ptr = ptr->next; 
    }
}
// Definition of find
int List::find(ElementType value) const
{
    List::NodePointer ptr = first; 
    int i = 0; 
    while (ptr != 0)
    {
        if (ptr->data == value)
            return i; 
        i++; 
        ptr = ptr->next; 
    }
    return -1; 
}

Aaaand водитель

#include <cctype>       // Provides toupper
#include <iostream>     // Provides cout and cin
#include <cstdlib>      // Provides EXIT_SUCCESS
#include <ctime>        // Provides seed for rand. 

using namespace std;
#include "List.h"  

// PROTOTYPES:
void print_menu();
// Postcondition: A menu of choices has been printed.

string get_string();
// Postcondition: The user has been prompted to enter an integer number. The
// number has been read, echoed to the screen, and returned by the function.

string generate_string(); 


int main()
{
    List test;     // A List to perform tests on
    char choice;   // Command entered by the user
    srand((unsigned int) time(0));
    cout << "I have initialized an empty list of strings." << endl;

    do
    {
        print_menu();
        cout << "Enter choice: ";
        cin >> choice;
        choice = toupper(choice);
        ElementType value;
        int position;

        switch (choice)
        {
        case 'A': 
            cout << "Enter the amount of items to add: "; 
            cin >> position; 
            for (int i = 0; i < position; i++)
            {
                test.insert(generate_string(), test.getSize());
            }
            break;
        case 'E': // Is Empty
            cout << "Empty: " << boolalpha << test.empty() << endl; 
            break;
        case 'F': // add code to find item in the list.
            break;
        case 'P': //Print
            test.display(cout); 
            break;
        case 'I': //Insert
            cout << "Enter value: "; 
            cin >> value; 
            cout << endl << "Enter position: "; 
            cin >> position; 
            test.insert(value, position);
            break;
        case 'R': //Erase
            cout << endl << "Enter position: ";
            cin >> position;
            test.erase(position);
            break;
        case 'Q': cout << "Test program ended." << endl;
            break;
        default:  cout << choice << " is invalid." << endl;
        }
    } while ((choice != 'Q'));

    return EXIT_SUCCESS;
}

void print_menu()
{
    cout << endl;
    cout << "The following choices are available: " << endl;
    cout << " A     Add a number of random strings to end of list" << endl;
    cout << " E     Print the result from the empty( ) function" << endl;
    cout << " F     Find and item in the list using find( )" << endl;
    cout << " P     Print a copy of the entire list" << endl;
    cout << " I     Insert a new string with the insert(...) function" << endl;
    cout << " R     Remove a string with the erase( ) function" << endl;
    cout << " Q     Quit this test program" << endl;
}

char get_user_command()
// Library facilities used: iostream
{
    char command;

    cout << "Enter choice: ";
    cin >> command; // Input of characters skips blanks and newline character

    return command;
}

string get_string()
// Library facilities used: iostream
{
    string result;

    cout << "Please enter an string for the list: ";
    getline(cin, result);
    cout << result << " has been read." << endl;
    return result;
}

string generate_string()
{
    const int STR_LENGTH = 5; // Length of random generated strings. 
    string randomString; 
    for (int i = 0; i < STR_LENGTH; i++)
        randomString += (char)((rand() % 52) + 65); 
    return randomString; 
}

Еще раз спасибо.

Теги:
pointers
data-structures
linked-list

2 ответа

0
Лучший ответ

Посмотрите на метод вставки:

delete ptr;                 //return pointer to heap

Если вы вставляете узел, не нужно ничего удалять. Этот код

newPtr->next = predPtr->next;

присваивает newPtr->next с ptr, который после удаления ptr указывает на освобожденную память.

  • 0
    Это добилось цели. Огромное спасибо.
0

Создайте диаграмму (поля и стрелки) о том, как происходит вся операция, шаг за шагом. Это должно показать, где ваш код сбивается с пути.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню