这是一个简单的代码,其中3个不同的函数 [localStrPtr,localIntPtr,localCharPtr] 返回指向其局部变量 [string,integer,char] 的指针他们各自的职能。
CODE:
#include <stdio.h>
char* localStrPtr (char*);
int* localIntPtr (int, int);
char* localCharPtr (char);
main()
{
int *pInt;
char *pChar;
printf( "localStrPtr = %s\n", localStrPtr("abcd") );
pInt = (int*) localIntPtr(3, 5);
printf( "localIntPtr = %d\n", *pInt );
pChar = (char*) localCharPtr('y');
printf( "localCharPtr = %c\n", *pChar );
}
char* localStrPtr(char* argu)
{
char str[20];
// char* str = (char*) malloc (20);
strcpy (str, argu);
return str;
}
int* localIntPtr (int argu1, int argu2)
{
int local;
local = argu1 + argu2;
return (&local);
}
char* localCharPtr (char argu)
{
char local;
local = argu;
return (&local);
}
COMPILE LOG:
stringManip.c: In function `localStrPtr':
stringManip.c:27: warning: function returns address of local variable
stringManip.c: In function `localIntPtr':
stringManip.c:34: warning: function returns address of local variable
stringManip.c: In function `localCharPtr':
stringManip.c:41: warning: function returns address of local variable
运行日志:
localStrPtr =
localIntPtr = 8
localCharPtr = y
正如您在日志文件中看到的那样,localStrPtr返回“some garbage”,而localIntPtr和localCharPtr返回“expected”值。
但是,在函数 localStrPtr 中,如果我更改char str[20]
-to-&gt; char* str = (char*) malloc (20)
,localStrPtr正确返回字符串“abcd”。一旦进行了上述更改,这是RUN LOG。
NEW RUN LOG:
localStrPtr = abcd
localIntPtr = 8
localCharPtr = y
问题:
[1]在函数localIntPtr和localCharPtr中,返回的局部变量的内容解决了WORKED,但对于函数localStrPtr,使用malloc返回“only”的正确值,但不会使用local char STR [20]。为什么在使用局部变量char和int?
时不能使用str [20][2]为什么我们在COMPILE LOG中看到所有3个函数的下面几行?
答案 0 :(得分:8)
您无法从函数返回局部变量。局部变量存在于堆栈中,一旦函数完成,该堆栈空间就会被释放,并可供下一个函数调用使用。
如果使用malloc,它会在堆上分配内存。当函数结束时,不会释放此内存,因此您可以返回它,并且该内存仍然在调用函数的空间中分配(这也是为什么malloc可能导致内存泄漏,但本地数组不会)。
这并不像看起来那么清晰,因为返回值总是按值传递。如果返回一个本地int,它将返回该int的值,并且它可以正常工作。如果返回一个本地数组,它将返回指向该数组的指针的值,如果该指针不再指向内存的有用部分,则该指针将无法正常运行。
答案 1 :(得分:3)
如果在函数中声明变量,它将成为该函数的本地变量,因此,当该函数结束时,它将释放其所有局部变量。因为你正在返回一个指向那个将自动释放的内存空间的指针,所以你犯了一个错误并收到警告。 使用malloc,你需要从进程虚拟内存(堆)中获取空间,并且你承担了对该内存的责任:你要求它,所以你应该释放它(当你想要的时候,但如果你想要的话则不是。必须这样做)。
将C内存分配仅仅视为后续初始化/分配的工具是一个错误,远不止于此。
所以,对于你的第二个问题,几乎在我上面的答案中解释,但基本上是编译器所说的:你正在返回只属于你的本地函数的东西的地址。你可能正在返回指向垃圾的指针。
[编辑]还有一件事:返回和'非引用传递参数'是变量的副本而不是'THE'变量。这很重要,所以你理解为什么它可以工作,例如,如果你有:
int localIntPtr(){
int hi;
...
return hi;
}
希望这有帮助。
答案 2 :(得分:1)
编译器日志中的警告是有原因的。您永远不应该返回指向局部变量的指针。这些变量使用的内存可以随时重用。这就是您在localStrPtr()
输出中看到垃圾的原因。你很幸运,其他两个函数的输出是正确的。这不保证会发生。
使用malloc()
按预期工作的原因是因为它分配了一些内存,在您通过相应的free()
调用明确告诉计算机这样做之前,这些内存不会被回收。对于局部变量,计算机可以随时重用内存。
答案 3 :(得分:1)
正如编译器提到的那样,你在堆栈上返回一个地址。在您返回之后,堆栈中的值可能会被或稍后可能会被其他函数调用覆盖。你获得int或char的事实只是机会。如果您在再次返回之前发出另一个printf( "localIntPtr = %d\n", *pInt );
,则可能会发现pInt已被覆盖。
答案 4 :(得分:0)
虽然到目前为止给出的答案很好地解释了为什么返回指向局部变量的指针是绝对不可接受的,但是有使用malloc()的替代方法。最常见的是传入一个指向需要填充的数据的指针。例如,我们可以将一个空的char数组传递给一个用字符串填充它的函数。或者我们可以将一个指向整数的指针传递给一个用值填充指针的函数。
要在函数中分配内存,只能使函数返回指向某些数据的指针,通常是一个不好的选择。它强制该函数的调用者释放数据[或者会有泄漏,这是一件坏事]。最好有一个允许调用者自由地在调用函数中分配或使用局部变量的函数。
显然,在某些情况下,这意味着必须将相同的变量从功能的较低层传递到几层函数调用到填充内容的“顶部”函数,然后在返回的路上进行处理在各个级别,也可能存储在malloc的内存位置。这是非常好的做法,应该受到鼓励。
只有当数据量以前未知时才应使用Malloc,因此调用者无法知道要分配多少内存,或者实际需要存储数据一段时间,并且本地变量赢了“ t“做”。但总是想要释放分配的内存。