Функция C, которая создает связанный список с «делимыми на 3» числами из другого связанного списка - PullRequest
1 голос
/ 17 мая 2019

Сначала мне нужно создать и показать список, который заканчивается номером 1000. Это хорошо работает.

Затем я хочу создать еще один список, в котором в первом списке будут только числа, которые делятся на 3., но это не работает.

Хуже всего то, что он даже не говорит мне, что происходит.Он просто выдает ошибку при выполнении, но консоль ничего не говорит.

Я буду очень признателен за любую помощь.

Я перепробовал все.

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

#define CANTIDAD_NUMEROS 13
#define CANTIDAD_NUMEROS2 6
#define DESDE 1
#define HASTA 10

typedef struct lista{
    int num;
    struct lista *sig;
}nodo;


void crear (nodo *pt, int, int);
void crear2 (nodo *pt, int, nodo *pt2);
void mostrar(nodo *pt);

int main()
{
    int i=0;
    int t=0;

    nodo *prin;
    nodo *prin2;

    prin=(nodo*)malloc(sizeof(nodo));
    prin2=(nodo*)malloc(sizeof(nodo));

    crear(prin,i, t); //creates first list
    mostrar (prin); //shows first list
    crear2(prin,i, prin2); //gets 'divisible by 3' numbers
    mostrar(prin2); // shows second list

    return 0;
}

//creates list
void crear (nodo *registro, int cont, int t)
{

    scanf("%d", &t);
    registro->num = t;

    if (registro->num == 1000) 
        registro->sig=NULL;
    else
    {
        registro->sig=(nodo*)malloc(sizeof(nodo));
        cont++;
        crear (registro->sig,cont, t);
    }
    return;
}
//shows list
void mostrar (nodo *registro)
{
    if (registro->sig !=NULL)
    {
        printf ("%d\n",registro->num);
        mostrar (registro->sig);
    }else{
        printf("%d\n",registro->num);
    }
    return;
}
//creates second list with only numbers that are divisible by 3
void crear2 (nodo *registro, int cont, nodo *registroNuevo)
{
    if ((registro->num % 3) == 0){
        registroNuevo->num = registro->num;
        registroNuevo->sig = (nodo*)malloc(sizeof(nodo));
    }

    if(registro->sig != NULL){
        crear2(registro->sig,cont, registroNuevo->sig);
    }else{
        return;
    }

}

Я ожидаючтобы отобразился 1-й список (что происходит), а также 2-й список с номерами, которые делятся на 3, чего не происходит.

Ответы [ 2 ]

1 голос
/ 17 мая 2019
void crear2 (nodo *registro, int cont, nodo *registroNuevo) {

   if ((registro->num % 3) == 0) {
       registroNuevo->num = registro->num;
       registroNuevo->sig = (nodo*)malloc(sizeof(nodo));
       if (registro->sig != NULL)
           crear2(registro->sig, cont, registroNuevo->sig);
   }
   else {
       if (registro->sig != NULL)
           crear2(registro->sig, cont, registroNuevo);
   }
}

Это мой подход, но вы все еще получаете последний неожиданный 0 при последнем вызове Mostrar (); и вам все равно нужно делать «бесплатные» звонки. Я думаю, что вы должны избегать рекурсивных вызовов, есть более простые способы сделать это. Saludos.

0 голосов
/ 17 мая 2019

Прежде всего, я восхищаюсь вашей преданностью рекурсии!

Проблема в том, что в 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) { ... } является четким и позволяет избежать проблем с нулевыми параметрами.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...