【问题标题】:Display circular list endless loop显示循环列表无限循环
【发布时间】:2017-07-24 12:31:12
【问题描述】:

我有两个功能:

void display(struct node *start) {
    struct node *ptr;

    ptr = start;

    while (ptr -> next != start) {
        printf("\t %d", ptr -> data);
        ptr = ptr -> next;
    }

    printf("\t %d", ptr -> data);
}

struct node *insert_beg(struct node *start) {
    struct node *new_node;

    new_node = (struct node *)malloc(sizeof(struct node));
    printf("\n Enter data : ");
    scanf("%d", &new_node -> data);

    new_node -> next = start;
    start = new_node;

    return start;
}

使用insert_beg(start) 并尝试使用display(start) 显示此列表后,我有一个无限循环。

感谢您的支持。

【问题讨论】:

  • 在函数insert_beg 中,变量start 是一个本地 变量。一旦函数返回,您认为对它的更改会发生什么?我建议您搜索并阅读有关 emulating pass by reference in c
  • @Someprogrammerdude 的评论是显而易见的(也是迄今为止最明智的),但您如何知道列表是循环的?它可能有一个起始尾部,例如数字 6。您的算法很容易受到攻击。
  • 这是循环链表在哪里插入结束函数
  • 请创建一个Minimal, Complete, and Verifiable Example 并告诉我们。也请花一些时间read about how to ask good questions。我还建议您阅读 Eric Lippert 的 How to debug small programs

标签: c pointers struct linked-list


【解决方案1】:

你不是在这里创建一个循环列表。

为了创建循环列表,当列表中没有元素时,您必须处理另一种情况,即 start 为 NULL(列表为空)。

在 insert_beg() 函数的 scanf 部分之后对其进行以下编辑:

if(start == NULL){     // this is the required condition to be added
     start = new_node;
     start->next = start;
}
else{
     // this code for adding element is to be performed only when list is not empty
     struct node *tmp = start->next;
     start->next = new_node;
     new_node->next = temp;
}

希望能解决你的问题!!

【讨论】:

  • 修复是部分的:你需要让最后一个节点也指向新的开始节点。
  • 感谢您的建议!!请现在检查它是否可以工作,因为编辑的代码在开始指针节点之后添加了新节点。
  • 编辑后的代码按照您的建议在开始节点之后添加了新节点!!由于它是循环列表,我认为传递给函数 insert_beg() 的指针应该被视为开始节点。
  • 感谢您的建议,但它解决了问题的无限循环问题。除了您推荐的当前解决方案之外,我仍然会添加另一个解决方案。
  • 我觉得正确答案也差不多@chqrlie
【解决方案2】:

由于您没有提供完整的示例,如何构建循环列表,让我假设您使用错误的insert_beg 函数。

如果我像下面这样使用你的函数,就没有无限循环:

int main() {
    struct node* start;

    start = (struct node*)malloc(sizeof(struct node));
    start->data = 1;
    start->next = start; /* initializing the next pointer to itself */

    start->next = insert_beg(start->next);
    start->next = insert_beg(start->next);
    start->next = insert_beg(start->next);

    display(start);
    return 0;
}

我在您的insert_beg 中也看到了一个问题:

start = new_node;

如果您打算覆盖start 指向的位置,则必须将函数签名更改为以下内容:

struct node *insert_beg(struct node **start);

然后在函数内部你可以做以下事情:

new_node->next = *start; /* access the pointer pointed by start */
*start = new_node; /* overwrite where the pointer pointed by start points to*/

return *start; /* losts its meaning */

上面的修改让你可以使用你的insert_beg函数如下:

insert_beg(&start->next);
insert_beg(&start->next);
insert_beg(&start->next);

【讨论】:

  • 非常感谢,非常有帮助,您能解释一下为什么我们应该使用 **start 而不是 *start 吗?
  • @Fela93,struct node* start表示指向struct node类型实例的指针,即如果这是一个函数参数,它允许你传递一个指针按值,因此更改该指针指向的位置不会对您传递的指针进行任何更改。 struct node** start 表示指向struct node 类型实例的指针。在这种情况下,间接(取消引用)允许您更改传递的指针指向的位置,这将更改您通过地址传递的指针。请注意,指针也是一个变量,它保存其目标的地址。
  • 那么如果struct node *start 是一个指向结构的全局指针,我就不需要双指针了吗?
  • @Fela93,全局变量是不同的,因为您可以在同一范围内以函数形式访问它们,而无需将它们作为参数传递。因此,在这种情况下,您不必使用指向指针的指针。
  • 很好的解释!!
猜你喜欢
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-19
  • 2015-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多