回 帖 发 新 帖 刷新版面

主题:[原创][讨论]尝试解释一个大家都觉得疑惑的问题

见得多的一个比较大脑袋的问题:
定义一个函数,在函数内部申请一块内存空间(通过malloc函数(C++中对应为new))并对其进行赋值,然后通过指针返回内存块首地址(此指针变量是函数局部的),结果往往是主调函数能正常使用被调函数申请、赋值的空间,正是这一点,使大家百思不得其解,因为它似乎违背了“函数调用结束,内部申明的自动变量亦释放”。

解释之前弄懂几句术语:
对内存分配上的“栈 stack”和“堆 heap”简单的来讲,stack上分配的内存系统自动释放,heap上分配的内存,系统不释放,哪怕程序退出,那一块内存还是在那里。stack一般是静态分配内存,heap上一般是动态分配内存。

由malloc系统函数分配的内存就是从堆上分配内存。从堆上分配的内存一定要自己释放。用free释放,不然就是“内存泄露”--像函数fun1那样;而fun1函数中定义的数组是栈内存分配,函数结束后系统自动收回内存区域,所以我们看到的输出是不可预料的。(所以 大家一定要注意malloc和free成对使用(C++中对应为new和delete))

表达能力及专业知识不够强、可能解释不够准确,大家发表发表下自己的看法。

/*例程*/
#include <stdio.h>
#include <malloc.h>

int *fun1(int); /*fun1通过malloc函数申请内存 返回首地址*/
int *fun2(void);/*fun2通过定义数组申请内存 返回首地址*/

void main()
{
    int i, n=10, *p;

    p=fun1(n);
    for(i=0;i<n;i++)
        printf("%d ",p[i]);/*输出结果为1 2 3 4 5 6 7 8 9 10*/

    p=fun2();
    for(i=0;i<n;i++)
        printf("%d ",p[i]);/*输出结果不可预料*/
}

int *fun1(int size)/*堆内存分配*/
{
    int i, *po;
    po=(int*)(malloc(sizeof(int)*size));

    for(i=0;i<size;i++)
        po[i]=i+1;
    
    return po;
}

int *fun2()/*栈内存分配*/
{
    int *po=NULL,a[]={1,2,3,4,5,6,7,8,9,10};
    po=a;
    return po;
}

回复列表 (共16个回复)

11 楼

当然不是,malloc的内存是操作系统给的,你不显示的还操作系统当你没有还,没有把它加进内存空间,永远流失了;

12 楼

楼主说的这些,我好象在c语言习题与解析上有详细的解释。
我开始的时候也是不太理解,但是我想了一个我能理解的办法。
(什么“栈 stack”和“堆 heap”拉,我一盖理解不了)

我把malloc分配的内存理解为一个全局变量分配的内存,但是他比全局变量更顽固,当主程序结束的时候,他仍然不会释放,只能是主程序结束前,自己用free将他释放。

其它的在函数内部分配的内存,当此函数结束的时候,就自动释放了。

所以在用malloc的时候,最后一定不要忘了用free。不然malloc分配的内存就会孤独的躺在内存的某个角落里被遗忘了。
(戏说,希望对大家有帮助,不对的地方望大家指正~~~~~~~~~~~)

13 楼

解释之前弄懂几句术语:
对内存分配上的“栈 stack”和“堆 heap”简单的来讲,stack上分配的内存系统自动释放,heap上分配的内存,系统不释放,哪怕程序退出,那一块内存还是在那里。stack一般是静态分配内存,heap上一般是动态分配内存。



有问题,stack上的内存是系统管理的这个不错但是heap上的空间是用户(程序员)自己管理的,在heap上分配的空间如果不及时的释放掉就会造成“内存漏洞”,虽然系统会在程序完全退出后释放到heap的内存但是只申请不释放是一个不好的习惯就象借别人的东西不还一样。
把你的fun2改一下程序就会没错的
int *fun2()/*栈内存分配*/
{
    static int a[]={1,2,3,4,5,6,7,8,9,10};//静态的!
    int* po=a;
    return po;
}
另:
windows下有虚拟内存所以内存好象永远也用不完。

14 楼

TO:第 13 楼
1.
static int a[]={1,2,3,4,5,6,7,8,9,10};//静态的!
//之所以不设置成静态的[int a[]={1,2,3..]是为了解释问题作对比

2.
虚拟内存与这个搭不上
虚拟内存是把硬盘当作内存用---也不是用不完的 而且即使使用虚拟内存技术,在调用虚拟内存上的数据时也同样要将硬盘上的数据转到内存中,要记住的是CPU是不能直接对硬盘进行操作的。

15 楼

“对内存分配上的“栈 stack”和“堆 heap”简单的来讲,stack上分配的内存系统自动释放,heap上分配的内存,系统不释放,哪怕程序退出,那一块内存还是在那里。”
//有点问题,程序退出,那一块内存即使没有使用free函数,程序结束时会被释放。((也如 fopen函数,程序结束时,没有使用fclose的文件指针的缓冲区也会自动释放)
所谓的“内存泄露”,不是程序结束后,而是在程序运行中,程序运行时使用的堆内存是有限的,所以要使用 free释放。

16 楼

程序结束后,不存在“内存泄露”,

我来回复

您尚未登录,请登录后再回复。点此登录或注册