进阶C语言 第五章-------《动态内存管理》 (malloc、free,calloc、realloc、柔性数组、C/C++程序在内存)知识点+完整思维导图+基本练习题+深入细节+通俗易懂+建议收藏(一0

简介: 进阶C语言 第五章-------《动态内存管理》 (malloc、free,calloc、realloc、柔性数组、C/C++程序在内存)知识点+完整思维导图+基本练习题+深入细节+通俗易懂+建议收藏(一0

绪论

       书接上回,本章来到动态内存管理,这章的知识相较于结构体来说来简单一点,但是有许多地方需要注意不能马虎,并且该章的知识也比较重要,通过名称可以知道动态的内存管理,这样就可以对内存有一个很方便的管理方法!

image.png

所以安全带系好,发车啦(建议电脑观看)。



思维导图:

image.png


要XMind思维导图的话可以私信哈


目录


1.动态内存分配存在的意义

2.动态内存函数

2.1malloc

2.2free

2.3callloc

2.4realloc

3.动态内存常见的错误

3.1对NUL指针的解应用操作

3.2对动态内存开辟的空间越界访问

3.3对非动态开辟的内存进行free释放

3.4使用free释放动态内存开辟的一部分空间

3.5对同一块动态内存空间多次释放

3.6动态内存空间的忘记释放

4.动态内存常见问题、笔试题

5.C/C++程序在内存中的内存开辟

6.柔性数组

1.动态内存分配存在的意义

为什么要有动态内存管理?

下面通过对比来解释:

在我们一般申请内存的时候都是通过创建变量类型来申请的空间

如:int(4byte)、char(1byte)、int [ ]、结构体、联合体、枚举......

而这些内存的空间当我们创建好后他就固定死了,就比较的局限(死板)。

现在C语言提供了一种方式就是动态内存管理(函数)当我们需要时就创建一定的空间,当空间不够后又可以再次的补充其空间,当然当空间过大也可以减小空间的大小

2.动态内存函数

2.1malloc

知识点:

image.png

对于malloc函数来说他的类型是void *malloc(size_t);

用法:申请一个连续可用的size字节大小的空间,开辟成功时返回指向这块空间的指针

头文件:#include<stdlib.h>

所以一般的用法是要将返回来的void * 强转成自己所需要的指针类型

如:

int main()
{
    //当你要开辟多个以整型大小为基础的空间时
    int * ptr = (int *)malloc(sizeof(int) * 10);//当然你也可以直接在()内写成“40”byte
    //对于上面因为你需要开辟的是整形个大小的空间所以最后将返回的指针强转成整形指针类型
    //并且ptr也要是整形指针这是你所要用的,你甚至可以把它想像成开辟了一个大小为10的整形数组
    return 0;
}

为什么这样写我已经写上了注释

细节:

既然是申请那就有可能会失败,所以当申请失败的时候系统会返回一个空指针(NULL)

所以在我们写完后要加上一个判断,判断其是否申请成功

    if (ptr == NULL)
    {
        printf("%s\n", strerror(errno));//打印错误
        //perror("ptr");//打印错误
        return 0;
    }

image.png


不能开辟0byte的空间

判断空间是否申请成功

用free释放申请好的空间(并且将其指针置为空)

练习        

用动态内存分配的空间来打印打印1~10:

分析:

因为最终传回来的是指针所以就可以通过指针的方法来进行内存的访问,并且所开辟的大小也是以整形大小一个个开辟的,所以直接+1即可

 #define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int main()
{
    //当你要开辟多个以整型大小为基础的空间时
    int* ptr = (int*)malloc(40);
    if (ptr == NULL)
    {
        perror("ptr");//打印错误
        return 0;
    }
    for(int i = 0; i<10 ; i++)
    {
        *(ptr+i) = i +1;
       printf("%d ",*(ptr + i)); 
    }
    free(ptr);//释放向内存中借的空间
  ptr = NULL;
    return 0;
}


2.2free

知识点:

函数:void free (void* ptr);

当我们向操作系统借了的空间所以用完了后我们需要将其归还(若不归还的话对这空间再你没有结束程序的过程中都处于被借的状态也就浪费了这片没有用的空间)

用法:释放所传递过来的动态内存开辟的指针所指向的空间

细节:

对于free所释放的空间,虽然将其所存的内存归还给了操作系统,但ptr所指地址并不会被其改变,所以为了防止我们后面不小心还使用ptr这个地址指向的被已经释放的内存,所以需要再将ptr置为NULL

free(ptr);
ptr = NULL;

当所传递过来的是NULL时,free什么都不做。

不能释放不是动态内存开辟的空间

2.3callloc

知识点:

void* calloc (size_t num, size_t size);

该函数的意义和malloc一样,都是用来开辟空间的。

但是其参数不相同,num表示的是元素个数,而size表示的是每个元素的大小,返回值一样

所以对于之前用malloc开辟的10个整形大小的空间(40byte)就还可以写成calloc形式的:

int main()
{
    int* p = (int*)calloc(10, sizeof(int));
    if (p == NULL)
    {
        perror("p");
        return 0;
    }
//使用
    free(p);
    p = NULL;
    return 0;
}

细节:

同样的calloc也需要判断是否申请成功

用free释放申请好的空间(并且将其指针置为空)

image.png

通过对比上面两段代码我们可知:

malloc在申请往空间后不会对这部分空间有任何作业

calloc在申请完空间后会对这部分全部空间初始化为0

所以在我们使用时可以通过他们不同的类型进行选择使用

上面的malloc、calloc都是开辟内存的空间的,而下面的realloc就是修改开辟的内存空间

2.4realloc

知识点:

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

第一个参数是要调整的内存地址(由malloc、calloc、realloc开辟的内存块),第二个参数是所要调整的新的空间的大小(size个字节),返回情况是一样的

具体使用如下

int main()
{
  int* p = (int*)malloc(sizeof(int) * 5);
  if (p == NULL)
  {
    perror("malloc");
    return 1;
  }
  for (int i = 0; i < 5; i++)
  {
    *(p + i) = i + 1;
    printf("%d ", *(p + i));
  }
  int* ptr = (int *)realloc(p, sizeof(int) * 10);
  if(ptr != NULL)//当等于空指针时就没有动作了不用管ptr
  {
    p = ptr;
        ptr = NULL;
  }
  for (int i = 5; i < 10; i++)
  {
    *(p + i) = i + 1;
    printf("%d ", *(p + i));
  }
  free(p);
  p = NULL;
  return 0;
}

细节:

在上述代码中我们可以发现在用realloc增加或减少动态内存的空间后 返回时 接收返回值的指针是一个新的指针(int * ptr)而不是所要改变的那片空间的地址(p),这是因为:realloc开辟空间时分着两种情况:

1.当realloc所要开辟的空间在原始空间的后面有足够的空间让其使用时那就直接在原始位置处开辟

image.png

2.当realloc所要开辟的空间在原始位置后面没有足够的空间让其使用,此时就会寻找一个放的下的空间,并且将原数据拷贝过去,并且释放掉原空间和返回新的地址

image.png

3.就是因为可能的两种情况,所以为了避免第二种释放原位置返回新地址,所以用一个新指针接收其返回的地址,如果直接写成  p = realloc(p,sizeof(int)*10)的话 假如开辟没有成功那就会返回NULL而原本还有的5个空间大小直接就没了(p = NULL)。


当第一个参数传的是NULL时其用法和malloc类型开辟申请一块新的空间:

realloc(NULL,40) == malloc(40)  ;

并且返回指向这块空间的地址

相关文章
|
9月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
301 26
|
C语言
C语言学习笔记-知识点总结上
C语言学习笔记-知识点总结上
270 1
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
2894 1
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
301 0
|
9月前
|
存储
阿里云轻量应用服务器收费标准价格表:200Mbps带宽、CPU内存及存储配置详解
阿里云香港轻量应用服务器,200Mbps带宽,免备案,支持多IP及国际线路,月租25元起,年付享8.5折优惠,适用于网站、应用等多种场景。
2891 0
|
9月前
|
存储 缓存 NoSQL
内存管理基础:数据结构的存储方式
数据结构在内存中的存储方式主要包括连续存储、链式存储、索引存储和散列存储。连续存储如数组,数据元素按顺序连续存放,访问速度快但扩展性差;链式存储如链表,通过指针连接分散的节点,便于插入删除但访问效率低;索引存储通过索引表提高查找效率,常用于数据库系统;散列存储如哈希表,通过哈希函数实现快速存取,但需处理冲突。不同场景下应根据访问模式、数据规模和操作频率选择合适的存储结构,甚至结合多种方式以达到最优性能。掌握这些存储机制是构建高效程序和理解高级数据结构的基础。
958 1
|
9月前
|
存储 弹性计算 固态存储
阿里云服务器配置费用整理,支持一万人CPU内存、公网带宽和存储IO性能全解析
要支撑1万人在线流量,需选择阿里云企业级ECS服务器,如通用型g系列、高主频型hf系列或通用算力型u1实例,配置如16核64G及以上,搭配高带宽与SSD/ESSD云盘,费用约数千元每月。
1149 0
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
1054 0
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。