简体   繁体   English

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

[英]error: function returns address of local variable

I'm beginner with C and I am learning on my own.我是 C 的初学者,我正在自学。 I am creating the following function:我正在创建以下功能:

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 ...
}

I am basically trying to return an appended string, but I get the following error:我基本上是想返回一个附加的字符串,但出现以下错误:

"error: function returns address of local variable", any suggestions, how to fix this? “错误:函数返回局部变量的地址”,有什么建议,如何解决这个问题?

The local variables have a lifetime which extends only inside the block in which it is defined.局部变量的生命周期仅在定义它的块内扩展。 The moment the control goes outside the block in which the local variable is defined, the storage for the variable is no more allocated (not guaranteed).当控制超出定义局部变量的块时,变量的存储不再分配(不保证)。 Therefore, using the memory address of the variable outside the lifetime area of the variable will be undefined behaviour.因此,在变量的生命周期区域之外使用变量的内存地址将是未定义的行为。

On the other hand you can do the following.另一方面,您可以执行以下操作。

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

And use the str_to_ret instead.并使用str_to_ret代替。 And when return ing str_to_ret , the address allocated by malloc will be returned.并且当return ing str_to_ret ,将返回malloc分配的地址。 The memory allocated by malloc is allocated from the heap, which has a lifetime which spans the entire execution of the program. malloc分配的malloc是从堆中分配的,它的生命周期跨越程序的整个执行过程。 Therefore, you can access the memory location from any block and any time while the program is running.因此,您可以在程序运行时随时从任何块访问内存位置。

Also note that it is a good practice that after you have done with the allocated memory block, free it to save from memory leaks.另请注意,在完成分配的内存块后,将其free以防止内存泄漏是一个很好的做法。 Once you free the memory, you can't access that block again.释放内存后,您将无法再次访问该块。

I came up with this simple and straight-forward (i hope so) code example which should explain itself!我想出了这个简单而直接(我希望如此)的代码示例,它应该可以自我解释!

#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
}

When compiling it, you get the [intended] warning:编译时,您会收到 [预期] 警告:

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? :)
            ^~~~~~

...basically what we are discussing here! ...基本上我们在这里讨论的是什么!

running my example yields this output:运行我的示例会产生以下输出:

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 

Theory:理论:

This has been answered very nicely by User @phoxis.用户@phoxis 已经很好地回答了这个问题。 Basically think about it this way: Everything inbetween { and } is local scope, thus by the C-Standard is "undefined" outside.基本上这样想: {} 之间的所有内容都是局部范围,因此根据 C-Standard 在外部是“未定义的”。 By using malloc you take memory from the HEAP (programm scope) and not from the STACK (function scope) - thus its 'visible' from outside.通过使用 malloc,您可以从HEAP (程序范围)而不是从堆栈(函数范围)中获取内存 - 因此它从外部“可见”。 The second correct way to do it is call-by-reference .第二种正确的方法是call-by-reference Here you define the var inside the parent-scope, thus it is using the STACK (because the parent scope is the main() ).在这里,您在父作用域内定义 var,因此它使用堆栈(因为父作用域是main() )。

Summary:概括:

3 Ways to do it, One of them false. 3 种方法,其中一种是错误的。 C is kind of to clumsy to just have a function return a dynamically sized String. C 有点笨拙,只是让函数返回一个动态大小的字符串。 Either you have to malloc and then free it, or you have to call-by-reference.要么你必须 malloc 然后释放它,要么你必须按引用调用。 Or use C++ ;)或使用 C++ ;)

Neither malloc or call by reference are needed.不需要 malloc 或按引用调用。 You can declare a pointer within the function and set it to the string/array you'd like to return.您可以在函数内声明一个指针并将其设置为您想要返回的字符串/数组。

Using @Gewure's code as the basis:使用@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; 
}

works perfectly.完美地工作。

With a non-loop version of the code in the original question:使用原始问题中代码的非循环版本:

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

    strcpy(a, b);

    return a_ptr;
}

a is an array local to the function.Once the function returns it does not exist anymore and hence you should not return the address of a local variable. a是函数的局部数组。一旦函数返回,它就不再存在,因此您不应返回局部变量的地址。
In other words the lifetime of a is within the scope( { , } ) of the function and if you return a pointer to it what you have is a pointer pointing to some memory which is not valid.换句话说, a生命周期在函数的范围( { , } )内,如果你返回一个指向它的指针,你所拥有的是一个指向某个无效内存的指针。 Such variables are also called automatic variabels because their lifetime is automatically managed you do not need to manage it explicitly.此类变量也称为自动变量,因为它们的生命周期是自动管理的,您无需显式管理它。

Since you need to extend the variable to persist beyond the scope of the function you You need to allocate a array on heap and return a pointer to it.由于您需要扩展变量以使其超出函数的范围,因此您需要在堆上分配一个数组并返回指向它的指针。

char *a = malloc(1000); 

This way the array a resides in memory untill you call a free() on the same address.这样,数组a驻留在内存中,直到您在同一地址上调用free()为止。
Do not forget to do so or you end up with a memory leak.不要忘记这样做,否则会导致内存泄漏。

This line:这一行:

char b = "blah";

Is no good - your lvalue needs to be a pointer.不好 - 你的左值需要是一个指针。

Your code is also in danger of a stack overflow, since your recursion check isn't bounding the decreasing value of x.您的代码也有堆栈溢出的危险,因为您的递归检查并未限制 x 的递减值。

Anyway, the actual error message you are getting is because char a is an automatic variable;无论如何,您得到的实际错误消息是因为char a是一个自动变量; the moment you return it will cease to exist.return的那一刻,它就不复存在了。 You need something other than an automatic variable.您需要的不是自动变量。

a is defined locally in the function, and can't be used outside the function. a在函数中本地定义,不能在函数外使用。 If you want to return a char array from the function, you'll need to allocate it dynamically:如果你想从函数返回一个char数组,你需要动态分配它:

char *a = malloc(1000);

And at some point call free on the returned pointer.并且在某些时候在返回的指针上调用free

You should also see a warning at this line: char b = "blah";您还应该在这一行看到警告: char b = "blah"; : you're trying to assign a string literal to a char . :您正在尝试将字符串文字分配给char

char b = "blah"; 

应该:

char *b = "blah"; 

All the answer explain the problem really good.所有的答案都很好地说明了问题。

However, I would like to add another information.但是,我想添加另一个信息。

I faced the same problem at the moment I wanted the output of a function to be a vector.当我希望函数的输出是向量时,我遇到了同样的问题。

In this situation, the common solution is to declare the output as an argument of the function itself.在这种情况下,常见的解决方案是将输出声明为函数本身的参数。 This way, the alloc of the variable and the physical space necessary to store the information are managed outside the function.这样, alloc变量和存储信息所必需的物理空间中的功能外管理。 Pseudocode to explain the classical solution is:解释经典解决方案的伪代码是:

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

In this case, the example code within the question should be changed in:在这种情况下,问题中的示例代码应更改为:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM