尝试删除链表的最后一个节点时程序崩溃
Program crashes when trying to delete last node of a linked list
我正在创建一个程序,您可以在其中随时删除节点。但是,当我尝试删除列表中的最后一个节点时,程序崩溃了。有人可以告诉我我做错了什么吗?
void delete_node(Node **head_ref) {
int position, counter = 0;
Node *curr_node = *head_ref;
if(*head_ref == NULL) {
printf("No nodes to delete!");
return;
}
printf("Enter position between 1 and %d: ", node_number);
scanf("%d", &position);
if(position == 1) {
*head_ref = (*head_ref)->next;
free(curr_node);
} else if(position == node_number) {
while(counter != position) {
counter++;
if(counter == position - 1)
curr_node->next = NULL;
curr_node = curr_node->next;
}
}
printf("\nNode deleted successfully!\n");
if( *head_ref == NULL )
printf("\nLast node deleted!\n");
}
我正在调用 main
中的函数:
int main() {
//... other part of the program
delete_node(&head);
}
在 while 循环中,你做
while(counter != position) {
counter++;
if(counter == position - 1)
curr_node->next = NULL;
curr_node = curr_node->next;
}
让我们以具有 3 个节点的列表为例:
我将使用 (°) 来标识 curr_node 指向的节点。
- 第一次迭代:
初始状态:
(°)----------------()------------()
计数器 = 0
您只需更改变量。
- 第二次迭代:
初始状态:
()------------(°)------------()
计数器 = 1
现在,您的代码做的第一件事是递增 counter
。然后计数器的值现在是 2。
如果语句结果为真,现在你实际上删除了最后一个节点:
()------------(°)------------空
作为第二次迭代的最后一个操作,您执行了导致 cur_node = NULL
的赋值 curr_node = curr_node->next;
。最后,您以以下状态结束第二次迭代:
cur_node = NULL
counter = 2
问题是您将开始另一个迭代,因为结束条件是 counter != position
,这仍然成立。所以你有第三次迭代:
- 第三次迭代:
初始状态:
()------------()-------------NULL°
计数器 = 2
注意:curr_node指向NULL。
在此迭代结束时,您尝试执行 curr_node = curr_node->next;
,这会导致崩溃,因为 curr_node 实际上是 NULL。
您可以尝试通过更改 while 条件来解决
while (counter != position -1)
当counter == position - 1
你将current->next
设置为NULL
时,但是会再循环一次,在那个迭代中current
会是NULL
所以当您在最后一次迭代中访问 current->next
时,您将 运行 进入异常。
您可以做的一些事情:
- 引入一个
prev_node
引用,它在 curr_node
之后落后一步。
- 您不需要将尾节点的删除作为一个单独的案例来处理。
- 您不需要
counter
,因为您可以减少 position
的值。
- 不要忘记在
else
情况下释放内存,因为目前您只在删除头节点时这样做。
- 删除成功后不要忘记减小
node_number
的值
这是一些更新的代码:
void delete_node(Node **head_ref) {
int position;
Node *curr_node = *head_ref;
if(*head_ref == NULL) {
printf("No nodes to delete!");
return;
}
printf("Enter position between 1 and %d: ", node_number);
scanf("%d", &position);
if (position == 1) {
*head_ref = (*head_ref)->next;
} else { // All other positions can be treated in the same way
Node *prev_node = curr_node; // Maintain a separate reference for previous node
curr_node = curr_node->next;
while (curr_node != NULL && position > 2) { // Can use position without counter
prev_node = curr_node;
curr_node = curr_node->next;
position--;
}
if (curr_node == NULL) { // The input position was too great
printf("\nThere is no node at that position!\n");
return;
}
prev_node->next = curr_node->next;
}
free(curr_node);
node_number--; // Don't forget to keep this updated
printf("\nNode deleted successfully!\n");
if (*head_ref == NULL)
printf("\nLast node deleted!\n");
}
注意:最好不要在这个函数中处理 I/O,而是将位置作为单独的参数传递。仅在主程序代码中处理 I/O。该函数可以 return 一个布尔值或整数,指示是否找到并删除了节点。调用方应处理打印消息。
我正在创建一个程序,您可以在其中随时删除节点。但是,当我尝试删除列表中的最后一个节点时,程序崩溃了。有人可以告诉我我做错了什么吗?
void delete_node(Node **head_ref) {
int position, counter = 0;
Node *curr_node = *head_ref;
if(*head_ref == NULL) {
printf("No nodes to delete!");
return;
}
printf("Enter position between 1 and %d: ", node_number);
scanf("%d", &position);
if(position == 1) {
*head_ref = (*head_ref)->next;
free(curr_node);
} else if(position == node_number) {
while(counter != position) {
counter++;
if(counter == position - 1)
curr_node->next = NULL;
curr_node = curr_node->next;
}
}
printf("\nNode deleted successfully!\n");
if( *head_ref == NULL )
printf("\nLast node deleted!\n");
}
我正在调用 main
中的函数:
int main() {
//... other part of the program
delete_node(&head);
}
在 while 循环中,你做
while(counter != position) {
counter++;
if(counter == position - 1)
curr_node->next = NULL;
curr_node = curr_node->next;
}
让我们以具有 3 个节点的列表为例:
我将使用 (°) 来标识 curr_node 指向的节点。
- 第一次迭代:
初始状态:
(°)----------------()------------()
计数器 = 0
您只需更改变量。
- 第二次迭代:
初始状态:
()------------(°)------------()
计数器 = 1
现在,您的代码做的第一件事是递增counter
。然后计数器的值现在是 2。
如果语句结果为真,现在你实际上删除了最后一个节点:
()------------(°)------------空
作为第二次迭代的最后一个操作,您执行了导致cur_node = NULL
的赋值curr_node = curr_node->next;
。最后,您以以下状态结束第二次迭代:
cur_node = NULL
counter = 2
问题是您将开始另一个迭代,因为结束条件是counter != position
,这仍然成立。所以你有第三次迭代: - 第三次迭代:
初始状态:
()------------()-------------NULL°
计数器 = 2
注意:curr_node指向NULL。
在此迭代结束时,您尝试执行curr_node = curr_node->next;
,这会导致崩溃,因为 curr_node 实际上是 NULL。
您可以尝试通过更改 while 条件来解决while (counter != position -1)
当counter == position - 1
你将current->next
设置为NULL
时,但是会再循环一次,在那个迭代中current
会是NULL
所以当您在最后一次迭代中访问 current->next
时,您将 运行 进入异常。
您可以做的一些事情:
- 引入一个
prev_node
引用,它在curr_node
之后落后一步。 - 您不需要将尾节点的删除作为一个单独的案例来处理。
- 您不需要
counter
,因为您可以减少position
的值。 - 不要忘记在
else
情况下释放内存,因为目前您只在删除头节点时这样做。 - 删除成功后不要忘记减小
node_number
的值
这是一些更新的代码:
void delete_node(Node **head_ref) {
int position;
Node *curr_node = *head_ref;
if(*head_ref == NULL) {
printf("No nodes to delete!");
return;
}
printf("Enter position between 1 and %d: ", node_number);
scanf("%d", &position);
if (position == 1) {
*head_ref = (*head_ref)->next;
} else { // All other positions can be treated in the same way
Node *prev_node = curr_node; // Maintain a separate reference for previous node
curr_node = curr_node->next;
while (curr_node != NULL && position > 2) { // Can use position without counter
prev_node = curr_node;
curr_node = curr_node->next;
position--;
}
if (curr_node == NULL) { // The input position was too great
printf("\nThere is no node at that position!\n");
return;
}
prev_node->next = curr_node->next;
}
free(curr_node);
node_number--; // Don't forget to keep this updated
printf("\nNode deleted successfully!\n");
if (*head_ref == NULL)
printf("\nLast node deleted!\n");
}
注意:最好不要在这个函数中处理 I/O,而是将位置作为单独的参数传递。仅在主程序代码中处理 I/O。该函数可以 return 一个布尔值或整数,指示是否找到并删除了节点。调用方应处理打印消息。