进阶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)  ;

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

相关文章
|
3月前
|
C语言
【C语言】:动态内存管理函数malloc,calloc,realloc和free的介绍的介绍
【C语言】:动态内存管理函数malloc,calloc,realloc和free的介绍的介绍
44 0
|
18天前
|
编译器 Linux C语言
【C++小知识】为什么C语言不支持函数重载,而C++支持
【C++小知识】为什么C语言不支持函数重载,而C++支持
|
23天前
|
存储 编译器 C语言
C++内存管理(区别C语言)深度对比
C++内存管理(区别C语言)深度对比
48 5
|
2月前
|
程序员 编译器 C语言
云原生部署问题之C++中的nullptr相比C语言中的NULL优势如何解决
云原生部署问题之C++中的nullptr相比C语言中的NULL优势如何解决
45 10
|
2月前
|
存储 编译器 C语言
|
2月前
|
存储 C语言 C++
【C/C++】动态内存管理( C++:new,delete)
C++的`new`和`delete`用于动态内存管理,分配和释放内存。`new`分配内存并调用构造函数,`delete`释放内存并调用析构函数。`new[]`和`delete[]`分别用于数组分配和释放。不正确匹配可能导致内存泄漏。内置类型分配时不初始化,自定义类型则调用构造/析构。`operator new`和`operator delete`是系统底层的内存管理函数,封装了`malloc`和`free`。定位`new`允许在已分配内存上构造对象,常用于内存池。智能指针等现代C++特性能进一步帮助管理内存。
|
2月前
|
存储 编译器 程序员
【C/C++】动态内存管理(C:malloc,realloc,calloc,free)
探索C++与C语言的动态内存管理:从malloc到new/delete,了解内存分布及栈、堆的区别。文章涵盖malloc、realloc、calloc与free在C中的使用,强调内存泄漏的风险。C++引入new和delete,支持对象构造与析构,还包括operator new和placement-new。深入分析内存管理机制,揭示C与C++在内存处理上的异同。别忘了,正确释放内存至关重要!
|
2月前
|
编译器 C语言 C++
C++从遗忘到入门问题之C++持从C语言的过渡问题如何解决
C++从遗忘到入门问题之C++持从C语言的过渡问题如何解决
|
3月前
|
存储 Linux C语言
c++进阶篇——初窥多线程(二) 基于C语言实现的多线程编写
本文介绍了C++中使用C语言的pthread库实现多线程编程。`pthread_create`用于创建新线程,`pthread_self`返回当前线程ID。示例展示了如何创建线程并打印线程ID,强调了线程同步的重要性,如使用`sleep`防止主线程提前结束导致子线程未执行完。`pthread_exit`用于线程退出,`pthread_join`用来等待并回收子线程,`pthread_detach`则分离线程。文中还提到了线程取消功能,通过`pthread_cancel`实现。这些基本操作是理解和使用C/C++多线程的关键。
|
3月前
|
C语言 图形学 C++
下一篇
云函数