C 链表函数的几个问题

C 链表函数的几个问题,c,recursion,struct,C,Recursion,Struct,我尝试为链表创建几个函数。这些都是,但是我对函数delete\u all和delete有问题 delete\u All需要删除具有给定值的所有元素,并且delete只需首先删除 我找不到的第一个错误是free()(在代码中标记为“HERE!!!”),当我们放入链表的head,同时在需要删除的下一个元素值中,在delete\All中也会出现无休止的程序工作 例如,(1,1,2,3,4,)无法删除第一对“1”delete和其他一些函数不能使用free函数 #include <stdlib.h&

我尝试为链表创建几个函数。这些都是,但是我对函数
delete\u all
delete
有问题

delete\u All
需要删除具有给定值的所有元素,并且
delete
只需首先删除


我找不到的第一个错误是
free()
(在代码中标记为“HERE!!!”),当我们放入链表的
head
,同时在需要删除的下一个元素值中,在
delete\All
中也会出现无休止的程序工作

例如,(1,1,2,3,4,)无法删除第一对“1”
delete
和其他一些函数不能使用
free
函数

#include <stdlib.h>
#include <stdio.h>

struct uzel {
    int n;
    struct uzel *next;
};

struct uzel *
initializef(struct uzel *head)
{
    static int c = 0;
    int a;

    printf("uzel[%d] = ", c);
    scanf("%d", &a);
    if (a == 0) {
        head->next = NULL;
    }
    else {
        c++;
        head->n = a;
        head->next = malloc(sizeof(struct uzel));
        initializef(head->next);
    }
    return head;
}

void
gprint(struct uzel *head)
{
    printf("(");
    while (head->next != NULL) {
        printf("%d ", head->n);
        head = head->next;
    }
    printf(")\n");
}

struct uzel *
delete(struct uzel *head, int val)
{
    if (head->n == val) {
        struct uzel *newhead = head;

        newhead = head->next;
        struct uzel *del = head;

        // free(del);//HERE!!!!!!!!!
        return newhead;
    }
    struct uzel *right = head;
    struct uzel *left = right;

    while (left->next) {
        right = left->next;
        if (right->next != NULL) {
            if (right->n == val) {
                struct uzel *del = right;

                left->next = right->next;
                free(del);
            }
        }                               // but here is ok!!!
        left = left->next;
    }
    return head;
}

struct uzel *
delete_all(struct uzel *head, int val)
{
    struct uzel *newhead = head;

    while (newhead->n == val) {
        newhead = head->next;
        // struct uzel* del=head;//here!!!!!!!!!!!!!!
        // free(del);
        if ((newhead->n) == NULL) {
            printf("No more elements to work with,ERROR");
            return 0;
        }
    }
    struct uzel *right = newhead;
    struct uzel *left = newhead;

    while (left->next) {
        right = right->next;
        if (right->n == val) {
            struct uzel *tmp = right;

            left->next = right->next;
            free(tmp);
        }
        else {
            left = left->next;
        }
    }
    return newhead;
}

void
addAfter(int info, int after_what, struct uzel *head)
{
    struct uzel *left = head;
    struct uzel *right = head;

    while ((left->n) != after_what) {
        right = right->next;
        left = left->next;
    }
    right = right->next;
    struct uzel *newelem = malloc(sizeof(struct uzel));

    newelem->n = info;
    newelem->next = right;
    left->next = newelem;
}

void
addAfterALL(int info, int after_what, struct uzel *head)
{
    struct uzel *left = head;
    struct uzel *right = head;

    while ((right->next)) {
        while (((left->n) != after_what)) {
            right = right->next;
            left = left->next;
        }
        right = right->next;
        struct uzel *newelem = malloc(sizeof(struct uzel));

        newelem->n = info;
        newelem->next = right;
        left->next = newelem;
    }
}

