段故障-C中的链表



我正在C中创建一个基本链表,但当在测试文件中调用我的add-to-back函数时,我遇到了段错误。它似乎有问题,因为列表的头是NULL,但我不明白为什么这是一个问题。当我使用cgdb工具时,它"告诉"我错误发生在以下行:prev->next=新节点。我已经在下面附上了完整的代码,请让我知道我没有看到什么来解决这个问题。

头文件

#ifndef LINKED_LIST_H
#define LINKED_LIST_H
typedef struct Node {
int data;
struct Node *next;
} Node;
Node *create_node(int data);
void free_list(Node *head);
void add_to_front(struct Node **head, int data);
void print_list(struct Node *head);
void reverse_list(struct Node **head);
void add_to_back(Node **head, int data);
#endif // LINKED_LIST_H

.c文件

#include <stdio.h>
#include <stdlib.h>
#include "linked_list.h"
/* returns a new node whose data is set to DATA and next is set to NULL */
Node *create_node(int data) {
struct Node *new_node = malloc(sizeof(struct Node));
if (new_node == NULL) {
perror("Malloc failedn");
}
new_node->data = data;
new_node->next = NULL;
return new_node;
}

/* Frees the list starting at HEAD */
void free_list(Node *head) {
while (head != NULL) {
Node *temp = head->next;
free(head);
head = temp;
}
}
/* Creates a new node whose data is set to DATA and adds it to the front of the
list pointed to by HEAD.
*/
void add_to_front(struct Node **head, int data) {
/* Check if the head is NULL to make sure that we do not dereference a NULL pointer
because that would result in a segfault */
if (head == NULL) return;
struct Node *new_node = create_node(data);
if (*head != NULL) {
/* The list is not empty */
/* The new node's next should point to the head */
new_node->next = *head;
}
/* We must set HEAD using the following line in order to change the original list */
*head = new_node;
/* The following line would not work because it would only change our local copy of HEAD */
/* head = new_node */
}
/* Prints out a linked list starting at HEAD */
void print_list(struct Node *head) {
struct Node *curr;
for (curr = head; curr != NULL; curr = curr->next) {
printf("%d->", curr->data);
}
printf("NULLn");
}
/* Iteratively reverses a linked list whose first node is HEAD */
void reverse_list(struct Node **head) {
if (head == NULL || *head == NULL) {
return;
}
struct Node *curr = *head;
struct Node *next = (*head)->next;
curr->next = NULL;
while (next != NULL) {
struct Node *temp = next->next;
next->next = curr;
curr = next;
next = temp;
}
*head = curr;
}
/* Creates a new node with a data field set to DATA and adds the node
to the back of the list pointed to by HEAD */
void add_to_back(Node **head, int data) {
if (head == NULL || *head == NULL) {
return;
}
Node *new_node = create_node(data);
Node *prev;
for (Node *curr = *head; curr != NULL; curr = curr->next) {
prev = curr;
}
prev->next = new_node;
}

测试文件

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "linked_list.h"
int main(int argc, char **argv) {
printf("Running tests...nn");
Node *head = NULL;
/*********** reverse_list test ***********/
reverse_list(&head);
for (int i = 0; i < 5; ++i) {
add_to_front(&head, i);
reverse_list(&head);
}
int expected_values[] = {3, 1, 0, 2, 4};
Node *curr = head;
for (int i = 0; i < 5; ++i) {
assert(curr->data == expected_values[i]);
curr = curr->next;
}
free_list(head);
printf("Congrats! You have passed the reverse_list test!nn");
/************ add_to_back test ***********/
Node *head_2 = NULL;
add_to_back(&head_2, 15);
add_to_back(&head_2, 12);
add_to_back(&head_2, 18);
int expected_values_2[] = {15, 12, 18};
Node *curr_2 = head_2;
for (int i = 0; i < 3; ++i) {
assert(curr_2->data == expected_values_2[i]);
curr_2 = curr_2->next;
}
free_list(head_2);
printf("Congrats! All of the test cases passed!n");
return 0;
}
函数add_to_back中的if语句
if (head == NULL || *head == NULL) {
return;
}

没有意义,因为它不允许将节点附加到空列表中。

该函数可以定义为例如

void add_to_back( Node **head, int data ) 
{
if ( head == NULL ) return;
Node *new_node = create_node(data);
while ( *head ) head = &( *head )->next;
*head = new_node;
}

或者使用您的方法然后

void add_to_back( Node **head, int data ) 
{
if ( head == NULL ) return;
Node *new_node = create_node(data);
Node *prev = NULL;
for ( Node *curr = *head; curr != NULL; curr = curr->next ) 
{
prev = curr;
}
prev == NULL ? ( *head = new_node ) : ( prev->next = new_node );
}

一般来说,

if ( head == NULL ) return;

也是多余的。如果用户将传递一个空指针,那么函数将具有未定义的行为。

另一方面,函数create_node应按照以下方式编写

Node * create_node( int data ) 
{
struct Node *new_node = malloc(sizeof(struct Node));
if ( new_node != NULL )
{
new_node->data = data;
new_node->next = NULL;
}
return new_node;
}

相应地,例如函数add_to_back可以像一样编写

int add_to_back( Node **head, int data ) 
{
Node *new_node = create_node( data );
int success = new_node != NULL;
if ( success )
{
Node *prev = NULL;
for ( Node *curr = *head; curr != NULL; curr = curr->next ) 
{
prev = curr;
}
prev == NULL ? ( *head = new_node ) : ( prev->next = new_node );
}
return success;
}

问题出在add_to_back((函数中。由于函数if (head == NULL || *head == NULL) { return; }中的第一行,它将继续返回而不执行其余的代码。因此,如果您在三次调用add_to_back函数后打印列表,那么您的列表中只有NULL,这就是您出现分段错误的原因。我做了以下更改,您的代码运行良好`void add_to_back(节点**头,int数据({

Node *new_node = create_node(data);
if (*head == NULL){
*head =  new_node;
return;
}
Node *prev;
for (Node *curr = *head; curr != NULL; curr = curr->next) {
prev = curr;
}
prev->next = new_node;

}`

最新更新