通过递归函数打印链表的节点

时间:2015-03-20 20:34:04

标签: c list function exception recursion

我被要求使用C制作一些程序。在其中一个程序中,我需要创建一个链表,以便我可以用它做一些事情。但是,我不允许在任何这些程序中使用全局变量或循环(While,For等)。所以这是一个我写的新程序链接列表的小程序:

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

struct node {

    int number;
    struct node *next;

};

void create (struct node *, struct node *);
void insert (struct node *, struct node *);
void display (struct node *);

int main(void) {

    struct node *head;
    struct node *current;
    struct node *temp;

    create ( head, current );

    insert ( head, current );

    temp = head;

    display ( temp );

}

void create ( struct node *head, struct node *current ) {

    int a;

    printf("Insert: ");
    scanf("%d", &a);
    current = malloc(sizeof(struct node));
    current -> number = a;
    current -> next = NULL;
    head = current;

}

void insert ( struct node *head, struct node *current ) {

    int b;

    printf("insert: ");
    scanf("%d", &b);

    if ( b == -1 ) return;
    else {

        current = malloc(sizeof(struct node));
        current -> number = b;
        current -> next = NULL;

    }

    insert ( head, current );

}

void display ( struct node *temp ) {

    if ( temp != NULL ) {

        printf("%d \t", temp -> number); //Error: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
        temp = temp -> next;

        display ( temp );

    }
    else return;

}

它或多或少是每本书所具有的标准代码,但我使用递归函数而不是循环。仔细观察,我的display()函数有问题。我收到此错误:函数内的EXC_BAD_ACCESS(代码= EXC_I386_GPFLT),在printf()行。所以我无法在屏幕上打印我的列表。我现在已经调试了4个小时了,我找不到什么错误,任何帮助都会受到赞赏!

3 个答案:

答案 0 :(得分:0)

两个主要缺点:

  1. 您尚未在main()中初始化列表指针,因此它们的值实际上是随机

  2. 您正在将这些变量的副本传递给create()insert()函数。这些函数无效,因为函数返回时会丢弃副本。

  3. 结果是当你尝试display()列表时,你会发生崩溃,因为你传递的是未经初始化的指针。

    <强>更新

    以下是您的计划的修订版。插入,显示和释放是递归的。它不是传递要修改的insert()函数的双指针,而是返回列表的新头部。请注意,创建空列表只需将其指针设置为NULL即可。另外,请注意display()更简单。

    #include <stdio.h>
    #include <stdlib.h>
    
    struct node {
        int number;
        struct node *next;
    };
    
    struct node *insert (struct node *head) {
       // return new list pointer
        int b = 0;
        struct node *current;
        printf("Insert: ");
        if (1 != scanf("%d", &b) || b == -1)
            return head;
        current = malloc(sizeof(struct node));
        if (current == NULL) {
            printf("Bad malloc!\n");
            exit (1);
            }
        current->number = b;
        current->next = head;
        return insert(current);
    }
    
    void display (struct node *list) {
        if (list) {
            printf("%d \t", list->number);
            display(list->next);
        }
    }
    
    void free_list (struct node *list) {
        if (list) {
            free_list(list->next);
            free(list);
        }
    }
    
    int main(void) {
        struct node *head = NULL;
        head = insert (head);
    
        printf("List is: ");
        display(head);
        printf("\n");
    
        free_list (head);
        return 0;
    }
    

    节目输出:

    Insert: 1
    Insert: 2
    Insert: 3
    Insert: 4
    Insert: -1
    List is: 4      3       2       1
    

    处理了一些小问题:不检查scanf()malloc()的返回值。这样做似乎很麻烦,但是随着时间的推移,你会重视检查你所做的一切的例程,因为C中的大多数语言检查都是在编译时发生的,而不是在运行时。在运行时,几乎没有保护。

答案 1 :(得分:0)

风向标发布的第三个问题:

你的插页非常奇怪。您要求输入,然后再次递归调用插入。要求输入,...... 但是你永远不会挂钩链表中的当前链接。

答案 2 :(得分:0)

您的代码包含两个问题。首先,insert和create函数应该使用struct node **参数而不是struct node * arguments。然后你需要以这种方式调用它们:

  create ( &head, &current );
  insert ( &head, &current );

因为否则对head和current的更改不会反映在head和current的值中,因为C具有按值语义调用(并且通过引用调用通过使用指针进行模拟)。所以,current = malloc(...);和头=当前;这些行实际上并没有改变主函数中的当前和头部指针,只是局部变量。

然后,您需要以这种方式访问​​它们:

  *current = malloc(sizeof(struct node));
  (*current) -> number = a;
  (*current) -> next = NULL;
  *head = *current;

这将是create function代码的一部分。

您还没有实际更新插入中当前节点的下一个链接。所以,而不是:

    current = malloc(sizeof(struct node));
    current -> number = b;
    current -> next = NULL;

试试这个:

    (*current)->next = malloc(sizeof(struct node));
    *current = (*current)->next;
    (*current) -> number = b;
    (*current) -> next = NULL;

我还发现您的代码中存在一个问题,即您没有检查malloc的返回值。你永远不应该假设内存分配总是成功的。通过打印描述性错误消息并退出程序来处理malloc的NULL返回。