代码之家  ›  专栏  ›  技术社区  ›  Nate

因为我不能返回一个局部变量,从C或C++函数返回字符串的最好方法是什么?

  •  18
  • Nate  · 技术社区  · 17 年前

    this question :

    据我所见,这应该如预期的那样工作:

    void greet(){
      char c[] = "Hello";
      greetWith(c);
      return;
    }
    

    但这将导致未定义的行为:

    char *greet(){ 
      char c[] = "Hello";
      return c;
    }
    

    如果我是对的,那么修复第二个问候函数的最佳方法是什么?在嵌入式环境中?在桌面上?

    8 回复  |  直到 9 年前
        1
  •  33
  •   Community Mohan Dere    6 年前

    你说得对。第二个例子中的c数组是在堆栈上分配的,因此内存将立即被重用。特别是,如果你有

     printf("%s\n",greet());
    

    您将得到奇怪的结果,因为对printf的调用会重用数组的一些空间。

    char c[] = "Hello";
    
    char * greet() {
        return c;
    }
    

    会有用的。另一种选择是在范围内静态分配:

    char * greet() {
        static char c[] = "Hello";
        return c;
    }
    

    第三种选择是通过malloc在堆上分配它:

    char * greet() {
       char * c = (char *) malloc(strlen("Hello")+1);  /* +1 for the null */
       strcpy(c, "Hello");
       return c;
    }
    

    但是现在你必须确保以某种方式释放内存,否则你就有内存泄漏。

    更新

    其中一件事似乎比我想象的更令人困惑,那就是“内存泄漏”到底是什么。泄漏是指动态分配内存,但由于地址丢失而无法释放。这些示例都不一定有泄漏,但只有第三个示例可能有泄漏,因为它是唯一动态分配内存的实例。因此,假设第三个实现,您可以编写以下代码:

    {
        /* stuff happens */
        printf("%s\n", greet());
    }
    

    printf 使用它,然后它就丢失了;你不能再释放它了。另一方面,

    {
        char * cp ;
        /* stuff happens */
        cp = greet();
        printf("%s\n", cp);
        free(cp);
    }
    

    泄漏,因为指针保存在自动变量中 cp 足够长的时间打电话 free() 在上面。现在,尽管cp一旦执行通过了end brace就消失了,但是由于free已经被调用,内存被回收并且没有泄漏。

        2
  •  12
  •   Greg Hewgill    17 年前

    如果您使用C++,那么您可能需要考虑使用 std::string 要从第二个函数返回字符串:

    std::string greet() {
        char c[] = "Hello";
        return std::string(c); // note the use of the constructor call is redundant here
    }
    

    或者,在单线程环境中,您可以执行以下操作:

    char *greet() {
        static char c[] = "Hello";
        return c;
    }
    

    这个 static 这里在全局内存区域中分配空间,它永远不会消失。这个 静止的 然而,这种方法充满了危险。

        3
  •  9
  •   Evan Teran    17 年前

    char* greet()
    {
      char* ret = malloc(6 * sizeof(char)); // technically " * sizeof(char)" isn't needed since it is 1 by definition
      strcpy(ret,"hello");
      return ret;
    }
    

    注意,您应该稍后调用free()来清理。如果您没有访问动态分配的权限,则需要使其成为全局或堆栈上的变量,但在调用堆栈的更高层。

        4
  •  7
  •   j_random_hacker    17 年前

    std::string

    malloc() 正如Jesse Pepper建议的那样;但是另一种避免动态分配的方法是 greet() 拿一个 char * 参数并将其输出写入:

    void greet(char *buf, int size) {
        char c[] = "Hello";
    
        if (strlen(c) + 1 > size) {
            printf("Buffer size too small!");
            exit(1);
        }
    
        strcpy(buf, c);
    }
    

    这个 size

        5
  •  5
  •   Johannes Schaub - litb    17 年前

    您可以使用以下任一选项:

    char const* getIt() {
        return "hello";
    }
    
    char * getIt() {
        static char thing[] = "hello";
        return thing;
    }
    
    char * getIt() {
        char str[] = "hello";
        char * thing = new char[sizeof str];
        std::strcpy(thing, str);
        return thing;
    }
    
    shared_array<char> getIt() {
        char str[] = "hello";
        shared_array<char> thing(new char[sizeof str]);
        std::strcpy(thing.get(), str);
        return thing;
    }
    

    第一种方法要求不写入返回的字符串,但也是最简单的方法。最后一个使用共享的数组,如果对内存的引用丢失(最后一个共享的数组超出范围),它可以自动清理内存。如果每次调用函数时都需要新字符串,则必须使用last和second last。

        6
  •  4
  •   Steve Rowe    17 年前

    最好是强制调用方为您提供内存,然后将字符串复制到内存中。这样打电话的人会注意到他/她需要清理。

        7
  •  1
  •   user50264    17 年前

    char *greet(char *buf, int size) {
         char *str = "Hello!"
         if (strlen(str) + 1 > size) { // Remember the terminal null!
              return NULL;
         } 
         strcpy(buf, str);
         return buf;
    }
    
    void do_greet() {
        char buf[SIZE];
        if (greet(buf, SIZE) == NULL) {
            printf("Stupid C");
         } 
         else {} // Greeted!
    }
    

    一个简单的任务需要大量的工作。。。但有C代表你:-) 哎呀!我想我被随机黑客打败了。。。

        8
  •  0
  •   dmckee --- ex-moderator kitten    17 年前

    在堆中分配字符数组?

    是否可以使用 malloc