在C中删除链接列表中节点时出现段错误

4nkexdtk  于 2022-12-03  发布在  其他
关注(0)|答案(1)|浏览(170)

上下文:https://stackoverflow.com/a/73725376/15603477
代码按预期工作。但是,有一个函数没有在整个程序中使用:del_node。试图在case开关选项部分使用它,导致分段错误。
我如何删除链接列表尾部的一个。或者在这个上下文中使用del_node
主要变更原件为

case 2:   /* fallthhrough to 3 intentional until something to do */

更改为

case 2:
        del_node(list.tail);
        break;

分段故障原因:在主功能情况下,开关部分:两次插入(选项1)〉〉一次删除(选项2)〉〉一次打印输出(选项3)结果:

StudentID: 0, firstname: 1, lastname: 1 class: 1
, graduates: 1
Segmentation fault (core dumped)

所以它确实删除了节点。
完整代码。

/*
https://stackoverflow.com/questions/65223330/function-to-add-a-node-to-linked-list-not-working-c/65226293#65226293
gcc -Wall -Wextra -O3 -pedantic -Wshadow -Ofast  \
    -Wno-declaration-after-statement \
    -fexcess-precision=standard \
    -Wmissing-prototypes \
    -Wmissing-format-attribute \
    linked_list_3.c && ./a.out
    
valgrind ./a.out

*/
#include "linked_list_3.h"
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#include<limits.h>
#define MAXC    128
void instructions(void)
{
/* align it so it looks like your menu */
  printf( "\nEnter your choice:\n"
          "   1.  to insert an element into the list.\n"
          "   2.  to delete an element from the list.\n"
          "   3.  view list.\n"
          "   4.  to end.\n\n"
          " Your choice: ");
}

/** simple implementation of POSIX strdup() */
char *strdupe(const char *src)
{
    char *dst = NULL;
    size_t len = strlen(src);   /* get length of source */
    if(!(dst = malloc(len+1))){ /* allocate/validate destination */
        perror("malloc-strdupe");
        return NULL;
    }
    return memcpy(dst,src,len+1);
}

/** create node function, allocates and validates the node and
 *  each member of student_t requring allocation and set the member
 *  values to the value provided in the parameters, initializing the 
 *  next/prev pointers NULL. Returns pointer to allocated node on success
 *  NULL otherwise.
 */
student_t *createnode(char *name,char*lastname,char *class, long studentID,int grad_year)
{
    /* allocate for node */
    student_t *node = malloc(sizeof *node);
    if(!node){
        perror("malloc-createnode-dst");
        return NULL;
    }
    node->next = node->prev = NULL;

    if(!(node->name = strdupe(name))){  /*from string name to node */
        return NULL;
    }
    if(!(node->lastname = strdupe(lastname))){  /*from string lastname to node */
        return NULL;
    }
    if(!(node->class = strdupe(class))){    /*from string class to node */
        return NULL;
    }

    /* assign remaining member values */
    node->studentID = studentID;
    node->grad_year =  grad_year;
    return node;         /* return pointer to allocated node */
}

/** must have return type to indicate success/failure of insert.
 *  you cannot just blindly assume allocations succeed. It's not
 *  "if", but "when" an allocation fails.
 *
 *  returns pointer to allocated node on success, NULL on failure.
 * 
 */
student_t *insert(DLL_t *list,char *name,char *lastname
    ,char *class,long studentID,int grad_year)
{
    /* create and validate new node */
    student_t *node = createnode(name,lastname,class,studentID,grad_year);
    if(!node){
        return NULL;
    }
    
    if(!list->head)                  /* if 1st node, node is head/tail */
        list->head = list->tail = node;
    else {
        node->prev = list->tail;    /* set prev to tail */
        list->tail->next = node;     /* add at end, update tail pointer */
        list->tail = node;
    }
    return node;
}

/** print helper for single node */
void prn_node(student_t *node)
{
    printf("StudentID: %ld, firstname: %s, lastname: %s class: %s, graduates: %d\n"
        ,node->studentID,node->name,node->lastname,node->class,node->grad_year);
}

/** print all nodes in list */
void prn_list(DLL_t *list)
{
    if(!list->head) {
        printf("list empty\n");
        return;
    }
    /* loop over each node in list */
    for(student_t *n =list->head; n; n = n->next){
        prn_node(n);
    }
}

/** delete single node helper */
void del_node(student_t *node)
{
    free(node->name);
    free(node->lastname);
    free(node->class);
    free(node);
}

/** delete all nodes in list */
void del_list(DLL_t *list)
{
    student_t *n = list->head;
    while(n)
    {
        student_t *victim = n;
        n = n->next;
        del_node(victim);
    }
    list->head = list->tail = NULL;
    list->maxID = 0;
}

int main(void)  /* argument is void if you pass no arguments */
{
    char buf[MAXC];
    int option;
    DLL_t list = {.head = NULL};

    while(1)
    {
        instructions();
        if(!fgets(buf,MAXC,stdin)){
            printf("user cancelled input\n");
            exit(EXIT_SUCCESS);
        }

        if(sscanf(buf,"%d",&option) != 1){
            fprintf(stderr,"error: invalid integer input\n");
            exit(EXIT_FAILURE);
        }
        switch (option)
        {
        case 1:
            {
                /* temp storage for strings */
                char name[MAXC],lastname[MAXC],class[MAXC];
                int grad_year = 0;
                /* there is no conversion in the string - no need for printf() */
                fputs("enter first name: ",stdout);
                if(!fgets(name,MAXC,stdin)){
                    puts("user cancelled input");
                    exit(EXIT_FAILURE);
                }
                name[strcspn(name,"\n")] = 0;

                fputs("enter  last name: ",stdout);
                if(!fgets(lastname,MAXC,stdin)){
                    puts("user cancelled input");
                    exit(EXIT_FAILURE);
                }
                lastname[strcspn(lastname,"\n")] = 0;

                fputs("enter class name: ",stdout);
                if(!fgets(class,MAXC,stdin)){
                    puts("user cancelled input");
                    exit(EXIT_FAILURE);
                }
                class[strcspn(class,"\n")] = 0;

                fputs("enter grad year: ",stdout);
                if(!fgets(class,MAXC,stdin)){
                    puts("user cancelled input");
                    exit(EXIT_FAILURE);
                }
                if(sscanf(buf,"%d", &grad_year) != 1){
                    fprintf(stderr,"error: invalid int input\n");
                    exit(EXIT_FAILURE);
                }
                /* validate insertion of values into list */
                if(!insert(&list,name,lastname,class,list.maxID,grad_year)){
                    continue;
                }
                list.maxID += 1;
                break;
            }
        case 2:
            del_node(list.tail);
            break;
        case 3:
            prn_list(&list);
            break;
        case 4:
            goto donelooping;
            break;
        
        default:
            printf("invalid choice\n");
            break;
        }
    }
    donelooping:;
    del_list(&list);
    exit(EXIT_SUCCESS);
}
ulmd4ohb

ulmd4ohb1#

你的del_node函数只是一个删除节点的助手,它并不把节点从链表中删除,如果你以后还打算使用链表的话,那么在删除节点之前就需要把节点从链表中删除。

相关问题