是否可以在不调用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的新手,还在学习。
答案 0 :(得分:12)
您无法从函数返回临时值,除非您使用malloc,否则函数中定义的字符数组将是临时的。一种替代解决方案是将字符数组作为参数传递给函数,并将其用作输出参数。
答案 1 :(得分:12)
从函数返回字符串有三种常用方法。 (嗯,实际上没有,但有三种常用的方法可以将指针返回给字符串,然后调用者可以使用它来访问字符串。)
使用函数内的malloc()
为字符串分配空间。这是最灵活的方法,但它使调用者负责free()
分配的数组。它也会带来一些性能开销。
要求调用者为字符串分配空间并传入指向该空间的指针。这给呼叫者带来了一些不便。特别是,调用者必须决定字符串的大小。
返回指向函数内定义的static
数组(的第一个元素)的指针。函数返回后,数组将继续存在,但只有一个副本,这意味着连续的调用将破坏先前调用返回的结果。这也意味着数组必须具有一定的固定大小,在编写代码时选择。
答案 2 :(得分:7)
取决于。
您可以决定并记录返回的字符串是指向某个静态内部缓冲区的指针。那么你的例程就不是可重入的(也不是线程安全的)。例如,ctime
或getpwent
可以做到这一点。
更好的方法是将结果字符串和size 作为参数传递,并填充该字符串并可能返回该字符串。 getcwd
(或返回大小而不是指针的snprintf
或strftime
就是这样做的。
但通常情况下,您决定并记录返回的字符串是堆分配的,并且调用者对free
的责任。在这种情况下,您可能希望使用strdup
或asprintf
。
您可以在整个程序Boehm's conservative garbage collector中使用(例如,将GC_STRDUP
或GC_MALLOC_ATOMIC
用于字符串,将GC_MALLOC
用于包含某些指针的堆值。)
如果您认为标准malloc
或strdup
太慢(但请先测量一下),您可以拥有自己的池分配器等。
您也可以有替代方案(但记录它们很重要)。例如,您可以返回一些interned string,甚至是规范的实习字符串(有时称为“夸克”或“符号”) - 然后能够使用指针相等而不是字符串相等。你也可以有一些reference counter计划。例如,Glib(来自GTK,但可以在GUI程序之外使用!)提供:GString-s,GQuark-s,string utilities
然而,重要的是确定结果是否已分配堆,并明确定义谁有责任释放(以及如何释放)堆分配结果。
您可能希望使用valgrind来追踪内存泄漏。不要忘记将-Wall -g
传递给gcc
编译器!
PS。我会考虑使用Boehm的GC。我不认为malloc
(或strdup
,asprintf
....)因性能原因而被拒绝(您可以选择其他一些&amp;更快malloc
实现,或使用自己的内存池)。但是,内存泄漏可能是一个问题。
答案 3 :(得分:2)
将内存分配移出函数的正常方法是传入指针。虽然在实践中你也想确保你不会超过缓冲区界限。
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
}
}
答案 4 :(得分:2)
由于你的字符串(显然)总是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,所以速度更快。
答案 5 :(得分:2)
在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;
}
或者,您可以将字符串声明为static,或者在文件或全局范围内,并将其复制到其中。但是,请确保如果您在此符号中存储指向堆分配缓冲区的指针,则在重新分配之前将其释放。
答案 6 :(得分:1)
我不是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强制执行所谓的“返回值优化”。
我也不知道您是否不需要分配,因为您根本无法分配或仅用于表演。 如果是第二个,则可以实现一个结构,该结构在字符串不适合预定义的大小(此处为99)时有条件地进行分配。
这基本上是std::string
在C ++中的工作,因为短字符串实际上不会分配。
请注意,如果这可行,那么它将也是线程安全的。 (这里依赖全局变量的其他解决方案也不是线程安全的。)
答案 7 :(得分:0)
只需在函数中声明字符串为static,然后将其返回。