【问题标题】:Creating a linked list in C, getting segmentation fault在C中创建一个链表,得到分段错误
【发布时间】:2019-11-07 19:29:24
【问题描述】:

我需要创建一个节点链表,这样主函数才能工作;我无法更改主要功能中的任何内容。我是 C 的新手,所以我可能会犯一两个简单的错误,当我尝试运行我的代码时遇到了分段错误。我错过了什么明显的东西吗?

分段错误发生在标记线上

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

typedef struct Node{
    char *value;
    struct Node *next;
}Node;
typedef struct Node** List;

Node *new_node(char *input);
void delete_node(Node *input);
void push(List list, char *value);
List new_list();

Node *new_node(char *input) {
  Node *new;
  new = malloc(sizeof(Node));
  new->value = input;
  return new;
}

void delete_node(Node *input) {
  free(input);
}

void push(List head, char *input) {
  if (*head == NULL) {  
    *head = new_node(input);
  }
  else {
    Node *new = new_node(input);
    while ((*head)->next != NULL) {
      *head = (*head)->next;
    }
    (*head)->next = new;    
  } 
}

List new_list() {
  List list = malloc(sizeof(List));
  *list = NULL;
  return list;
}

int main( void ) {
  List list = new_list();
  push(list, "First!\n");
  push(list, "Second!\n");
  push(list, "Third!\n");
  push(list, "Fourth!");

  printf("%s", (*list)->value);
  printf("%s", (*list)->next->value);
  printf("%s", (*list)->next->next->value);       //Segmentation fault
  printf("%s", (*list)->next->next->next->value);

  return 0;
}

当我用 gdb 运行它时,我得到了消息:

Third!                                                                                                               

Program received signal SIGSEGV, Segmentation fault.                                                                 
0x0000000000400752 in main () at main.c:54                                                                           
54        printf("%s", (*list)->next->next->value);

【问题讨论】:

  • 哎哟! typedef struct Node** List; 你会想要评论:Is it a good idea to typedef pointers?。我不敢相信你不能改变这一点。当您将指针隐藏在 typedef 后面时,实际了解正在发生的事情变得非常困难。

标签: c linked-list


【解决方案1】:

当您创建一个新节点时,您永远不会设置新创建节点的next 成员。这使它未初始化,导致当您取消引用指针时出现未定义的行为。

修复很简单。添加

new->next = NULL;

在您分配value 后,进入您的new_node 函数。

【讨论】:

  • 感谢您的帮助,但问题似乎仍然存在。我收到了相同的错误消息,但地址不同。
  • @AskerOfQuestions 这是一个不同的问题。提示:当你推东西时,你在用“头”做什么?使用你的调试器看看里面到底发生了什么。
  • 我查看了调试器,但不知道如何解决问题。这些值似乎只设置了第一个和第二个值,然后它们被第三个和第四个覆盖,因为 *head 的值正在更改为 *head->next。有没有解决这个问题的好方法,因为我似乎无法解决它?
  • @AskerOfQuestions 不要在push 中更改*head,除非是分配第一个节点。请改用局部变量。
【解决方案2】:

链表可以有单指针或双指针。单链表有一个指向下一个元素的指针,双链表有一个指向下一个元素和前一个元素的指针。您选择了一个单链表。

添加到列表末尾的函数必须在每次追加到列表操作时遍历整个列表。这意味着添加到列表是一个 O(n) 复杂度操作。链表的主要好处是 O(1) 的添加和删除操作,当实现该功能时。

将列表声明为指向(列表的)头和(列表的)尾的指针,

typedef struct {
    Node* head;
    Node* tail;
} List;

而不是将列表声明为指向节点的指针,

typedef struct Node** List;

现在,添加到列表和从列表中删除的复杂性是 O(1)(恒定)时间操作...

//enqueue to tail of list (not push)
void enqueue(List* list, char *input) {
  if( !list ) return; //no list
  Node* new = new_node(input); //new node
  if( NULL == list->head ) { //list empty
    list->head = new; //add at tail, tail equals head
  }
  else {
    list->tail->next = new; //list not empty, add at tail
  }
  list->tail = new;
}

//dequeue from head of list
Node* dequeue(List* list) {
    if( !list ) return NULL; //no list
    if( NULL == list->head ) return NULL; //list empty
    Node* node = list->head; //node at head of list
    list->head = list->head->next; //remove from list
    if( NULL == list->head ) list->tail = NULL; //empty now
    //oh, should also: node->next = NULL;
    return node;
}

而且,正如其他人所说,您应该初始化“构造函数”中的所有指针,

Node *new_node(char *input) {
  Node *new;
  if( ! (new = malloc(sizeof(Node))) ) return NULL;
  //new = calloc(sizeof(Node)); //calloc fills allocated memory with zero bytes
  //initialize all values in Node structure
  new->value = input;
  new->next = NULL; //either use calloc or init the individual elements
  return new;
}

【讨论】:

    猜你喜欢
    • 2020-08-14
    • 2013-06-29
    • 2018-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多