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

C语言:动态内存管理

在这里插入图片描述

文章目录

  • 一、动态内存函数
    • 1. malloc
    • 2. calloc
    • 3. realloc
    • 4. free
  • 二、常见的错误
    • 1.malloc或calloc开辟的空间未检查
    • 2.越界访问
    • 3.对非malloc和calloc开辟的空间,用free释放
    • 4.对同一块动态内存多次释放
    • 5.用free释放动态内存的一部分
  • 三、通讯录(动态版本改写)
  • 总结


一、动态内存函数

要介绍动态内存函数,我们就要知道动态内存函数开辟的空间在内存的什么位置。
如下图所示:
动态内存函数开辟的空间在堆区
动态内存函数开辟的空间在堆区,该区域的空间,只有free函数和程序结束才会释放。

1. malloc

函数的声明:void* malloc (size_t size);包含在<stdlib.h>头文件中。
调用该函数可以向内存中申请大小为size个字节的连续空间,并返回该空间的起始地址。
注意:

  • 如果malloc开辟空间成功,则返回成功开辟好空间的起始地址
  • 如果malloc开辟空间失败,则返回NULL
  • 不要开辟大小为0的空间,这是标准未定义的。

因此,malloc开辟空间后,我们要检查返回值。

#include <stdio.h>
#include <stdlib.h>int main()
{int* pa = (int*)malloc(sizeof(int) * 10);//开辟大小为40个字节的空间//检查是否空间开辟失败if (pa == NULL){exit(-1);}free(pa);pa = NULL;return 0;
}

2. calloc

函数的声明:void* calloc (size_t num, size_t size);包含在<stdlib.h>头文件中。
调用该函数可以向内存中申请num个大小是size个字节的连续空间,再将空间每一个字节初始化为0,并返回该空间的起始地址。
calloc与malloc的唯一区别在于,calloc会将空间每一个字节初始化为0。
如下所示:

#include <stdio.h>
#include <stdlib.h>int main()
{int* arr1 = (int*)malloc(sizeof(int) * 10);if (arr1 == NULL){exit(-1);}for (int i = 0; i < 10; i++){printf("%d ", arr1[i]);}printf("\n");int* arr2 = (int*)calloc(sizeof(int), 10);if (arr2 == NULL){exit(-1);}for (int i = 0; i < 10; i++){printf("%d ", arr2[i]);}free(arr1);free(arr2);arr1 = NULL;arr2 = NULL;return 0;
}

在这里插入图片描述

3. realloc

函数的声明:void* realloc (void* ptr, size_t size);包含在<stdlib.h>头文件中。
调用该函数可以调整由malloc和calloc开辟的空间大小,调整为size个字节大小的空间。
但要注意,其调整空间大小的方式有两种,原地扩容和异地扩容。

  • 原地扩容,原地址空间后空间大小充足,在原地址空间直接扩容。

  • 异地扩容,原地址空间后空间大小不够,在堆区另找一片充足的空间使用。

  • 如果调整的大小过大,realloc会返回NULL。

//异地扩容
int main()
{int* pa = (int*)malloc(sizeof(int) * 10);if (pa == NULL){exit(-1);}printf("%p\n", pa);int* tmp = (int*)realloc(pa, sizeof(int) * 20);if (tmp != NULL){pa = tmp;printf("%p\n", pa);}free(pa);pa = NULL;return 0;
}

在这里插入图片描述


//原地扩容
int main()
{char* pa = (char*)malloc(sizeof(char) * 10);if (pa == NULL){exit(-1);}printf("%p\n", pa);char* tmp = (char*)realloc(pa, sizeof(char) * 20);if (tmp != NULL){pa = tmp;printf("%p\n", pa);}free(pa);pa = NULL;return 0;
}

在这里插入图片描述

4. free

函数的声明:void free (void* ptr);包含在<stdlib.h>头文件中。
调用该函数可以释放由malloc和calloc开辟的空间,指针变量ptr本身内容不变,需要程序员本身置空。

  • 如果ptr是NULL,则函数什么事都不会做
  • 如果ptr并不是malloc和calloc开辟的空间,那free函数的行为未定义

如下:

