当前位置: 首页 > news >正文

【C进阶】动态内存管理

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

我们之前学的都是开辟固定大小的空间,但有时候需要空间的大小只有在程序运行时才能知道,那么就引入了动态内存开辟

内存分布所在:

二、动态内存函数的介绍

2.1malloc和free

动态内存开辟的函数

void * malloc(size_t  size)      (字节为单位)

头文件:<stdlib.h>

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

(1)开辟成功:返回指向开辟好空间的指针

(2)开辟失败:返回一个NULL指针,空指针是不能进行操作的(因此malloc的返回值一定要做检查

(3)返回值的类型是 void*,具体使用时自己进行强制类型转换

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


动态内存的释放和回收

void free(void * ptr)

头文件:<stdlib.h>

把这块空间还给操作系统,但是ptr指向的还是这块地址,也就是ptr变为了野指针(那么为了安全,free结束后都会使ptr=free

(1)如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的
(2)如果参数 ptr 是NULL指针,则函数什么事都不做


malloc函数申请的空间,释放有两种情形:

(1)free主动释放

(2)程序退出(前提)后,malloc申请的空间被操作系统回收(被动释放)

#include<stdlib.h>
#include<stdio.h>
int main()
{//申请一块空间,来存放10个整形int* p = (int*)malloc(10 * sizeof(int));if (p == NULL){perror("malloc");return 1;//异常返回}//使用for (int i = 0; i < 10; i++){*(p + i) = i;}for (int i = 0; i < 10; i++){printf("%d ", p[i]);}//释放free(p);p = NULL;return 0;
}

2.2calloc

也是用来动态开辟的(比malloc多一个参数num,而且会自动初始化为0)

void * calloc (size_t  num , size_t  size)

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


2.3realloc(re-alloc再开辟空间)

有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整

void * realloc (void * ptr ,size_t size)

(1)ptr 是要调整的内存地址

(2)size 调整之后新大小

(3)返回值为调整之后的内存起始位置

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

realloc空间再开辟也可能失败,失败就返回NULL,那么空间就变小了

(如果为NULL,没有ptr,realloc创建的地址直接赋给原地址p,p变为NULL,空间变小了,p连原来的空间都访问不了)

为了防止这样的情况出现:

int* ptr = (int*)realloc(p, 2000 * sizeof(int));
if (ptr != NULL)
{p = ptr;
}

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

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

直接原有内存之后直接追加空间,原来空间的数据不发生变化

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

扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。

<1>将旧的空间数据拷贝到新的空间(不能让数据丢了)

<2>释放掉旧的空间

<3>返回新的空间地址

 

 (6)当realloc的第一个参数为NULL时,realloc等价于malloc

nt* p = (int*)realloc(NULL, 40);// ==malloc(40)
if (p == NULL)
{}

realloc代码演示: 

#include<stdlib.h>
#include<stdio.h>
int main()
{//申请一块空间,来存放10个整形int* p = (int*)calloc(10 , sizeof(int));if (p == NULL){perror("calloc");return 1;}//使用for (int i = 0; i < 10; i++){*(p + i) = i;}for (int i = 0; i < 10; i++){printf("%d ", p[i]);}//空间不够,希望调整空间为20个整形空间int* ptr = (int*)realloc(p, 20 * sizeof(int));if (ptr != NULL){p = ptr;}//释放free(p);p = NULL;return 0;
}

三、 常见的动态内存错误

3.1 对NULL指针的解引用操作

void test()
{int *p = (int *)malloc(INT_MAX/4);*p = 20;//如果p的值是NULL,就会有问题free(p);
}

需要加上:

if (p == NULL)
 {

       perror("malloc");
        return 1;
 }

 3.2 对动态开辟空间的越界访问

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);
}

3.3 对非动态开辟内存使用free释放

局部变量在堆区,动态释放的空间在栈区

void test()
{int a = 10;int *p = &a;free(p);//ok?
}

3.4 使用free释放一块动态开辟内存的一部分

为了不让p动,可以再定义一个指针变量等于p

void test()
{int *p = (int *)malloc(100);p++;free(p);//p不再指向动态内存的起始位置
}

3.5 对同一块动态内存多次释放

所以free开辟的空间以后一定要加上p=NULL

void test()
{int* p = (int*)malloc(100);free(p);free(p);//重复释放
}

3.6 动态开辟内存忘记释放(内存泄漏)