int
main()
{
    int a, b;
    struct uzel head2;
    struct uzel *mainhead1 = initializef(&head2);

    gprint(mainhead1);
    printf("Enter a number to delete: ");
    scanf("%d", &a);
    printf("Delete all %d ? If yes enter 2 if no enter 1: ", a);
    scanf("%d", &b);
    if (b == 2) {
        struct uzel *mainhead = delete_all(mainhead1, a);

        gprint(mainhead);
    }
    else {
        struct uzel *mainhead = delete(mainhead1, a);

        gprint(mainhead);
    }
    printf("Enter after what number u want to insert smth: ");
    int r;

    scanf("%d", &r);
    printf("Enter what number u want to insert: ");
    int u;

    scanf("%d", &u);
    printf("After all numbers %d ? If yes enter 1 If no enter 2:", r);
    int g;

    scanf("%d", &g);
    if (g == 2) {
        addAfter(u, r, mainhead1);
        gprint(mainhead1);
    }
    if (g == 1) {
        addAfterALL(u, r, mainhead1);
        gprint(mainhead1);
    }
}
#包括
#包括
乌泽尔结构{
int n;
结构uzel*下一步;
};
乌泽尔结构*
initializef(结构uzel*头部)
{
静态int c=0;
INTA;
printf(“uzel[%d]=”,c);
scanf(“%d”和“&a”);
如果(a==0){
head->next=NULL;
}
否则{
C++;
头部->n=a;
head->next=malloc(sizeof(struct-uzel));
初始化EF(头部->下一步);
}
回流头;
}
无效的
gprint(结构uzel*头)
{
printf(“(”);
while(head->next!=NULL){
printf(“%d”,头部->n);
头部=头部->下一步;
}
printf(“)\n”);
}
乌泽尔结构*
删除(结构uzel*头,int val)
{
如果(head->n==val){
结构uzel*newhead=head;
newhead=head->next;
结构uzel*del=头部;
//免费(del);//这里!!!!!!!!!
返回newhead;
}
结构uzel*右=头部;
结构uzel*左=右;
while(左->下一步){
右=左->下一步;
如果(右->下一步!=NULL){
如果(右->n==val){
结构uzel*del=右侧;
左->下一步=右->下一步;
免费(del);
}
}//但这里没问题!!!
左=左->下一步;
}
回流头;
}
乌泽尔结构*
全部删除(结构uzel*头,int val)
{
结构uzel*newhead=head;
while(newhead->n==val){
newhead=head->next;
//struct-uzel*del=head;//在这里!!!!!!!!!!!!!!
//免费(del);
如果((newhead->n)==NULL){
printf(“无需处理的元素,错误”);
返回0;
}
}
struct uzel*right=newhead;
结构uzel*左=新头;
while(左->下一步){
右=右->下一步;
如果(右->n==val){
结构uzel*tmp=右侧;
左->下一步=右->下一步;
免费(tmp);
}
否则{
左=左->下一步;
}
}
返回newhead;
}
无效的
addAfter(int-info,int-after\u-what,struct-uzel*head)
{
结构uzel*左=头部;
结构uzel*右=头部;
while((左->n)!=在什么之后){
右=右->下一步;
左=左->下一步;
}
右=右->下一步;
struct uzel*newelem=malloc(sizeof(struct uzel));
newelem->n=info;
newelem->next=右;
左->下一步=newelem;
}
无效的
addAfterALL(int-info,int-after\u-what,struct-uzel*head)
{
结构uzel*左=头部;
结构uzel*右=头部;
while((右->下一步)){
而((左->n)!=在什么之后){
右=右->下一步;
左=左->下一步;
}
右=右->下一步;
struct uzel*newelem=malloc(sizeof(struct uzel));
newelem->n=info;
newelem->next=右;
左->下一步=newelem;
}
}
int
main()
{
INTA,b;
结构uzel头2;
struct uzel*mainhead1=initializef(&head2);
gprint(mainhead1);
printf(“输入要删除的数字:”);
scanf(“%d”和“&a”);
printf(“删除所有%d?如果是,则输入2;如果否,则输入1:”,a);
scanf(“%d”和“b”);
如果(b==2){
struct uzel*mainhead=delete_all(mainhead1,a);
gprint(主机头);
}
否则{
struct uzel*mainhead=delete(mainhead1,a);
gprint(主机头);
}
printf(“在您要插入的数字后面输入smth:”);
INTR;
scanf(“%d”、&r);
printf(“输入要插入的数字:”);
国际大学;
scanf(“%d”和“&u”);
printf(“在所有数字%d之后?如果是,则输入1;如果否,则输入2:”,r);
int g;
scanf(“%d”和“&g”);
如果(g==2){
addAfter(u、r、mainhead1);
gprint(mainhead1);
}
如果(g==1){
添加(u、r、主标题1);
gprint(mainhead1);
}
}

