C 使用递归创建链表

C 使用递归创建链表,c,recursion,linked-list,C,Recursion,Linked List,我想使用递归创建一个链表。在执行代码之后,我只得到第一个节点的值,其余的都没有被打印出来 #include<stdio.h> #include<malloc.h> typedef struct node NODE; struct node { int data; struct node *next; } *start=NULL,*ptr; void display(); int create(int); int main() { int n

我想使用递归创建一个链表。在执行代码之后,我只得到第一个节点的值,其余的都没有被打印出来

#include<stdio.h>
#include<malloc.h>

typedef struct node NODE;

struct node
{
    int data;
    struct node *next;
} *start=NULL,*ptr;

void display();
int create(int);

int main()
{
    int n;
    printf("\nEnter the no of node?\t");
    scanf("%d",&n);
    create(n);
    display();
}
int create(int x) 
{
    if(x==0)
        return;

    else{
        NODE *node;
        node=((NODE *)malloc(sizeof(NODE)));

        printf("Enter the data:\n");
        scanf("%d",&node->data);

        node->next=NULL;
        if(start==NULL)
        {
            ptr=start=node;
        }
        else
        {
            ptr=node->next;
            ptr=node;
        }   
        ptr->next=NULL;
    }
    create(x-1);
}

void display()
{
    NODE *ds;
    ds=start;
    while(ds!=NULL)
    {
        printf("%d->",ds->data);
        ds=ds->next;
    }   
}
#包括
#包括
typedef结构节点;
结构节点
{
int数据;
结构节点*下一步;
}*start=NULL,*ptr;
void display();
int创建(int);
int main()
{
int n;
printf(“\n输入节点号?\t”);
scanf(“%d”和“&n”);
创建(n);
显示();
}
整数创建(整数x)
{
如果(x==0)
返回;
否则{
节点*节点;
node=((node*)malloc(sizeof(node));
printf(“输入数据:\n”);
scanf(“%d”,&node->data);
节点->下一步=空;
if(start==NULL)
{
ptr=开始=节点;
}
其他的
{
ptr=节点->下一步;
ptr=节点;
}   
ptr->next=NULL;
}
创建(x-1);
}
无效显示()
{
节点*ds;
ds=启动;
while(ds!=NULL)
{
printf(“%d->”,ds->data);
ds=ds->next;
}   
}
我想问题是当我调用
create(x-1)时,但我不确定。

我的逻辑正确吗?有人能指出我的错误吗?

试着改变逻辑

int create(int x) {
    if (x == 0)
        return 0;
    else {
        NODE *node;
        node = ((NODE *) malloc(sizeof (NODE)));
        printf("Enter the data:\n");
        scanf("%d", &node->data);
        node->next = NULL;
        if (start == NULL) {
            ptr = start = node;
        } else {
            //ptr = node->next;
            ptr->next = node;
            ptr = node;
        }
        ptr->next = NULL;
    }
    create(x - 1);
}
您没有正确重置磁头


当您执行此操作时,也可以查看此实现:

ptr=node->next;
ptr=node;
ptr->next = node;
ptr = ptr->next;
您失去了对列表尾部的引用,因此没有将
节点添加到列表中。您应该这样做:

ptr=node->next;
ptr=node;
ptr->next = node;
ptr = ptr->next;
这将当前尾部的
next
指针指向新节点,然后将
ptr
向下移动到新尾部


此外,循环末尾的
ptr->next=NULL
是不必要的,因为
ptr
现在与
节点
相同,并且您已经执行了
node->next=NULL

导致问题的重要错误是在
create(int)
中分配了指针。您正确分配了第一个指针,但随后将
NULL
分配给了所有剩余的指针。有几种方法可以处理此问题,但一种简单明了的方法是只在
else
块中前进
ptr=ptr->next
,如下所示:

if (start == NULL)
{
    ptr = start = node;
}
else
{
    ptr->next = node;
    ptr = ptr->next;
}   
您正在动态分配内存,因此这意味着您负责跟踪内存的使用情况,保留指向每个分配起始块的指针,并在不再使用内存时释放内存。从现在开始。养成在分配内存时处理内存清理的习惯,不要简单地依赖程序出口来完成。虽然现在这看起来很简单,但当您开始处理具有多个分配的函数时,如果您在这方面没有养成良好的习惯,那么您的代码很可能会像筛子一样泄漏内存。简单的清理功能只能是:

void destroy()
{
    if (!start) return;

    NODE *ds = start;
    while (ds != NULL)
    {
        NODE *victim = ds;
        ds = ds->next;
        free (victim);
    }
}
malloc
问题
malloc
返回分配的内存块的起始地址,不需要用C转换返回值。为刚刚声明的数据类型分配内存时,请使用带有
sizeof
的变量,而不是数据类型。e、 g:

NODE *node;
node = malloc (sizeof *node);
而不是

node = malloc (sizeof (NODE));
在处理指向指针的指针时,这一点会变得很明显。对变量进行操作比记住是为
节点*
还是
节点**
进行分配更有意义。当分配在代码中的声明下许多行时,或者在函数参数列表中接收指针时,尤其如此

此外,每次分配内存时都需要验证malloc的返回,以确保没有耗尽可用内存。e、 g:

NODE *node;
if (!(node = malloc (sizeof *node))) {
    fprintf (stderr, "error: virtual memory exhausted\n");
    exit (EXIT_FAILURE);
}
最后,综上所述,解决问题的一种方法是:

#include <stdio.h>
#include <stdlib.h>   /* for exit & EXIT_FAILURE */

typedef struct node NODE;

struct node {
    int data;
    struct node *next;
} *start=NULL,*ptr;

void display();
void create (int);
void destroy();

int main (void)
{
    int n;
    printf ("\nEnter the no of node: ");
    scanf ("%d",&n);
    create (n);
    display();
    destroy();
    return 0;
}

void create (int x) 
{
    if (x == 0) return;

    NODE *node;
    if (!(node = malloc (sizeof *node))) {
        fprintf (stderr, "error: virtual memory exhausted\n");
        exit (EXIT_FAILURE);
    }

    printf ("Enter the data: ");
    scanf ("%d",&node->data);

    node->next = NULL;
    if (start == NULL)
    {
        ptr = start = node;
    }
    else
    {
        ptr->next = node;
        ptr = ptr->next;
    }   

    create (x-1);
}

void display()
{
    if (!start) return;

    NODE *ds = start;
    while (ds != NULL)
    {
        if (ds == start)
            printf ("%d", ds->data);
        else
            printf("->%d", ds->data);
        ds = ds->next;
    }
    printf ("\n");
}

void destroy()
{
    if (!start) return;

    NODE *ds = start;
    while (ds != NULL)
    {
        NODE *victim = ds;
        ds = ds->next;
        free (victim);
    }
}
使用内存检查器

不管您的平台是什么,最好使用内存检查器,如Linux上的
valgrind
,检查内存错误并确保已释放所有分配的内存。内存检查器不仅可以确认所有内存都已释放,还可以报告您尝试访问已分配内存时出现的细微错误,从而提醒您以后可能遇到的问题。它使用简单,简单:

$ valgrind ./bin/llrecurse
==17434== Memcheck, a memory error detector
==17434== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==17434== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==17434== Command: ./bin/llrecurse
==17434==

Enter the no of node: 4
Enter the data: 2
Enter the data: 4
Enter the data: 6
Enter the data: 8
2->4->6->8
==17434==
==17434== HEAP SUMMARY:
==17434==     in use at exit: 0 bytes in 0 blocks
==17434==   total heap usage: 4 allocs, 4 frees, 64 bytes allocated
==17434==
==17434== All heap blocks were freed -- no leaks are possible
==17434==
==17434== For counts of detected and suppressed errors, rerun with: -v
==17434== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

这应该会让你开始学习,如果你及早学会好习惯,当你进一步学习C语言编程时,管理内存将变得容易得多。

标准警告:不要像
malloc
&friends返回的那样抛出
void*
。C不是C++!另请注意:不要对类型/变量使用所有大写标识符。它们应该只用于宏和_enum-constants_这是C语言中为数不多的被广泛接受的命名约定之一。创建带有递归的链表听起来是一个相当愚蠢的要求-对不起,但我不能更礼貌地说。很简单,因为您将在一个元素之后创建/附加(或前置)一个元素。不需要循环。您发现任何答案有用吗?如果是这样,请随意选择其中一个。语法/格式/澄清。标准警告:不要按
malloc
&朋友返回的方式强制转换
void*
。C不是C++!另请注意:不要对类型/变量使用所有大写标识符。它们应该只用于宏和_enum-constants_这是C语言中为数不多的被广泛接受的命名约定之一。你不应该复制OP的缺陷。