IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 地表最强C语言汇总(十三)动态内存管理(持续更新) -> 正文阅读

[C++知识库]地表最强C语言汇总(十三)动态内存管理(持续更新)

最新更新时间:2021.12.22
环境:CLion2021.3;64位macOS Big Sur


地表最强C语言系列传送门:
地表最强C语言汇总(一)基本数据类型(持续更新)
地表最强C语言汇总(二)变量和常量(持续更新)
地表最强C语言汇总(三)字符串+转义字符+注释(持续更新)
地表最强C语言汇总(四)分支语句(持续更新)
地表最强C语言汇总(五)循环语句(持续更新)
地表最强C语言汇总(六)函数(持续更新)
地表最强C语言汇总(七)数组(持续更新)
地表最强C语言汇总(八)操作符(持续更新)
地表最强C语言汇总(九)关键字(持续更新)
地表最强C语言汇总(十)#define定义常量和宏(持续更新)
地表最强C语言汇总(十一)指针(持续更新)
地表最强C语言汇总(十二)结构体(持续更新)
占位置
占位置
占位置
地表最强C语言汇总(十六)一些自定义函数(持续更新)
地表最强C语言汇总(十七)阅读程序(持续更新)

十三、动态内存管理

13.1 为什么存在动态内存分配

举一个简单的例子:张三接触到了数组没多久,想用数组将自己好朋友全部保存起来,于是定义了一个可以存放10个人的数组;过了几天他想试着将全班的人的信息都存放在数组中,于是便重新定义了一个可以存放50个人的数组;又过了几天他想将和他同届的人全部存放在数组中,于是又重新定义了一个可以存放1000人的数组;又过了几天…
就这样不断的折腾,有一天他瘫坐在椅子上心想:要是数组的大小能够动态分配就好了,这样既不会浪费空间,也不会造成空间不足的情况,而且维护起来还很方便。

13.2 动态内存函数的介绍:malloc、free、calloc、realloc

  1. void* malloc( size_t size )
    malloc函数向内存的堆区申请一块连续可用的空间,并返回指向这块空间的指针:
    (1)若开辟成功,则返回一个指向开辟好空间的指针
    (2)若开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做空指针检查
    (3)返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定,即强制类型转换
    (4)如果参数size为0,malloc的行为是标准为定义的,取决于编译器
	int *p = (int *) malloc(10 * sizeof(int));
    //使用这些空间的时候要检查是否为空指针
    if (NULL == p) {
        perror("main");//若有错误,打印main:xxxxxxx
        return 0;
    }
    //使用
    for (int i = 0; i < 10; i++) {
        *(p + i) = i;
    }
    for (int i = 0; i < 10; i++) {
        printf("%d ", p[i]);//*(p+i)
    }
    //	回收空间void free( void* ptr ),和malloc等成对出现
    //  如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的
    //  如果参数ptr是NULL指针,则函数什么都不做。
    free(p);//只是将空间还给操作系统,p中仍然存放着那块空间的地址,为了防止非法访问,最好将p置空
    p = NULL;//手动将p置空
  1. void* calloc( size_t num, size_t size )
//	分配10个int大小的空间
    int *p = (int *) calloc(10, sizeof(int));//calloc会对分配的内存初始化,malloc不会;参数不一样,其他和malloc完全一样
    if (NULL == p) {
        perror("main");
        return 1;
    }
    for (int i = 0; i < 10; i++)
        printf("%d ", p[i]);
    free(p);
    p = NULL;
  1. void *realloc( void *ptr, size_t new_size )
    (1)若原空间后边的空间足够新的空间,直接将后边的空间分配给p,返回原地址p;
    (2)若原空间后边的空间不足够开辟新的空间,则会新开辟一块空间,将原空间的数据拷贝到新空间,返回新空间地址,将原空间释放;
    (3)若找不到合适的空间来调整大小,则返回空指针。因此不要直接用原指针接收返回值,防止原地址丢失。
    int *p = (int *) calloc(10, sizeof(int));//先分配10个int的空间
    if (NULL == p) {
        perror("main");
        return 1;
    }
    for (int i = 0; i < 10; i++)
        *(p + i) = 5;
    //若此时需要p指向的空间更大,需要20个int的空间,使用realloc调整空间
    //  若原空间后边的空间足够新的空间,直接将后边的空间分配给p,返回原地址p;
    //  若原空间后边的空间不足够开辟新的空间,则会新开辟一块空间,将原空间的数据拷贝到新空间,返回新空间地址,将原空间释放;
    //  若找不到合适的空间来调整大小,则返回空指针。因此不要用原指针接收返回值
    int *ptr = (int *) realloc(p, 20 * sizeof(int));
    if (NULL != ptr)
        p = ptr;//确定分配成功再赋值给p,方便维护
    free(p);
    p = NULL;

//	realloc(NULL,40)当第一个参数传递空指针时,效果和malloc一样
  1. void free (void* ptr)
    回收申请的空间,一般和上面三个函数成对出现

13.3 常见的动态内存错误

  1. 对空指针的解引用操作,解决方法:对malloc函数的返回值做判空判断
    int* p = (int*)malloc(10000000000000);
    for (int i = 0; i < 10; ++i) {
        *(p+i) = i;
    }
    申请的空间太大,导致申请失败,而申请失败则会返回空指针,即p其实是空指针,后又对其解引用,导致错误
  1. 对动态开辟空间的越界访问
    int *p = (int *) malloc(10 * sizeof(int));
    if (NULL == p)
        return 1;
    //越界访问只开辟了10个int型的空间
    for (int i = 0; i < 40; ++i) {
        *(p + i) = i;//只开辟了10个int型的空间,无法访问到10以后的空间
    }
    free(p);
    p = NULL;
  1. 对非动态开辟内存使用free释放
    int arr[10] = {0};//局部变量,存放在栈区
    int* p = arr;
    free(p);//err,p不是动态开辟的空间,不能用free释放
    p = NULL;
  1. 使用free释放一块动态开辟内存的一部分
    int *p = (int *) malloc(10 * sizeof(int));
    if (NULL == p)
        return 1;
    for (int i = 0; i < 5; ++i) {
        *p++ = i;
    }
    free(p);//此时p已经不指向动态开辟空间的首地址,此时free有两个风险:
    //1.只free掉一部分,这是个操作本身就很离谱       
    //2.动态申请的空间的起始位置无法找到,可能会内存泄漏
    p = NULL;
  1. 对同一块动态内存多次释放
    int* p = (int*)malloc(100);
    free(p);
    free(p);//err,避免方法:第一次释放完后p=NULL;free(NULL)什么事情都不会发生
  1. 动态开辟内存忘记释放(内存泄漏)
    动态开辟的空间只有两种情况才能被销毁:
    (1)主动free
    (2)程序结束,注意是程序而非函数
void test()
{
    int* p  = (int*)malloc(100);
    if(NULL == p)
        return;
    //假装在这里使用了p,但是最后没有释放
}
int main()
{
	test();//出了这个函数,想释放都无法释放,因为局部变量p已经被销毁,再也无法找到那块儿空间
	//这样每次调用test都会泄漏一点儿内存,久而久之内存就会被占满
	return 0;
}

13.4 几个经典的笔试题

13.5 柔性数组

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-23 15:34:46  更:2021-12-23 15:35:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 12:24:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码