我非常了解C,但我对临时存储的工作原理感到困惑。
就像函数返回时一样,在该函数内发生的所有分配都被释放(从堆栈中或者实现决定这样做)。
例如:
void f() {
int a = 5;
} // a's value doesn't exist anymore
但是,我们可以使用return
关键字将一些数据传输到外部世界:
int f() {
int a = 5;
return a;
} // a's value exists because it's transfered to the outside world
如果有任何错误,请阻止我。
现在这是奇怪的事情,当你使用arrays
执行此操作时,它不起作用。
int []f() {
int a[1] = {5};
return a;
} // a's value doesn't exist. WHY?
我知道数组只能通过指针访问,并且你不能像其他数据结构那样传递数组而不使用指针。这是你无法返回数组并在外界使用它们的原因吗?因为它们只能通过指针访问?
我知道我可以使用动态分配将数据保存到外部世界,但我的问题是关于临时分配。
谢谢!
答案 0 :(得分:10)
当您返回某些内容时,会复制其值。 a
在第二个示例中,不在函数外部存在;它的价值确实如此。 (它作为右值存在。)
在上一个示例中,您隐式将数组a
转换为int*
,并返回该副本。 a
的生命终结,你指着垃圾。
永远不会有任何变量超出其范围。
答案 1 :(得分:1)
在第一个示例中,数据被复制并返回到调用函数,但是第二个返回一个指针,因此指针被复制并返回,但是指向的数据被清除。
答案 2 :(得分:0)
在C I的实现中(主要用于嵌入式8/16位微控制器),在调用函数时为堆栈中的返回值分配空间。
在调用函数之前,假设堆栈是这样的(行可以表示各种长度,但都是固定的):
[whatever]
...
当调用例程(例如sometype myFunc(arg1,arg2)
)时,C会将函数的参数(返回值的参数和空间,它们都是固定长度)抛出到堆栈,后跟返回地址以继续执行代码,并可能备份一些处理器寄存器。
[myFunc local variables...]
[return address after myFunc is done]
[myFunc argument 1]
[myFunc argument 2]
[myFunc return value]
[whatever]
...
当函数完全完成并返回到它被调用的代码时,它的所有变量都已从堆栈中释放出来(理论上它们可能仍然存在,但有< em>没有保证)
在任何情况下,为了返回数组,你需要在其他地方为它分配空间,然后将地址返回到第0个元素。
有些编译器会将返回值存储在处理器的临时寄存器中,而不是使用堆栈,但这种情况很少见(仅在某些AVR编译器上看到过)。
答案 3 :(得分:0)
当您尝试返回本地分配的数组时,调用函数会获得一个指针,指向用于的数组在堆栈中的位置。这可能会造成一些非常令人毛骨悚然的崩溃,在以后,其他东西会写入数组,并且会破坏堆栈帧...如果被破坏的帧在调用序列中很深,那么它可能直到很久才会显现出来。调试此类错误令人抓狂的是,真正的错误(返回本地数组)可以使其他一些绝对完美的功能爆炸。
答案 4 :(得分:0)
你仍然返回一个内存地址,你可以尝试检查它的值,但是它指向的内容在函数范围之外是无效的,所以不要将值与引用混淆。
答案 5 :(得分:0)
int []f() {
int a[1] = {5};
return a;
} // a's value doesn't exist. WHY?
首先,编译器不知道要返回的数组大小。我在使用你的代码时遇到了语法错误,但是使用了typedef,我得到了一个错误,表示函数不能返回数组,我知道。
typedef int ia[1];
ia h(void) {
ia a = 5;
return a;
}
其次,你不能这样做。你也做不到
int a[1] = {4};
int b[1];
b = a; // Here both a and b are interpreted as pointer literals or pointer arithmatic
虽然你没有这样写出来,并且编译器实际上甚至不需要为它生成任何代码,但是这种操作必须在语义上发生才能实现这一点,以便可以使用新的变量名称引用函数返回的值。如果将它包含在结构中,则编译器可以很好地复制数据。
此外,在声明和sizeof语句之外(如果编译器具有该扩展名,则可能是操作类型)每当数组名称出现在代码中时,编译器都会将其视为指针文字或指针算术块这会产生一个指针。这意味着return语句看起来就像你返回了错误的类型 - 指针而不是数组。
如果你想知道为什么不能这样做 - 它就是不能。编译器可以隐含地考虑数组,就好像它在结构中并使它发生一样,但这不是C标准所说的那样。