将本地指针变量的地址返回给main()函数

3
在以下示例中,函数func()返回一个指向本地指针变量的地址给main()函数。在GCC中运行良好。
那么,这是良好定义的行为吗?
#include <stdio.h>
#include <stdlib.h>

int *func(void);

int *func(void)
{
   int *p;
   p = malloc(sizeof *p);
   *p = 10;
   return p;
}

int main() 
{
    int *ptr = func();
    printf("%d\n",*ptr);
    return 0;
}

9
是的。是什么让你认为它不是呢?它返回的不是“指针变量的地址”,而是“指针变量的”(当然,这个值是一个地址)。 - user2371524
@FelixPalmen 在 func() 和 main() 函数中打印指针的地址相同。请参见 http://ide.geeksforgeeks.org/sULNzy - msc
你打印出来的不是指针的地址,而是指针的值。在func函数中,指针的地址应该是&p,在main函数中则应该是&ptr。当然,一个指针的值就是一个地址(但它指向的是对象的地址)。 - user2371524
4个回答

9

不,你不能返回一个指向局部变量的指针(即地址)。这样做就像是

int i = 10;
return &i;

相反,您返回在堆上分配的对象的指针。

但是,您确实存在内存泄漏问题,因为您没有在任何地方释放内存。调用free应该由调用您的函数的代码执行(除非它反过来返回指针,其中责任在调用链上传递)。


4
重申一遍,OP 正在返回指针的,而不是局部变量的地址 - Jonathon Reinhart
1
为了完整起见,可能需要提到,在OP的示例中,main()(或在printf()语句之后调用的其他函数)需要调用free(ptr)。如果在func()内释放了malloc分配的内存,在main()中访问*ptr将会产生未定义的行为。 - Peter

4
func()内部,p是指向由malloc()分配的内存的指针(或者是指向可能已分配的内存,因为malloc()可能会失败,返回空指针,这需要进行检查)。如果成功,这个内存分配将持续到显式地调用free为止。 p的值被返回到调用函数main()中。在这种情况下,p是指向成功分配的内存的指针,或者是一个空指针,并且被返回的值(它是临时的,不是一个左值)然后被赋值给ptr。所以,分配的存储可以通过ptr来访问,ptr是一个副本,保存了pfunc()返回之前的值,尽管p本身的生命周期已经结束,因为func()已经返回了。
当不再需要ptr时,当然要free它,以避免内存泄漏。如果malloc()失败,ptr就是一个空指针,这里有潜在的未定义行为。

1

这是完全有效的。

不能保证的是当函数返回并且堆栈帧缩小时,堆栈帧上的变量会发生什么。

你返回的是一块 malloc 的内存地址,而不是局部变量(在堆栈上分配的)。这与 strdup() 的工作方式非常相似。以下是从 这里 获取的 strdup() 实现。

char *
strdup(str)
    const char *str;
{
    size_t len;
    char *copy;

    len = strlen(str) + 1;
    if (!(copy = malloc((u_int)len)))
        return (NULL);
    bcopy(str, copy, len);
    return (copy);
}

这种方式的一个明显缺点(正如“Some programmer dude”所提到的那样)是释放内存的责任被转移给了调用者。

1

这是一段有效且正确的代码,尽管有点令人困惑。

该函数分配大小为int的内存。分配是通过解引用int类型的指针变量完成的。

在分配之后,将整数值10设置在内存中。 10应设置为整数(可能与编译器有关)。但绝对不会大于整数的大小,因此应该是安全的操作。

然后函数返回指针值。

在main()中,返回的指针设置为另一个整数指针。 这指向malloc()分配的原始内存。

之后,在printf()语句中打印解引用的整数指针。 这将打印值10。

缺少的是free()调用,这在这里不是好的行为。

这可以是孩子们进行良好学术锻炼的好机会。


1
“分配是通过取消 int 类型的指针变量来完成的。” 不,sizeof 只对表达式的 类型 进行操作。这里不会发生取消引用。 - user2371524

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接