简体   繁体   中英

Segmentation fault when free the linked list node

LNode * deleteNext (LNode *L) {
  if (L == NULL) { return L; }

  LNode *deleted = L->next;
  L->next = L->next->next;
  //L->next->next = NULL;

  delete deleted;
  return L->next;
}

This is a function to delete the next node of pointed node, simple logic. The current code works fine. But if I uncomment the commented line, there will be a segmentation-fault, which seems weird to me. Thanks in advance.

It is a wrong implementation. What if L->next is NULL?

Here is one possible (correct) implementation:

LNode * deleteNext (LNode *L) 
{
  if (L == NULL || L->next == NULL) return NULL;

  LNode *deleted = L->next; //L->next is NOT NULL
  L->next = L->next->next;  
          //^^^^^^^^^^^^ could be NULL though

  delete deleted;
  return L->next; //L->next could be NULL here
}

Now it is up to you what you want to return from the function. You could return L instead of L->next , or you could return std::pair<LNode*, bool> containing L and a boolean value indicating whether delete is done or not.

It all depends how your list's head and tail are implemented. I will assume the last element of the list has its next link set to null (ie the list is not a ring closing on itself).

The call is conceptually wrong. You cannot handle a single-linked list without keeping a reference to its head (first element), unless you use the first element as the head, which is ugly and inefficient.

Also you must decide what to do with the removed element. Deleting it and then returning a pointer to its still warm corpse is at any rate not the best choice.

I will assume the caller might be interrested in retrieving the element (in which case it's the caller that will have to delete it once he's done using it).

LNode * removeNext (LNode *L)
{
  if (L == NULL) panic ("Caller gave me a null pointer. What was he thinking?");
  // should panic if the caller passes anything but a valid element pointer,
  // be it NULL or 0x12345678

  LNode * removed = L->next;
  if (removed = NULL) return NULL; // L is the end of list: nothing to remove
  L->next = removed->next; // removed does exist, so its next field is valid

  // delete removed; // use this for the void deleteNext() variant
  return removed;
}

This will be unable to empty the list completely. At least a single element will remain stuck in it (the pseudo-head, so to speak).

Also you will have to initialize the list with the said pseudo-head. Calling removeNext with the pseudo-head is safe, it will be equivalent to using the list as a LIFO. This implementation will not allow an easy use as a FIFO though, since there will be no easy way to maintain a fixed reference to the tail (last element) of the list.

The way I would do it is rather like so:

typedef struct _buffer {
   struct _buffer * next;
   unsigned long    data;
   } tBuffer;

typedef struct {
   tBuffer * head;
   } tLIST; 

/* ---------------------------------------------------------------------
   Put a buffer into a list
   --------------------------------------------------------------------- */
static void list_put (tLIST * mbx, tBuffer * msg)
{
   msg->next = mbx->head;
   mbx->head = msg;
}

/* ---------------------------------------------------------------------
   get a buffer from a list
   --------------------------------------------------------------------- */
static tBuffer * list_get (tLIST * mbx)
{
   tBuffer * res;

   /* get first message from the mailbox */
   res = mbx->head;

   if (res != NULL)
      {
      /* unlink the buffer */
      mbx->head = res->next;
      }

   return res;
}

(I wrote this back in the mid-90's. Genuine vintage ANSI C. Ah, those were the days...)

It boils down to this: if you're going to implement a singly-linked list, don't try to use it like a random access data structure. It's inefficient at best, and more often than not a nest of bugs. A single-linked list can be used as a FIFO or possibly a stack, and that's about it.

std:: templates offer you everything you could dream of in terms of storage structures, and they have been tested and optimized over the last 20 years or so. No man alive (except Donald Knuth maybe) could do better with a design from scratch.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM