【问题标题】:C function that creates a linked list with "divisible by 3" numbers from another linked list从另一个链表中创建一个具有“可被 3 整除”数字的链表的 C 函数
【发布时间】:2019-05-16 23:03:05
【问题描述】:

首先,我需要创建并显示一个以数字 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;
    }

}

我希望显示第一个列表(它正在发生)以及显示可被 3 整除的数字的第二个列表,这不会发生。

【问题讨论】:

  • 澄清一下——这需要是链表结构,而不是数组?
  • 是的。它需要是一个链表。我这样做的方式(但工作)......
  • 在第一个列表中,当用户插入 1000 时,我停止创建节点。
  • 在第二个中,它应该是用可以被 3 整除的数字创建的
  • 你的创建函数是无故递归的;制作这些简单的循环将简化事情并防止堆栈问题。此外,在 crear2() 中,如果第一个数字不是 3 的倍数,那么您的递归调用包括 registroNuevo->sig,它从未设置过,因此将调用未定义的行为。事实上,这里真的没有理由在任何地方进行递归。

标签: c recursion linked-list


【解决方案1】:

首先,我很佩服你对递归的奉献精神!

问题是在crear2 中,registroNuevo-&gt;sig 未初始化,这会导致段错误。我几乎总是通过检查参数节点是否为空来启动对递归链接数据结构进行操作的函数。如果是这样,我可以安全地继续使用函数体。按照这种防止空值的逻辑,我们需要在 registro-&gt;num % 3 != 0 的情况下传递 registroNuevo 节点而不触及它,并确保其所有字段都已初始化。

这是修正后的函数:

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);
        }
    }
}

话虽如此,由于几个原因,此功能仍然不太理想。首先,名称含糊不清,可以更好地描述行为。此外,如果没有可被三整除的项目,则在调用范围内有一个 malloced 节点,该节点永远不会被初始化,因此在这方面它有点脆弱。第三,即使有一个参数,它也感觉像是一个高度特定的函数,没有太多的可重用性因素,可以在调用范围内迭代地编写,例如:

#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
  • 考虑避免使用诸如31000 等硬编码值的高度特定的函数。设置这些参数以最大限度地提高可重用性。
  • crear2 从不使用 cont 成员,并且您有未使用的全局常量。清理这些内容以帮助澄清您的调试工作并减少视觉混乱是一个好主意。
  • No need 转换 malloc 的结果。
  • if (registro-&gt;sig !=NULL) 作为函数的第一行将在 null 上崩溃。你也不需要!= NULLif (registro) { ... } 最清晰,避免了空参数的问题。

【讨论】:

  • 非常感谢!!!!我正在尝试做我在另一篇文章中提到的事情,但我做不到。
  • 你认为你可以做另外2个功能1)如果两个数字的总和大于20,则添加一个0。2)如果两个数字的总和小于,则删除第二个数字超过 10 个。如果可以,我将不胜感激。我会在这里给你看,让你明白。 imgur.com/a/mDOo4EX
  • 我不完全清楚你在问什么,但我鼓励你自己尝试一下——这听起来像是一项学校作业。
【解决方案2】:
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);
   }
}

这是我的方法,但在最后一个 mostrar() 调用中你仍然得到一个最终的意外 0;而且您仍然需要拨打“免费”电话。我认为你应该避免递归调用,有更简单的方法可以做到这一点。萨鲁多斯。

【讨论】:

    猜你喜欢
    • 2020-04-22
    • 1970-01-01
    • 2012-11-30
    • 1970-01-01
    • 1970-01-01
    • 2022-07-29
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    相关资源
    最近更新 更多