Прежде всего, я восхищаюсь вашей преданностью рекурсии!
Проблема в том, что в crear2
, registroNuevo->sig
не инициализируется, что вызывает ошибку сегмента.Я почти всегда запускаю функцию, которая работает с рекурсивной структурой связанных данных, проверяя, является ли узел параметра нулевым.Если это так, я могу безопасно продолжить работу с основной частью функции.Следуя этой логике защиты от нулей, нам нужно передать узел registroNuevo
, не касаясь его в случае, когда registro->num % 3 != 0
, и убедиться, что все его поля инициализированы.
Вот исправленная функция:
void crear2(nodo *registro, int cont, nodo *registroNuevo)
{
if (registro) {
if (registro->num % 3 == 0) {
registroNuevo->num = registro->num;
registroNuevo->sig = NULL;
if (registro->sig) {
registroNuevo->sig = malloc(sizeof(nodo));
}
crear2(registro->sig, cont, registroNuevo->sig);
}
else {
crear2(registro->sig, cont, registroNuevo);
}
}
}
Сказав это, эта функция все еще немного не идеальна по нескольким причинам.Во-первых, имя расплывчато и может лучше описать поведение.Кроме того, если нет элементов, кратных трем, у вас есть узел malloc
ed в области вызова, который никогда не инициализируется, так что это немного хрупко в этом отношении.В-третьих, даже с параметром, это похоже на очень специфическую функцию без большого коэффициента повторного использования, которая может быть написана итеративно внутри вызывающей области, например:
#include <stdio.h>
#include <stdlib.h>
typedef struct nodo
{
int num;
struct nodo *sig;
} nodo;
nodo *crear(nodo *registro, int num)
{
nodo *n = malloc(sizeof(nodo));
n->num = num;
n->sig = registro;
return n;
}
void mostrar(nodo *registro)
{
if (registro)
{
printf("%d->", registro->num);
mostrar(registro->sig);
}
else puts("");
}
void free_lista(nodo *registro)
{
if (registro)
{
free_lista(registro->sig);
free(registro);
}
}
int main()
{
nodo *prin = NULL;
nodo *prin_div_3 = NULL;
for (int t; scanf("%d", &t) && t != 1000;)
{
prin = crear(prin, t);
}
nodo *tmp = prin;
while (tmp)
{
if (tmp->num % 3 == 0)
{
prin_div_3 = crear(prin_div_3, tmp->num);
}
tmp = tmp->sig;
}
mostrar(prin);
mostrar(prin_div_3);
free_lista(prin);
free_lista(prin_div_3);
return 0;
}
Это не идеально - без хвостовых узлов, добавляяк списку чуть меньше идеала, но висячие головы исключены, и, надеюсь, он демонстрирует альтернативный подход к организации логики и функций программы.
Несколько других замечаний:
- Всегда свободная память, которую вы выделили.Для этого вы можете написать простую рекурсивную подпрограмму, например
free_lista
, как показано в приведенном выше примере. - Не используйте очень специфичные функции с жестко закодированными значениями, такими как
3
и 1000
.Задайте эти параметры для максимального повторного использования. crear2
никогда не использует элемент cont
, и у вас есть глобальные константы, которые не используются.Это хорошая идея, чтобы очистить их, чтобы уточнить ваши усилия по отладке и уменьшить визуальный беспорядок. - Нет необходимости , чтобы привести к результату
malloc
. if (registro->sig !=NULL)
поскольку первая строка функции завершится с ошибкой.Вам тоже не нужно != NULL
.if (registro) { ... }
является четким и позволяет избежать проблем с нулевыми параметрами.