Важной ошибкой, возникшей из-за вашей проблемы, было ваше назначение указателей в create(int)
. Вы правильно назначили первый указатель, но затем назначили NULL
всем остальным указателям. Есть несколько способов справиться с этим, но чистый и простой способ это только заранее ptr=ptr->next
в else
блока следующим образом:
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);
}
}
The malloc
вопрос. malloc
возвращает начальный адрес для выделенного блока памяти, нет необходимости отбрасывать возврат в C. Когда вы выделяете память для типов данных, которые вы только что объявили, используйте переменную с sizeof
вместо типа данных. например .:
NODE *node;
node = malloc (sizeof *node);
вместо
node = malloc (sizeof (NODE));
Это станет очевидным при работе с указателями на указатели и т.д.Это имеет гораздо больший смысл для работы с вашей переменной, чем для того, чтобы помнить, выделяете ли вы для NODE*
или NODE**
. Это особенно актуально, когда распределение представляет собой много строк под декларацией в вашем коде или при приеме указателя в списке аргументов функции.
Кроме того, каждый раз, когда вы выделяете память, вам необходимо подтвердить возврат с malloc
, чтобы вы не исчерпали доступную память. например:
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);
}
}
Пример
$ ./bin/llrecurse
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
Использование Checker памяти
Независимо от вашей платформе, полезно использовать средство проверки памяти, например 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.
Стандартное предупреждение: не набрасывайте 'void *' как возвращаемые 'malloc' и друзьями. C isn ** не ** C++! Также обратите внимание: не используйте идентификаторы all-uppercase для типов/переменных. Они должны использоваться только для макросов и _enum-constants_This является одним из немногих общепринятых соглашений об именах в C. – Olaf
Создание связанного списка с рекурсией звучит как совершенно немое требование - извините, но я не могу сказать это более вежливо. Просто потому, что вы создадите/добавите (или добавьте) один элемент за другим. Не требуется петли. – Olaf
Вы нашли ответы полезными? Если да, не стесняйтесь [принять] (http://stackoverflow.com/help/accepted-answer) один из них. – dbush