动态内存开辟详解

  • 动态内存分配
    • 什么是动态内存分配?
  • 一、为什么使用动态内存分配呢?
  • 二、动态内存函数
    • 1.malloc和free
    • 2.calloc和realloc
  • 三、常见的动态内存错误
    • 1.对`NULL指针`的解引用操作
    • 2.对动态内存开辟的`越界访问`
    • 3.向free传递一个非malloc函数返回的指针
    • 4.动态开辟内存忘记释放造成`内存泄漏`
  • 总结

动态内存分配

什么是动态内存分配?

所谓的动态内存分配,就是在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不像数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需求即时分配


一、为什么使用动态内存分配呢?

示例:当我们在声明一个数组的时候,我们需要指定数组的长度,它所需要的内存编译时分配。但是在程序运行的时候我们才可能知道真实所需要的长度,因为它所需要的内存空间取决于输入的数据

char arr[10] = {0};//在栈空间上开辟10个字节的连续空间

这种方法的优点是很简单,但是如果程序需要使用的元素数量超过了声明的长度,就无法处理这种情况。那怎么办呢?我们很容易就想到那就把数组声明的大一点,这确实是一个办法,然而这也会使得很大部分的内存空间浪费掉了,所以我们引出动态内存分配

我们先看看内存的分区

二、动态内存函数

1.malloc和free

C语言函数库提供了俩个函数,mallocfree,分别用来执行动态内存的分配和释放,当一个程序需要内存时,就会调用malloc函数,malloc从内存池()中提取一块内存,并向该程序返回一个指向这块内存的指针(此块内存此时并未初始化)。

void* malloc (size_t size);
void free(void* ptr);

1.它们的头文件在stdlib.h中声明,malloc的参数是需要分配的内存字节数,若开辟成功,则返回一个指向被开辟的内存块的起始位置的指针,注意malloc所分配的是一块连续的内存;如果内存池是空的或者它的可用内存无法满足你的请求的时候,malloc则返回一个NULL空指针,所以对每个malloc返回的指针都应该进行检查。
由于返回值的类型是void*,所以mall函数并不知道开辟空间的类型是整型、浮点型、结构或者是数组,具体使用的时候可以转换为其他任何类型的指针。
2.free函数专门用来做动态内存的释放和回收的:

如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
如果参数 ptr 是NULL指针,则函数什么事都不做。

我们看下面这个例子:

int main()
{//int arr[10] = { 0 };//动态内存开辟int* p = (int*)malloc(40);if (p == NULL)//判断p是否为空指针{printf("%s\n", strerror(errno));return 1;//异常返回}//使用内存int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;printf("%d ", *(p + i));}//没有free//当程序退出的时候,系统自动回收内存空间free(p);p = NULL;return 0;//正常返回
}

判断p不为空指针是进行(使用代码)

将申请的空间内存释放回收:

free( p);
p = NULL;

2.calloc和realloc

(1)calloc函数也用于内存分配,它与malloc之间的主要区别在于calloc返回地址之前把申请的空间的每个字节初始化为全0。另外一个小的区别在于它们请求内存数量的方式不同。calloc的参数包括所需要元素的数量和每个元素的字节数,根据这些值计算出需要开辟的内存

void* calloc (size_t num, size_t size);

例如:

int main()
{int* p = (int*)calloc(10, sizeof(int));if (p == NULL){printf("%s\n", strerror(errno));return 1;}//打印int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(p + i));}//释放free(p);p = NULL;return 0;
}

我们看这段代码运行的结果:

我们什么也没有做,但是代码打印的值全被赋成了0,说明calloc函数在开辟好空间之后,把内容初始化成0,然后把起始地址返回来。
所以在calloc和malloc之间如何选择我们就有了一点的了解,如果你需要初始化则选择calloc。
(2)realloc函数用于修饰一个原先已经分配的内存块的大小,它可以使一块内存块扩大或者缩小:
realloc函数原型:

