C“错误:函数返回局部variables的地址”
我是C的初学者,我正在自学。 我正在创build以下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 ... }
我基本上试图返回一个附加的string,但我得到以下错误:
“错误:函数返回局部variables的地址”,有什么build议,如何解决这个问题?
局部variables的生命周期只在其定义的块内部扩展。 当他的控制超出了定义局部variables的块之外时,variables的存储就不再被分配(不保证)。 因此,使用variables的生命周期以外的variables的内存地址将是未定义的行为。 其他
另一方面,您可以执行以下操作。
char *str_to_ret = malloc (sizeof (char) * required_size); . . . return str_to_ret;
并使用str_to_ret
来代替。 当return
str_to_ret
, malloc
分配的地址将被返回。 malloc
分配的malloc
是从堆中分配的,这个堆的使用时间跨越了整个程序的执行。 因此,您可以在程序运行期间随时访问任意块的内存位置。
另外请注意,在完成分配的内存块之后,将其free
以免内存泄漏是一个好习惯。 释放内存后,将无法再访问该块。
这一行:
char b = "blah";
不好 – 你的左翼需要成为一个指针。
你的代码也有堆栈溢出的危险,因为你的recursion检查不是限制x的递减值。
无论如何,你正在得到的实际错误信息是因为char a
是一个自动variables; 您return
的那一刻将不复存在。 你需要的东西不是一个自动variables。
a
是函数的本地数组。一旦函数返回它不再存在,因此你不应该返回一个局部variables的地址。
换句话说, a
的生命周期在函数的作用域( {
, }
)内,如果你返回一个指向它的指针,那么你的指针指向的是一些无效的内存。 这些variables也被称为自动variables,因为它们的生命周期是自动pipe理的,你不需要明确地pipe理它们。
既然你需要扩展variables来保持超出函数的范围,你需要在堆上分配一个数组并返回一个指针。
char *a = malloc(1000);
这样数组a
驻留在内存中,直到你在相同的地址上调用一个free()
。
不要忘了这样做,否则你最终会发生内存泄漏。
实践:
我现在正在教我一个C的朋友的基本概念 – 并想出了这个非常简单和直接的(我希望如此)代码示例,基本上解释了一切。 不想把你藏起来! 🙂
#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标准在外面是“未定义的”。 通过使用malloc,你可以从HEAP (程序范围)中获取内存,而不是从STACK (function范围) – 从外部看到它的“可见”。 第二个正确的方法是通过引用来调用 。 这里你定义了父范围内的var,因此它使用了STACK(因为父范围是main() )。
概要:
3种方法做到这一点,其中一个是虚假的。 C是一种笨拙的只有一个函数返回一个dynamic大小的String。 要么你必须malloc然后释放它,否则你必须通过引用来调用。 或者使用C ++;)
a
是在函数中本地定义的,不能在函数外部使用。 如果你想从函数返回一个char
数组,你需要dynamic分配它:
char *a = malloc(1000);
并在某些时候在返回的指针上free
调用。
你也应该在这行看到一个警告: char b = "blah";
:你正试图给字符分配一个string。
malloc或通过引用调用都不需要。 您可以在函数中声明一个指针,并将其设置为您想要返回的string/数组。
以@ 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; }
char b = "blah";
应该:
char *b = "blah";