删除
和删除所有
的代码非常相似,因此可以将其移动到通用功能

#include <stdlib.h>
#include <stdio.h>

struct uzel {
    int n;
    struct uzel *next;
};

struct uzel *
initializef(struct uzel *head)
{
    static int c = 0;
    int a;

    printf("uzel[%d] = ", c);
    scanf("%d", &a);
    if (a == 0) {
        head->next = NULL;
    }
    else {
        c++;
        head->n = a;
        head->next = malloc(sizeof(struct uzel));
        initializef(head->next);
    }
    return head;
}

void
gprint(struct uzel *head)
{
    printf("(");
    while (head->next != NULL) {
        printf("%d ", head->n);
        head = head->next;
    }
    printf(")\n");
}

struct uzel *
delete(struct uzel *head, int val)
{
    if (head->n == val) {
        struct uzel *newhead = head;

        newhead = head->next;
        struct uzel *del = head;

        // free(del);//HERE!!!!!!!!!
        return newhead;
    }
    struct uzel *right = head;
    struct uzel *left = right;

    while (left->next) {
        right = left->next;
        if (right->next != NULL) {
            if (right->n == val) {
                struct uzel *del = right;

                left->next = right->next;
                free(del);
            }
        }                               // but here is ok!!!
        left = left->next;
    }
    return head;
}

struct uzel *
delete_all(struct uzel *head, int val)
{
    struct uzel *newhead = head;

    while (newhead->n == val) {
        newhead = head->next;
        // struct uzel* del=head;//here!!!!!!!!!!!!!!
        // free(del);
        if ((newhead->n) == NULL) {
            printf("No more elements to work with,ERROR");
            return 0;
        }
    }
    struct uzel *right = newhead;
    struct uzel *left = newhead;

    while (left->next) {
        right = right->next;
        if (right->n == val) {
            struct uzel *tmp = right;

            left->next = right->next;
            free(tmp);
        }
        else {
            left = left->next;
        }
    }
    return newhead;
}

void
addAfter(int info, int after_what, struct uzel *head)
{
    struct uzel *left = head;
    struct uzel *right = head;

    while ((left->n) != after_what) {
        right = right->next;
        left = left->next;
    }
    right = right->next;
    struct uzel *newelem = malloc(sizeof(struct uzel));

    newelem->n = info;
    newelem->next = right;
    left->next = newelem;
}

void
addAfterALL(int info, int after_what, struct uzel *head)
{
    struct uzel *left = head;
    struct uzel *right = head;

    while ((right->next)) {
        while (((left->n) != after_what)) {
            right = right->next;
            left = left->next;
        }
        right = right->next;
        struct uzel *newelem = malloc(sizeof(struct uzel));

        newelem->n = info;
        newelem->next = right;
        left->next = newelem;
    }
}

int
main()
{
    int a, b;
    struct uzel head2;
    struct uzel *mainhead1 = initializef(&head2);

    gprint(mainhead1);
    printf("Enter a number to delete: ");
    scanf("%d", &a);
    printf("Delete all %d ? If yes enter 2 if no enter 1: ", a);
    scanf("%d", &b);
    if (b == 2) {
        struct uzel *mainhead = delete_all(mainhead1, a);

        gprint(mainhead);
    }
    else {
        struct uzel *mainhead = delete(mainhead1, a);

        gprint(mainhead);
    }
    printf("Enter after what number u want to insert smth: ");
    int r;

    scanf("%d", &r);
    printf("Enter what number u want to insert: ");
    int u;

    scanf("%d", &u);
    printf("After all numbers %d ? If yes enter 1 If no enter 2:", r);
    int g;

    scanf("%d", &g);
    if (g == 2) {
        addAfter(u, r, mainhead1);
        gprint(mainhead1);
    }
    if (g == 1) {
        addAfterALL(u, r, mainhead1);
        gprint(mainhead1);
    }
}
下面是一个重构版本(带有一些注释),它简化了删除代码,并使其适用于这两种情况