void* realloc (void* ptr, size_t size);

  • ptr是要调整的内存地址
  • size是调整后的新的大小

1.当用于扩大一个内存块时,这块内存原先的内容将依然保留,新增加的内存添加到原先内存块的后面,且新内存并没有进行初始化。

2.当缩小一块内存的时候,该内存块尾部的部分内存被拿掉,剩下的原先内容保留不变。
3. 当原先的内存块无法改变大小,realloc将分配另一块正确大小的内存,并把原先内存的内容复制到新的内存块上。所以在使用realloc之后,不能再使用指向旧的内存的指针,而是该用realloc所返回的新指针。

举个例子:

int main()
{int* p = (int*)malloc(40);if (NULL == p){printf("%s\n", strerror(errno));return 1;}//使用  1 2 3 4 5 6 7 8 9 10int i = 0;for (i = 0; i < 10; i++){*(p + i) = i + 1;}//扩容int* ptr = (int*)realloc(p, 80); //用ptr来接收if (ptr != NULL){p = ptr;//p得到有效的地址(/新)}//使用for (i = 0; i < 10; i++){printf("%d ", *(p + i));}//释放 free(p);p = NULL;return 0;

三、常见的动态内存错误

1.对NULL指针的解引用操作

不检查从malloc函数返回的指针是否为空

void test()
{int *p = (int *)malloc(20);*p = 20;//如果p的值是NULL,会出错free(p);
}

2.对动态内存开辟的越界访问

访问动态分配的内存之外的区域

void test()
{int i = 0;int *p = (int *)malloc(10*sizeof(int));if(NULL == p){printf("%s\n", strerror(errno));return 1;}for(i=0; i<=10; i++){*(p+i) = i;//当i是10的时候越界访问}free(p);p=NULL:return 0;
}

3.向free传递一个非malloc函数返回的指针

对非动态内存开辟使用free释放

void test()
{int a = 10;int *p = &a;free(p);//ok?
}

4.动态开辟内存忘记释放造成内存泄漏

void TEST()
{int *p = (int *)malloc(100);if(NULL != p){*p = 20;}
}
int main()
{TEST();return 0;
}

内存泄漏会增加程序的体积,可能导致程序或系统崩溃,所以

一定要正确的释放内存


总结

1.malloc和calloc函数用于动态分配一块内存,并返回一个指向该内存的指针,malloc的参数就是需要分配的内存的字节数,而calloc的参数时需要分配的元素个数和每个元素的长度;calloc函数在返回时将内存初始化为0,而malloc则不会进行初始化。

2.realloc函数可以调整动态内存分配的大小。以及出现的两种情况

3.如果请求内存开辟失败,malloc、calloc和realloc函数返回的是一个NULL指针。若一个指针不是从这些函数返回的,则它不能作为参数传递给free函数,同时,我们也不能只释放一块内存的一部分。

到这里,相信大家对动态内存分配有了一定的了解与掌握吧!我在这里是把我所学习到的和书上的知识内容做个总结与叙述,希望能有所帮助,谢谢。

【C语言】------ 动态内存分配相关推荐

  1. c语言动态内存分配数组,【C】动态内存分配

    ## 动态内存分配的意义 C语言中的一切操作都是基于内存的 变量和数组都是内存的别名 内存分配由编译器在编译期间决定 定义数组的时候必须指定数组长度 数组长度是在编译期就必须确定的需求: 程序在运行过 ...

  2. linux 在指定区域分配内存 c语言,C语言动态内存分配:(一)malloc/free的实现及malloc实际分配/释放的内存...

    一.malloc/free概述 malloc是在C语言中用于在程序运行时在堆中进行动态内存分配的库函数.free是进行内存释放的库函数. 1.函数原型 #include void *malloc( s ...

  3. C语言动态内存分配:(一)malloc/free的实现及malloc实际分配/释放的内存

    最新个人博客 shankusu.me 以下内容转载或参考或引用自 https://blog.csdn.net/zxx910509/article/details/62881131 一.malloc/f ...

  4. C语言动态内存分配详解

    文章目录 前言 一.为什么存在动态内存分配 1.已掌握的内存开辟方式 2.上述开辟空间方式的特点 3.为什么存在动态内存分配 二.动态内存函数的介绍 1.malloc 2.free 3.calloc ...

  5. C语言:动态内存分配+经典面试题

    前言: 通常,我们在栈空间开辟的内存都是固定的,这是十分不方便使用的.为了更加灵活的分配和使用内存,我们要学习C语言中一些常用的与内存分配相关联的函数.顺便,我们会补充数组中柔性数组的知识. 内存分区 ...

  6. 浅谈C语言动态内存分配及柔性数组

    文章目录 前言 1.动态内存的简单介绍 1.动态内存分配是什么? 2.为什么存在动态内存分配? 3.动态内存分配具体方法 1.动态内存函数 2.动态内存注意事项 2.经典面试题分析 3.C/C++程序 ...

  7. C语言动态内存分配函数

    目录 1.malloc() 2.free() 3.calloc() 4.realloc() 5.小结 在C中我们开辟内存空间有两种方式 : 1.静态开辟内存 : 例如: int a; int b[10 ...

  8. C语言-动态内存分配总结

    目录 1 malloc 2 calloc 区别联系 3 memset 4 realloc 1 malloc void *malloc( unsigned int num_bytes) 分配长度为num ...

  9. C语言——动态内存分配

    内存分配函数: malloc函数--分配内存块,但是不对其进行初始化. calloc函数--分配内存块,并且对其进行初始化(清0). realloc函数--调整先前分配的内存块大小. 函数原型: vo ...

  10. 不允许指针指向不完整的类类型_8.7 C语言动态内存分配与指向它的指针变量

    01什么是内存的动态分配 1.全局变量是分配在内存中的静态存储区的,非静态的局部变量(包括形参)是分配在内存中的动态存储区的,这个存储区是一个"栈"的区域. 2.C语言允许建立内存 ...

最新文章

  1. KWrite 和 Kate 在 Linux 上的应用
  2. JavaScript语言基础6
  3. 【Linux】28.Linux脚本判断是否安装了某软件
  4. hibernate教程--检索方式详解(hql,sql,QBC)
  5. 27.4. /etc/bandwidthd.conf
  6. 原创跑酷小游戏《Cube Duck Run》 - - 方块鸭快跑
  7. Oracle 10.2.0.5 非归档current redolog损坏处理一例
  8. 中文 转gbk编码_go查找中文首字母
  9. android 手机 与 python服务器_Python服务器与多种客户端(Python/Java/Android)之间的通信...
  10. HaspMap的新奇用法
  11. jquery概述_jQuery事件方法概述
  12. Android studio 不能识别(显示?????)部分手机的解决办法
  13. Win7如何删除家庭组
  14. LinkedList的底层实现
  15. 锂离子电池容量保持率和容量恢复率
  16. 基于SSM的Java图书管理系统
  17. 【CAD】DWF文件格式详细说明,清晰易懂
  18. WizTree v4.03 最快的磁盘空间分析工具中文便携版
  19. NXP JN5169 烧录器原理图(带按键)
  20. vcf构建idx索引

热门文章

  1. 红心In 支持国产Pad 爱心传递
  2. 怎样理解前端智能化这一新浪潮?
  3. 将sheet工作表批量另存为独立的工作簿,并命名成sheet表的名称
  4. 编程进阶之路,虽无捷径但有长短
  5. Linux图形界面与命令行界面
  6. Ubuntu 开机黑屏 光标闪烁
  7. (7)椭圆的生成之中点画椭圆法
  8. 107 下载安装启动xampp
  9. pgsql获取日期段_PostgreSQL时间段查询
  10. Cocos Creator 安卓构建发布 报错