返回一个用malloc分配的字符串?

时间:2014-04-09 19:09:09

标签: c malloc

我正在创建一个返回字符串的函数。字符串的大小在运行时是已知的,因此我计划使用malloc(),但我不想让用户在使用我的函数后让用户负责调用free() #39; s返回值。

如何实现这一目标?返回字符串(char *)的其他函数如何工作(例如getcwd()_getcwd()GetLastError()SDL_GetError())?

6 个答案:

答案 0 :(得分:5)

您的挑战是某些需要释放资源(即导致free()发生)。

通常,调用者可以通过直接调用free()来释放分配的内存(例如,查看strdup用户如何工作),或者通过调用您提供换行free的函数来释放已分配的内存。例如,您可能需要呼叫者呼叫foo_destroy功能。正如另一张海报所指出的,可能选择将其包装在不透明的struct中,尽管这不是必需因为拥有自己的分配和销毁功能即使没有(例如,用于资源跟踪)。

然而,另一种方法是使用某种形式的清理功能。例如,在分配字符串时,您可以将其附加到池中分配的资源列表,然后在完成后立即释放池。这就是apache2apr_pool结构一起使用的方式。一般情况下,您不会free()具体在该模型下的任何内容。请参阅here和(更易于阅读)here

你不能在C中做什么(因为没有malloc() d结构的引用计数)直接决定了对象的最后一个'引用'何时超出范围然后释放它。那是因为你没有引用,你有指针。

最后,您询问现有函数如何返回char *个变量:

  • 有些(在某些情况下,如strdupget_current_dir_namegetcwd)希望来电者可以免费使用。

  • 有些(在其他情况下,如strerror_rgetcwd)期望调用者传入足够大小的缓冲区。

  • 有些人都这样做:来自getcwd手册页:

  

作为POSIX.1-2001标准的扩展,Linux(libc4,libc5,glibc)getcwd()动态分配缓冲区   如果malloc(3)buf,请使用NULL。在这种情况下,分配的缓冲区长度为size,除非size为零,何时为   buf根据需要分配。调用者应该free(3)返回的缓冲区。

  • 有些人使用内部静态缓冲区,因此不是可重入/线程安全的(哎呀 - 不要这样做)。请参阅strerror以及发明strerror_r的原因。

  • 有些只返回指向常量的指针(所以重入是好的),并且不需要空闲。

  • 有些(例如libxml)要求您使用单独的free函数(在这种情况下为xmlFree()

  • 有些(如apr_palloc)依赖于上面的池技术。

答案 1 :(得分:1)

无法在C 中执行 。您必须传递带有大小信息的参数,以便可以在被调用函数中调用malloc()free(),或者调用函数必须在malloc()之后调用。

许多面向对象的语言(例如C ++)以执行您想要的方式处理内存,而不是C.

修改

通过大小 信息作为参数,我的意思是让被调用的函数知道您传递的指针拥有多少字节的内存。这可以通过直接查看被调用的字符串来完成,如果已经为其分配了值,例如:

char test1[]="this is a test";
char *test2="this is a test";  

当这样调用时:

readString(test1); // (or test2) 

char * readString(char *abc)
{
    int len = strlen(abc);
    return abc;
}

这两个参数都会导致len = 14

然而 如果您创建一个非填充变量,例如:

char *test3; 

并分配相同数量的内存,但不要填充它,例如:

test3 = malloc(strlen("this is a test") +1);  

被调用函数无法知道已分配的内存。 len的第一个原型中的变量readString()将== 0。但是,如果您将原型readString()更改为:

readString(char *abc, int sizeString);  Then size information as an argument can be used to create memory:    

void readString(char *abc, size_t sizeString)
{
    char *in;
    in = malloc(sizeString +1);

    //do something with it  
    //then free it
    free(in);

}  

示例电话:

int main()
{
     int len;
     char *test3;

     len =  strlen("this is a test") +1; //allow for '\0'  
     readString(test3, len);
     // more code
     return 0;
}

答案 2 :(得分:1)

许多库强制用户处理内存分配。这是个好主意,因为每个应用程序都有自己的对象生存和重用模式。图书馆尽可能少地假设其用户是很好的。

假设用户想要像这样调用您的库函数:

for (a lot of iterations)
{ 
    params = get_totally_different_params();
    char *str = your_function(params);
    do_something(str);
    // now we're done with this str forever
}

如果您的libary malloc每次都是字符串,那么调用malloc会浪费很多精力,并且如果malloc每次选择不同的块,可能会显示缓存行为不佳。

根据您图书馆的具体情况,您可能会这样做:

int output_size(/*params*/);
void func(/*params*/, char *destination);

其中destination的大小至少为output_size(params),或者您可以执行类似套接字recv API的操作:

int func(/*params*/, char *destination, int destination_size);

返回值为:

< desination_size: this is the number of bytes we actually used
== destination_size: there may be more bytes waiting to output

这些模式在重复调用时都表现良好,因为调用者可以反复重复使用相同的内存块而无需任何分配。

答案 3 :(得分:0)

你无法在C中执行此操作。

返回一个指针,由调用该函数的人调用free

或者使用C ++。 shared_ptr

答案 4 :(得分:0)

您可以将其包装在不透明的结构中。

允许用户访问指向结构的指针,但不能访问其内部指针。创建一个释放资源的功能。

void release_resources(struct opaque *ptr);

当然用户需要调用该函数。

答案 5 :(得分:0)

您可以跟踪分配的字符串并在atexit例程(http://www.tutorialspoint.com/c_standard_library/c_function_atexit.htm)中释放它们。在下面,我使用了一个全局变量,但如果你有一个方便的话,它可以是一个简单的数组或列表。

#include <stdlib.h>
#include <string.h>
#include <malloc.h>
char* freeme = NULL;
void AStringRelease(void)
{
    if (freeme != NULL)
        free(freeme);
}
char* AStringGet(void)
{
    freeme = malloc(20);
    strcpy(result, "A String");
    atexit(AStringRelease);
    return freeme;
}