我正在为双链表研究一种删除方法,在该方法中,我尝试在将一些节点添加到我的列表后删除它们。下面我提供了一些最小可重现的代码。
当我运行此代码时,我收到错误Segmentation Fault: 11
。我知道我正在尝试删除同一个节点两次,但这只会导致我的代码出错,并显示Invalid commandn
消息,但是当发生这种情况时,我的整个程序都会停止并且我会收到Segmentation Fault: 11
。我相信这与下面delete
方法中的(*current)->next->prev = (*current)->prev;
有关。
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
typedef struct NodeStruct Node;
//struct for each office item
struct NodeStruct {
int id;
struct NodeStruct *next;
struct NodeStruct *prev; //Create doubly linked list node
};
/** Structure for the whole list, including head and tail pointers. */
typedef struct {
/** Pointer to the first node on the list (or NULL ). */
Node *head;
Node *last;
} List;
List *list;
List *makeList();
void insert(int idInsert, List *list);
static void *addRecord(List *list, int newID);
static void printReverse(List *list);
void delete(int key, List *list);
bool search(List *list, int x);
int main(void) {
//Create an empty list for you to start.
list = (List *)makeList();
addRecord(list, 1);
addRecord(list, 2);
addRecord(list, 3);
addRecord(list, 4);
addRecord(list, 4);
addRecord(list, 7);
insert(15, list);
delete(7, list);
delete(1, list);
delete(4, list);
delete(2, list);
delete(5, list);
delete(2, list);
printReverse(list);
}
List *makeList()
{
List *list = (List *) malloc( sizeof( List ) );
list->head = NULL;
list->last = NULL;
return list;
}
void insert(int idInsert, List *list)
{
//Insert the record based on the ID if no duplicates exist
//Special case: insert at front if idInsert is less than the ID of the current head
if (idInsert < list->head->id) {
//Make the node with idInsert the first node
Node *new = malloc(sizeof(Node)); //Allocate memory for the new node
list->head->prev = new;
new->prev = NULL;
//Add in data
new->id = idInsert;
new->next = list->head;
list->head = new;
// if the new node is the last one
} else if (idInsert > list->last->id) {
addRecord(list, idInsert);
printf("RECORD INSERTED: %dn", idInsert);
return;
} else { //Locate the node before the point of insertion
//Allocate memory for the node
Node *new = malloc(sizeof(Node));
//Add in data
new->id = idInsert;
Node *current = list->head;
while (current->next != NULL && current->next->id < new->id) {
current = current->next;
}
new->next = current->next;
if (current->next != NULL) {
new->next->prev = new;
}
current->next = new;
new->prev = current;
}
//Print this message if successful
printf("RECORD INSERTED: %dn", idInsert);
}
static void *addRecord(List *list, int newID)
{
//Allocate memory for the node
Node *new = malloc(sizeof(Node));
//Add in data
new->id = newID;
new->prev = list->last;
new->next = NULL;
list->last = new;
// if list is empty
if(!list->head)
{
list->head = new;
return EXIT_SUCCESS;
}
Node **next_p = &list->head;
while (*next_p) {
next_p = &(*next_p)->next;
}
*next_p = new;
return EXIT_SUCCESS;
}
static void printReverse(List *list) {
Node **tail = &list->last;
printf("LIST IN REVERSE ORDER:n");
//Traversing until tail end of linked list
while (*tail) {
printf("Item ID: %dn", (*tail)->id);
tail = &(*tail)->prev;
}
}
void delete(int key, List *list)
{
//Check if ID exists in list
if (search(list, key) == false) {
printf("Invalid commandn");
} else {
printf("RECORD DELETED: %dn", key);
}
//If linked list is empty (base case)
Node **current = &list->head;
//current points to the pointer pointing towards the current node
//For the first iteration, it is the address of the head pointer
while (*current && key != (*current)->id) {
current = &(*current)->next;
}
(*current)->next->prev = (*current)->prev;
if (*current) {
Node *temp = *current;
*current = (*current)->next;
free(temp);
}
}
bool search(List *list, int x)
{
Node *current = list->head; //Initialize current node
while (current != NULL) {
if (current->id == x) {
return true;
}
current = current->next;
}
return false;
}
我想要的结果是:
RECORD INSERTED: 15
RECORD DELETED: 7
RECORD DELETED: 1
RECORD DELETED: 4
RECORD DELETED: 2
RECORD DELETED: 5
Invalid command
LIST IN REVERSE ORDER:
Item ID: 15
Item ID: 3
而不是分段错误。如何改进删除方法中的代码,以免收到此错误,为什么当前会出现此错误?
打印出Invalid Command
后,你的代码是做什么的? 它继续在函数内执行,最终到达(*current)->next->prev = (*current)->prev;
行,这将导致段错误,因为*current
将为 NULL。
这暴露了三个问题。 首先,您有效地搜索了两次key
:一次是查看它是否在列表中,然后第二次是找到列表中该节点所在的位置,以便可以将其删除。 这些应该组合在一起,因此只需要进行一次搜索。 执行此操作的一种方法是find
返回适当的指针,以便您可以找到并删除节点。 另一种方法是手动进行搜索(不调用find
),如果找不到key
,则报告错误。
第二个问题是打印Invalid Command
后缺少return
,尽管实现前面的建议可以避免此问题。
第三个问题是,对(*current)->next->prev
的赋值应在以下if (*current)
范围内,以避免取消引用空指针。