2013-07-23 71 views
3

在C中,函数可能会返回指向该函数动态分配的内存的指针,并要求调用代码释放它。通常要求调用代码向第二个函数提供缓冲区,第二个函数然后设置该缓冲区的内容。例如:返回一个指向动态分配结构的指针,而不是从调用函数分配内存?

struct mystruct { 
    int a; 
    char *b; 
}; 


struct mystruct *get_a_struct(int a, char*b) 
{ 
    struct mystruct *m = malloc(sizeof(struct mystruct)); 
    m->a = a; 
    m->b = b; 

    return m; 
} 

int init_a_struct(int a, char*b, struct mystruct *s) 
{ 
    int success = 0; 
    if (a < 10) { 
     success = 1; 
     s->a = a; 
     s->b = b; 
    } 

    return success; 
} 

是一种方法还是其他方法?我可以想到两个参数:对于get_a_struct方法,调用代码被简化了,因为它只需要返回结构体;对于init_a_struct方法来说,由于调用代码本身可能分配了内存,因此调用代码将不能动态分配内存,因此调用代码将失败。

+0

您不能释放()由.dll分配的结构。 (至少我不认为你可以。)所以,如果你正在搞乱dll,要小心。 – Jiminion

+0

init_a_struct可以更有效率,因为结构可以重用。 –

+0

@Jim然后让.dll提供一个可以释放给定结构的函数。 – glglgl

回答

1

我认为,提供已分配结构作为一个参数是最好的,因为在大多数情况下,你不会需要调用malloc /释放calloc调用代码,因此担心free'ing它。例如:

int init_struct(struct some_struct *ss, args...) 
{ 
    // init ss 
} 

int main() 
{ 
    struct some_struct foo; 
    init_struct(&foo, some_args...); 
    // free is not needed 
} 
1

的“在优选传递一个指针”,除非它的绝对必需的每个对象是由于某种原因后勤“从堆中分配新对象” - 例如它将作为一个节点放入一个链表中,链表处理程序最终会通过调用free来销毁这些元素 - 或者其他情况,其中“从这里创建的所有东西将在稍后进入free”。

注意,“不叫malloc”始终是如果可能,首选的解决方案。不仅呼唤malloc需要一定的时间,这也意味着一些地方,你将不得不调用free上分配的内存,和每一个分配的对象需要几个字节的“开销”(通常为12-40个字节) - 对于小对象,所以分配空间肯定是浪费

+0

感谢您的回答。很长一段时间,我没有真正使用动态内存分配进行编程,但最近我已经越来越多地使用它,因为我认为它的灵活性。 – Nate

+1

我希望有一个函数返回一个新的内存块,而不是从调用者接收它的唯一时间是,如果有人需要做大量的工作,将结果存储在某个位置,然后才能知道缓冲区的大小将需要。否则,我会建议有一个函数,可以给它一个指向缓冲区的指针并指示它的大小,或者要求指出它需要的缓冲区大小。 – supercat

3

这要看具体的情况,但总体供应分配的缓冲区似乎是更可取的。

正如吉姆提到的,如果调用的函数分配内存的DLL可能会导致问题。如果您决定将代码作为Dll进行分发,并且将get_a_struct导出到/可由DLL的用户看到,则会是这种情况。然后,用户必须从文档中找出是否应该使用免费,删除或其他操作系统特定功能释放内存。此外,即使他们使用正确的函数释放内存,他们也可能使用不同版本的C/C++运行时。这可能会导致很难找到的错误。检查this Raymond Chen发布或搜索“内存分配dll边界”。典型的解决方案是从DLL中导出自己的免费函数。所以你会得到这对:get_a_struct/release_a_struct。

在另一方面,有时只被调用函数知道需要分配的内存量。在这种情况下,被调用函数进行分配更有意义。如果这是不可能的,比如说由于DLL边界问题,一个典型的丑陋的解决方案是提供一种机制来查找这些信息。例如在Windows中,GetCurrentDirectory函数将返回所需的缓冲区大小,如果您传递0和NULL作为其参数。

0

我同意路过分配struct优先其他的答案,但有一个情况下返回一个指针,可以首选。

如果你需要在结尾处明确释放一些资源(关闭一个文件或套接字,或者释放结构内部的某些内存,或者加入一个线程或其他需要C++析构函数的东西),我认为内部分配可能会更好,然后返回指针。

我认为这是因为在C中,它意味着某种契约:如果你分配你自己的struct,你不应该做任何事情来销毁它,它会在结束时自动清除功能。另一方面,如果你收到了一些动态分配的指针,你最终不得不调用某些东西来摧毁它,这个函数就是你需要的其他清理任务,freefree

相关问题