int main()
{int* pa = (int*)malloc(sizeof(int) * 10);if (pa == NULL){exit(-1);}free(pa);//释放pa所指向的空间pa = NULL;//pa置NULL,防止野指针return 0;
}

二、常见的错误

1.malloc或calloc开辟的空间未检查

有时开辟空间过大,而未检查时,会发生对NULL的解引用


int main()
{int* pa = (int*)malloc(sizeof(int) * INT_MAX);*pa = 10;free(pa);pa = NULL;return 0;
}

在这里插入图片描述

2.越界访问

访问超出开辟空间大小

int main()
{int* pa = (int*)malloc(sizeof(int) * 10);if (pa == NULL){exit(-1);}for (int i = 0; i < 11; i++){pa[i] = 0;}free(pa);pa = NULL;return 0;
}

在这里插入图片描述

3.对非malloc和calloc开辟的空间,用free释放

free函数只能用了释放动态内存空间

int main()
{int arr[10] = { 0 };free(arr);return 0;
}

在这里插入图片描述

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

动态内存空间释放一次即可

int main()
{int* pa = (int*)malloc(sizeof(int) * 10);if (pa == NULL){exit(-1);}free(pa);free(pa);pa = NULL;return 0;
}

在这里插入图片描述

5.用free释放动态内存的一部分

开辟的动态内存空间实际大小要大于我们申请的大小,那多出的一部分空间要记录我们这次申请空间的信息,free函数就可以根据这一部分信息来释放我们申请的空间大小。如果我们传递的指针并未指向空间首地址,那么free就找不到信息来释放空间。

int main()
{int* pa = (int*)malloc(sizeof(int) * 10);if (pa == NULL){exit(-1);}pa++;free(pa);pa = NULL;return 0;
}

在这里插入图片描述

三、通讯录(动态版本改写)

静态版本通讯录
相对于静态版本而言,动态版本改变并不多也不难,下面就是要改变的部分。

  1. 结构
//动态版本
typedef struct Contact
{PeoInfo* data;int sz;//记录此时已用的大小int capacity;//记录通讯录的大小
}Contact;

2.初始化InitContact

#define INITSIZE 10//初始化通讯录
void InitContact(Contact* pc)
{pc->sz = 0;pc->capacity = INITSIZE;pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INITSIZE);if (pc->data == NULL){perror("malloc");return;}
}
  1. 扩容AddCapacity
bool AddCapacity(Contact* pc)
{PeoInfo* tmp = realloc(pc->data, sizeof(PeoInfo) * (pc->capacity) * 2);if (tmp == NULL){perror("realloc");return false;}pc->data = tmp;pc->capacity *= 2;return true;
}//添加联系人
void AddContact(Contact* pc)
{assert(pc);if (pc->sz == pc->capacity){if (AddCapacity(pc) == true){printf("扩容成功\n");}else{printf("扩容失败\n");return;}}printf("请输入联系人名字:>");scanf("%s", pc->data[pc->sz].name);printf("请输入联系人性别:>");scanf("%s", pc->data[pc->sz].sex);printf("请输入联系人年龄:>");scanf("%d", &(pc->data[pc->sz].age));printf("请输入联系人电话:>");scanf("%s", pc->data[pc->sz].tele);printf("请输入联系人地址:>");scanf("%s", pc->data[pc->sz].adder);pc->sz += 1;
}
  1. 退出ExitContact
//退出通讯录
void ExitContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;
}

总结

以上就是我对于动态内存管理的了解和应用。

相关文章:

C语言:动态内存管理

文章目录 一、动态内存函数1. malloc2. calloc3. realloc4. free 二、常见的错误1.malloc或calloc开辟的空间未检查2.越界访问3.对非malloc和calloc开辟的空间&#xff0c;用free释放4.对同一块动态内存多次释放5.用free释放动态内存的一部分 三、通讯录(动态版本改写)总结 一、…...

如何往MySQL中插入100万条数据?

需求 现在有一个 数据量 为100万的数据样本 100w_data.sql 其数据格式如下&#xff0c;截取最后十条数据 999991,XxGdnLZObA999991,XxGdnLZObA,XxGdnLZObA,2020-3-18,1 999992,TBBchSKobC999992,TBBchSKobC,TBBchSKobC,2020-9-8,2 999993,rfwgLkYhUz999993,rfwgLkYhUz,rfwgLk…...

