1

可能重复:
从函数返回“本地”char* 与从函数返回“本地”int* 之间的区别

这是一个简单的代码,其中 3 个不同的函数[localStrPtr, localIntPtr, localCharPtr]在各自的函数中返回一个指向它们的局部变量[string, integer, char]的指针。

代码:

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

编译日志:

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 返回“一些垃圾”,而 localIntPtr 和 localCharPtr 返回“预期”值。

但是,在函数localStrPtr中,如果我更改char str[20]-to-> char* str = (char*) malloc (20), localStrPtr 会正确返回字符串“abcd”。这是运行日志,一旦进行了上述更改。

新的运行日志:

localStrPtr = abcd
localIntPtr = 8
localCharPtr = y

问题:

[1] 在函数 localIntPtr 和 localCharPtr 中,返回的局部变量地址的内容 WORKED,但对于函数 localStrPtr, “仅”使用 malloc返回正确的值,而不会使用 local char str[20]。为什么它不适用于 str[20] 而与局部变量 char 和 int 一起使用?

[2] 为什么我们在 COMPILE LOG 中看到以下所有 3 个函数的行?

  • stringManip.c:27:警告:函数返回局部变量的地址
  • stringManip.c:34:警告:函数返回局部变量的地址
  • stringManip.c:41:警告:函数返回局部变量的地址
4

5 回答 5

8

您不能从函数返回局部变量。局部变量存在于堆栈中,一旦函数完成,堆栈空间就会被释放,可供下一个函数调用使用。

如果您使用 malloc 它会在堆上分配内存。函数结束时不会释放此内存,因此您可以将其返回,并且该内存仍分配在调用函数的空间中(这也是 malloc 会导致内存泄漏但本地数组不会导致内存泄漏的原因)。

这并不像看起来那么清楚,因为返回值总是按值传递。如果您返回一个本地 int,它会返回该 int 的值并且它工作正常。如果您返回一个本地数组,它会返回指向该数组的指针的值,如果该指针不再指向内存的有用部分,那就不行了。

于 2013-01-09T00:20:36.500 回答
3

如果您在函数中声明变量,它将成为该函数的本地变量,因此,当该函数结束时,它会释放其所有局部变量。由于您要返回指向将自动释放的内存空间的指针,因此您犯了错误并收到警告。使用 malloc,您从进程虚拟内存(堆)中请求空间,并且您对该内存负责:您请求它,因此您应该释放它(当您想要时,但如果您想要,则不要。这是必须做的)。

仅将 C 内存分配视为稍后初始化/分配的工具是错误的,远不止于此。

所以,对于你的第二个问题,我上面的回答几乎已经解释过了,但基本上就是编译器所说的:你正在返回只属于你的本地函数的东西的地址。您可能正在返回指向垃圾的指针。

[编辑] 还有一件事:返回和“非引用传递的参数”是变量的副本,而不是“THE”变量。这很重要,因此您了解为什么它会起作用,例如,如果您有:

int localIntPtr(){
 int hi;
 ...
 return hi;
}

希望这可以帮助。

于 2013-01-09T00:30:48.507 回答
1

编译器日志中的警告是有原因的。您永远不应该返回指向局部变量的指针。这些变量使用的内存可以随时重复使用。这就是为什么您在输出中看到垃圾的原因localStrPtr()。你很幸运,其他两个函数的输出是正确的。保证会发生这种情况。

usingmalloc()按预期工作的原因是因为它分配的内存不会被回收,除非你通过相应的调用明确告诉计算机这样做free()。对于局部变量,计算机可以随时重用内存。

于 2013-01-09T00:31:24.763 回答
1

正如编译器所提到的,您正在返回堆栈上的地址。完成返回后,堆栈中的值可能会或可能不会被稍后传入的其他函数调用覆盖。您获得 int 或 char 的事实只是机会。如果您printf( "localIntPtr = %d\n", *pInt );在再次返回之前发出另一个,您可能会看到 pInt 已经被覆盖。

于 2013-01-09T00:35:47.440 回答
0

虽然到目前为止给出的答案很好地解释了为什么永远不能接受返回指向局部变量的指针,但还有使用 malloc() 的替代方法。最常见的一种是传入一个指向需要填充的数据的指针。例如,我们可以将一个空的 char 数组传递给一个用字符串填充它的函数。或者我们可以将一个指向整数的指针传递给一个用值填充指针的函数。

在函数中分配内存,只是为了让函数可以返回指向某些数据的指针,这通常是一个糟糕的选择。它强制该函数的调用者释放数据[否则会发生泄漏,这是一件坏事]。最好有一个函数允许调用者在调用函数中自由分配或使用局部变量。

显然,在某些情况下,这意味着必须将同一个变量从较低层的函数传递到几层函数调用,然后传递给填充某些内容的“顶层”函数,然后在返回的路上,它在各个层次上得到处理,并且可能还存储在 malloc 的内存位置。这是非常好的做法,应该受到鼓励。

只有当数据量以前未知时才应使用 malloc,因此调用者将无法知道要分配多少内存,或者数据实际上需要存储一段时间,并且局部变量不会“做”。但始终记得释放分配的内存。

于 2013-01-09T00:45:57.250 回答