c语言—动态内存管理
一.为什么存在动态内存开辟
开辟空间的特点:
空间开辟大小是固定的
数组在申明时,必须指定数组长度,她所需要的内存在编译时分配
但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,
那数组的编译时开辟空间的方式就不能满足了。
这时候就只能试试动态存开辟了
二.动态内存函数的介绍
1.malloc和free
void*malloc(size_t size);
这个函数向内存申请一块连续的内存空间,并返回这块空间的指针。
如果开辟成功,则返回一个指向这块空间的指针
如果开辟失败,这返回一个NULL,因此malloc函数的返回值一定要做检查
返回的类型是void*,所以malloc函数并不知到开辟空间的类型,具体在使用时使用者自己决定
如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器
free函数使用来释放动态开辟的内存的
void free(void*ptr)
如果参数ptr指向的空间不是动态内存开辟的,那么free函数的行为是未定义的
如果ptr是NULL,则free函数什么都不做
注:malloc和free都声明在stdlib.h的文件中
例:
#include<stdio.h>int main()
{int num=0;scanf("%d",&num);int arr[num]=0;//变长数组int*ptr=NULL;ptr=(int*)malloc(num*sizeof(int));if(NULL!=ptr)//判读ptr是否为空指针{int i=0;for(i=0;i<num;i++){*(ptr+i)=i;}}free(ptr);//释放ptr所指向的动态内存ptr=NULL;//是否有必要?return 0;
}
虽然程序结束后被开辟的内存空间会被释放,但是这样浪费的很多空间,而free能够充分利用内存空间。
最后虽然free(ptr)释放了开辟的动态空间,但是ptr仍然指向那个空间的地址,所以要将ptr设置为空指针来避免空间被不会好意的人通过ptr找到。
2.calloc
void*callor(size_t num,size_t size)
函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0
与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。
例:
#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = calloc(10, sizeof(int));if(NULL != p){//使用空间}free(p);p = NULL;return 0;
}
3.realloc
realloc函数的出现让动态内存管理更加灵活
realloc 函数就可以做到对动态开辟内存大小
的调整。
void*realloc(void*str,size_t size);
ptr是要调整的内存地址
size是调整之后的内存大小
返回调整之后内存的起始位置
这个函数在调整原内存空间的大小的基础上,还会将原内存的数据移到新的空间里
realloc在调整内存空间时有两种情况
情况1:原有空间之后有足够大的空间
情况2:原有空间之后没有足够大的空间
当是情况1的时候,要扩展的内存就在原有的内存之后追加新的空间,原来的数据不发生改变。
当是情况2的时候,扩展的方式就是在堆空间上另找一个适合大小的连续空间使用。这样函数返回的是一个新的内存地址。
例:
int main()
{int* ptr = (int*)malloc(100);if (NULL == ptr){perror(ptr);}else{int i = 0;for(i=0;i<100;i++){*(ptr + i) = i;}}//扩展容量ptr = (int*)realioc(ptr, 1000);//这样可以吗?(如果申请失败会如何?)if (NULL == ptr){perror(ptr);}else{int i = 0;for(i=100;i<=1000;i++){*(ptr + i) = i;}free(ptr);ptr = NULL;return 0;
}
不能像代码1一样操作,因为若(int*)realloc(ptr, 1000)中realloc开辟失败,返回的空指针赋给了ptr,
那么ptr被改掉,ptr指向的空间就找不到了
修改后:
int main()
{int* ptr = (int*)malloc(100);if (NULL == ptr){perror(ptr);}else{int i = 0;for (i = 0; i < 100; i++){*(ptr + i) = i;}}//扩展容量int* p = NULL;p=realloc(ptr, 1000);if (p == NULL){perror(p);}else{ptr = p;int i = 0;for (i = 100; i <= 1000; i++){*(ptr + i) = i;}}free(ptr);ptr = NULL;return 0;
}
三.常见的动态内存错误
1.对空指针的解引用操作
void test()
{int* p = (int*)malloc(INT_MAX);*p = 20;//如果p是空指针就会有问题free(p);
}
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.对非动态开辟内存使用free释放
void test()
{int a = 10;int* p = &a;free(p);
}
4.使用free释放动态开辟内存的一部分
void test()
{int* p = (int*)malloc(10 * sizeof(int));p++;free(p);//p不再指向动态内存的起始位置
}
5.对同一块内存多次释放
void test()
{int *p = (int *)malloc(100);free(p);free(p);//重复释放
}
6.动态内存开辟忘记释放(内存泄漏)
void test()
{int *p = (int *)malloc(100);if(NULL != p){*p = 20;}
}
int main()
{test();while(1);
}
注:忘记释放不再使用的动态开辟的空间会造成内存泄漏
四.几个经典的笔试题
题目1.
void GetMemory(char *p)
{p = (char *)malloc(100);
}
void Test(void)
{char *str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}
请问运行Test 函数会有什么样的结果?
结果:
运行代码会出现兵溃的现象
程序存在内存泄漏
原因是str以值传递的形式给p
p是GetMemory函数的形参,只能在函数内部有效
等GetMemory函数返回返回之后,动态开辟内存尚未释放
并且无法找到,所以会造成内存泄漏
改进:
法一:
可以传str的指针给GetMemory函数,*p就是str
在使用完str后释放它指向的内存空间并将str置为NULL
void GetMemory(char **p)
{*p = (char *)malloc(100);
}
void Test(void)
{char *str = NULL;GetMemory(&str);strcpy(str, "hello world");printf(str);free(str);str=NULL;
}int main()
{test();return 0;
}
法二:
将GetMemory的返回类型改为char*,返回指向开辟空间的地址
在使用完str后释放它指向的内存空间并将str置为NULL
char* GetMemory(char *p)
{p = (char *)malloc(100);return p;
}
void Test(void)
{char *str = NULL;str=GetMemory(&str);strcpy(str, "hello world");printf(str);free(str);str=NULL;
}int main()
{test();return 0;
}
题目2.
char *GetMemory(void)
{char p[] = "hello world";return p;
}
void Test(void)
{char *str = NULL;str = GetMemory();printf(str);
}int main()
{test();return 0;
}
请问运行Test 函数会有什么样的结果?
结果:打印的是随机值
相关文章:
c语言—动态内存管理
一.为什么存在动态内存开辟开辟空间的特点:空间开辟大小是固定的数组在申明时,必须指定数组长度,她所需要的内存在编译时分配但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道ÿ…...
请说明Ajax、Fetch、Axios三者的区别
相同点: 1、三者都用于网络请求,但是不同维度 2、 Ajax(Asynchronous Javascript and XML),一种技术的统称,并不是实际的API 3、Fetch是一个具体的API,浏览器里面直接有一个API就叫Fetch 4、 Axios是一个第三方库&…...
阿里p8测试总监,让我们用这份《测试用例规范》,再也没加班过
经常看到无论是刚入职场的新人,还是工作了一段时间的老人,都会对编写测试用例感到困扰?例如: 固然,编写一份好的测试用例需要:充分的需求分析能力 理论及经验加持,作为测试职场摸爬打滚的老人&…...
【Unity】数据持久化路径Application.persistentDataPath
今天突然想到这个路径Application.persistentDataPath,热更的重要路径,该文件夹可读可写,在移动端唯一一个可读写操作的文件夹。移动端可以将本地的资源(资源MD5值配置表)等一些文件放到StreamingAssets文件夹下&#…...
华为OD机试 - 插队(Java JS Python)
题目描述 某银行将客户分为了若干个优先级, 1 级最高, 5 级最低,当你需要在银行办理业务时,优先级高的人随时可以插队到优先级低的人的前面。 现在给出一个人员到来和银行办理业务的时间序列,请你在每次银行办理业务时输出客户的编号。 如果同时有多位优先级相同且最高…...
MongoDB数据库从入门到精通系列之八:调整oplog大小
MongoDB数据库从入门到精通系列之八:调整oplog大小 一、oplog的概念二、oplog大小三、调整oplog大小详细步骤一、oplog的概念 操作日志oplog包含了主节点执行的每一次写操作。oplog是存在于主节点local数据库中的一个固定集合。从节点通过查询此集合以获取需要复制的操作。每个…...
PCL 间接平差法拟合二维直线
目录 一、算法原理二、代码实现三、结果展示四、相关链接一、算法原理 通过传统最小二乘法对点云数据进行二维直线拟合时,可将误差只归因于一个方向上,本文假设误差只存在于 y y y轴方向上,设点云拟合的二维直线方程为: y =...
进程调度的基本过程
这里写目录标题什么是进程进程管理结构体或类的主要属性pid内存指针文件描述符表辅助进程调度的属性并发并行并发什么是进程 进程是操作系统对一个正在运行的程序的一种抽象,也就是说,一个运行起来的程序就是一个进程。 进程又是操作系统进行资源分配的…...
python自动化办公(二)
上接python自动化办公(一) 文章目录文件和目录操作使用shutil库文件查找globfnmatchhashlib文件和目录操作 使用shutil库 shutil库也是Python标准库,它可以处理文件、文件夹、压缩包,能实现文件复制、移动、压缩、解压缩等功能。…...
Qt Quick - GridLayout 网格布局
GridLayout 理论总结一、概述二、依赖属性三、例子1. 不含跨行的2. 带跨行列的3. 从右到左一、概述 GridLayout 是最常用的布局器,也叫网格布局器,如果网格布局被调整大小,布局中的所有 Item 将被重新排列。它类似于基于widget的QGridLayout…...
安卓手机也可以使用新必应NewBing
没有魔法安卓手机也可以使用新必应NewBing 目前知道的是安卓手机 安卓手机先安装一个猴狐浏览器 打开手机自带浏览器,搜索关键词:猴狐浏览器,找到官网 也可以直接复制这个网址 狐猴浏览器 lemurbrowser CoolAPK 我的手机是荣耀安卓手机…...
支付系统设计:消息重试组件封装
文章目录前言一、重试场景分析一、如何实现重试1. 扫表2. 基于中间件自身特性3. 基于框架4. 根据公司业务特性自己实现的重试二、重试组件封装1. 需求分析2. 模块设计2.1 持久化模块1. 表定义2. 持久化接口定义3. 持久化配置类2.2 重试模块1.启动2.重试3. 业务端使用1. 引入依赖…...
Visual Studio 2022 c#中很实用的VS默认快捷键和原生功能
常常使用VS感觉还是有必要掌握其默认的快捷键,我这个人比较懒,不喜欢动不动就去设置快捷键,系统有就用,记住了就可以到处用,问题是像我们这种有很多个工作场所的人不可能每台电脑都去配置一下快键键。实际上我使用3dma…...
Python的30个编程技巧
1. 原地交换两个数字 Python 提供了一个直观的在一行代码中赋值与交换(变量值)的方法,请参见下面的示例: x,y 10,20 print(x,y) x,y y,x print(x,y) #1 (10, 20) #2 (20, 10) 赋值的右侧形成了一个新的元组,左侧立即解…...
MySQL:JDBC
什么是JDBC? JDBC( Java DataBase Connectivity ) 称为 Java数据库连接 ,它是一种用于数据库访问的应用程序 API ,由一组用Java语言编写的类和接口组成,有了JDBC就可以 用统一的语法对多种关系数据库进行访问,而不用担…...
C++【list容器模拟实现函数解析】
list容器&&模拟实现函数解析 文章目录list容器&&模拟实现函数解析一、list容器使用介绍二、list容器模拟实现及函数解析2.1 list结构体创建2.2 迭代器封装2.21 构造函数:2.22 前置和后置及- -2.23 解引用2.24 判断相等2.25 箭头重载2.26 第二个和第…...
(Java)试题 算法提高 约数个数
一、题目 (1)资源限制 内存限制:512.0MB C/C时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s (2)输入 输入一个正整数N (3)输出 N有几个约数 &a…...
魔法反射--java反射初入门(基础篇)
👳我亲爱的各位大佬们好😘😘😘 ♨️本篇文章记录的为 java反射初入门 相关内容,适合在学Java的小白,帮助新手快速上手,也适合复习中,面试中的大佬🙉🙉🙉。 ♨️如果文章有…...
概率统计_协方差的传播 Covariance Propagation
1. 方差的传播 误差的传播是指分析在形如的关系中,参量误差(x)对变量误差(y)的影响有多大。误差的传播与函数的微分紧密相关,本质是在利用当Δ x 不大时,。 方差计算公式: X为变量,为总体均值,N为总体例数。求变量X与均值的差的平方再求平均值,即得到方差。方差…...
大学生考研的意义?
当我拿起笔头,准备写这个话题时,心里是非常难受的,因为看到太多的学生在最好的年华,在自由的大学本应该开拓知识,提升认知,动手实践,不断尝试和试错,不断历练自己跳出学生思维圈&…...
【C++笔试强训】第三十一天
🎇C笔试强训 博客主页:一起去看日落吗分享博主的C刷题日常,大家一起学习博主的能力有限,出现错误希望大家不吝赐教分享给大家一句我很喜欢的话:夜色难免微凉,前方必有曙光 🌞。 选择题 &#x…...
toString()、equals()是什么,为啥需要重写,多种方法来重写
https://m.runoob.com/java/java-object-class.html toString() 1.为什么会有toString 子类继承父类就可以使用父类所有非私有的属性的方法。 在Java中所有类都直接或者间接继承Object类,可以说只要是Object类里面定义的非私有的属性和方法,任何类都可…...
家装材料清单中会有哪些装饰材料?
在家居装修中,业主可以根据装修公司出具的材料清单去一一采购,这样不至于有遗漏,就算采用全包的方式,通过材料清单也可以大致了解当时房子装修所用的材料,补充自己的装修知识。下面跟随小编一起了解下房子装修材料中所…...
【C++初阶】6. CC++内存管理
1. C/C内存分布 我们先来看下面的一段代码和相关问题 int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] { 1, 2, 3, 4 };char char2[] "abcd";const char* pChar3 "abcd";int* …...
【数据结构】万字超详解顺序表(比细狗还细)
我这个人走得很慢,但是我从不后退。 ——亚伯拉罕林肯 目录 一.什么是线性表? 二.什么是顺序表? 三.接口函数的实现 1.创建工程 2.构造顺序表 3.初始化顺序表 3.初始化顺序表 4.顺序表的尾插 5.顺序…...
yolov5 剪枝、蒸馏、压缩、量化
文章大纲 剪枝推理优化YOLOv5 剪枝可能出现的问题参考文献与学习路径考察神经网络时期重要的激活函数sigmoid和tanh,它们有一个特点,即输入值较大或者较小的时候,其导数变得很小,而在训练阶段(详见1.2.3节),需要求取多个导数值,并将每层得到的导数值相乘,这样一旦层数…...
如何用python代码,更改照片尺寸,以及更换照片底色
前言 python浅浅替代ps?如何用代码来p证件照并且更换底色? 唉,有个小姐姐给我扔了张照片,叫我帮忙给她搞成证件照的尺寸还得换底色,她说自己忙的很 可惜电脑上没有ps只有pycharm,没得办法只能来试试看代…...
【pygame游戏】Python实现蔡徐坤大战篮球游戏【附源码】
前言 话说在前面,我不是小黑子~😏 本文章纯属技术交流~娱乐 前几天我获得了一个坤坤打篮球的游戏,也给大家分享一下吧~ 好吧,其实并不是这样的游戏,往下慢慢看吧。 准备工作 开发环境 Python版本:3.7.8 …...
通过指针引用字符串详解,以及字符指针变量和字符数组的比较
在平常的案例中已大量地使用了字符串,如在 printf函数中输出一个字符串。这些字符串都是以直接形式 (字面形式) 给出的,在一对双引号中包含若干个合法的字符。在本节中将介绍使用字符串的更加灵活方便的方法:通过指针引用字符串。 目录 一、…...
Vue基本整合(一)
NPM安装npm是node的包管理工具https://nodejs.org/en/脚手架安装npm i -g vue/clihttps://registry.npmjs.org/vue浏览器插件https://devtools.vuejs.org/guide/installation.html#chromehttps://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhble…...
福建省建设监理网官方网站/下载百度到桌面
前提 假设你了解过 SpringBoot 和 Kafka。 1、SpringBoot 如果对 SpringBoot 不了解的话,建议去看看 DD 大佬 和 纯洁的微笑 的系列博客。 2、Kafka Kafka 的话可以看看我前两天写的博客 : Kafka 安装及快速入门 学习的话自己开台虚拟机自己手动搭建环境…...
广州商城网站建设报价/百度app客服电话
一、Context 全局的环境对象,提供了很多方便的操作,帮助我们快速的获取数据,进行一些常规的操作。 1.1、获取路径 getFilesDir()等同于/data/data/包名/files/ File file new File(getFilesDir(),"info.txt"); 1.2、缓存文件路径 getCacheDir()等同于/da…...
湖南省住房和城乡建设厅网站/南宁seo排名首页
本文价值与收获 看完本文后,您将能够作出下面的界面 看完本文您将掌握的技能 绘制虚线设置虚线宽度和颜色实战需求 我需要创建一条虚线。我尝试通过创建带有虚线笔触的Rectangle视图来解决这个问题。但是,将矩形的高度设置为1时,会导致出现一条双线,因为它同时显示了视图…...
学院招生网站建设方案/临沂百度推广多少钱
给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。 完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。 …...
阿里云 iis 默认网站/西安seo托管
昨晚本想偶尔看一集《圣斗士冥王篇》,结果一不小心12集统统看完了。谁知道最后也不算结束,仿佛是又出现“神斗士”了。“真正的战斗才刚刚开始!”,还是这句片子中的鬼话。急得本人四处打探,还请高人指点,小…...
有哪些做投行网站/quark搜索引擎入口
导读:谈到锁住,大家应该都熟悉,有朋友问台式电脑键盘锁是哪个键,还有人问台式电脑键盘被锁住按什么键恢复,这到底是咋回事?事实上台式电脑键盘被锁住按什么键恢复呢,以下是小编为你精心整理的台…...