Как инициализировать член класса, который является указателем на структуру - PullRequest
0 голосов
/ 09 апреля 2020

У меня проблема с падением приложения в строке кода, где if (! Head) упоминается внутри функции: insertNode (). head и tail являются членами класса типа node *. Похоже, я что-то упускаю в способе инициализации членов класса: head, tail. Это ошибка времени выполнения: «Необработанное исключение в 0x00245246 в SLinkedlist_array.exe: 0xC0000005: Местоположение чтения нарушения доступа 0x00000000.»

    slinkedlist.h:
    typedef struct node
    {
        int value;
        struct node* next;
    } node;

    class slinkedlist
    {
    public:
        //ctor, dtor, insertNode(int, int), displayList()
    private:
        node* head, tail;
    };

    slinkedlist.cpp:
    bool slinkedlist::insertNode(int value, int aftNodeVal)
    {
        int toinsertval = value;
        int searchkey = aftNodeVal;
        bool retval = false;

        // If it's a new linked list
        if(!head)  // THIS IS WHERE THE APPLICATION CRASHES!
        {
            node* head = new node;
            head->value = toinsertval;
            head->next = NULL;
            return true;
        }
        else //It's not a new list
        {
            while(head->next != NULL)
            {
                 //some more code here... 
            }
        }
        return retval;
    }

    void slinkedlist::displayList()
    {
        while(!head)
        {
            do
            {
                cout << head->value << " " ;
                head = head->next;
            }
            while(head->next != NULL);
        }
        //return void;
    }

    main.cpp:
    int main()
    {
        slinkedlist *s1 = NULL;
        s1->insertNode(4, -1);
        s1->displayList();
        while(1);
    }`

Ответы [ 2 ]

1 голос
/ 09 апреля 2020

Ответ прост: у вас есть разыменование нулевого указателя здесь:

slinkedlist *s1 = NULL;
s1->insertNode(4, -1);
s1->displayList();

Это именно то, что система говорит вам: «Место чтения нарушения доступа 0x00000000»

Решение может быть например:

slinkedlist *s1 = new slinkedlist;
s1->insertNode(4, -1);
s1->displayList();
delete s1;

Или вот так (почему бы не использовать просто объект в стеке?):

slinkedlist s1;
s1.insertNode(4, -1);
s1.displayList();

Или больше C ++ (если вам нужен указатель):

auto s1 = make_unique<slinkedlist>(); // s1 is a std::unique_ptr<slinkedlist>
s1->insertNode(4, -1);
s1->displayList();
0 голосов
/ 09 апреля 2020
slinkedlist *s1 = NULL;

определяет указатель на slinkedlist и выполняет его инициализацию. К сожалению, он инициализирует его значением NULL, адресом безопасной парковки, где (как правило) ни один объект не может существовать. Для подавляющего большинства процессоров (каждый процессор, на котором я когда-либо работал) доступ к этой мертвой зоне вокруг NULL приведет к взлому sh программы, что значительно упростит обнаружение ошибок.

Нет необходимости указатель здесь. Если вам не нужен указатель, не используйте его. Ваша жизнь будет намного проще.

int main()
{
    slinkedlist s1; // default initializes
    s1.insertNode(4, -1);
    s1.displayList();
    while(1); // rethink this. If you want to hold a program open to see the output 
              // while debugging, place a breakpoint in the debugger.   
}

Инициализация по умолчанию из s1 сама по себе не поможет, поскольку она выполнит абсолютную минимальную работу по инициализации своих переменных-членов, а также в В случае указателя минимальная работа - ничего не делать и оставлять head и tail неинициализированными и указывать (вроде. tail НЕ указатель) на неопределенное место. Поскольку вы также не спрашиваете об ошибке компилятора, которую вы должны получить, присваивая NULL для tail, программа явно не инициализирует tail, и я предполагаю, что конструктор slinkedlist мало что делает.

Примечание: если у вас есть конструктор или деструктор, который ничего не делает (и не должен ничего делать), оставьте их и позвольте компилятору сгенерировать соответствующий код. Код, который не существует (и не должен существовать), не содержит ошибок.

class slinkedlist
{
public:
    //ctor, dtor, insertNode(int, int), displayList()
private:
    node* head, tail; // the * only applies to head.
};

может быть

class slinkedlist
{
public:
    //ctor, dtor, insertNode(int, int), displayList()
private:
    node* head = nullptr;
    node* tail = nullptr;
};

, если вы компилируете в последний (2011 или более новый) C ++ Стандарты. Вам не понадобится конструктор, работа сделана за вас с заданиями по умолчанию. Вам все еще понадобится деструктор вместе с конструктором копирования и оператором присваивания, чтобы удовлетворить Правило трех .

В старых стандартах C ++ вам нужно сделать конструктор умнее

class slinkedlist
{
public:
    slinkedlist(): head(NULL), tail(NULL)
    {
    }
    //dtor, insertNode(int, int), displayList()
private:
    node* head; // I recommend splitting the definitions up. It makes the code easier 
                // to read and makes it harder to make mistakes.
    node* tail;
};

Вам все еще понадобятся деструктор, конструктор копирования и оператор присваивания.

Обратите внимание, что это также относится к node. Если вы динамически выделяете узел и не устанавливаете в явном виде значение next, вы не будете знать, куда указывает next, и все тесты, такие как

while(head->next != NULL)

, будут ужасно провалены.

...