简体   繁体   中英

Program crashes when trying to delete last node of a linked list

I am creating a program in which you can and delete a node at any time. However, when I try to delete the last node in the list, the program crashes. Can somebody tell me what I am doing wrong?

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");
}

I am calling the function in main :

int main() {
    //... other part of the program
    delete_node(&head);
}

In the while loop, you do

while(counter != position) {
            counter++;

            if(counter == position - 1)
                curr_node->next = NULL;

            curr_node = curr_node->next;
        }

Let's take the example of a list with 3 nodes:
I'll use (°) to identify the Node pointed by curr_node.

  • first iteration:
    initial status:
    (°)--------------()--------------()
    counter = 0

you only change variables.

  • second iteration:
    initial status:
    ()--------------(°)--------------()
    counter = 1

    Now, the first thing your code do is increment counter . Then counter' value is now 2.
    If statement results True, and now you actually delete the last node:
    ()--------------(°)--------------NULL
    As last operation of second iteration, you do the assignment curr_node = curr_node->next; that results in cur_node = NULL . Finally, you end the second iteration with the following status:
    cur_node = NULL
    counter = 2

    The problem is that you will start another iteration, because the ending condition is counter != position , that is still true. So you have a third iteration:
  • third iteration:
    initial status:
    ()--------------()--------------NULL°
    counter = 2
    Note: curr_node points to NULL.
    In the end of this iteration, you try to perform curr_node = curr_node->next; , that causes the crash because curr_node is actually NULL.

    You can try to solve by changing the while condition in while (counter != position -1)

When counter == position - 1 you set current->next to NULL , but there will be one more iteration of the loop, and in that iteration current will be NULL and so you will run into an exception when you access current->next in that final iteration.

Some things you can do:

  • Introduce a prev_node reference, that follows curr_node one step behind.
  • You don't need to treat the deletion of the tail node as a separate case.
  • You don't need counter as you can decrease the value of position instead.
  • Don't forget to free the memory in the else case as currently you only do that when deleting the head node.
  • Don't forget to decrease the value of node_number when the deletion is successful.

Here is some updated code:

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");
}

NB: It would be better if you would not deal with I/O inside this function, and instead pass the position as a separate argument. Deal with I/O only in the main program code. The function could return a boolean or int indicating whether the node was found and deleted or not. The caller should deal with printing messages.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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