链表节点消除函数

Linked-list node eliminating function

我只是想消除包含偶数的节点 x % 2 == 0

我写了一个非常简单的函数,但是在我使用它之后,编译器不显示修改后的列表,我不明白为什么。

如果头部包含一个偶数元素,它可以正常工作(我在 main 中这样做),但是当我尝试从内部删除一些东西时,它确实不想工作...

我真的不知道我做错了什么

#include <stdio.h>
#include <stdlib.h>
struct test{
    int val;
    struct test *next;
};

void erase (struct test *x)
{ 
    struct test *t;
    t=x->next;
    x->next=t->next;
    free(t);
    return ;
}

int main ()
{
    
    struct test *head,*p,*q, *aux;
    int n,i;
    
    printf("Number of elements:");
    scanf("%d",&n);
    p=(struct test * )malloc(sizeof(struct test));
    
    printf("First value:");
    scanf("%d",&p->val);
    p->next=NULL;
    head=p;
    for(i=2;i<=n;i++)
    {
        q=(struct test * )malloc(sizeof(struct test));
        printf("Value %d:",i);
        scanf("%d",&q->val);
        q->next=NULL;
        p->next=q;
        p=q;
    }
    
    for(p=head;p!=NULL;p=p->next) {
        printf("%d ",p->val);
    }
    while((head->val)%2==0) {
        aux=head;
        head=head->next;
        free(aux);
    }
    
    for( p=head ; p!=NULL; p = p->next) {
        if((p->next->val)%2==0) {
            erase (p);
        }
    }
    printf("\n");
    for(p=head ;p!=NULL;p=p->next) {
        printf("%d ",p->val);
    }
}


while 循环后

while((head->val)%2==0) {
    aux=head;
    head=head->next;
    free(aux);
}

指针头可以等于NULL。所以下一个 for 循环可以调用未定义的行为。此外,在擦除具有偶数值的节点后,您正在冗余地推进指针 p。

将此替换为循环

for( p=head ; p!=NULL; p = p->next) {
    if((p->next->val)%2==0) {
        erase (p);
    }
}

对于以下代码

if ( head != NULL ) {
    for( p=head ; p->next!=NULL; ) {
       if((p->next->val)%2==0) {
           erase (p);
       }
       else {
           p = p->next;
       } 
   }
}

这里有一个错误:

for( p=head ; p!=NULL; p = p->next) {
    if((p->next->val)%2==0) {
        erase (p);
    }
}

列表中的最后一个元素发生了什么?

p 不是 NULL.

p->nextNULL

p->next->val 将取消引用 NULL 指针。

让我们看看你的函数做了什么:

void erase (struct test *x)
{ 
    struct test *t;
    t=x->next;
    x->next=t->next;
    free(t);
    return ;
}

它获得一个指向您的结构之一的指针 x 并假定它不指向 NULL。

x -> [         ]

那个指向的结构指向另一个结构。

x-> [          ] -> [         ]

该函数创建一个指针,指向它。

x-> [          ] -> [NULL?  ]
t------------------>

t 现在可以指向 NULL,但函数不检查它。

然后它尝试重新指向 x 指向的内容,指向任何未检查的内容指向的内容,这可能会取消引用 NULL。

    [          ] -> [??NULL??  ] ??->?? ????[]????
t------------------>
x ----------------------------?-?-?-?-?-?-?-?-?->

此时您面临取消引用 NULL 的风险。