我已阅读以下帖子:
Is returning a heap-allocated pointer from function OK?
这表明可以返回指向堆分配变量的指针。但是,指针在技术上是否是“堆栈分配的变量”,则该变量将在函数返回时被释放?
例如:
int* test(){
int arr[5];
int *ptr = arr;
return ptr; //deallocated ptr?
}
int *test2(){
int arr[5];
return arr;
}
正在测试
也可以说 arr是一个指针,它指向一些新创建的int数组arr,指向&arr[0]
。如果arr
不是指针,为什么返回满足函数返回类型的有效吗?
既然ptr和arr都是堆栈分配的,为什么代码只能在test()
而不是test2()
中工作? test()是否给出未定义的行为?
答案 0 :(得分:5)
如果访问返回的值,它们都将是undefined behaviour。因此,它们都不是“ OK”。
您正试图返回一个指向块范围变量的指针,该变量的存储持续时间为auto
。因此,一旦作用域结束,变量的生命周期就结束了。
引用C11
,第6.2.4 / P2章,关于生存期(强调矿山)
对象的生存期是程序执行期间存储空间的一部分 保证为其保留。对象存在,具有恒定地址并保留 它在整个生命周期中的最后存储值。 如果在对象之外引用对象 一生中,行为是不确定的 [...]
然后,从P5开始,
一个其标识符声明为没有链接且没有存储类的对象 说明符静态具有自动存储期限, [...]
和
对于这样一个不具有可变长度数组类型的对象,其寿命会延长 从进入与其关联的块开始,直到该块的执行结束 任何方式。 [...]
因此,在您的情况下,变量arr
具有自动存储功能,并且其生存期仅限于函数体。该地址返回给呼叫者后,尝试访问该地址处的内存将是UB。
哦,在C标准中没有“堆栈”或“堆”,我们所拥有的只是变量的生存期。
答案 1 :(得分:2)
test
和test2()
都是等效的。它们返回您不能取消引用的实现定义的指针,否则将导致UB。
如果不取消引用返回的指针,则调用test()
或test2()
不会导致未定义的行为,但是这样的功能可能不是很有用。
答案 2 :(得分:1)
输入功能后,新的堆栈框架将添加到堆栈中。堆栈帧是存储所有auto(函数中声明的非静态变量)的位置。当我们离开函数时,返回值放置在CPU的一个寄存器(通常为R0)中,然后减小堆栈指针以删除堆栈帧。然后,将控制权返回到调用函数的位置,然后从寄存器中获取返回值。
因此,在这种情况下,您有int arr[5]
,当程序进入函数时,新的堆栈框架将添加到堆栈中。在此堆栈帧中,数组中有5个整数的内存,变量arr
实际上确实等效于指向数组中第一个元素的指针。当您返回变量arr
时,您将返回一个指向堆栈框架中数据的指针,当该函数退出并返回至上一个函数时,堆栈指针将减小以删除您所使用的函数的堆栈框架刚刚退出。
指针仍指向内存中我们之前分配了数组的位置。因此,当堆栈增加时,arr
指向的内存将被覆盖。更改返回值指向的数据可能会导致某些非常“令人兴奋”的事情发生,因为我们不知道现在何时使用内存。
数组与指针示例:
char arr[5];
char * ptr = arr;
在这种情况下,编译器知道arr
的大小,但不知道ptr
的大小,因此我们可以执行sizeof(arr),并且编译器将在编译时进行计算。在运行时,它们是内存中的等效值。
答案 3 :(得分:0)
两种情况在技术上都是相同的。
在两种情况下,都返回指向arr的指针。虽然返回的指针的值确实指向用于包含arr的内存,但是arr已从内存中释放。
因此,有时在访问指针时,您仍会在此处找到arr的内容,这些内容刚好尚未被覆盖。有时,您可能会在此内存被覆盖后访问它,并得到未定义的数据甚至是分段错误。
答案 4 :(得分:0)
您仍然似乎对指针也是一个自动变量感到困惑,因此,即使返回指向某个有效内存(例如静态数组)的指针,您也担心它会无效。
重要的是要记住,在C中,所有参数和返回值的传递均通过值完成。如果您像return p;
中那样“返回指针”,则其机制与如果您“返回整数”,例如return i;
:变量的 value 会复制到某个地方并由调用方获取。对于i
,该值可能是42;在p
的情况下,值可以是3735928559(或换句话说,是0xdeadbeef)。该值表示内存中的位置,例如因为函数返回,所以数组在不存在之前就已经存在。复制的地址超过42个更改时,该地址不会更改,并且完全独立于曾经包含该地址的变量p
的生存期-毕竟是及时复制了它。< sup> 1
1 这超出了问题的范围,但从概念上技术上,将为返回值创建一个临时对象。在现代C ++中,临时者的生存期和语义得到了更系统的分类。