void test()
{int* p = (int*)malloc(100);if (NULL != p){*p = 20;}
}
int main()
{test();while (1);
}

忘记释放不再使用的动态开辟的空间会造成内存泄漏。

切记:

动态开辟的空间一定要释放,并且正确释放

int* test()
{int* p = (int*)malloc(40);//...if (3)return p;free(p);p = NULL;
}int main()
{int* ret = test();while (1){;}free(ret);//在main函数中freeret = NULL;return 0;
}

本次内容就到此啦,欢迎评论区或者私信交流,觉得笔者写的还可以,或者自己有些许收获的,麻烦铁汁们动动小手,给俺来个一键三连,万分感谢 ! 

相关文章:

【C进阶】动态内存管理

一、为什么存在动态内存分配 我们之前学的都是开辟固定大小的空间&#xff0c;但有时候需要空间的大小只有在程序运行时才能知道&#xff0c;那么就引入了动态内存开辟 内存分布所在&#xff1a; 二、动态内存函数的介绍 2.1malloc和free 动态内存开辟的函数 void * malloc…...

神经网络的梯度优化方法

神经网络的梯度优化是深度学习中至关重要的一部分&#xff0c;它有助于训练神经网络以拟合数据。下面将介绍几种常见的梯度优化方法&#xff0c;包括它们的特点、优缺点以及原理。 梯度下降法 (Gradient Descent): 特点: 梯度下降是最基本的优化算法&#xff0c;它试图通过迭代…...

linux 装机教程(自用备忘)

文章目录 安装 pyenv 管理多版本 python 环境安装使用使用 pyenv 和 virtualenv 管理虚拟 python 环境 vscode 连接远程服务器tmux 美化zsh 安装 pyenv 管理多版本 python 环境 安装 &#xff08;教程参考&#xff1a;https://www.modb.pro/db/155036&#xff09; sudo apt-…...

Tensorboard安装及简单使用

Tensorboard 1. tensorboard 简单介绍2. 安装必备环境3. Tensorboard安装4. 可视化命令 1. tensorboard 简单介绍 TensorBoard是一个可视化的模块&#xff0c;该模块功能强大&#xff0c;可用于深度学习网络模型训练查看模型结构和训练效果&#xff08;预测结果、网络模型结构…...

SpringCloud 微服务全栈体系(二)

第三章 Eureka 注册中心 假如我们的服务提供者 user-service 部署了多个实例&#xff0c;如图&#xff1a; 思考几个问题&#xff1a; order-service 在发起远程调用的时候&#xff0c;该如何得知 user-service 实例的 ip 地址和端口&#xff1f;有多个 user-service 实例地址…...

flutter 常用组件:列表ListView

文章目录 总结#1、通过构造方法直接构建 ListView 提供了一个默认构造函数 ListView,我们可以通过设置它的 children 参数,很方便地将所有的子 Widget 包含到 ListView 中。 不过,这种创建方式要求提前将所有子 Widget 一次性创建好,而不是等到它们真正在屏幕上需要显示时才…...

十四天学会C++之第七天:STL(标准模板库)

1. STL容器 什么是STL容器&#xff0c;为什么使用它们。向量&#xff08;vector&#xff09;&#xff1a;使用向量存储数据。列表&#xff08;list&#xff09;&#xff1a;使用列表实现双向链表。映射&#xff08;map&#xff09;&#xff1a;使用映射实现键值对存储。 什么…...

Linux 下安装 miniconda,管理 Python 多环境

安装 miniconda 1、下载安装包 Miniconda3-py37_22.11.1-1-Linux-x86_64.sh&#xff0c;或者自行选择版本 2、把安装包上传到服务器上&#xff0c;这里放在 /home/software 3、安装 bash Miniconda3-py37_22.11.1-1-Linux-x86_64.sh 4、按回车 Welcome to Miniconda3 py37…...

Django和jQuery,实现Ajax表格数据分页展示

1.需求描述 当存在重新请求接口才能返回数据的功能时&#xff0c;若页面的内容很长&#xff0c;每次点击一个功能&#xff0c;页面又回到了顶部&#xff0c;对于用户的体验感不太友好&#xff0c;我们希望当用户点击这类的功能时&#xff0c;能直接加载到数据&#xff0c;请求…...

k8s认证

