1

假设以下函数:

float *dosomething(const float *src, const int N)
{
    float *dst = (float *)malloc(sizeof(float) * N);
    if(!dst)
    {
        printf("Cannot allocate memory\n");
        exit(EXIT_FAILURE);
    }
    for(int i = 0; i < N; i++)
           dst[i] = src[i] * 2;          
    return dst;
}

在这种情况下,如果我们想使用它,我们不需要预先分配内存吗?

现在,只是另一种情况:

void dosomething(float *dst, const float *src, const int N)
{
    for(int i = 0; i < N; i++)
        dst[i] = src[i] * 2;
}

在最后一种情况下,我们需要预先分配内存。所以我分享它,我想知道哪个是返回数组的最佳方法。它们中的哪一个为图书馆或班级的用户提供了更多的安全性?最推荐哪种方法?为什么?

4

3 回答 3

2

什么是更好的实践或更好的想法取决于您实际尝试做的事情。

char *strdup(const char *s)(POSIX) 这样的函数的实现方式与第一种情况类似,它接受一个字符串作为参数,为另一个相同长度的内存分配内存,然后将源复制到新的内存中。这很方便,并且使您免于手动执行为字符串副本分配缓冲区的常见操作。您可以假设这就像调用malloc然后strcpy/ memcpy

然后你有一个类似的函数char *strcpy(char *dest, const char *src),就像第二种情况一样,你可以控制字符串将被复制到哪里。这样,您就不会被迫将字符串复制到动态分配的、不是您选择的内存中。

如果您需要创建和初始化某种动态结构(列表、树等),第一种方法可能会派上用场,但第二种方法也足以让您控制正在使用的内存;您可以在堆上使用动态分配的内存,或者在堆栈上使用局部变量等。

就个人而言,我通常会采用第二种方式,因为我可以更好地控制要初始化的变量,而且我不会被迫使用新malloc的内存(如果我希望我的局部变量被初始化怎么办? )。然后,您始终可以编写一个包装函数,该malloc函数使用新分配的内存作为目标调用然后调用您的函数。

这完全取决于您和您的设计以及您想要实现的目标,没有正确和错误的方法,只要您记住分配的内存,您就不应该有任何问题。我不会说两者中的任何一个都更“安全”。

于 2012-09-14T22:55:06.110 回答
1

没有正确的答案。

C 语言本质上是不安全的,即只有复制并返回副本才能使数据安全。从而向调用者隐藏原始的真实位置。

更重要的是如何处理共享数据的内存解除分配,这通常表明该方法更正确。

在示例中,您引用的唯一数据是调用者已经传递(并且已经拥有)的数据。所以你分配内存,对数据做一些事情并将分配的内存返回给调用者的事实很好。只需记录该函数的工作方式(就像 strdup() 在 C 字符串上工作,调用者负责对任何返回的非 NULL 指针使用 free() )。

FWIW,您不会“共享”数据。调用者调用函数代表它对数据进行处理,一旦函数返回,就不再发生访问。如果存在(由函数)保留的内存指针(或其他数据),则将这种情况描述为共享数据是正确的。因为在将来的某个时候,可能会以某种方式使用保留的内存指针(或其他数据)。

于 2012-09-14T22:46:41.787 回答
1

没有明确的“这个比另一个好”。我从来没有真正考虑过这些事情,只是做任何想到的事情。对于手头的问题,这可能是更“自然”的解决方案。如果结果证明它是“坏的”......好吧,幸运的是我们不是通过在石碑上雕刻来编程。

在您的情况下,根本不了解该软件,没有什么“感觉”更好。这实际上很常见。您在编程中所做的几乎所有事情都可以以不同的方式完成,并且通常除了个人喜好或只是随机的“这就是我首先想到的”之外没有实际的区别。

例如,您的第二个解决方案让调用者复制到现有内存,这可能是更大对象的一部分。另一方面,他每次都必须提供目标内存。尽管这也可能意味着通过仅使用一个内存块进行多次调用来节省分配。对于简单的情况,第一个解决方案似乎稍微方便一些,但在这种情况下会“锁定”用户:总是分配一个新的内存块。

于 2012-09-14T22:57:02.563 回答