IntelliJ IDEA 2023.2 最新变化

主要更新 AI Assistant 限定访问 Ultimate 在此版本中&#xff0c;我们为 IntelliJ IDEA 引入了一项重要补充 – AI Assistant。 AI Assistant 当前具备一组由 AI 提供支持的初始功能&#xff0c;提供集成式 AI 聊天&#xff0c;可以完成一些任务&#xff0c;例如自动编写文档…...

1300*B. T-primes

解析&#xff1a; 有且只有三个因数&#xff0c;当且仅当&#xff0c;完全平方数并且sqrt&#xff08;n&#xff09;为素数 #include<bits/stdc.h> using namespace std; typedef long long ll; const int N1e55; ll t,n; bool prime(ll x){if(x<2) return 0;for(int…...

重新C++系列之运算符重载

一、什么是运算符重载 简单来讲就是对运算符赋予新的意义&#xff0c;但是又不能改变原有的含义&#xff0c;它本身也就是一个函数。运算符重载的本质是以函数的方式来体现。 二、运算符重载有几种 1、按照作用域来划分&#xff0c;有全局操作符重载函数和成员函数操作符重载函…...

kotlin异常处理try-catch-finally

kotlin异常处理try-catch-finally fun main(args: Array<String>) {try {println("a")} catch (e: Exception) {//异常捕获println("a-catch: $e")} finally {//善后&#xff0c;无论是否异常&#xff0c;都会执行println("a-finally")}t…...

Pytorch在cuda、AMD DirectML和AMD CPU下性能比较

一、测试环境 CUDA环境: i7-8550u 16G DDR4 2133MHz nVidia MX150 2GB AMD DirectML环境: Ryzen 5 5600G 32G DDR4 3200MHz Vega7 4GB AMD 纯CPU环境&#xff1a;Ryzen 5 5600G 32G DDR4 3200MHz 其他硬件配置的硬盘、电源均一致。Pytorch版本为2.0.0&#xff0c;Pyt…...

哈工大计算机网络课程局域网详解之:交换机概念

哈工大计算机网络课程局域网详解之&#xff1a;交换机概念 文章目录 哈工大计算机网络课程局域网详解之&#xff1a;交换机概念以太网交换机&#xff08;switch&#xff09;交换机&#xff1a;多端口间同时传输交换机转发表&#xff1a;交换表交换机&#xff1a;自学习交换机互…...

Jenkins Pipeline的hasProperty函数

函数的作用 用于判断某个参数或者字段是否存在。 用法 例子一 def projectStr "P1,P2,P3" pipeline {agent anyparameters {extendedChoice(defaultValue: "${projectStr}",description: 选择要发布的项目,multiSelectDelimiter: ,,name: SELECT_PROJ…...

芯片制造详解.净洁室的秘密.学习笔记(三)

这是芯片制造系列的第三期跟学up主三圈&#xff0c;这里对其视频内容做了一下整理和归纳&#xff0c;喜欢的可以看原视频。 芯片制造详解03&#xff1a; 洁净室的秘密&#xff5c;为何芯片厂缺人&#xff1f; 芯片制造详解.净洁室的秘密.学习笔记 三 简介一、干净的级别二、芯片…...

可解释的 AI:在transformer中可视化注意力

Visualizing Attention in Transformers | Generative AI (medium.com) 一、说明 在本文中&#xff0c;我们将探讨可视化变压器架构核心区别特征的最流行的工具之一&#xff1a;注意力机制。继续阅读以了解有关BertViz的更多信息&#xff0c;以及如何将此注意力可视化工具整合到…...

k8s Webhook 使用java springboot实现webhook 学习总结

k8s Webhook 使用java springboot实现webhook 学习总结 大纲 基础概念准入控制器&#xff08;Admission Controllers&#xff09;ValidatingWebhookConfiguration 与 MutatingWebhookConfiguration准入检查&#xff08;AdmissionReview&#xff09;使用Springboot实现k8s-Web…...

JS逆向之猿人学爬虫第20题-wasm

文章目录 题目地址sign参数分析python算法还原往期逆向文章推荐题目地址 https://match.yuanrenxue.cn/match/20第20题被置顶到了第1页,题目难度 写的是中等 算法很简单,就一个标准的md5算法,主要是盐值不确定, 而盐值就在wasm里面,可以说难点就在于wasm分析 sign参数分…...

【双指针优化DP】The 2022 Hangzhou Normal U Summer Trials H

Problem - H - Codeforces 题意&#xff1a; 思路&#xff1a; 首先很明显是DP 因为只有1e6个站点&#xff0c;因此可以以站点作为阶段 注意到K很小&#xff0c;因此可以尝试把这个当作第二维 设dp[i][j]为到达第i个站点&#xff0c;已经花了j元钱的最小步数 然后就想了一…...

[论文笔记] LLM数据集——金融数据集

一、chatglm_金融 ModelScope 魔搭社区 请将modelscope sdk升级到v1.7.2rc0&#xff0c;执行&#xff1a; ​ pip3 install "modelscope1.7.2rc0" -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html # 方式1 git clone http://www.modelscope…...

在亚马逊平台,如何有效举报违规行为?

众所周知&#xff0c;在每个行业都有一些违规现象&#xff0c;甚至这些违规现象还会给自己带来利益方面的损失&#xff0c;一旦触犯到自己的利益的话&#xff0c;那自己是需要想办法解决的&#xff0c;想办法规避。 就拿开亚马逊店铺来说&#xff0c;比较容易遇到的就是产品侵…...

深度学习入门教学——神经网络

深度学习就是训练神经网络。 1、神经网络 举个最简单的例子&#xff0c;以下是一个使用线性回归来预测房屋价格的函数。这样一个用于预测房屋价格的函数被称作是一单个神经元。大一点的神经网络&#xff0c;就是将这些单个神经元叠加起来。例如&#xff1a;神经网络根据多个相…...

阿里Java开发手册~OOP 规约

1. 【强制】避免通过一个类的对象引用访问此类的静态变量或静态方法&#xff0c;无谓增加编译器解析成 本&#xff0c;直接用 类名 来访问即可。 2. 【强制】所有的覆写方法&#xff0c;必须加 Override 注解。 说明&#xff1a; getObject() 与 get 0 bject() 的问题。…...

【Mysql数据库面试01】内连接 左连接 右连接 全连接

【Mysql数据库】内连接 左连接 右连接 全连接 0.准备1.内连接1.1 SQL(不带where)1.2 SQL&#xff08;带where&#xff09;1.3总结 2.左连接2.1SQL&#xff08;不带where&#xff09;2.2SQL&#xff08;带where&#xff09;2.3总结 3.右连接3.1 SQL&#xff08;不带where&#x…...

事务隔离:为什么你改了我还看不见

前提概要 你肯定不陌生&#xff0c;和数据库打交道的时候&#xff0c;我们总是会用到事务。最经典的例子就 是转账&#xff0c;你要给朋友小王转 100 块钱&#xff0c;而此时你的银行卡只有 100 块钱。 转账过程具体到程序里会有一系列的操作&#xff0c;比如查询余额、做加减法…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

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

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

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

MySQL的pymysql操作

本章是MySQL的最后一章&#xff0c;MySQL到此完结&#xff0c;下一站Hadoop&#xff01;&#xff01;&#xff01; 这章很简单&#xff0c;完整代码在最后&#xff0c;详细讲解之前python课程里面也有&#xff0c;感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...

数据库正常,但后端收不到数据原因及解决

从代码和日志来看&#xff0c;后端SQL查询确实返回了数据&#xff0c;但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离&#xff0c;并且ai辅助开发的时候&#xff0c;很容易出现前后端变量名不一致情况&#xff0c;还不报错&#xff0c;只是单…...

【51单片机】4. 模块化编程与LCD1602Debug

1. 什么是模块化编程 传统编程会将所有函数放在main.c中&#xff0c;如果使用的模块多&#xff0c;一个文件内会有很多代码&#xff0c;不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里&#xff0c;在.h文件里提供外部可调用函数声明&#xff0c;其他.c文…...