1. 证书介绍 服务端保留公钥和私钥&#xff0c;客户端使用root CA认证服务端的公钥 一共有多少证书&#xff1a; *Etcd&#xff1a; Etcd对外提供服务&#xff0c;要有一套etcd server证书Etcd各节点之间进行通信&#xff0c;要有一套etcd peer证书Kube-APIserver访问Etcd&a…...

基于python开发的IP修改工具

工作中调试设备需要经常修改电脑IP&#xff0c;非常麻烦&#xff0c;这里使用Pythontkinter做了一个IP修改工具 说明: 1.启动程序读取config.json文件2.如果没有该文件则创建&#xff0c;写入当前网卡信息3.通过配置信息进行网卡状态修改4.更新文件状态&#xff0c;删除或修…...

Mybatis源码分析

1. Mybatis整体三层设计 SSM中&#xff0c;Spring、SpringMVC已经在前面文章源码分析总结过了&#xff0c;Mybatis源码相对Spring和SpringMVC而言是的简单的&#xff0c;只有一个项目&#xff0c;项目下分了很多包。从宏观上了解Mybatis的整体框架分为三层&#xff0c;分别是基…...

python树结构包treelib入门及其计算应用

树是计算机科学中重要的数据结构。例如决策树等机器学习算法设计、文件系统索引等。创建treelib包是为了在Python中提供树数据结构的有效实现。 Treelib的主要特点包括&#xff1a; 节点搜索的高效操作。支持常见的树操作&#xff0c;如遍历、插入、删除、节点移动、浅/深复制…...

Rust之自动化测试(三): 测试组合

开发环境 Windows 10Rust 1.73.0 VS Code 1.83.1 项目工程 这里继续沿用上次工程rust-demo 测试组合 正如本章开始时提到的&#xff0c;测试是一个复杂的学科&#xff0c;不同的人使用不同的术语和组织。Rust社区根据两个主要类别来考虑测试:单元测试和集成测试。单元测试很…...

专业管理菜单的增删改、查重

1&#xff0c;点击专业管理菜单------查询所有专业信息列表 ①点击菜单&#xff0c;切换专业组件 ②切换到列表组件后&#xff0c;向后端发送请求到Servlet ③调用DAO层&#xff0c;查询数据库&#xff08;sql&#xff09;&#xff0c;封装查询到的内容 ④从后端向前端做出…...

vue3插件开发,上传npm

创建插件 在vue3工程下&#xff0c;创建组件vue页: toolset.vue。并设置组件名称。注册全局组件。新建index.js文件。内容如下&#xff0c;可在main.js中引入index.js&#xff0c;注册该组件进行测试。![在这里插入图片描述](https://img-blog.csdnimg.cn/a3409d2cbeec41c797d5…...

python【多线程、单线程、异步编程】三个版本--在爬虫中的应用

并发编程在爬虫中的应用 之前的课程&#xff0c;我们已经为大家介绍了 Python 中的多线程、多进程和异步编程&#xff0c;通过这三种手段&#xff0c;我们可以实现并发或并行编程&#xff0c;这一方面可以加速代码的执行&#xff0c;另一方面也可以带来更好的用户体验。爬虫程…...

大模型LLM相关面试题整理-位置编码-tokenizer-激活函数-layernorm

10 LLMs 位置编码篇 10.1.1 什么是位置编码&#xff1f; 位置编码是一种用于在序列数据中为每个位置添加位置信息的技术。在自然语言处理中&#xff0c;位置编码通常用于处理文本序列。由于传统的神经网络无法直接捕捉输入序列中的位置信息&#xff0c;位置编码的引入可以帮助…...

python在nacos注册微服务

安装 首先需要安装python的nacos sdk pip install nacos-sdk-python 注册 注册过程非常简单&#xff0c;需要注意的是&#xff0c;注册完要定时发送心跳&#xff0c;否则服务会被nacos删掉。 import nacos import timeSERVER_ADDRESSES "http://1.2.3.4:8848" …...

tuxera ntfs2024破解版mac电脑磁盘读写软件

大家都知道由于操作系统的原因&#xff0c;在苹果电脑上不能够读写NTFS磁盘&#xff0c;但是&#xff0c;今天小编带来的这款tuxera ntfs 2024 mac版&#xff0c;完美的解决了这个问题。这是一款在macOS平台上使用的磁盘读写软件&#xff0c;能够实现苹果Mac OS X系统读写Micro…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...