Ошибка сегментации C добавление элемента связанного списка

#c #linked-list

#c #связанный список

Вопрос:

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

  #include <iostream>


    class node{
    public:
        int data;
        class node *next;
    };
    class LinkedList {
    public:
        node *head;
        LinkedList(int num);

        void add(int number);
        void display();
    };

    const int null = 0;
    LinkedList::LinkedList(int num) {
        // TODO Auto-generated constructor stub
        std::cout<<"Constructor Called"<<std::endl;
        head->data = num;
        head->next = null;
        std::cout<<"Constructor Call completed"<<std::endl;
    }



    void LinkedList::add(int num) {
        struct node *n=new node;
        n->data = num;
        n->next = null;
        struct node *current = head;
        while (current->next != null) {
            current = current->next;
        }
        current->next = n;
    }
    void LinkedList::display() {
        std::cout<<"Display"<<std::endl;
        struct node *current = head;

        while (current!= null) {
            std::cout << current->data << "->";
            current = current->next;
        }
        std::cout << "null"<<std::endl;
    }

    int main() {
        LinkedList l(1);
        l.display();
        l.add(2);
        l.display();
        return 0;
    }
 

Пожалуйста, загляните в журналы отладки gdb: узел n не ссылается ни на одну ячейку памяти. Поэтому его не удалось инициализировать. Пожалуйста, дайте мне знать, если вам потребуется дополнительная информация.

Заранее спасибо!

 struct node *n=new node;
 
Вызывается конструктор
Вызов конструктора завершен

Точка останова 1, main () в SampleCPP.cpp: 60
60 л.display();
(gdb) s
LinkedList::display (this=0xbffff03c) в SampleCPP.cpp:48
48 std::cout
(gdb) n
51 while (current!= null) {
(gdb) n
52 std:: данные cout ";
(gdb) n
53 текущий = текущий-> следующий;
(gdb) n
51 в то время как (текущий!= null) {
(gdb) n
55 std::cout null
56 }
(gdb) n
main () в SampleCPP.cpp:61
61 l.add(2);
(gdb) s
LinkedList::add (this=0xbffff03c, num=2) в SampleCPP.cpp:38
38 узел структуры *n=новый узел;
(gdb) вывести n
$ 2 = (узел *) 0x0
(gdb) 

Ответ №1:

Вы никогда не выделяете память для head . Это ваша проблема.

Выделите его в конструкторе:

 LinkedList::LinkedList(int num) {
    std::cout<<"Constructor Called"<<std::endl;
    head = new node; // This is missing!
    head->data = num;
    head->next = null;
    std::cout<<"Constructor Call completed"<<std::endl;
}
 

и было бы неплохо освободить всю эту память до завершения работы вашей программы..

Комментарии:

1. Спасибо за вашу помощь. Это решает мою цель. Не могли бы вы сообщить мне, почему проблема не была выявлена в самом конструкторе? Я отладил конструктор, используя неправильный код, но сообщение о печати правильно напечатало данные в gdb.

2. Я не знаю этого наверняка, и это может потребовать дополнительного анализа, но я могу сформулировать гипотезу: если указатель не инициализируется, он может указывать на мусор, и запись в него может привести или не привести к сбою вашей программы (это называется неопределенным поведением , потому что вы не знаете, как это будет себя вести)

3. @Sambaran Я полагаю, вы имели в виду «почему проблема не была идентифицирована в самом конструкторе?» под «почему это не не идентифицировано во время компиляции. В противном случае утверждение бессмысленно. C не «применяет» какую-либо схему управления памятью, которую пользователь «должен» использовать, оставляя его решать, что делать, а что не делать. Если вы просто забудете выделить память для определенной переменной указателя (head здесь ), компилятор не заботится об этом (почему это должно быть?).

4. Да, Сарги прав. Я думал об этой интерпретации вашего вопроса, но я отказался от нее, поскольку она казалась слишком «очевидной», но я не даю ее как должное: отладчик не предназначен для проверки вашей программы на наличие неинициализированных переменных, неиспользуемого кода и тому подобного (это статический анализ), но он призван помочьвы обнаруживаете ошибку (например, предоставляя трассировку стека и переменные наблюдения после сбоя или в других сценариях)

Ответ №2:

вы не выделяете память для head; это должно быть так

 LinkedList::LinkedList(int num) {
    // TODO Auto-generated constructor stub
    head=new node();
    std::cout<<"Constructor Called"<<std::endl;
    head->data = num;
    head->next = null;
    std::cout<<"Constructor Call completed"<<std::endl;
}
 

Комментарии:

1. При публикации ответов вы должны хотя бы сначала проверить, что он ничего не добавляет к моему..

Ответ №3:

С небольшой модификацией,

 class node{
public:
    int data;
    class node *next;
    node(int num): data(num), next(NULL){} 
};
 

И

 LinkedList::LinkedList(int num): head(new node(num))  {
    // TODO Auto-generated constructor stub
    std::cout<<"Constructor Called"<<std::endl;
    //Do sth if you wish
    std::cout<<"Constructor Call completed"<<std::endl;
}
 

Это устраняет некоторые дополнительные сложности. Измените, где когда-либо вы создавали экземпляр узла с помощью нового конструктора.

Ответ №4:

Я хотел бы предложить следующую реализацию:

 #include <iostream>

using namespace std;


class node
{
private:
    int data;
    node* next;

public:
    // Because of that we store the pointer, default implementations of the
    // copying operations are not acceptable -- they can lead to memory leakage.
    node(const nodeamp;) = delete;
    nodeamp; operator =(const nodeamp;) = delete;

    node(int d, node* prev = nullptr) :
        data(d), next(nullptr)
    {
        if(prev)
        {
            // Free memory before assigning the pointer.
            delete prev->next;
            prev->next = this;
        }
    }
    ~node()
    {
        // Deletes up to the end of the subchain.
        delete next;
    }

    inline node* getNext() const
    {
        return next;
    }
    inline operator int() const
    {
        return data;
    }
};

class LinkedList
{
private:
    node* head;
    node* curr;

public:
    LinkedList(int first_entry) :
        head(new node(first_entry)), curr(head)
    {}
    ~LinkedList()
    {
        delete head;
    }

    void add(int entry)
    {
        curr = new node(entry, curr);
    }
    void display() const
    {
        for(node* i = head; i; i = i->getNext())
            cout << (int)*i << "->";
        cout << "null" << endl;
    }
};


int main(int argc, char* argv[])
{
    LinkedList l(1);
    l.display();
    l.add(2);
    l.display();

    return EXIT_SUCCESS;
}
 

В этом подходе дополнительное внимание было уделено управлению памятью. Кроме того, он более интенсивно использует ООП.