C语言动态内存分配

C语言动态内存分配

在进程的地址空间中,代码区、常量区、全局数据区的内存在程序启动时就已经分配好了,他们大小固定,不能由程序员分配和释放,只能等到程序运行结束由操作系统回收。这称为静态内存分配。

栈区和堆区的内存在程序运行期间可以根据实际需求来分配和释放,不用在程序刚启动时就备足所有内存。这称为动态内存分配。

使用静态内存的优点是速度快,省区了向操作系统申请内存的时间,缺点就是不灵活,缺乏表现力,例如不能控制数据的作用范围,不能使用较大的内存。而使用动态内存可以让程序对内存的管理更加灵活和高效,需要内存就立即分配,而且需要多少就分配多少,从几个字节到几个GB不等;不需要时就立即回收,再分配给其他程序使用。

栈和堆的区别

栈区和堆区的管理模式有所不同:栈区内存由系统分配和释放,不受程序员控制;堆区内存完全由程序员掌控,想分配多少就分配多少,想什么时候释放就什么时候释放,非常灵活。

程序启动时会为栈区分配一块大小适当的内存,对于一般的函数调用这已经足够了,函数进栈出栈只是esp、ebp寄存器指向的变换,或者是向已有的内存写入数据,不涉及内存的分配和释放。当函数中有较大的局部数组时,比如1024*10个元素,编译器就会在函数代码中插入针对栈的动态内存分配函数,这样函数被调用时才分配内存,不调用就不分配。

我们经常听说“栈内存的分配效率要高于堆”就是这个道理,因为大部分情况下并没有真的分配栈内存,仅仅是对已有内存操作。

动态内存分配函数

堆(Heap)是唯一由程序员控制的内存区域,我们常常说的动态内存分配也是在这个区域。在堆上分配和释放内存需要用到C语言标准库中的几个函数:malloc()、calloc()、realloc()和free()。

这里仅说明简单对比,若想深入了解,请自行查阅资料。

malloc()

原型:void* malloc(size_t size);

作用:在堆区分配size字节的内存空间

返回值:成功返回分配的内存地址,失败则返回NULL

注意:分配内存在动态存储区(堆区),手动分配,手动释放,申请时空间可能有也可能没有,需要自行判断,由于返回的时void*,建议手动强制类型转换。

calloc()

原型:void* calloc(size_t n, size_t size);

功能:在堆区分配n*size字节的连续空间。

返回值:成功返回分配的内存地址,失败则返回NULL。

注意:colloc()函数是对malloc()函数的简单封装,参数不同,使用时务必小心,第一参数是第二个参数的单元个数,第二个参数是单位的字节数。

realloc()

原型:void* realloc(void *ptr, size_t size);

功能:对ptr指向的内存重新分配size大小的空间,size可能比原来的大或者小,还可以不变(如果你觉得无聊)。

返回值:成功返回更改后的内存地址,失败则返回NULL。

free()

原型:void free(void* ptr)

功能:释放由malloc()、calloc()、realloc()申请的内存空间。

几点注意

  1. 每个内存分配函数必须有相应的free函数,释放后不能再次使用被释放的内存
  2. 在分配内存时最好不要直接用数字指定内存空间的大小,这样不利于程序的移植。因为在不同的操作系统中,同一数据类型的长度可能不一样。为了解决这个问题,C语言提供了一个判断数据类型长度的操作符,就是sizeof。
  3. free§并不能改变指针p的值,p依然指向以前的内存,为了防止再次使用该内存,建议将p的值手动置为NULL。

sizeof是一个单目操作符,不是函数,用以获取数据类型的长度时必须加括号,例如sizeof(int)、sizeof(char)等。

综合示例

#include <stdio.h>
#include <stdlib.h>

#define  N  (5)
#define  N1 (7)
#define  N2 (3)

int main()
{
    int *ip;
    int *large_ip;
    int *small_ip;
    if((ip = (int*)malloc(N * sizeof(int))) == NULL)
    {
        printf("memory allocated failed!\n");
        exit(1);
    }
    int i;
    for(i = 0; i < N; i++)
    {
        ip[i] = i;
        printf("ip[%d] = %d\t", i, ip[i]);
    }
    printf("\n");

    if((large_ip = (int* )realloc(ip, N1 * sizeof(int))) == NULL)
    {
        printf("memory allocated failed!\n");
        exit(1);
    }
    for(i = N; i < N1; i++)
        large_ip[i] = 9;
    for(i = 0; i < N1; i++)
        printf("large_ip[%d] = %d\t", i, large_ip[i]);
    printf("\n");

    if((small_ip = (int*)realloc(large_ip, N2 * sizeof(int))) == NULL)
    {
        printf("memory allocated failed!\n");
        exit(1);
    }
    for(i = 0; i < N2; i++)
        printf("small_ip[%d] = %d\t", i, small_ip[i]);
    printf("\n");

    free(small_ip);
    small_ip = NULL;

    system("pause");
    return 0;
}

运行结果:

ip[0] = 0 ip[1] = 1 ip[2] = 2 ip[3] = 3 ip[4] = 4
large_ip[0] = 0 large_ip[1] = 1 large_ip[2] = 2 large_ip[3] = 3 large_ip[4] = 4 large_ip[5] = 9 large_ip[6] = 9
small_ip[0] = 0 small_ip[1] = 1 small_ip[2] = 2

代码说明:

  1. 代码看似很长,其实较为简单,首先分配一个包含5个整型的内存区域,分别赋值0到4;再用realloc函数扩大内存区域以容纳7个整型数,对额外的两个整数赋值为9;最后再用realloc函数缩小内存区域,直接输出结果(因为realloc函数会自动复制数据)。

  2. 这次把分配函数与验证返回值验证写在了一起,为的是书写方便,考虑到优先级问题添加了适当的括号,这种写法较为常用,注意学习使用。

  3. 本例free函数只用释放small_ip指针即可,如函数介绍中注意里提到的,另外两个指针已被系统回收,不能再次使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JayerZhou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值