从单链列表中删除元素时非常意外的问题

问题描述 投票:0回答:2
void insertbeg(n*head)
{

    n *x,*q=head;
    q=(n*)malloc(sizeof(n));
    printf("Enter the data to be entered: ");
    scanf("%d",&q->data);
    q->link=NULL;
    if(head==NULL)
    {
        head=q;
    }
    else
    {
        q->link=head;
        head=q;
    }
    x=head;
    while(x!=NULL)
    {
        printf("%d\t",x->data);
        x=x->link;
    }
    printf("\n");
}   

此代码按预期运行,这是该函数,驱动程序将获取实际列表,并一旦完成调用此函数。最后,它将打印输出并带有用户输入的元素,直到开始为止。我有一系列的开关案例,每种情况在开头都调用一个函数,例如insert元素,从end删除等,但是当我说完诸如delete from end的任何操作后再说其他选项时,它将删除最后一个元素并打印在实际列表上而不是修改列表上进行操作后的结果,例如:1 2 3 4是实际列表我选择在开头插入一个元素。在我说7之后,它会打印7 1 2 3 4。之后,我选择从结尾删除元素。打印1 2 3。**但应该打印7 1 2 3 **每当执行操作时,都会在实际列表上而不是在修改后的列表上进行操作,并打印结果。

任何帮助,将不胜感激。Images of the actual driver program added

c linked-list singly-linked-list
2个回答
0
投票

对于初学者,请不要提供对图像的引用。所有相关代码均应键入并出现在问题中。提供可重现该问题的最少说明性程序。

我不希望看到图像是您在问题中所引用的参考,但是您认为“有效”的功能insertbeg已经无效。它处理列表的头节点的副本。所以这条语句

head=q;

不会更改作为参数传递给函数的原始指针。它更改了原始指针的副本。

请注意每个功能都应该思考。如果要输出列表,请再编写一个函数来执行此任务。

此外,该函数还必须获取将作为参数添加到列表中的数据。

最好通过引用将指针传递给函数。

该函数可以通过以下方式查看

int insertbeg( n **head, int data )
{
    n *q = malloc( sizeof( n ) );

    int success = q != NULL;

    if ( success )
    {
        q->data = data;
        q->link = *head;
        *head = q;
    }

    return success;
}

这里是一个演示程序,显示了如何定义将节点附加到列表开头并从其末尾删除节点的功能。

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

typedef struct node
{
    int data;
    struct node *link;
} n;

int insert_in_begin( n **head, int data )
{
    n *q = malloc( sizeof( n ) );

    int success = q != NULL;

    if ( success )
    {
        q->data = data;
        q->link = *head;
        *head = q;
    }

    return success;
}

void delete_from_end( n **head )
{
    if ( *head != NULL )
    {
        while ( ( *head )->link != NULL ) head = &( *head )->link;

        free( *head );

        *head = NULL;
    }
}

void output( n *head )
{
    for ( ; head != NULL; head = head->link )
    {
        printf( "%d -> ", head->data );
    }

    puts( "null" );
}

int main(void) 
{
    enum { N = 10 };

    n *head = NULL;

    for ( int i = 0; i < N; i++ )
    {
        insert_in_begin( &head, i );
    }

    while ( head != NULL )
    {
        output( head );
        delete_from_end( &head );
    }

    output( head );

    return 0;
}

程序输出为

9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> null
9 -> 8 -> 7 -> 6 -> 5 -> null
9 -> 8 -> 7 -> 6 -> null
9 -> 8 -> 7 -> null
9 -> 8 -> null
9 -> null
null

0
投票

我认为问题出在以下几行:

head=q;

虽然您尝试执行的逻辑很可靠,但是这里的问题是您正在更改堆栈中head的值。换句话说,您在此函数中以参数形式收到的是列表中第一个元素的地址。该地址放在堆栈上,您可以在insertbeg函数中使用它。现在,您需要在此处以某种方式告诉正在调用此函数的代码(我认为您在问题中将其称为驱动程序)头地址已更改。我认为最好的方法是将参数从n *更改为n **。这样,您将收到指针变量head的地址,而不仅仅是第一个元素的地址。

总而言之,我建议进行以下更改:

1)将参数从n*head更改为n **addressOfHeadPointer

2)将代码中每次出现的head更改为*addressOfHeadPointer

对我们刚才在这里所做的一些解释:

1)现在,传递第一个元素本身地址的开头的变量(第一个元素的地址)的地址INSTEAD。这样,我们可以将有关第一个元素(头)的新地址的信息传播回调用该函数的代码。

2)由于我们在第1点中所做的事情,我们不再具有包含列表首个元素的地址的head参数。尽管通过取消引用我们的双指针,我们仍然可以获得该地址。像这样*addressOfHeadPointer。使用这个表达式,我们基本上告诉编译器“请给我存储位置addressOfHeadPointer中的数字”。该数字是第一个元素(即标头)的地址。

希望,我能帮上忙。

© www.soinside.com 2019 - 2024. All rights reserved.