关于C局部变量的生命周期。写了两个函数:struct TestNode* test_node1 (TestList *l) {TestNode tntn.n
关于C局部变量的生命周期。
写了两个函数:
struct TestNode* test_node1 (TestList *l) {
TestNode tn;
tn.n = 12;
printf("%p\n", &tn);
*l = &tn;
return &tn;
}
struct TestNode* test_node2 (TestList *l) {
TestNode *tn = (TestNode *) malloc (sizeof(struct TestNode));
tn -> n = 12;
printf("%p\n", &tn);
*l = tn;
return tn;
}
第一个函数 程序编译的时候警告,不能返回局部变量的地址,而第二种方式确不发出警告,函数的局部变量不是放在栈中吗?当函数调用结束的时候不是栈空间会北回收吗,那么局部变量的地址被外部变量所引用的时候,那么这快栈中的数据会变无效吗?之类就想不通啊
[解决办法]
内存中的每个字节永远都存在。夸张点说,即使电脑断电了,也不能说它就消失不存在了。
所谓“回收”只是表示那个字节中的内容将来可能会被修改以用作它途;但也可能直到你关机之前没人修改它。
[解决办法]
回收的概念有问题,这块储存空间(虚拟地址)是属于这个程序的,在这个程序结束前不会被其它程序访问到;只有可能被这个程序其它函数覆盖。
[解决办法] 订正一下,“动态分配的变量拥有的生命周期只限于函数调用期间”,应该是“局部变量拥有的生命周期只限于定义它的块内。
例如:
int fun1()
{
int i;
...
}
i的生命周期从定义到"}",离开这个函数,这个变量地址就不再有效了。
int fun1()
{
int i;
{
int j;
...
}
.....
}
同理,j的生命周期也只限于红色的部分,程序执行到红色的},这个变量也就不再有效了。
你错误了的理解的动态分配的变量。
动态分配的变量特指用malloc(c语言)或者用new(c++)分配的单个变量或者数组。(c99中好像可以定义动态数组,他也应该在堆中分配(待研究))在调用free(c)或者delete(c++)之前,他一直有效。动态分配的变量是放在堆中的,可分配一块很大的一块存储区,如果你的内存够大,分配一块1个GB的buffer也没有问题。它不像局部变量,局部变量是位于栈中的,连接器在链接程序的时候,对栈的大小是做了规定的,默认值是好像是1M,不信,你定义一个10M的数组试一试,看看能否工作。
[解决办法]有点问题。
1.lifetime和storage duration是两个概念。不像C++,C对storage duration只视为分类,
只说有几个而不是几种(因为本身就是种类):static, thread, automatic, allocated。所以说对象具有的storage duration不管对象在哪个函数中声明。而automatic对象的lifetime并不对应函数或函数作用域(函数作用域只适用于label而不是对象;作用域在C中其实也只是“几个”,特殊地,任意结束为止相同的作用域被视为等价),而是对应块作用域(当一个块是函数体的时候基本同LZ的理解)。
2.非static/_Thread_local修饰的automatic storage duration对象的确可以算“动态”——在运行时分配的,但分配多少还是静态确定的。而malloc得到的allocated storage duration对象反而是更正牌的“动态”。
------解决方案--------------------
不让你引用局部变量的地址是因为,局部变量在函数返回就被释放了。简单的说,原来局部变量所占用的空间会被其他的变量或者值覆盖掉。这点相信你已经明白了。
你不明白的是,返回一个变量的引用和返回一个指向malloc分配的内存的区别。
简单的说:你返回的局部变量的引用,变量的值分配在栈中,函数返回栈要被释放。
你返回的malloc分配的变量,变量的值分配的堆中,函数返回堆中的内存并没有被释放。
并且如果你不调用free(), 堆中的分配的那块内存知道程序结束也不会释放。
还有重要的一点,你会指向堆内存的指针,局部变量的值会被复制一份返回。
所以当 TestNode* tn = test_node2(); 返回给tn的值不过是局部变量的一个复制。