我是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 ...
}
我基本上是在尝试返回附加的字符串,但是我收到以下错误:
“错误:函数返回局部变量的地址”,任何建议,如何解决这个问题?
答案 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";