从函数返回不带malloc的字符串



是否可以从函数返回字符串而不调用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,否则在函数中定义的字符数组将是临时值。另一种解决方案是将字符数组作为参数传递给函数,并将其用作输出参数。

从函数返回字符串有三种常用方法。(好吧,实际上没有,但是有三种常见的方法来返回指针到字符串,调用者可以使用它来访问字符串。)

  1. 在函数内部使用malloc()为字符串分配空间。这是最灵活的方法,但它使调用者负责free()分配的数组。

  2. 要求调用者为字符串分配空间并传递指向该空间的指针。这给打电话的人带来了一些不便。特别是,调用者必须决定字符串的大小。

  3. 返回一个指向函数内部定义的static数组(第一个元素)的指针。函数返回后,数组将继续存在,但只有一个副本,这意味着后续调用将破坏前一次调用返回的结果。这也意味着数组必须有固定的大小,在编写代码时选择。

看情况

您可以决定并记录返回的字符串是指向某个静态内部缓冲区的指针。那么你的例程就不是可重入的(也不是线程安全的)。例如ctimegetpwent就是这样做的。

更好的方法是传递结果字符串和size作为参数,并填充该字符串并可能返回该字符串。getcwd(或snprintfstrftime,它返回一个大小,而不是指针)是这样工作的。

但是通常,您决定并记录返回的字符串是堆分配的,并且它是free的调用者的责任。在这种情况下,您可能需要使用strdupasprintf

你可以在你的整个程序中使用Boehm的保守垃圾收集器(例如使用它的GC_STRDUPGC_MALLOC_ATOMIC来处理字符串,GC_MALLOC来处理包含一些指针的堆值)

如果您觉得标准的mallocstrdup太慢了(但请先测量一下),您可以使用自己的池分配器,等等。

您也可以有替代方案(但重要的是要记录它们)。例如,您可以返回一些内部字符串,甚至是一个规范的内部字符串(有时称为"夸克"或"符号")-然后能够使用指针相等而不是字符串相等。你也可以有一些参考计数器方案。看看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++中所做的,对于短字符串,它实际上不会分配。

请注意,如果这工作,它将是线程安全的。(这里依赖全局变量的其他解决方案不是线程安全的)

只需在函数中声明字符串为静态并返回它。

相关内容

  • 没有找到相关文章

最新更新