Ошибка доступа к памяти в методе класса

245
28 февраля 2018, 09:19

Беда следующая: работаю со списком в классе(Использование STL запрещено) худо бедно расписал методы. Далее когда описываю экземпляр в main и пытаюсь вызвать метод addElement возникает ошибка доступа к памяти. Как быть? Из-за чего так происходит?

Листинг main.cpp

#include "stdafx.h"
#include "vset.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
    vset a;
    a.AddElement(&a.ilast, 5);
    //  a.AddElement(&a.last, 7);
    a.PrintList(a.ihead);
    return 0;
}

Листинг реализации класса vset.cpp

    #pragma once
    #include "vset.h"
    #include <iostream>
    using namespace std;
    vset::SingleList * vset::makeFirst(int d)
    {
        SingleList *cRec = new SingleList;
        cRec->Data = d; cRec->next = 0; cRec->prev = 0;
        return cRec;
    }
    void vset::AddElement(vset::SingleList **last, int d)
    {
        vset::SingleList *cRec = new SingleList;
        cRec->Data = d; cRec->next = 0; cRec->prev = *last;
        (*last)->next = cRec;
        *last = cRec;
    }
    vset::SingleList * vset::search(SingleList * const pbeg, int d)
    {
        SingleList *cRec = pbeg;
        while (cRec)
        {
            if (cRec->Data == d)break;
            cRec = cRec->next;
        }
        return cRec;
    }
    bool vset::remove(vset::SingleList **head, vset::SingleList **last, int key)
    {
        if (SingleList *pkey = search(*head, key))
        {
            if (pkey == *head)
            {
                *head = (*head)->next;
                (*head)->prev = 0;
            }
            else if (pkey == *last)
            {
                *last = (*last)->prev;
                (*last)->next = 0;
            }
            else {
                (pkey->prev)->next = pkey->next;
                (pkey->next)->prev = pkey->prev;
            }
            delete pkey;
            return true;
        }
        return false;
    }
    vset::SingleList * vset::insert(vset::SingleList * const head, vset::SingleList **last, int key, int d)
    {
        if (SingleList *pkey = search(head, key))
        {
            SingleList *cRec = new SingleList;
            cRec->Data = d; cRec->next = pkey->next;
            cRec->prev = pkey; pkey->next = cRec;
            if (pkey != *last) (cRec->next)->prev = cRec;
            else *last = cRec;
            return cRec;
        }
        return 0;
    }
    void vset::PrintList(vset::SingleList * const head)
    {
        SingleList *cRec = head;
        while (cRec)
        {
            cout << cRec->Data << " ";
            cRec = cRec->next;
        }
    }
    void getData()
    {
    }
    vset::vset()
    {
        SingleList *ihead = makeFirst(0);
        SingleList *ilast = ihead;
    //  getLast(&last);
    }
    vset::vset(int d)
    {
        SingleList *ihead = makeFirst(d);
        SingleList *ilast = ihead;
    }
    /*vset::SingleList getLast(vset::SingleList **last)
    {
        static vset::SingleList **olast;
        if (!last) olast = last;
        return **olast;
    }*/
    vset::~vset()
    {
    }

Интерфейс vset.h

    #pragma once
    class vset
    {
    public:
        struct SingleList
        {
            int Data;
            SingleList *next;
            SingleList *prev;
        };
        SingleList *ihead;
        SingleList *ilast;
    public:
        vset();
        vset::vset(int d);
        ~vset();
        SingleList * makeFirst(int d);
        void AddElement(SingleList **last, int d);
        SingleList * search(SingleList * const pbeg, int d);
        bool remove(SingleList **head, SingleList **last, int key);
        SingleList * insert(SingleList * const head, SingleList **last, int key, int d);
        void PrintList(SingleList * const head);
        void getData();
        vset::SingleList getLast(vset::SingleList);
    };
Answer 1

Начнем исправление ошибок:)

  • #pragma once в cpp классе? серьезно?
  • vset::vset(int d); - вот так в объявлении класса не нужно писать. Правильно писать вот так vset(int d);или ещё лучше так explicit vset(int d);
  • Ошибки в конструкторе-деструкторе

    vset::vset()
    {
        SingleList *ihead = makeFirst(0);
        SingleList *ilast = ihead;
    //  getLast(&last);
    }
    

Здесь объявлены указатели, имя которых пересекается с переменными класса. По выходу с конструктора эти указатели потеряются, а значение переменных класса так и останется неинициализированным. Правильно конструктор писать где то так

    vset::vset()
    {
        ihead = makeFirst(0);
        ilast = ihead;
    }

После этого код как минимум уже запускается и работает как нужно.

Но в нем есть ещё утечка - в деструкторе не освобождается память. По хорошему можно написать функцию clear, которая будет очищать содержимое и просто вызывать ее в деструкторе.

Но есть ещё пару замечаний. Функция AddElement требует указателя на последний элемент. Если ей передать просто указатель на произвольный элемент, то она испортит список. (будет как бы вилка). Поэтому, лучше этот параметр оттудова совсем убрать.

Также функции у Вас названы в разнобой. Есть и маленькими буквами, и CamelCase, и camelCase. Приведите все к одному виду.

READ ALSO
Ошибка сегментирования что делать?

Ошибка сегментирования что делать?

Вылетает ошибка сегментирования (сделан дамп памяти)Если не сложно, объясните, что именно не так

320
Изменить COM-порт устройства программно

Изменить COM-порт устройства программно

У меня подключено устройство (arduino), оно определяется и подключается к какому-нибудь COM-портуНомер порта можно изменить через Устройства и принтеры...

250
Время выполнения программы

Время выполнения программы

Узнаю время работы так:

256