注意使用额外的
next
变量来防止“空闲后使用”[这可能是调用
free
]时出现问题的根源]

#include <stdlib.h>
#include <stdio.h>

struct uzel {
    int n;
    struct uzel *next;
};

struct uzel *
initializef(struct uzel *head)
{
    static int c = 0;
    int a;

    printf("uzel[%d] = ", c);
    scanf("%d", &a);
    if (a == 0) {
        head->next = NULL;
    }
    else {
        c++;
        head->n = a;
        head->next = malloc(sizeof(struct uzel));
        initializef(head->next);
    }
    return head;
}

void
gprint(struct uzel *head)
{
    printf("(");
    while (head->next != NULL) {
        printf("%d ", head->n);
        head = head->next;
    }
    printf(")\n");
}

struct uzel *
delete_common(struct uzel *head, int val, int allflg)
{
    struct uzel *cur;
    struct uzel *prev;
    struct uzel *next;

    prev = NULL;
    for (cur = head;  cur != NULL;  cur = next) {
        next = cur->next;

        // wait for match
        if (cur->n != val) {
            prev = cur;
            continue;
        }

        // remove from middle/end of list
        if (prev != NULL)
            prev->next = next;

        // remove from head of list
        else
            head = next;

        // release the storage for the node we're deleting
        free(cur);

        // stop if we're only deleting the first match
        if (! allflg)
            break;
    }

    return head;
}

struct uzel *
delete(struct uzel *head, int val)
{

    head = delete_common(head,val,0);

    return head;
}

struct uzel *
delete_all(struct uzel *head, int val)
{

    head = delete_common(head,val,1);

    return head;
}

void
addAfter(int info, int after_what, struct uzel *head)
{
    struct uzel *left = head;
    struct uzel *right = head;

    while ((left->n) != after_what) {
        right = right->next;
        left = left->next;
    }
    right = right->next;
    struct uzel *newelem = malloc(sizeof(struct uzel));

    newelem->n = info;
    newelem->next = right;
    left->next = newelem;
}

void
addAfterALL(int info, int after_what, struct uzel *head)
{
    struct uzel *left = head;
    struct uzel *right = head;

    while ((right->next)) {
        while (((left->n) != after_what)) {
            right = right->next;
            left = left->next;
        }
        right = right->next;
        struct uzel *newelem = malloc(sizeof(struct uzel));

        newelem->n = info;
        newelem->next = right;
        left->next = newelem;
    }
}

int
main()
{
    int a, b;
    struct uzel head2;
    struct uzel *mainhead1 = initializef(&head2);

    gprint(mainhead1);
    printf("Enter a number to delete: ");
    scanf("%d", &a);
    printf("Delete all %d ? If yes enter 2 if no enter 1: ", a);
    scanf("%d", &b);
    if (b == 2) {
        struct uzel *mainhead = delete_all(mainhead1, a);

        gprint(mainhead);
    }
    else {
        struct uzel *mainhead = delete(mainhead1, a);

        gprint(mainhead);
    }
    printf("Enter after what number u want to insert smth: ");
    int r;

    scanf("%d", &r);
    printf("Enter what number u want to insert: ");
    int u;

    scanf("%d", &u);
    printf("After all numbers %d ? If yes enter 1 If no enter 2:", r);
    int g;

    scanf("%d", &g);
    if (g == 2) {
        addAfter(u, r, mainhead1);
        gprint(mainhead1);
    }
    if (g == 1) {
        addAfterALL(u, r, mainhead1);
        gprint(mainhead1);
    }
}
制作:

1 1 2 3 4 5 9 6 7
而不是:

1 1 2 3 4 5 9 5 6 7
同样,两个
addAfter
功能可以组合和简化

关于使用
列表
结构的一些附加想法

当我们传递列表指针时,调用者不必担心被调用者是否需要调整列表的标题。被调用的函数就是这样做的

