简体   繁体   English

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

[英]Return a string allocated with malloc?

I'm creating a function that returns a string. 我正在创建一个返回字符串的函数。 The size of the string is known at runtime, so I'm planning to use malloc() , but I don't want to give the user the responsibility for calling free() after using my function's return value. 字符串的大小在运行时是已知的,所以我打算使用malloc() ,但是在使用函数的返回值之后,我不想让用户负责调用free()

How can this be achieved? 怎么能实现这一目标? How do other functions that return strings ( char * ) work (such as getcwd() , _getcwd() , GetLastError() , SDL_GetError() )? 返回字符串( char * )的其他函数如何工作(例如getcwd()_getcwd() getcwd() _getcwd()GetLastError()SDL_GetError() )?

Your challenge is that something needs to release the resources (ie cause the free() to happen). 你的挑战是的东西需要释放资源(即引起free()发生)。

Normally, the caller frees the allocated memory either by calling free() directly (see how strdup users work for instance), or by calling a function you provide the wraps free . 通常,调用者可以通过直接调用free()释放分配的内存free()例如,查看strdup用户如何工作),或者通过调用您提供的包装函数来free You might, for instance, require callers to call a foo_destroy function. 例如,您可能需要调用者调用foo_destroy函数。 As another poster points out you might choose to wrap that in an opaque struct , though that's not necessary as having your own allocation and destroy functions is useful even without that (eg for resource tracking). 正如另一张海报所指出的,你可能会选择将它包装在一个不透明的struct ,尽管这并不是必需的,因为拥有自己的分配和销毁功能即使没有它也是有用的(例如用于资源跟踪)。

However, another way would be to use some form of clean-up function. 但是,另一种方法是使用某种形式的清理功能。 For instance, when the string is allocated, you could attach it to a list of resources allocated in a pool, then simply free the pool when done. 例如,在分配字符串时,您可以将其附加到池中分配的资源列表,然后在完成后立即释放池。 This is how apache2 works with its apr_pool structure. 这就是apache2如何与其apr_pool结构一起工作。 In general, you don't free() anything specifically under that model. 通常,您不会free()特定于该模型下的任何内容。 See here and (easier to read) here . 这里和(更易于阅读) 在这里

What you can't do in C (as there is no reference counting of malloc() d structures) is directly determine when the last 'reference' to an object goes out of scope and free it then. 你不能在C中做什么(因为没有malloc() d结构的引用计数)直接决定了对象的最后一个'引用'何时超出范围然后释放它。 That's because you don't have references, you have pointers. 那是因为你没有引用,你有指针。

Lastly, you asked how existing functions return char * variables: 最后,您询问现有函数如何返回char *变量:

  • Some (like strdup , get_current_dir_name and getcwd under some circumstances) expect the caller to free. 一些(如strdupget_current_dir_namegetcwd在某些情况下)期望调用者释放。

  • Some (like strerror_r and getcwd in under other circumstances) expect the caller to pass in a buffer of sufficient size. 一些(在其他情况下像strerror_rgetcwd )期望调用者传入足够大小的缓冲区。

  • Some do both: from the getcwd man page: 有些人都这样做:来自getcwd手册页:

