【学习笔记之我要C】动态内存管理

简介: 【学习笔记之我要C】动态内存管理

一、为什么存在动态内存管理


内存分为三个区,栈区、堆区和静态区(也被叫做数据段)。栈区用来存放局部变量、函数形参等临时变量;堆区用来进行动态内存开辟;静态区用来存放全局变量、静态变量等。

 形如int val = 20;、char arr[10] = {0};的内存开辟方式是在栈空间上开辟的, 它空间开辟大小是固定的,并且在申明数组的时候,必须指定数组的长度,它所需要的内存在编译时分配。

 但是有时我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了,这时候就只能试试动态存开辟了。


0026ebbcec0e4552b39ada9f8b3900dc.png


二、动态内存介绍

1、malloc函数和free函数

  1. malloc函数介绍


c0a40601f1fa4a8ea10e28e5394036cf.png


这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针;

如果开辟成功,则返回一个指向开辟好空间的指针;

如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查;

返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定;

如果参数size为0,malloc的行为是标准是未定义的,取决于编译器。


2.free函数介绍


0d91cc60e68347ec9dc6623d0c28526a.png


C语言提供了另外一个函数free,专门是用来做动态内存的释放和回收的;

如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的;

如果参数 ptr 是NULL指针,则函数什么事都不做。

  1. 代码实例


int main() {
  //假设开辟10个整型空间 - 10* sizeof(int)
  //动态内存开辟空间
  int* p = (int*)malloc(10 * sizeof(int));//void*
  //使用这些空间的时候
  if (NULL == p) {
    //printf + strerror
    perror("main");//main:xxxxxxxxxxxxx
    return 0;
  }
  //使用
  int i = 0;
  for (i = 0; i < 10; i++) {
    *(p + i) = i;
    printf("%d\n", *(p + i));
  }
  for (i = 0; i < 10; i++) {
    printf("%d ", p[i]);//p[i] --> *(p + i)
  }
  //回收空间
  free(p);
  p = NULL;//手动把p置为NULL,防止访问越界在,造成野指针
  return 0;
}


malloc基本上和free是成对出现的。

2、calloc函数

  1. calloc函数介绍


84a113ce59614ca4b4c5ef19921b3d34.png

函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0;

与函数malloc的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全0。


e827de625f8b4a4eb8b49e2a6bf8e9eb.png


beab0518f99a49b28204b5556297bb26.png

  1. 代码实例
int main() {
  int* p = calloc(10, sizeof(int));
  if (NULL == p)
    return 1;
  int i = 0;
  for (i = 0; i < 10; i++) {
    printf("%d\n", *(p + i));
  }
  free(p);
  p = NULL;
  return 0;
}


3、realloc函数

  1. realloc函数介绍



0ea4e8685bc049789d3a956bccf75051.png


ptr 是要调整的内存地址;

size 调整之后新大小;

返回值为调整之后的内存起始位置;

这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间;

realloc在调整内存空间的是存在两种情况:

 情况1:原有空间之后有足够大的空间

 情况2:原有空间之后没有足够大的空间


情况一:


a7610ebd3acc49bbb4d2993d9bb88504.png


情况二:


63d0c1300fc74fdfa1554a434a5317ef.png

  1. 代码实例
int main() {
  int* p = calloc(10, sizeof(int));
  if (NULL == p) {
    perror("mian");
    return 1;
  }
  //使用
  int i = 0;
  for (i = 0; i < 10; i++) {
    printf("%d\n", *(p + i));
  }
  //这里需要p指向的空间更大,需要20个int函数
  //realloc调整空间
  int* ptr = realloc(p, 20 * sizeof(int));
  if (ptr != NULL) {
    p = ptr;
  }
  free(p);
  p = NULL;
  return 0;
}


三、常见动态内存错误


  1. 对NULL指针进行解引用操作


void test()
{
  int* p = (int*)malloc(INT_MAX / 4);
  *p = 20;//如果p的值是NULL,就会有问题
  free(p);
}
  1. 对动态开辟的空间越界访问
void test()
{
  int i = 0;
  int* p = (int*)malloc(10 * sizeof(int));
  if (NULL == p)
  {
    exit(EXIT_FAILURE);
  }
  for (i = 0; i <= 10; i++)
  {
    *(p + i) = i;//当i是10的时候越界访问
  }
  free(p);
}
  1. 对非动态开辟的内存使用free释放
void test()
{
  int a = 10;
  int* p = &a;
  free(p);//ok?
}


  1. 使用free释放一块动态开辟内存的一部分
void test()
{
  int* p = (int*)malloc(100);
  p++;
  free(p);//p不再指向动态内存的起始位置
}


  1. 对同一块动态内存多次释放
void test()
{
  int* p = (int*)malloc(100);
  free(p);
  free(p);//重复释放
}
  1. 动态开辟内存忘记释放,导致内存泄漏
void test()
{
  int* p = (int*)malloc(100);
  if (NULL != p)
  {
    *p = 20;
  }
}
int main()
{
  test();
  while (1);
}


目录
相关文章
|
9月前
【深入理解计算机系统】int 不是整数 | float 不是实数 | 内存引用错误的例子 | 学习笔记
【深入理解计算机系统】int 不是整数 | float 不是实数 | 内存引用错误的例子 | 学习笔记
56 0
|
2月前
|
存储 编译器 C语言
【C++】学习笔记——内存管理
【C++】学习笔记——内存管理
37 15
|
2月前
|
存储 C++
C primer plus 学习笔记 第12章 存储类别、链接和内存管理
C primer plus 学习笔记 第12章 存储类别、链接和内存管理
|
存储 缓存 Linux
计算机操作系统学习笔记(5)——内存管理
计算机操作系统学习笔记(5)——内存管理
98 0
|
10月前
|
NoSQL Redis
Redis学习笔记-内存碎片对性能的影响
Redis学习笔记-内存碎片对性能的影响
82 0
|
存储 缓存 算法
十五、Linux性能优化实战学习笔记 - Linux内存是怎么工作的
内存管理也是操作系统最核心的功能之一。内存主要用来存储系统和应用程序的指令、数据、缓存等
267 1
|
存储 缓存 NoSQL
二十一、Linux性能优化实战学习笔记- 如何“快准狠”找到系统内存的问题?
已用内存、剩余内存、共享内存、可用内存、缓存和缓冲区的用量。
121 0
|
存储 缓存 Linux
十八、Linux性能优化实战学习笔记- 内存泄漏了,我该如何定位和处理?
当进程通过 malloc() 申请虚拟内存后,系统并不会立即为其分配物理内存,而是在首次访问时,才通过缺页异常陷入内核中分配内存.对应用程序来说,动态内存的分配和回收,是既核心又复杂的一个逻辑功能模块。管理内存的过程中,也很容易发生各种各样的“事故”.
102 0
|
存储 缓存 BI
|
存储 并行计算 测试技术
【CUDA学习笔记】第五篇:内存以及案例解释(附案例代码下载方式)(二)
【CUDA学习笔记】第五篇:内存以及案例解释(附案例代码下载方式)(二)
148 0
【CUDA学习笔记】第五篇:内存以及案例解释(附案例代码下载方式)(二)