动态内存管理(上)

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

本章内容

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

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函数来完成任务。

目录
相关文章
|
算法 安全 PHP
密码学系列之二:密码学基本概念
密码学系列之二:密码学基本概念
1013 0
密码学系列之二:密码学基本概念
|
缓存 监控 Python
解密Python中的装饰器:优雅而强大的编程利器
Python中的装饰器是一种强大而又优雅的编程工具,它能够在不改变原有代码结构的情况下,为函数或类添加新的功能和行为。本文将深入解析Python装饰器的原理、用法和实际应用,帮助读者更好地理解和利用这一技术,提升代码的可维护性和可扩展性。
|
6月前
|
存储 Java API
Java Optional 完全指南:彻底告别 NullPointerException
Java 8 引入的 `Optional` 类旨在解决 `null` 带来的空指针异常问题,通过提供容器类显式处理可能为空的值,提升代码健壮性和可读性。本文从基础到进阶解析 `Optional` 的用法,涵盖创建、检查、获取值、处理值等核心功能,结合实际应用场景与最佳实践,助你彻底告别 `NullPointerException`,编写更优雅的 Java 代码。
306 0
|
缓存 资源调度 JavaScript
Vue3+TS+Vite开发组件库并发布到npm
**vue-amazing-ui 组件库** 是一个基于 Vue 3 的高质量 UI 组件库,提供了丰富的组件和工具函数。该库已发布至 npm,可通过 `pnpm i vue-amazing-ui`、`yarn add vue-amazing-ui` 或 `npm install vue-amazing-ui` 安装使用。组件包括按钮、面包屑、卡片、日期选择器等,同时提供了日期格式化、节流、防抖等实用工具函数。项目结构清晰,支持按需加载,并提供了详细的文档与在线预览。
279 1
Vue3+TS+Vite开发组件库并发布到npm
|
存储 Linux 5G
Linux 基于 LVM 逻辑卷的磁盘管理【简明教程】
这篇文章介绍了LVM(逻辑卷管理)如何提供灵活的磁盘管理方式,允许动态调整逻辑卷的大小而不会丢失数据。
Linux 基于 LVM 逻辑卷的磁盘管理【简明教程】
|
人工智能 分布式计算 算法
3D-Speaker多模态说话人问题之3D-Speaker的开源代码和数据集如何获取
3D-Speaker多模态说话人问题之3D-Speaker的开源代码和数据集如何获取
328 1
|
12月前
|
安全 网络安全 数据安全/隐私保护
【Azure Developer】System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
157 2
|
11月前
|
存储 算法 安全
FreeMQTT:一款Python语言实现的开源MQTT Server
FreeMQTT 是一款用 Python 语言并基于 Tornado 开发的开源 MQTT 服务器,支持 MQTT3.1.1 和 MQTT5.0 协议,提供多租户安全隔离、高效 Topic 匹配算法及实时上下线通知等功能,适用于 IoT 场景。快速启动仅需克隆仓库、安装依赖并运行服务。
1235 0
|
机器人 Shell 开发者
`roslibpy`是一个Python库,它允许非ROS(Robot Operating System)环境(如Web浏览器、移动应用等)与ROS环境进行交互。通过使用`roslibpy`,开发者可以编写Python代码来远程控制ROS节点,发布和订阅话题,以及调用服务。
`roslibpy`是一个Python库,它允许非ROS(Robot Operating System)环境(如Web浏览器、移动应用等)与ROS环境进行交互。通过使用`roslibpy`,开发者可以编写Python代码来远程控制ROS节点,发布和订阅话题,以及调用服务。