C语言静态内存释放的问题,请大神指教
/*Dynamic.cpp--C语言静态内存释放的问题,请大神指教*/#include<stdio.h>#include<malloc.h>int*staticArr(v...
/*Dynamic.cpp -- C语言静态内存释放的问题,请大神指教*/
#include <stdio.h>
#include <malloc.h>
int * staticArr(void)
{
int arr[5] = {1, 2, 3, 4, 5};
arr[0] = 0;
arr[1] = 1;
arr[2] = 2;
arr[3] = 3;
arr[4] = 4;
return arr;
}
int main(void)
{
int * pArr;
pArr = staticArr();
printf("%d\n", *( pArr + 1) ); //这里能访问到staticArr创建的静态数组
return 0;
}
staticArr()函数结束后,arr数组所占的内存被释放了,释放是指内存被销毁,还是arr和内存单元首地址的连线断了呢。如果是第二种,那么为何还可以通过arr的地址访问数组。在函数结束的瞬间,系统做了哪些操作来完成释放这个动作?
第二个就是
int main(void)
{
int * pArr;
pArr = staticArr();
printf("%d\n", *( pArr + 1) );//这里可以访问到1
printf("%d\n", *( pArr + 2) );//这里不可访问2了,为什么只能第一次访问正确?
return 0;
}
静态内存释放收,只能访问一次正确值,后面的值都是不正确的。这是什么原因呢?
---------------------------------------------------------------------------------------------------------------
还有一个困扰我多年的问题,可以向您请教一下吗?
刚才那程序加了 int * p = (int *)malloc( sizeof(int) * 8); 确实无法访问arr数组了,即使访问 ,输出的也是一个错误值。
关键就是这个错误值,
当输出语句为:printf("%d\n", pArr[i]);
无论编译运行多少次,结果都是一样的 。
1
2
1
1245000
4249606
但是当输出语句变成了:printf("a[%d] = %d\n", i, pArr[i]);
输出结果也发生了变化
a[0] = 1
a[1] = 1
a[2] = 1245000
a[3] = 4249610
a[4] = 4337572
这是什么原因呢? 展开
#include <stdio.h>
#include <malloc.h>
int * staticArr(void)
{
int arr[5] = {1, 2, 3, 4, 5};
arr[0] = 0;
arr[1] = 1;
arr[2] = 2;
arr[3] = 3;
arr[4] = 4;
return arr;
}
int main(void)
{
int * pArr;
pArr = staticArr();
printf("%d\n", *( pArr + 1) ); //这里能访问到staticArr创建的静态数组
return 0;
}
staticArr()函数结束后,arr数组所占的内存被释放了,释放是指内存被销毁,还是arr和内存单元首地址的连线断了呢。如果是第二种,那么为何还可以通过arr的地址访问数组。在函数结束的瞬间,系统做了哪些操作来完成释放这个动作?
第二个就是
int main(void)
{
int * pArr;
pArr = staticArr();
printf("%d\n", *( pArr + 1) );//这里可以访问到1
printf("%d\n", *( pArr + 2) );//这里不可访问2了,为什么只能第一次访问正确?
return 0;
}
静态内存释放收,只能访问一次正确值,后面的值都是不正确的。这是什么原因呢?
---------------------------------------------------------------------------------------------------------------
还有一个困扰我多年的问题,可以向您请教一下吗?
刚才那程序加了 int * p = (int *)malloc( sizeof(int) * 8); 确实无法访问arr数组了,即使访问 ,输出的也是一个错误值。
关键就是这个错误值,
当输出语句为:printf("%d\n", pArr[i]);
无论编译运行多少次,结果都是一样的 。
1
2
1
1245000
4249606
但是当输出语句变成了:printf("a[%d] = %d\n", i, pArr[i]);
输出结果也发生了变化
a[0] = 1
a[1] = 1
a[2] = 1245000
a[3] = 4249610
a[4] = 4337572
这是什么原因呢? 展开
展开全部
首先这个数组不是静态数组,因为你没有写static关键字!
所以这个数组是局部数组,进入函数时创建,函数结束时撤销。
这个程序编译时一般会有警告——你返回了一个已撤销的数组的起始地址。
打个比方:你在旅馆里开了5间房,并把第一间房的房号作为函数值。
函数结束时,退了房,但房号(即地址)还是在的,但那房间却不属于你的了。
如果没有新人入住,那么里面的内容就没变。一旦新人入住,那么里面的内容就会改变。
直接看第二个程序:
1) pArr = staticArr();
2) printf("%d\n", *(pArr + 1));
3) printf("%d\n", *(pArr + 2));
第1行:pArr得到了已撤销的数组的起始地址。
第2行:调用printf函数之前,首先通过*(pArr+1)获取了这个已撤销数组的第一个元素的值,由于房间还没新人入住,所以可以得到原来的值。接着,就把这个值传给printf函数,注意它是复制了一份再发给printf函数的。
注意:所有函数在调用时所给出的实际参数都将被复制给被调函数的形式参数的——即函数的形式参数都是复制品。
现在调用printf函数——新人入住了,那个数组的房间现在分配给printf函数去用了,其中内容被改变,但是printf函数输出的是复制品,不是原件,所以“看起来没变”。
第3行:再次通过*(pArr + 2)取值的时候,就取到了被前一个printf函数改变以后留下的垃圾值,而且这个printf函数将再次改变这些房间,留下不同的垃圾值。
用任何方法输出这个已经不属于你的数组的内容,都是毫无意义的,因为它都是前一个printf函数结束工作后留下的垃圾数据。
如果你在数组定义前加static关键字,结果就不同了。
static int a[5] = {...};
不信,你就试一试!
所以这个数组是局部数组,进入函数时创建,函数结束时撤销。
这个程序编译时一般会有警告——你返回了一个已撤销的数组的起始地址。
打个比方:你在旅馆里开了5间房,并把第一间房的房号作为函数值。
函数结束时,退了房,但房号(即地址)还是在的,但那房间却不属于你的了。
如果没有新人入住,那么里面的内容就没变。一旦新人入住,那么里面的内容就会改变。
直接看第二个程序:
1) pArr = staticArr();
2) printf("%d\n", *(pArr + 1));
3) printf("%d\n", *(pArr + 2));
第1行:pArr得到了已撤销的数组的起始地址。
第2行:调用printf函数之前,首先通过*(pArr+1)获取了这个已撤销数组的第一个元素的值,由于房间还没新人入住,所以可以得到原来的值。接着,就把这个值传给printf函数,注意它是复制了一份再发给printf函数的。
注意:所有函数在调用时所给出的实际参数都将被复制给被调函数的形式参数的——即函数的形式参数都是复制品。
现在调用printf函数——新人入住了,那个数组的房间现在分配给printf函数去用了,其中内容被改变,但是printf函数输出的是复制品,不是原件,所以“看起来没变”。
第3行:再次通过*(pArr + 2)取值的时候,就取到了被前一个printf函数改变以后留下的垃圾值,而且这个printf函数将再次改变这些房间,留下不同的垃圾值。
用任何方法输出这个已经不属于你的数组的内容,都是毫无意义的,因为它都是前一个printf函数结束工作后留下的垃圾数据。
如果你在数组定义前加static关键字,结果就不同了。
static int a[5] = {...};
不信,你就试一试!
更多追问追答
追问
嗯,首先感谢你的回答。但是我还是有一个地方不太明白,希望能再次得到您的指点:
为什么执行printf("%d\n", *( pArr + 1 ) ); 会改变原来被释放的arr数组里面的值呢。
也就是说:
“现在调用printf函数——新人入住了,数组的房间现在分配给printf函数去用了,内容被改变“ 为什么那个数组房间会被分配给printf呢。printf是如何产生垃圾值 放到那个数组中的。
追答
一个函数投入运行时,它的变量才正式分配空间;
当函数结束时,就收回该函数所有变量的空间。
这就是局部变量的特点。而且“局部变量被保存在栈上”。
栈是“后进先出”的,这个大家都知道。现在看看变量是怎么分配在栈上的:
程序首先运行主函数,为它的变量分配了内存——位于栈顶。
然后主函数调用了staticArr函数,这时为staticArr函数的变量(包括数组)才分配空间——这些变量进栈了——注意它位于新的栈顶。
等到staticArr函数结束,回收它的变量(包括数组)的内存——退栈了,现在栈顶上是主函数的那些变量。
再接下来,主函数调用printf函数,现在为printf函数的变量分配空间——进栈!printf函数的变量正好是前面staticArr函数退栈腾出来的位置。
等到printf函数完成任务,也回收内存空间——退栈!
这里麻烦在于printf函数是系统库函数,里面到底有多少变量、数组,我们看不到。
而且它进栈的数据量有多大也不清楚。
但是这些变量一定与前面staticArr函数曾经的变量的位置是重叠的。
所以等printf函数结束以后,再去访问时那数组时,staticArr曾经放在那里数据早已被printf改变了。
总之一句话,不要把函数中的局部变量或数组的地址作为函数值返回,
因为在函数结束的时候,那些变量或数组已经撤销(即出栈),不再属于你了!
有意思吧?“局部变量保存在栈中”大概就是这样的情况。
你如果有兴趣,可以写专门的测试程序,检测这些变量的地址,观察进栈、出栈的过程。
展开全部
函数不能通过返回指向栈内存的指针,如果你一定要这么做,其结果只能说是未定义的,具体的输出值,取决于编译器的行为。
例如,在gcc下,优化后编译的输出,就和你之前的结果不一样:
[root@~]# cat 3.c
#include <stdio.h>
#include <malloc.h>
int * staticArr(void)
{
int arr[5] = {1, 2, 3, 4, 5};
arr[0] = 0;
arr[1] = 1;
arr[2] = 2;
arr[3] = 3;
arr[4] = 4;
return arr;
}
int main(void)
{
int * pArr;
pArr = staticArr();
printf("%d\n", *( pArr + 1) ); //这里能访问到staticArr创建的静态数组
printf("%d\n", *( pArr + 2) ); //这里能访问到staticArr创建的静态数组
printf("%d\n", *( pArr + 3) ); //这里能访问到staticArr创建的静态数组
printf("%d\n", *( pArr + 4) ); //这里能访问到staticArr创建的静态数组
printf("%d\n", *( pArr + 5) ); //这里能访问到staticArr创建的静态数组
return 0;
}
[root@ ~]# cc -o 3 -g -Wall 3.c -O2
3.c: 在函数‘staticArr’中:
3.c:14: 警告:函数返回局部变量的地址
[root@ ~]# ./3
1
2
3
4
32767
所以,你不能因为看到程序输出的第一个值是正确的,第二个值不对,就认为所有情况下, 第一个值都对,第二个值都不对。不能以此作为经验。
追问
静态数组的地址不能作为返回值,那么malloc创建的动态数组的地址可以作为函数的返回值吗?
追答
可以,malloc分配的内存,除非你主动进行free,否则,总是可用的。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
当释放完内存后,分配给程序的内存归操作系统所有。这时,你能通过指针访问这段内存,但是这段内存可能是空闲的,也可能已被分配给其他的程序使用,这段内存有可能已被初始化,有可能未被初始化。就好比你租了间屋子,你不住了,突然有一天你回去了,你可能发现屋子还是你走的时候的样子,也有可能已经面目全非了。
追问
那为什么静态数组在函数结束的时候依然可以被访问到呢,并且只能被访问一次,第二次就是错误的值了
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询