As an extension to the POSIX.1-2001 standard, Linux (libc4, libc5, glibc) getcwd() allocates the buffer dynamically using malloc(3) if buf is NULL . 作为POSIX.1-2001标准的扩展,如果bufNULL ,则Linux(libc4,libc5,glibc) getcwd()使用malloc(3)动态分配缓冲区。 In this case, the allocated buffer has the length size unless size is zero, when buf is allocated as big as necessary. 在这种情况下,分配的缓冲区具有长度size除非size为零,当buf根据需要分配时。 The caller should free(3) the returned buffer. 调用者应free(3)返回的缓冲区。

  • Some use an internal static buffer and are thus not reentrant / threadsafe (yuck - do not do this). 有些使用内部静态缓冲区,因此不是可重入/线程安全的(哎呀 - 不要这样做)。 See strerror and why strerror_r was invented. 请参阅strerror以及为什么发明了strerror_r

  • Some only return pointers to constants (so reentrancy is fine), and no free is required. 有些只返回指向常量的指针(所以重入是好的),并且不需要空闲。

  • Some (like libxml ) require you to use a separate free function ( xmlFree() in this case) 一些(如libxml )要求您使用单独的free函数(在这种情况下为xmlFree()

  • Some (like apr_palloc ) rely on the pool technique above. 有些(比如apr_palloc )依赖于上面的池技术。

There is no way to do this in C . 在C中没有办法做到这一点。 You have to either pass a parameter with size information, so that malloc() and free() can be called in the called function, or the calling function has to call free after malloc() . 您必须传递一个带有大小信息的参数,以便可以在被调用函数中调用malloc()free() ,或者调用函数必须在malloc()之后调用free。

Many object oriented languages (eg. C++) handle memory in such a way as to do what you want to, but not C. 许多面向对象的语言(例如C ++)以执行您想要的方式处理内存,但不处理C.

Edit 编辑

By size information as an argument, I mean something to let the called function know the how many bytes of memory are owned by the pointer you are passing. 通过大小信息作为参数,我的意思是让被调用的函数知道你传递的指针拥有多少字节的内存。 This can be done by looking directly at the called string if it has already been assigned a value, such as: 这可以通过直接查看被调用的字符串来完成,如果已经为其分配了值,例如:

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

when called like this: 当像这样调用时:

readString(test1); // (or test2) 

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

Both of those arguments will result in len = 14 这两个参数都将导致len = 14

However if you create a non populated variable, such as: 但是,如果您创建一个非填充变量,例如:

char *test3; 

And allocate the same amount of memory, but do not populate it, for example: 并分配相同数量的内存,但不要填充它,例如:

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

There is no way for the called function to know what memory has been allocated. 被调用函数无法知道已分配的内存。 The variable len will == 0 inside the 1st prototype of readString() . 变量len将在readString()的第一个原型中== 0。 However, if you change the prototype readString() to: 但是,如果将原型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);

}  

example call: 示例电话:

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

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

Many libraries force the user to deal with memory allocation. 许多库强制用户处理内存分配。 This is a good idea because every application has its own patterns of object lifetime and reuse. 这是个好主意,因为每个应用程序都有自己的对象生存和重用模式。 It's good for the library to make as few assumptions about its users as possible. 图书馆尽可能少地对其用户做出假设是有好处的。

Say a user wants to call your library function like this: 假设用户想要像这样调用您的库函数:

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
}

If your libary malloc s the string every time, it is wasting a lot of effort calling malloc , and possibly showing poor cache behavior if malloc picks a different block each time. 如果你的libary malloc每次都是字符串,那么调用malloc就会浪费很多精力,如果malloc每次选择一个不同的块,可能会显示不良的缓存行为。

Depending on the specifics of your library, you might do something like this: 根据库的具体情况,您可能会执行以下操作:

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

where destination is required to be at least output_size(params) size, or you could do something like the socket recv API: 其中destination需要至少为output_size(params)大小,或者您可以执行类似socket recv API的操作:

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

where the return value is: 返回值为:

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

These patterns both perform well when called repeatedly, because the caller can reuse the same block of memory over and over without any allocations at all. 这些模式在重复调用时都表现良好,因为调用者可以反复重复使用相同的内存块而无需任何分配。

You cannot do this in C. 你不能用C做到这一点。

Return a pointer and it is up to the person calling the function to call free 返回一个指针,由调用该函数的人free调用

Alternatively use C++. 或者使用C ++。 shared_ptr etc shared_ptr

You can wrap it in a opaque struct. 您可以将其包装在不透明的结构中。

Give the user access to pointers to your struct but not its internal. 允许用户访问指向结构的指针,但不能访问其内部指针。 Create a function to release resources. 创建一个释放资源的功能。

void release_resources(struct opaque *ptr);

Of course the user needs to call the function. 当然用户需要调用该函数。

You could keep track of the allocated strings and free them in an atexit routine ( http://www.tutorialspoint.com/c_standard_library/c_function_atexit.htm ). 您可以跟踪分配的字符串并在atexit例程中释放它们( http://www.tutorialspoint.com/c_standard_library/c_function_atexit.htm )。 In the following, I have used a global variable but it could be a simple array or list if you have one handy. 在下面,我使用了一个全局变量,但如果你有一个方便的话,它可以是一个简单的数组或列表。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM