Что вызывает ошибку сегментации в функции добавления узла в двусвязном списке?

#c #data-structures #linked-list #append #doubly-linked-list

Вопрос:

Моя реализация двусвязного списка заключается в следующем: каждый узел содержит массив из четырех значений

 #define EMPTYNODE 0

struct node {
short data[4]; // pay attention
struct node* next;
struct node* prev;
};

typedef struct node nodeQ_t;

typedef enum{
   LIST_FALSE = 0,
   LIST_TRUE = 1,
} status_t;

nodeQ_t* createNode(short values[4]){

    nodeQ_t* node = (nodeQ_t*)malloc(sizeof(node));
    for(int i=0; i < 4; i  ){
       node->data[i] = values[i];
     }

   node->next = EMPTYNODE;
   node->prev = EMPTYNODE;
   return node;
}
 

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

 status_t appendNode(nodeQ_t* head, nodeQ_t* newNode){
if(head == EMPTYNODE || newNode == EMPTYNODE){
    return LIST_FALSE;
};

nodeQ_t* currentNode = head;

while(currentNode != EMPTYNODE){
    if(currentNode->next == EMPTYNODE){ //it means that current node is tail
        currentNode->next = newNode;  //segmenttion fault arises at exactly this line 
        newNode->prev = currentNode;
    }
    currentNode = currentNode->next;
}
return LIST_TRUE;
}
 

пожалуйста, дайте мне знать, в чем причина этого…
для вашей справки моя основная функция заключается в

 int main(){
  short array[4] = {1,2,3,4};

  nodeQ_t* head  = createNode(array);

  printList(head);


  short array2[4] = {5,6,7,8};

  nodeQ_t* newNode = createNode(array2);

  appendNode(head, newNode);


  printList(head);



  return 0;

}
 

если вам нужна какая-либо дополнительная информация или объяснение чего-либо, пожалуйста, дайте мне знать

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

1. break выйдите из while цикла, как только вставка завершится успешно.

2. Я думаю, что ваша проблема здесь: (nodeQ_t*)malloc(sizeof(node)) . Так и должно быть sizeof(*node) . node это указатель, поэтому вы выделяете байты для размера указателя, а не для размера структуры node , на которую указывает.

3. @500-InternalServerError: Я не говорю, что возврат из malloc не является указателем. Я говорю sizeof(node) о выделении всего 4 или 8 байтов (независимо от размера указателя), когда правильнее всего выделить *node байты, размер структуры. Смотрите ответ @Johnny Mopp ниже.

4. @sj95126: Извините, неоднозначное использование идентификатора node здесь.

Ответ №1:

Как упоминалось в комментариях, вам нужно break выйти из цикла, как только вы дойдете до конца:

 while(currentNode != EMPTYNODE) {
    if (currentNode->next == EMPTYNODE) {
        currentNode->next = newNode;
        newNode->prev = currentNode;
        // need a break here
    }
    currentNode = currentNode->next;
    // When at the end of the list the 1st time through, 
    // currentNode is the newly created node because you have
    //     currentNode->next = newNode
    // then
    //     currentNode = currentNode->next
    // On the next iteration, the new node next ends up getting pointed to itself 
    // since on that iteration newNode and currentNode are the same.
    // and you end up with an infinite loop.
}
 

Другой вариант-зациклиться на currentNode->next :

 while (currentNode->next) {
    currentNode = currentNode->next;
}
currentNode->next = newNode;
newNode->prev = currentNode;
 

Я должен отметить, что это работает, потому что вы ранее гарантировали, что currentNode это не NULL так .

Кроме того, ваше распределение здесь неверно:

 nodeQ_t* node = (nodeQ_t*)malloc(sizeof(node));
 

Потому node что это указатель и sizeof(node) размер указателя, а не размер struct node . Должно быть

 nodeQ_t* node = (nodeQ_t*)malloc(sizeof(*node));
 

Ответ №2:

Вы попадаете в бесконечный цикл:

 while(currentNode != EMPTYNODE){
    if(currentNode->next == EMPTYNODE){ //it means that current node is tail
        currentNode->next = newNode;  //segmenttion fault arises at exactly this line 
        newNode->prev = currentNode;
    }
 

currentNode всегда будет отличаться от EMPTYNODE .
Добавить разрыв или возврат после добавления нового элемента:

 while(currentNode != EMPTYNODE){
    if(currentNode->next == EMPTYNODE){ //it means that current node is tail
        currentNode->next = newNode;  //segmenttion fault arises at exactly this line 
        newNode->prev = currentNode;
        return LIST_TRUE;
    }