动态内存管理那些事:malloc、calloc、realloc、free 上

简介: 动态内存管理那些事:malloc、calloc、realloc、free

文章目录

一、为什么存在动态内存分配

🎗 在之前我们都是这样开辟空间的:

int i = 20; //在栈空间开辟4个字节

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

特点

1️⃣ 开辟的空间大小是固定的

2️⃣ 数组在声明的时候,必需包含常量值 (指定数组长度)

小结

以往开辟空间的方式不够灵活,有很大的局限性 (有时候我们需要的空间大小在程序运行的时候才能知道)

所以这篇文章主要了解在内存堆上开辟空间所使用的函数

二、动态内存函数的介绍

💦 malloc

⭕ 函数信息

#include<stdio.h>
#include<stdlib.h>
int main()
{
  //假设开辟10个整型的空间:
  int arr[10];//1.栈区开辟
  int* p = (int*)void* p = malloc(10 * sizeof(int));//2.堆区开辟
  /*-----------------分割线-----------------*/
  //使用
  //1.开辟失败
  if(p == NULL)
  {
    perror("main");
    return 0;
  }
  //2.开辟成功
  int i = 0;
  for(i = 0; i < 10; i++)
  {
    *(p + i) = i;
  }
  //打印
  for(i = 0; i < 10; i++)
  {
    printf("%d ", p[i]);
  }
  //回收空间
  free(p);
  p = NULL;
  return 0;
}

小结

1️⃣ malloc向内存申请一块连续可用的空间,且开辟成功时返回指向那块空间的地址;开辟失败返回NULL

2️⃣ 因为malloc函数的返回值是void*类型,所以在使用某一类型的指针变量接收时,也要强制类型转换为对应的类型

3️⃣ 如果malloc开辟失败,可能会对空指针进行非法解引用操作,所以malloc开辟的空间一定要检查

4️⃣ 使用完malloc开辟的空间,要主动回收空间。因为在回收空间后,那块空间的使用权已经不是自己能控制了,且能通过指针再去寻找到那块空间,所以为了避免非法访问,通常会主动将指向那块空间的指针置为NULL

💦 free

⭕ 函数信息

#include<stdio.h>
int main()
{
  int a = 10;
  int* p = &a;
  free(p);//1.err,回收栈空间
  p = NULL;
  free(NULL)//2.等同于-> //free(NULL)
  return 0;
}

小结

1️⃣ 如果参数ptr指向的空间不是动态开辟的,那么free函数的行为是标准未定义的

2️⃣ 如果参数ptr是NULL指针,则视为无效代码

3️⃣ 关于回收空间有2种方式:一是main函数结束后,开辟的空间会被动的还给OS,但是对于一个每天24小时不停跑的程序来说,如果不主动回收不用的空间的话,剩余的空间将会越来越少。二就是主动的把不用的空间主动回收掉

💦 calloc

⭕ 函数信息

#include<stdio.h>
#include<stdlib.h>
int main()
{
  //malloc和calloc都未主动初始化
  //1.malloc
  int* p = (int*)malloc(40);
  if(p == NULL)
    return 1;
  int i = 0;
  for(i = 0; i < 10; i++)
  {
    printf("%d\n", *(p + i));
  }
  free(p);
  p = NULL;
  //2.calloc
  int* q = (int*)calloc(10, sizeof(int));
  if(q == NULL)
    return 1;
  for(i = 0; i < 10; i++)
  {
    printf("%d\n", *(q + i));
  }
  free(q);
  q = NULL;
  return 0;
}

💨 结果:

小结

1️⃣ calloc相比malloc来说:calloc会主动初始化开辟的内存空间

💦 realloc

🎗 realloc的出现让动态内存管理更加灵活

在申请空间的时候,有时我们会发现过大了或过小了,需要灵活的调整:而能实现灵活调整的函数其实是realloc,所以malloc、calloc、realloc中realloc是毫无争议的一把手

⭕ 函数信息

#include<stdio.h>
#include<stdlib.h>
int main()
{
  //1.使用calloc开辟10个整形大小
  int* p = (int*)calloc(10, sizeof(int));
  if(p == NULL)
  {
    perror("main");
    return 0;
  }
  //2.使用开辟的空间
  int i = 0;
  for(i = 0; i < 10; i++)
  {
    *(p + i) = 5;
  }
  //3.到了这里还需要10个整型空间,而p所指向的空间已经被使用完了,所以使用realloc调整空间  
  //为什么这样设计,请看正面详解:
  int* pnew = (int*)realloc(p, 20 * sizeof(int));
  if(pnew != NULL)
  {
    p = pnew; 
  }
  //.回收空间
  free(p);
  p = NULL;
  return 0;
}

📝详解:

🎗 realloc开辟原理

❓❔ 思考:如何合适的接收realloc的地址呢

✖ int* p = (int*)realloc(p, 20 * sizeof(int));

如果用旧地址去接收:realloc有可能找不到合适的空间,来调整大小,这时就返回NULL。此时再交给p,不仅空间没开辟好,旧空间的内容也找不到了

—— 偷鸡不成蚀把米


✔ int* pnew = (int*)realloc(p, 20 * sizeof(int));

先用新地址接收,如果开辟成功再把它赋值给旧空间,这样不仅避免了旧空间的丢失,同样也适用场景一、场景二

🎗 realloc单独使用时能实现malloc的效果 (不会初始化)

#include<stdio.h>
#include<stdlib.h>
int main()
{
  int* p = (int*)realloc(NULL, 40);//同int* p = (int*)malloc(40);
  if (p == NULL)
    return 1;
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    printf("%d\n", *(p + i));
  }
  free(p);
  p = NULL;
  return 0;
}

💨 结果:


相关文章
|
2月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
2月前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
351 1
|
2月前
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
80 0
|
27天前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
211 1
|
17天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
26天前
|
Java
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80
|
27天前
|
Java
JVM运行时数据区(内存结构)
1)虚拟机栈:每次调用方法都会在虚拟机栈中产生一个栈帧,每个栈帧中都有方法的参数、局部变量、方法出口等信息,方法执行完毕后释放栈帧 (2)本地方法栈:为native修饰的本地方法提供的空间,在HotSpot中与虚拟机合二为一 (3)程序计数器:保存指令执行的地址,方便线程切回后能继续执行代码
21 3
|
27天前
|
存储 缓存 监控
Elasticsearch集群JVM调优堆外内存
Elasticsearch集群JVM调优堆外内存
45 1
|
1月前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
2月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
79 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS