【问题标题】:A very unexpected problem in deleting an element from singly linked lists从单链表中删除元素的一个非常意外的问题
【发布时间】:2020-03-09 13:11:43
【问题描述】:
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");
}   

此代码按预期运行,这是函数,驱动程序接收实际列表并在完成后调用此函数。最后它打印输出,并在开头输入用户输入的元素,一切都很好,直到这里。我有一系列开关案例,其中每个案例在开头调用插入元素、从结尾删除等函数,但是当我在从结尾删除等任何操作后说出任何其他选项时,它会删除最后一个元素并打印在实际操作而不是在修改后的列表上操作后的结果,例如: 1 2 3 4 是实际列表 我选择在开头插入一个元素。 在我插入说 7 后,它会打印 7 1 2 3 4。 之后我选择从末尾删除一个元素。 它打印 1 2 3。 ** 而是应该打印 7 1 2 3 ** 每次执行操作时都会发生这种情况,操作是在实际列表上而不是在修改后的列表上并打印结果。

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

【问题讨论】:

  • n *head 而不是 n*head 可能是错字?
  • @Gaming DEITY 请勿提供图片参考。在您的问题中提供了相关代码。否则你的问题将被否决。
  • 糟糕,您给我们展示了一个工作代码,说另一部分代码不起作用,但未能显示有问题的删除代码。作为新用户,您应该(再次)阅读并思考其他人在 [mvce] 中需要什么才能重现问题。在这里,我们需要一个可编译的示例,其中的输入显示问题。
  • @SergeBallesta 显示的函数也是无效的。:)
  • @VladfromMoscow:我必须承认,当他们说 代码按预期运行 并且没有对其进行测试时,我盲目地信任 OP。但是我真的坚持minimal reproducible example,没有它就不会测试。

标签: c linked-list singly-linked-list


【解决方案1】:

对于初学者,永远不要提供对图像的引用。所有相关代码都应输入并出现在问题中。提供重现问题的最小演示程序。

我不希望看到您在问题中引用的图像,但您认为“有效”的函数 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

【讨论】:

    【解决方案2】:

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

    head=q;
    

    虽然您尝试做的事情的逻辑是可靠的,但这里的问题是您正在更改堆栈中 head 的值。换句话说,您在此函数中作为参数收到的是列表第一个元素的地址。该地址被放入堆栈,您可以在 insertbeg 函数中使用它。

    现在,您需要在这里做的是以某种方式告诉调用此函数的代码(我认为您在问题中将其称为驱动程序)头部已更改。我认为最好的方法是将参数从 n* 更改为 n**。

    这样您将收到指针头的地址,而不仅仅是它所指向的地址(即第一个元素的地址)。

    综上所述,我建议进行以下更改:

    1) 将参数n*head改为n **addressOfHead

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

    稍微解释一下我们刚刚在那里做了什么:

    1) 我们现在传递保存第一个元素地址的变量的地址而不是第一个元素本身的地址。这样我们就可以将有关第一个元素的新地址的信息传播回调用该函数的代码。

    2) 由于我们在第 1 点中所做的,我们不再有包含列表第一个元素的地址的 head 参数。我们仍然可以通过取消引用我们拥有的双指针来获得该地址。喜欢这个*addressOfHead。通过这个表达式,我们基本上告诉编译器“请给我内存位置 addressOfHead 中的数字”。该数字是第一个元素的地址(即头部)。

    希望,我能帮上忙。

    【讨论】:

    • @Gaming DEITY 不要因为这样的错误而灰心。恕我直言,指针是一件很难掌握的事情。尝试可视化所涉及的变量。尝试将驱动程序的内存空间和您调用的函数绘制为单独的区域,并为每个变量(指针和常规)绘制框。然后用箭头连接指针和它们指向的框。想想你的代码是如何传递地址的,并在每一步之后重新绘制箭头。我知道这听起来微不足道(而且乏味),但是当我第一次遇到指针时,它帮助我掌握了很多:)
    • @Gaming DEITY 这也可能有帮助:geeksforgeeks.org/double-pointer-pointer-pointer-c
    • 非常感谢先生如此详细的解释,这对我弄清楚到底出了什么问题很有帮助。 @Istvan Balogh
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    • 2014-10-25
    • 1970-01-01
    • 2018-05-23
    相关资源
    最近更新 更多