error:函数返回局部变量的地址

时间:2012-09-12 03:19:44

标签: c return strcpy strcat

我是C的初学者,我正在自学。 我正在创建以下功能:

char *foo(int x){
     if(x < 0){
        char a[1000];
        char b = "blah";
        x = x - 1;
        char *c = foo(x);
        strcpy(a, b);
        strcat(a, c);
        return a;
      }
    blah ...
}

我基本上是在尝试返回附加的字符串,但是我收到以下错误:

“错误:函数返回局部变量的地址”,任何建议,如何解决这个问题?

8 个答案:

答案 0 :(得分:38)

局部变量的生命周期仅在定义它的块内部延伸。当控件超出定义局部变量的块之外时,不再分配(不保证)变量的存储。因此,使用变量的生命周期区域之外的变量的内存地址将是未定义的行为。

另一方面,您可以执行以下操作。

 char *str_to_ret = malloc (sizeof (char) * required_size);
  .
  .
  .
 return str_to_ret;

然后使用str_to_ret代替。当return str_to_ret时,将返回malloc分配的地址。由malloc分配的内存是从堆中分配的,其堆的生命周期跨越程序的整个执行。因此,您可以在程序运行时随时随地访问内存位置。

另请注意,在完成分配的内存块后,free可以节省内存泄漏,这是一个很好的做法。释放内存后,您无法再次访问该块。

答案 1 :(得分:8)

我想出了这个简单直接(我希望如此)的代码示例,它应该解释自己!

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

/* function header definitions */
char* getString();                     //<- with malloc (good practice)
char * getStringNoMalloc();  //<- without malloc (fails! don't do this!)
void getStringCallByRef(char* reference); //<- callbyref (good practice)

/* the main */
int main(int argc, char*argv[]) {

    //######### calling with malloc
    char * a = getString();
    printf("MALLOC ### a = %s \n", a); 
    free(a);

    //######### calling without malloc
    char * b = getStringNoMalloc();
    printf("NO MALLOC ### b = %s \n", b); //this doesnt work, question to yourself: WHY?
    //HINT: the warning says that a local reference is returned. ??!
    //NO free here!

    //######### call-by-reference
    char c[100];
    getStringCallByRef(c);
    printf("CALLBYREF ### c = %s \n", c);

    return 0;
}

//WITH malloc
char* getString() {

    char * string;
    string = malloc(sizeof(char)*100);

    strcat(string, "bla");
    strcat(string, "/");
    strcat(string, "blub");

    printf("string : '%s'\n", string);

    return string;
}

//WITHOUT malloc (watch how it does not work this time)
char* getStringNoMalloc() {

     char string[100] = {};

     strcat(string, "bla");
     strcat(string, "/");
     strcat(string, "blub");
     //INSIDE this function "string" is OK
     printf("string : '%s'\n", string);

     return string; //but after returning.. it is NULL? :)
}

// ..and the call-by-reference way to do it (prefered)
void getStringCallByRef(char* reference) {

    strcat(reference, "bla");
    strcat(reference, "/");
    strcat(reference, "blub");
    //INSIDE this function "string" is OK
    printf("string : '%s'\n", reference);
    //OUTSIDE it is also OK because we hand over a reference defined in MAIN
    // and not defined in this scope (local), which is destroyed after the function finished
}

编译时,会收到[预期]警告:

me@box:~$ gcc -o example.o example.c 
example.c: In function ‘getStringNoMalloc’:
example.c:58:16: warning: function returns address of local variable [-Wreturn-local-addr]
         return string; //but after returning.. it is NULL? :)
            ^~~~~~

...基本上我们在这里讨论的内容!

运行我的示例产生此输出:

me@box:~$ ./example.o 
string : 'bla/blub'
MALLOC ### a = bla/blub 
string : 'bla/blub'
NO MALLOC ### b = (null) 
string : 'bla/blub'
CALLBYREF ### c = bla/blub 

理论值:

User @phoxis已经很好地回答了这个问题。 基本上这样考虑一下: {} 之间的所有内容都是本地范围,因此C-Standard是&#34; undefined&# 34;外。 通过使用malloc,您可以从 HEAP (程序范围)而不是 STACK (功能范围)中获取内存 - 因此它可以看到&#39;从外面。 第二种正确的方法是按引用调用。在这里定义父范围内的var,因此它使用STACK(因为父范围是 main())。

要点:

3种做法,其中一种是假的。 C是一种笨拙的函数,只需要一个函数返回一个动态大小的字符串。您必须使用malloc然后释放它,或者您必须按引用调用。或者使用C ++;)

答案 2 :(得分:6)

不需要malloc或通过引用调用。您可以在函数中声明一个指针,并将其设置为您想要返回的字符串/数组。

使用@ Gewure的代码作为基础:

char *getStringNoMalloc(void){
    char string[100] = {};
    char *s_ptr = string;

    strcat(string, "bla");
    strcat(string, "/");
    strcat(string, "blub");
    //INSIDE this function "string" is OK
    printf("string : '%s'\n", string);

    return s_ptr; 
}

完美无缺。

在原始问题中使用非循环版本的代码:

char *foo(int x){    
    char a[1000];
    char *a_ptr = a;
    char *b = "blah";       

    strcpy(a, b);

    return a_ptr;
}

答案 3 :(得分:3)

这一行:

char b = "blah";

不好 - 你的左值必须是指针。

您的代码也存在堆栈溢出的危险,因为您的递归检查不会限制x的递减值。

无论如何,你得到的实际错误信息是因为char a是一个自动变量;你return它将不复存在的那一刻。你需要的不是自动变量。

答案 4 :(得分:2)

a是函数的局部数组。一旦函数返回它就不再存在,因此你不应该返回局部变量的地址。
换句话说,a 生命周期 属于该函数的范围({}),如果您返回指向它的指针是指向一些无效的内存的指针。此类变量也称为 自动 变量,因为它们的生命周期是自动管理的,您无需明确管理它。

由于您需要将变量扩展为超出函数范围,因此您需要在堆上分配数组并返回指向它的指针。

char *a = malloc(1000); 

这样,数组a就会驻留在内存中,直到您在同一地址呼叫free()
不要忘记这样做或最终导致内存泄漏。

答案 5 :(得分:1)

a在函数中本地定义,不能在函数外部使用。如果要从函数返回char数组,则需要动态分配它:

char *a = malloc(1000);

在某些时候,在返回的指针上调用free

您还应该在此行看到警告:char b = "blah";:您正在尝试将字符串文字分配给char

答案 6 :(得分:0)

所有答案都很好地说明了问题。

但是,我想添加其他信息。

当我想要输出a时,我遇到了同样的问题 成为向量。

在这种情况下,常见的解决方案是将输出声明为函数本身的参数。这样,变量的alloc和存储信息所需的物理空间将在函数外部进行管理。解释经典解决方案的伪代码是:

void function(int input, int* output){
    //...
    output[0] = something;
    output[1] = somethig_else;
    //...
    return;
}

在这种情况下,问题中的示例代码应更改为:

void foo(int x, char* a){
     if(x < 0){
        char b = "blah";
        //...
        strcpy(a, b);
        //..
        return;
      }
    //..
}

答案 7 :(得分:-2)

char b = "blah"; 

应该是:

char *b = "blah";