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的缺陷。