在原始代码中,
delete*
函数传回[可能]修改的
addAfter*
函数[由于其性质]无法更改列表的标题,因此它们不必返回更新后的标题值。在这两种情况下,这些函数的调用方(即
main
)必须“知道”这一点

如果我们在
addAfter*
中添加了一组类似的函数,这些函数在
info
值之前插入(例如
insertBefore*
),则它们可能必须更新头部。同样,打电话的人必须知道这一点

因此,使用
struct list
实际上简化了大多数函数的代码,并允许它们具有更统一的
#include <stdlib.h>
#include <stdio.h>

struct uzel {
    int n;
    struct uzel *next;
};

struct list {
    struct uzel *head;
};

void
initializef(struct list *list)
{
    int c = 0;
    int a;
    struct uzel *newelem;
    struct uzel *prev;

    prev = NULL;
    while (1) {
        printf("uzel[%d] = ", c);

        scanf("%d", &a);

        if (a == 0)
            break;

        newelem = malloc(sizeof(*newelem));
        newelem->n = a;
        newelem->next = NULL;

        if (prev != NULL)
            prev->next = newelem;
        else
            list->head = newelem;

        prev = newelem;

        ++c;
    }
}

void
gprint(struct list *list)
{
    struct uzel *cur;

    printf("(");

    for (cur = list->head;  cur != NULL;  cur = cur->next)
        printf("%d ",cur->n);

    printf(")\n");
}

void
delete_common(struct list *list, int val, int allflg)
{
    struct uzel *cur;
    struct uzel *prev;
    struct uzel *next;

    prev = NULL;
    for (cur = list->head;  cur != NULL;  cur = next) {
        next = cur->next;

        // wait for match
        if (cur->n != val) {
            prev = cur;
            continue;
        }

        // remove from middle/end of list
        if (prev != NULL)
            prev->next = next;

        // remove from head of list
        else
            list->head = next;

        // release the storage for the node we're deleting
        free(cur);

        // stop if we're only deleting the first match
        if (! allflg)
            break;
    }
}

void
delete(struct list *list, int val)
{

    delete_common(list,val,0);
}

void
delete_all(struct list *list, int val)
{

    delete_common(list,val,1);
}

void
addAfter_common(struct list *list, int info, int after_what, int allflg)
{
    struct uzel *cur;
    struct uzel *newelem;

    for (cur = list->head;  cur != NULL;  cur = cur->next) {
        // wait for a match
        if (cur->n != after_what)
            continue;

        // get new element to add
        newelem = malloc(sizeof(*newelem));
        newelem->n = info;

        // insert new element after the match
        newelem->next = cur->next;
        cur->next = newelem;

        // ensure that we don't infinitely add elements if the element value
        // we're adding matches the value(s) we're searching for
        // (e.g.) if info and after_what are the same
        cur = newelem;

        // stop unless adding after _all_ matches
        if (! allflg)
            break;
    }
}

void
addAfter(struct list *list, int info, int after_what)
{

    addAfter_common(list,info,after_what,0);
}

void
addAfterALL(struct list *list, int info, int after_what)
{

    addAfter_common(list,info,after_what,1);
}

int
main(void)
{
    int a, b;
    struct list listx = { .head = NULL };
    struct list *list = &listx;

    initializef(list);
    gprint(list);

    printf("Enter a number to delete: ");
    scanf("%d", &a);

    printf("Delete all %d ? If yes enter 2 if no enter 1: ", a);
    scanf("%d", &b);
    if (b == 2) {
        delete_all(list, a);
        gprint(list);
    }
    else {
        delete(list, a);
        gprint(list);
    }

    printf("Enter after what number you want to insert something: ");
    int r;
    scanf("%d", &r);

    printf("Enter what number you want to insert: ");
    int u;
    scanf("%d", &u);

    printf("After all numbers %d ? If yes enter 1 If no enter 2:", r);
    int g;
    scanf("%d", &g);

    if (g == 2) {
        addAfter(list, u, r);
        gprint(list);
    }
    if (g == 1) {
        addAfterALL(list, u, r);
        gprint(list);
    }

    return 0;
}