是否可以从函数返回字符串而不调用malloc
?我有一个函数如下:
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;
}
然后当我调用getString()
时,我将返回值赋给char*
,然后在我完成后释放它,就像下面一样:
void randomFunction(){
char* line = NULL;
int i = 0;
while (i < 1000) {
line = getString();
// do stuff with line
free (line);
line = NULL;
}
}
然而,我想知道如果没有malloc
,是否有任何方法可以做到这一点?而且,这是从C函数返回字符串的正确方式吗?我试图做一些关于如何返回没有malloc
的研究,但没有找到明确的答案。我是C的新手,还在学习中。
不能从函数返回临时值,除非使用malloc,否则在函数中定义的字符数组将是临时值。另一种解决方案是将字符数组作为参数传递给函数,并将其用作输出参数。
从函数返回字符串有三种常用方法。(好吧,实际上没有,但是有三种常见的方法来返回指针到字符串,调用者可以使用它来访问字符串。)
-
在函数内部使用
malloc()
为字符串分配空间。这是最灵活的方法,但它使调用者负责free()
分配的数组。 -
要求调用者为字符串分配空间并传递指向该空间的指针。这给打电话的人带来了一些不便。特别是,调用者必须决定字符串的大小。
-
返回一个指向函数内部定义的
static
数组(第一个元素)的指针。函数返回后,数组将继续存在,但只有一个副本,这意味着后续调用将破坏前一次调用返回的结果。这也意味着数组必须有固定的大小,在编写代码时选择。
看情况
您可以决定并记录返回的字符串是指向某个静态内部缓冲区的指针。那么你的例程就不是可重入的(也不是线程安全的)。例如ctime
或getpwent
就是这样做的。
getcwd
(或snprintf
或strftime
,它返回一个大小,而不是指针)是这样工作的。
但是通常,您决定并记录返回的字符串是堆分配的,并且它是free
的调用者的责任。在这种情况下,您可能需要使用strdup
或asprintf
。
你可以在你的整个程序中使用Boehm的保守垃圾收集器(例如使用它的GC_STRDUP
或GC_MALLOC_ATOMIC
来处理字符串,GC_MALLOC
来处理包含一些指针的堆值)
如果您觉得标准的malloc
或strdup
太慢了(但请先测量一下),您可以使用自己的池分配器,等等。
您也可以有替代方案(但重要的是要记录它们)。例如,您可以返回一些内部字符串,甚至是一个规范的内部字符串(有时称为"夸克"或"符号")-然后能够使用指针相等而不是字符串相等。你也可以有一些参考计数器方案。看看Glib(来自GTK,但可以在GUI程序之外使用!)提供的示例:GString-s, GQuark-s,字符串实用程序
然而,决定结果是否为堆分配,并明确定义谁负责释放(以及如何释放)堆分配的结果是很重要的。
您可能希望使用valgrind来跟踪内存泄漏。不要忘记将-Wall -g
传递给gcc
编译器!
p。我会考虑使用Boehm的GC。我不认为malloc
(或strdup
, asprintf
....)应该因为性能原因而被拒绝(您可以选择其他一些&更快的malloc
实现,或者使用您自己的内存池)。然而,内存泄漏可能是一个问题。
由于字符串(显然)总是20个字符,您可以简单地这样做:
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
}
因为这避免了许多小的malloc,所以速度更快。
将内存分配移出函数的正常方法是通过传递指针。虽然在实践中你也想确保你没有超过缓冲区边界。
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
}
}
在C中这样做的一种常见方法是将字符串作为参数传递给函数。
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;
}
或者,您可以将字符串声明为静态,或者在文件或全局作用域,并将其复制到其中。但是,如果您在此符号中存储了一个指向堆分配缓冲区的指针,请确保在再次分配之前释放该指针。
我不是C语言专家,但我认为这在C语言中是可能的(这是基于c++解决方案)。当然,您需要知道字符串大小的界限(这里是99),但是您可以不分配就返回字符串,也不需要输出参数。
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;
}
我不确定这是否取决于C强制所谓的返回值优化。
我也不知道你是否想要不分配,因为你根本不能分配,或者只是为了性能。如果是第二个,你可以实现一个struct,当字符串不适合预定义的大小(这里是99)时,它会有条件地分配。
这基本上是std::string
在c++中所做的,对于短字符串,它实际上不会分配。
请注意,如果这工作,它将是线程安全的。(这里依赖全局变量的其他解决方案不是线程安全的)
只需在函数中声明字符串为静态并返回它。