简体   繁体   English

C中的链接列表:我为什么要进行分类?

[英]Linked list in C: Why am I segfaulting?

I'm new to C and have been working on writing a linked list by hand. 我是C的新手,一直致力于手工编写链表。 Right now, I am working on a method to remove an element from the front of the list. 现在,我正在研究一种从列表前面删除元素的方法。 It reads: 它写道:

   void remove_from_front(List *l)
    {
      Node *head = l->first;

      l->first = l->first->next;

      free(head);
    }

I'm sure this is something obvious, but I'm not getting it. 我确信这是显而易见的,但我没有得到它。 Here is some relevant data on my question: 以下是我的问题的一些相关数据:

Prior research. 之前的研究。 I have looked through multiple SO posts, including this one , but all use different implementations that I can't seem to pick apart. 我查看了多个SO帖子,包括这个帖子,但都使用了我似乎无法分开的不同实现。 There are examples of this code all over the internet, but I do not understand how they work, and would rather learn what my code is doing wrong. 整个互联网上有这些代码的例子,但我不明白它们是如何工作的,宁愿知道我的代码做错了什么。

Relevant code snippets. 相关代码片段。 Here is the rest of the code in my program: 这是我程序中的其余代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct Node{
  void *element;
  struct Node *next;
  struct Node *prev;
} Node;

typedef struct List{
  struct Node *first;
  struct Node *last;
} List;

void add_to_front(List *l, void *toAdd)
{
  Node *n = (Node *)calloc(1, sizeof(Node));
  n->element = toAdd;
  n->next = l->first;
  n->prev = NULL;

  if(l->first != NULL)
    {
      l->first->prev = n;
    }
    l->first = n;
}


void add_to_back(List *l, void *toAdd)
{
  Node *n = (Node *)calloc(1, sizeof(Node));
  n->element = toAdd;
  n->next = NULL;
  n->prev = l->last;

  if(l->last != NULL)
    {
      l->last->next = n;
    }
    l->last = n;
}

void remove_from_front(List *l)
{
  Node *head = l->first;

  l->first = l->first->next;

  free(head);
}

int main(int argc, char *argv[])
{
  List *l = calloc(1, sizeof(List));
  l->first = NULL;
  l->last = NULL;

  add_to_front(l, (void *)'a');
  printf("First element: %c\n", l->first->element);
  add_to_back(l, (void *)'b');
  printf("Last element: %c\n", l->last->element);
  remove_from_front(l);
  printf("New first element: %c\n", l->first->element);
  return 0;
}

Debugger output. 调试器输出。 Here is the debugger output I get when I run this code. 这是我运行此代码时得到的调试器输出。

Valgrind: Valgrind的:

==9389== Invalid write of size 4
==9389==    at 0x804852E: remove_from_front (in /home/vagrant/plc/linkedList)
==9389==    by 0x80485D3: main (in /home/vagrant/plc/linkedList)
==9389==  Address 0x8 is not stack'd, malloc'd or (recently) free'd
==9389==
==9389==
==9389== Process terminating with default action of signal 11 (SIGSEGV)
==9389==  Access not within mapped region at address 0x8
==9389==    at 0x804852E: remove_from_front (in /home/vagrant/plc/linkedList)
==9389==    by 0x80485D3: main (in /home/vagrant/plc/linkedList)
==9389==  If you believe this happened as a result of a stack
==9389==  overflow in your program's main thread (unlikely but
==9389==  possible), you can try to increase the size of the
==9389==  main thread stack using the --main-stacksize= flag.
==9389==  The main thread stack size used in this run was 8388608.
==9389==

GDB: GDB:

Starting program: /home/vagrant/plc/linkedList
First element: a
Last element: b

Program received signal SIGSEGV, Segmentation fault.
0x0804852e in remove_from_front ()

The output when I run the executable with no debugger is simply: 我在没有调试器的情况下运行可执行文件时的输出只是:

First element: a
Last element: b
Segmentation fault

I would appreciate any help if possible. 如果可能的话,我将不胜感激。 Thank you! 谢谢!

The problem is that when you add in the front, if it's the first element in the list, you will need to setup the last pointer, let it pointer to the first element as well, that is, when the list have single element, the first and last should point to the same Node. 问题是当你在前面添加时,如果它是列表中的第一个元素,你需要设置最后一个指针,让它指向第一个元素,也就是说,当列表有单个元素时, first和last应该指向同一个Node。

// in add_to_front
if (l->last == NULL) {
    l->last = l->first;
}
// add to back:
if (l->first == NULL) {
    l->first = l->last;
}
// in remove from front, check if the list is empty:
if (l->first == NULL)
    return;

Second problem. 第二个问题。 If removing the last node, clear the last reference 如果删除最后一个节点,请清除最后一个引用

void remove_from_front(List *l)
{
  Node *head = l->first;

  l->first = l->first->next;

  if (!l->first)
  {
    l->last = 0;
  }

  free(head);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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