从没有malloc的函数返回字符串

时间:2013-03-16 20:00:55

标签: c pointers 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的新手,还在学习。

8 个答案:

答案 0 :(得分:12)

您无法从函数返回临时值,除非您使用malloc,否则函数中定义的字符数组将是临时的。一种替代解决方案是将字符数组作为参数传递给函数,并将其用作输出参数。

答案 1 :(得分:12)

从函数返回字符串有三种常用方法。 (嗯,实际上没有,但有三种常用的方法可以将指针返回给字符串,然后调用者可以使用它来访问字符串。)

  1. 使用函数内的malloc()为字符串分配空间。这是最灵活的方法,但它使调用者负责free()分配的数组。它也会带来一些性能开销。

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

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

答案 2 :(得分:7)

取决于。

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

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

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

您可以在整个程序Boehm's conservative garbage collector中使用(例如,将GC_STRDUPGC_MALLOC_ATOMIC用于字符串,将GC_MALLOC用于包含某些指针的堆值。)

如果您认为标准mallocstrdup太慢(但请先测量一下),您可以拥有自己的池分配器等。

您也可以有替代方案(但记录它们很重要)。例如,您可以返回一些interned string,甚至是规范的实习字符串(有时称为“夸克”或“符号”) - 然后能够使用指针相等而不是字符串相等。你也可以有一些reference counter计划。例如,Glib(来自GTK,但可以在GUI程序之外使用!)提供:GString-sGQuark-sstring utilities

然而,重要的是确定结果是否已分配堆,并明确定义谁有责任释放(以及如何释放)堆分配结果。

您可能希望使用valgrind来追踪内存泄漏。不要忘记将-Wall -g传递给gcc编译器!

PS。我会考虑使用Boehm的GC。我不认为malloc(或strdupasprintf ....)因性能原因而被拒绝(您可以选择其他一些&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,然后将其返回。