【问题标题】:Circular linked list crashes when displayed循环链表显示时崩溃
【发布时间】:2021-07-12 15:41:24
【问题描述】:

我正在尝试制作一个循环链表。当我在创建列表后尝试显示列表时,程序不断崩溃。这是我的代码:

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

typedef struct node {
    int data;
    struct node * next;
} node;

node * createList(int);
void display(node * head);

int main() {
    struct node * head;

    head = createList(5);
    display(head);

}

node * createList(int n) {

    int i = 0,data = 0;
    struct node * head = NULL;
    struct node * temp = NULL;
    struct node * p = NULL;

    for (i = 0; i < n; i++) {
        temp = (node*)malloc(sizeof(node));
        temp->data = data++;
        temp->next = head;

        if (head == NULL) {
            head = temp;
        } else {
            p = head;
            while (p->next != NULL) {
                p = p->next;
            }
            p->next = temp;
        }
    }
    return head;
}

void display(node * head) {
    struct node * temp = head->next;
    while (temp != head) {
        printf("%d-> \t",temp->data);
        temp = temp->next;
    }
    printf("\n");
}

我做错了什么?

【问题讨论】:

  • 提示:解释这行代码:temp-&gt;next = head; 它的目标是什么? (它会导致 while (p-&gt;next != NULL) { 永远循环。)
  • 循环列表中不会有while (p-&gt;next != NULL) --- 最后一个节点->next 指针指向头节点(因此是循环列表)

标签: c data-structures linked-list circular-list


【解决方案1】:
  1. 您已在temp-&gt;next = head; 中将每个tempnext 设置为head,但设置得太早(第一个只是NULL)。然后您在while (p-&gt;next != NULL) { 中针对NULL 测试了p-&gt;next,但您应该针对head 进行测试。或者,您可以继续针对NULL 进行测试,但您需要将temp-&gt;next 初始化为NULL,并仅在for 循环之后将head 分配给temp-&gt;next

  2. 您的显示代码从第二个链接开始。

这是使用上面1.中第一个选项的固定代码:

    for (i = 0; i < n; i++) {
        temp = (node*)malloc(sizeof(node));
        temp->data = data++;

        if (head == NULL) {
            head = temp;
        } else {
            p = head;
            while (p->next != head) {
                p = p->next;
            }
            p->next = temp;
        }
        temp->next = head;
    }

这是使用上面1. 中的替代选项的固定代码。您仍然需要将temp-&gt;next 初始化为NULL,因为malloc() 没有初始化。

    for (i = 0; i < n; i++) {
        temp = (node*)malloc(sizeof(node));
        temp->data = data++;
        temp->next = NULL;

        if (head == NULL) {
            head = temp;
        } else {
            p = head;
            while (p->next != NULL) {
                p = p->next;
            }
            p->next = temp;
        }
    }
    if (temp != NULL) {
        temp->next = head;
    }

但实际上,没有必要从头到尾“走”每一个创作。您可以简单地保留上一个并将其链接到下一个:

    for (i = 0; i < n; i++) {
        temp = (node*)malloc(sizeof(node));
        temp->data = data++;

        if (head == NULL) {
            head = p = temp;
        } else {
            p = p->next = temp;
        }
    }
    if (temp != NULL) {
        temp->next = head;
    }

这是display() 的修复:

void display(node * head) {
    struct node * temp = head;
    if (temp != NULL) {
        do {
            printf("%d-> \t",temp->data);
            temp = temp->next;
        } while (temp != head);
    }
    printf("\n");
}

【讨论】:

  • 感谢您的回复,我已经尝试了您的代码,但它仍然崩溃:/
  • @VenoM 我也将temp-&gt;next初始化为NULL,现在试试
  • 是的,添加 temp->next = NULL 成功了,谢谢!
【解决方案2】:

问题出在你初始化的第一个节点上:

    struct node *head = NULL;
    ...
    for (i = 0; i < n; i++) {
        ...
        temp->next = head;

所以tmp-&gt;next == NULL 在第一次迭代中离开head-&gt;next == NULL。这不适用于循环列表。当您尝试插入第二个节点时:

            p = head;
            while (p->next != NULL) {

head-&gt;next又是什么?? (哦,NULL)取消引用 NULL 指针(BOOM Segfault!)

正确地做你的循环列表。在插入第一个节点集时:

        if (head == NULL) {
            head = temp;
            head->next = temp;              /* you must set head->next to temp */
        } ...

所以在插入剩余节点时,您只需要:

        } else {
            p = head;
            while (p->next != head) {       /* iterate to last node */
                p = p->next;
            }
            p->next = temp;                 /* now set p->next = temp */
        }

现在,您以同样的方式处理您的 display() 函数,例如

void display (node *head)
{
    if (!head) {                            /* validate list not empty */
        puts ("(list-empty)");
        return;
    }
    
    struct node *temp = head;
    
    do {                                    /* same loop problem fixed in display() */
        printf ("%d-> \t", temp->data);
        temp = temp->next;
    } while (temp != head);
    
    putchar ('\n');
}

如果您进行了更改,那么您可以使用以下方法测试您的列表:

int main (void) {
    struct node *head, *tmp;

    head = createList(5);
    display (head);

    puts ("\niterate from mid-list");
    tmp = head;
    tmp = tmp->next;
    tmp = tmp->next;
    display (tmp);
}

使用/输出示例

$ ./bin/lls_circular_fix
0->     1->     2->     3->     4->

iterate from mid-list
2->     3->     4->     0->     1->

最后,struct node * head = NULL; 中的 node 类型不乘以 head 写成 struct node *head = NULL;(所有函数声明也一样)更具可读性。

当您从列表中删除一条笔记时,您必须为headtail(最后一个节点)创建一个特例。从这个意义上说,由于没有prev 节点指针来跟踪前一个节点,因此单链表比双向链表需要更多的努力。

检查一下,如果您有任何问题,请告诉我。

一个完整的例子是:

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

typedef struct node {
    int data;
    struct node *next;
} node;

node *createList (int);
void display (node *head);

int main (void) {
    struct node *head, *tmp;

    head = createList(5);
    display (head);

    puts ("\niterate from mid-list");
    tmp = head;
    tmp = tmp->next;
    tmp = tmp->next;
    display (tmp);
}

node *createList (int n)
{
    int i = 0,data = 0;
    struct node *head = NULL;
    struct node *temp = NULL;
    struct node *p = NULL;

    for (i = 0; i < n; i++) {
        if (!(temp = malloc (sizeof *temp))) {
            perror ("malloc-temp");
            return NULL;
        }
        temp->data = data++;
        temp->next = head;                  /* head is NULL on 1st node insertion */

        if (head == NULL) {
            head = temp;
            head->next = temp;              /* you must set head->next to temp */
        } else {
            p = head;
            while (p->next != head) {       /* iterate to last node */
                p = p->next;
            }
            p->next = temp;                 /* now set p->next = temp */
        }
    }
    return head;
}

void display (node *head)
{
    if (!head) {                            /* validate list not empty */
        puts ("(list-empty)");
        return;
    }
    
    struct node *temp = head;
    
    do {                                    /* same loop problem fixed in display() */
        printf ("%d-> \t", temp->data);
        temp = temp->next;
    } while (temp != head);
    
    putchar ('\n');
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多