可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Is it possible to return string from a function without calling malloc
?
I have a function as below:
char* getString(){
char tempStr[20]
// open file, read char by char and assign to tempStr
// ....
char* str = (char*)malloc(sizeof(char)*20);
strcpy(str, tempStr); // assume this copy the null terminating char as well
return str;
}
And then when I call the getString()
, I assign the return value to a char*
, and then free it when I'm done, just like below:
void randomFunction(){
char* line = NULL;
int i = 0;
while (i < 1000) {
line = getString();
// do stuff with line
free (line);
line = NULL;
}
}
However, I am wondering if there is any way to do this without malloc
? And, is this the proper way of returning string from a C function?
I tried to do some research regarding how to return without malloc
, but didn't find clear answers. I am new to C and still learning.
回答1:
You can not return temporary from a function and unless you use a malloc your character array defined in the function will be a temporary. An alterantive solution is to pass a character array as parameter to the function and use it as output parameter.
回答2:
There are three common ways to return a string from a function. (Well, actually there are none, but there are three common ways to return a pointer to a string, which the caller can then use to access the string.)
Allocate space for the string using malloc()
inside the function. This is the most flexible method, but it makes the caller responsible for free()
ing the allocated array. It can also impose some performance overhead.
Require the caller to allocate space for the string and pass in a pointer to that space. This imposes some inconvenience on the caller. In particular, the caller has to decide how big the string can be.
Return a pointer to (the first element of) a static
array defined inside the function. The array will continue to exist after the function returns, but there's only one copy, which means that successive calls will clobber the result returned by previous calls. It also means the array has to be of some fixed size, chosen when you write the code.
回答3:
It depends.
You could decide and document that the returned string is a pointer to some static internal buffer. Then your routine is not re-entrant (nor thread-safe). For instance ctime
or getpwent
does that.
A better thing would be to pass the result string and size as arguments, and to fill that string and possibly return that. getcwd
(or snprintf
or strftime
which returns a size, not a pointer) works that way.
But usually, you decide and document that the returned string is heap allocated, and it is the responsability of the caller to free
it. You might want to use strdup
or asprintf
in that case.
And you might use in your entire program Boehm's conservative garbage collector (e.g. use its GC_STRDUP
or GC_MALLOC_ATOMIC
for strings, and GC_MALLOC
for heap values containing some pointers.)
If you feel that standard malloc
or strdup
is too slow (but please measure that first), you could have your own pool allocators, etc.
You could also have alternate schemes (but it is important to document them). For example, you could return some interned string, or even a canonical interned string (sometimes called "quark" or "symbol") - then be able to use pointer equality instead of string equality. You could also have some reference counter scheme. Look for example at what Glib (from GTK, but usable outside of GUI programs!) provides: GString-s, GQuark-s, string utilities
It is however important to decide if the result is heap allocated or not, and to define clearly who has the responsibility to free (and how should it be freed) that heap-allocated result.
You may want to use valgrind to chase memory leaks. Don't forget to pass -Wall -g
to your gcc
compiler!
PS. I would consider using Boehm's GC. And I don't think that malloc
(or strdup
, asprintf
....) should be rejected for performance reasons (you could chose some other & faster malloc
implementation, or use your own memory pools). However, memory leaks could be an issue.
回答4:
Since your string is (apparently) always 20 characters, you can simply do this:
void getString( char *outputString ) {
// do stuff to outputString instead of mallocing, or use local memory and copy it at the end
}
char line[20];
for( ... ) {
getString( line );
// do things with line
}
Because this avoids many small mallocs, it is faster.
回答5:
normal way to move the memory allocation out of a function is by passing in pointers. Though in practice you'd want to make sure you aren't going over buffer bounds also.
char* getString(char* tempStr){
// open file, read char by char and assign to tempStr
// ....
return tempStr;
}
void randomFunction(){
char line[20];
int i = 0;
while (i < 1000) {
getString(line);
// do stuff with line
}
}
回答6:
A common way to do this in C is to have the string passed in as an argument to the function.
char *getString(char *str, int size){
// open file, read char by char and assign to tempStr
// ....
strncpy(str, tempStr, size); // assume this copies the null terminator
return str;
}
Alternatively, you could have the string declared static, or at a file or global scope, and copy into it. However, make sure that if you store a pointer to a heap allocated buffer in this symbol that you free it before allocating again.
回答7:
I am not a C-guru, but I think this is possible in C. (This is based in a C++ solution.) Of course you need to know a bound for the string size (99 here), but you can return a string without allocating, no need for output parameters either.
https://onlinegdb.com/r1akUBiHB
#include <stdio.h>
#include <string.h>
typedef struct str_{
char c[99];
} str;
str fun(int i){
str ret;
if(i > 5) strcpy(ret.c, "big");
else strcpy(ret.c, "small");
return ret;
}
int main(int argc, char* argv[]){
str ret = fun(argc);
printf("%s", ret.c);
return 0;
}
I am not sure if this depends on C enforcing something called Return Value Optimization.
Also I don't know if you want no allocations because you can't at all or for performances only.
If it is the second you can implement a struct that conditionally allocates if the string doesn't fit in the predefined size (99 here).
This is basically what std::string
does in C++, for short strings it will not allocate in practice.
Note that if this works, it is going to be thread-safe as well. (Other solutions here relying on global variables are not thread safe.)
回答8:
Just declare the string as static in the function and return it.