动态内存管理(上)

简介: 动态内存管理(上)

本章内容

为什么存在动态内存分配
动态内存函数的介绍

malloc
free
calloc
realloc

常见的动态内存错误

为什么存在动态内存分配

如果不使用动态内存分配的话,仅知道的内存开辟方式有:

int val = 20;//在栈空间上开辟四个字节

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

不过上述两种方式的内存开辟有两个特点:

  1. 空间开辟大小是固定的。
  2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配

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

动态内存函数的介绍

在C语言中,动态内存管理主要通过以下四个函数来实现,分别是malloc、free、calloc、realloc,接下里我们来了解一下这些函数。

malloc和free

malloc 是 C 语言中用于动态分配内存空间的函数。它接受一个 size_t 类型的参数,表示要分配的内存空间的大小(以字节为单位),并返回一个指向分配的内存空间的指针。

函数原型如下:

void* malloc(size_t size);

使用 malloc 函数可以在程序运行时动态地分配内存空间,这样可以灵活地管理内存,避免静态内存分配的限制。通过 malloc 分配的内存空间在堆上申请,并在程序运行结束后需要手动释放。我们通过free函数用来释放动态开辟的内存。

对于free函数我们需要知道两个知识。

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

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

下面是 malloc 函数的使用示例:

#include <stdio.h>
int main()
{
  int num;
  scanf("%d", &num);
  int* ptr = NULL;
  ptr = (int*)malloc(num * sizeof(int));
  if (NULL != ptr)//判断ptr指针是否为空
  {
    int i = 0;
    for (i = 0; i < num; i++)
    {
      *(ptr + i) = 5;
    }
  }
  free(ptr);//释放ptr所指向的动态内存
  ptr = NULL;//是否有必要?
  return 0;
}

我们考虑这些问题的时候,来看一下调试代码过程

这个时候代码即将运行到开辟动态内存赋值给ptr,在这里为了方便测试输入的num值是2,就不给大家显示了。

这是执行完动态内存开辟后的监视窗口,此时已经开辟了空间并赋给ptr,所以我们可以访问ptr了。

这是执行完给开辟空间赋值循环后的监视窗口,可以看到,我们开辟了两个整形字节的空间,并全部赋值5。

这里执行完free函数,释放了赋给ptr的值,可以看到ptr的值又变成了没有赋值之前的随机值(作者分两次运行截图的,显示不同,再一次运行时是相同的)。

最后我们把ptr设为空指针,就完成了。

可能有些小伙伴会好奇,为什么一定要释放动态内存开辟的值,那么接下来我们来了解一下原因。

当通过动态内存分配函数分配内存后,系统会为该内存保留空间供程序使用。在程序不再需要使用这块动态分配的内存时,应当通过调用 free 函数显式地将其释放。

这样做的好处有:

1.避免内存泄漏:如果不释放动态分配的内存,这些内存空间将会一直占用系统内存,造成内存泄漏。随着程序运行时间的增长,内存泄漏会导致系统内存耗尽,导致程序崩溃或系统性能下降。

2.提高内存利用率:释放不再使用的内存空间,可以让系统重新利用这些内存,从而提高整体内存利用率。

3.避免指针悬挂:如果没有及时释放动态分配的内存,并将指向该内存的指针继续使用,那么指针将变成“悬挂指针”,随时可能指向无效的内存空间,导致程序出现未定义行为或崩溃。

若不释放动态分配的内存,系统会在程序运行结束后会回收整个进程所使用的内存,但这并不是一个良好的做法。在长时间运行的程序中,不释放内存可能导致内存泄漏问题逐渐积累,最终影响系统的稳定性和性能。

因此,为保证程序的健壮性和内存的正确管理,当不再需要使用通过动态内存分配函数分配的内存时,应当使用 free 函数显式地释放该内存空间。同时,为了避免悬挂指针的问题,对释放后的指针,应将其设置为 NULL,这样可以提前发现并避免误用。

calloc

calloc 是 C 语言中用于动态分配内存空间并初始化为零的函数。它接受两个 size_t 类型的参数,分别表示要分配的元素数量和每个元素的大小,返回一个指向分配的内存空间的指针。

函数原型如下:

void* calloc(size_t num, size_t size);

calloc 函数在内存分配时会将分配的内存块初始化为零,相当于将所有位都设置为 0。这是与 malloc 函数的一个主要区别,malloc 分配的内存空间不进行初始化,可能包含垃圾数据。

使用 calloc 函数可以方便地进行内存分配和初始化操作,特别适用于需要分配并清零内存的场景,例如分配数组或结构体等。

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

#include <stdio.h>
#include <stdlib.h>
int main()
{
 int *p = (int*)calloc(10, sizeof(int));
 if(NULL != p)
 {
 //使用空间
 free(p);
 p = NULL;
 return 0;
}

所以如何我们对申请的内存空间的内容要求初始化,那么可以很方便的使用calloc函数来完成任务。

目录
相关文章
|
5天前
|
存储 缓存 C语言
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
22 3
|
1月前
|
程序员
动态内存管理
动态内存管理
14 0
|
5月前
|
存储 Linux C语言
5.C++动态内存管理(超全)
5.C++动态内存管理(超全)
|
存储 编译器 C语言
动态内存管理(1)
动态内存管理(1)
|
6月前
|
程序员 C语言 C++
详解动态内存管理!
详解动态内存管理!
|
11月前
|
程序员 C语言 C++
动态内存管理-2
动态内存管理
46 0
|
C语言 C++
C++中的动态内存管理
C++中的动态内存管理
|
程序员 编译器 C语言
动态内存管理(上)
动态内存管理(上)
45 0
|
程序员 编译器 C++
【C】动态内存管理详解
C/C++程序内存分配的几个区域: 1.栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。 2.堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似于链表。 3.数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。 4.代码段:存放函数体(类成员函数和全局函数)的二进制代码。
【C】动态内存管理详解