如何正确 return 一个结构数组(在此代码战示例中)?

How to return an array of structs properly (in this codewars example)?

我已经在这个特殊的代码战练习上停留了一段时间了。不是因为拼图本身很难(不,我只用了几分钟就能打印出正确的结果),而是因为我似乎无法弄清楚如何 return 结果。

我应该 return 一个结构数组。我知道我不能只是静态分配它然后 return 它。我必须动态分配内存和 return 指针。我这样做(n-m 是我可能需要的最大结构数量 return):

Pair* res = malloc((n-m)*sizeof(Pair));

然后我按如下方式赋值:

res[t].first = i;
res[t].snd = sum;

然后return数组:

return res;

如果我在 return 打印之前打印整个数组,它就会显示为已填满。但是 codewars 系统说我 returned 了一个空数组? 我能够通过向 return 地址添加一个符号来解决这个问题。通过这样做,它 return 第一个结构正确(我能够通过添加手动检查来解决这个问题),但第二个结构将是垃圾数据。

有人知道我可能做错了什么吗?

这是完整的函数(删除了计算,因为它们与问题无关,也可能会破坏在解决问题时偶然发现此问题的其他人的困惑):

Pair** listSquared(long long m, long long n, int* length) {
    Pair* res = malloc((n-m)*sizeof(Pair));
    int t = 0;
    long long sum = 0;

    for(int i = m; i<=n; i++)
    {
      if(sum = isSumSquare(i))
      {
        res[t].first = i;
        res[t].snd = sum;
        t++;
      }
    }

    *length = t;

    return res;
}

还有一件事:我确实注意到 return 类型是 Pair**。我猜这是我做错了什么,但我也尝试制作 res Pair** 的数据类型(然后在分配时将 . 替换为 ->),and/or 采用 sizeof(Pair*)而不仅仅是配对。我尝试了数不清的组合,但仍然没有得到任何有效的方法。我觉得我在这里缺少一些关于指针的基本知识......

谁能告诉我我做错了什么?

编辑:根据 Gilles 的要求,确切的问题陈述:https://i.imgur.com/gFdDJlz.png

如上所述,type控制着一切。你得到了一个带有 Pair **listSquared (...) 的函数原型。该函数必须 return 键入 Pair**(例如 指针到指针 以键入 Pair

返回一个指向指针的指针到动态分配的对象需要先在listSquared中声明Pair**类型的对象并分配指针的数量必需,例如

    Pair **res = malloc ((n-m) * sizeof *res);

(注意: 如果您总是使用解除引用的指针设置 typesizesizeof *res 而不是 sizeof (Pair*), 不可能出错)

然后在你填充每个struct Pair的循环中的函数中,你首先需要为每个结构分配一个内存块,并将该块的起始地址分配给你的指针,例如

        res[t] = malloc (sizeof *res[t]);

在每种情况下,对于每次分配,在尝试使用指针之前,您需要验证分配成功或内存块。例如:

    if (!res) {                 /* validate EVERY allocation */
        perror ("malloc-res");
        *length = 0;            /* set length zero */
        return NULL;            /* return NULL indicating failure */
    }

并且在为 res[t] 分配失败的情况下,您需要 free() 每个先前分配的结构 return 之前的指针避免造成内存泄漏,例如

        if(sum = isSumSquare(i))
        {   /* allocate for res[t] and validate, free all on failure */
            if (!(res[t] = malloc (sizeof *res[t]))) {
                perror ("malloc-res[t]");
                while (t--)         /* free previously allocated structs */
                    free (res[t]);
                free (res);         /* free pointers */
                *length = 0;        /* set length zero */
                return NULL;        /* return NULL indicating failure */
            }
            res[t].first = i;
            res[t].snd = sum;
            t++;
        }

根据我对你需要做什么的最佳理解,你可以把它和类似的东西放在一起:

Pair **listSquared (long long m, long long n, int *length)
{
    Pair **res = malloc ((n-m) * sizeof *res);
    int t = 0;
    long long sum = 0;

    if (!res) {                 /* validate EVERY allocation */
        perror ("malloc-res");
        *length = 0;            /* set length zero */
        return NULL;            /* return NULL indicating failure */
    }

    for(int i = m; i<=n; i++)
    {
        if(sum = isSumSquare(i))
        {   /* allocate for res[t] and validate, free all on failure */
            if (!(res[t] = malloc (sizeof *res[t]))) {
                perror ("malloc-res[t]");
                while (t--)         /* free previously allocated structs */
                    free (res[t]);
                free (res);         /* free pointers */
                *length = 0;        /* set length zero */
                return NULL;        /* return NULL indicating failure */
            }
            res[t].first = i;
            res[t].snd = sum;
            t++;
        }
    }

    *length = t;

    return res;
}

在分配失败的情况下,您的函数 returns NULL 并释放了它在失败点之前分配的所有内存,消除了所有潜在的内存泄漏。

很高兴您能正常工作并提交了您的代码。如果您对上述推理有任何疑问,请发表评论,我很乐意进一步提供帮助。