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

Hel*_*rld 24 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 ...
}
Run Code Online (Sandbox Code Playgroud)

我基本上试图返回一个附加的字符串,但我收到以下错误:

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

pho*_*xis 43

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

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

 char *str_to_ret = malloc (sizeof (char) * required_size);
  .
  .
  .
 return str_to_ret;
Run Code Online (Sandbox Code Playgroud)

并使用str_to_ret相反.当returning时str_to_ret,malloc将返回分配的地址.分配的内存malloc是从堆中分配的,其堆的生命周期跨越程序的整个执行.因此,您可以在程序运行时随时随地访问内存位置.

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

  • 站点注释:解决方案中的封装/生命周期/责任设计缺陷:调用者初始化 Malloc - 但被调用者必须释放它。另外,如果您不清理/检查赋予函数的值,您可能会轻松地在堆中分配一个非常大的块...... (2认同)

Gew*_*ure 9

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

#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
}
Run Code Online (Sandbox Code Playgroud)

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

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? :)
            ^~~~~~
Run Code Online (Sandbox Code Playgroud)

......基本上我们在这里讨论的是什么!

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

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 
Run Code Online (Sandbox Code Playgroud)

理论:

用户@phoxis已经很好地回答了这个问题.基本上这样考虑一下:{}之间的所有东西都是局部范围,因此C-Standard在外面是"未定义的".通过使用malloc,您可以从HEAP(程序范围)获取内存,而不是从STACK(函数范围)获取内存- 因此它从外部"可见".第二种正确的方法是按引用调用.在这里定义父范围内的var,因此它使用STACK(因为父范围是main()).

摘要:

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


AuC*_*ire 7

不需要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; 
}
Run Code Online (Sandbox Code Playgroud)

完美地工作。

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

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

    strcpy(a, b);

    return a_ptr;
}
Run Code Online (Sandbox Code Playgroud)

  • @Shyri 这段代码有点缺陷,因为你怀疑的是 100% 真实的。一旦函数返回,就不能保证数组会被保留。尝试用 C++ 进行同样的操作。创建一个带有自定义析构函数的类。您会注意到,函数作用域一结束,就会调用析构函数。但您仍然可以访问该数组。国际海事组织这很危险。 (3认同)
  • 我对c完全陌生。根据先前的回答:使用按引用调用将使用在调用者范围内声明的变量,这就是为什么要保留它的原因,并且使用malloc需要在释放内存之后避免内存泄漏。这在这里如何适用?指针是在被调用函数的作用域内创建的,当我们要读取指针时,如何知道该指针所寻址的存储区域保持不变?谢谢 (2认同)
  • @Shyri [检查此代码示例](https://gist.github.com/arunanshub/62a87244f33349538ed0a06eb447f17c)。 (2认同)

pb2*_*b2q 2

a是在函数内部定义的,不能在函数外部使用。如果你想char从函数返回一个数组,你需要动态分配它:

char *a = malloc(1000);
Run Code Online (Sandbox Code Playgroud)

并在某个时刻调用free返回的指针。

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