动态内存管理(malloc,calloc,realloc,free)+经典笔试题

动态内存管理

  • 一. malloc 和 free
    • 1. malloc
    • 2. free
  • 二. calloc
  • 三. realloc
  • 四.动态内存的错误
    • 1.对NULL指针的解引用操作
    • 2.对动态开辟空间的越界访问
    • 3.对非动态开辟内存使用free释放
    • 4.使用free释放一块动态开辟内存的一部分
    • 5.对同一块动态内存多次释放
    • 6.动态开辟内存忘记释放(内存泄漏)
  • 五.动态内存经典笔试题分析

前言:

  1. 当我们要开辟一块连续的内存空间时,我们第一时间想到的可能是数组。但是一但开辟了数组,数组的大小就确定了,无法调整数组的大小。
  2. 有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。
  3. 于是动态内存开辟函数(malloc,calloc,realloc,free)应运而生,下文带您一一了解其中的奥秘。

一. malloc 和 free

1. malloc

void* malloc(size_t size);

解释:在堆区中开辟一块大小为 size 个字节的空间,返回指向这块空间的起始地址(泛型指针void*)

因为这块空间存放的数据类型不知(由程序员自己确定),所以用泛型指针接收该地址,在使用的时候记得养成一个好习惯:强制类型转换为自己需要的数据类型。

  1. 如果开辟成功,则返回一个指向开辟好空间的指针。

  2. 如果开辟失败,则返回一个 NULL 指针,因此malloc的返回值一定要做检查。

  3. 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候程序员自己来决定。

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

2. free

void free(void* ptr);

解释:free是用来对动态内存的释放和回收的。free 对指针 ptr 指向的内容释放掉,但是指针仍然指向这块空间,若后面不再使用,及时将 ptr 置为 NULL,否则产生野指针。

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

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

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{//在堆区申请10个整形空间int* p=(int*)malloc(10*sizeof(int));if (p == NULL){//开辟空间失败perror("malloc");//打印错误信息//printf("%s\n", strerror(errno));//也是打印错误信息return 1;}//使用这块空间int i = 0;for (i = 0; i < 10; i++){*(p + i) = i + 1;}//打印这块空间for (i = 0; i < 10; i++){printf("%d ", *(p + i));}//释放这块空间free(p);//将这块空间还给了操作系统,我们已经没有权限再使用这块空间了//但是p仍然指向那块空间p = NULL;//若不将p置为NULL,那么p就是野指针return 0;
}

在这里插入图片描述

总结:

  1. 动态内存开辟的函数头文件都是 stdlib.h。
  2. 如果不释放的话,程序结束的时候也会被操作系统自动释放。
  3. 但是为了防止内存泄漏,将其置为NULL。这是一个好习惯。

二. calloc

void* calloc(size_t num, size_t size);

解释:在堆区中开辟一块大小为 num * size 个字节的空间,返回指向这块空间的起始地址,其中 num 为数据的个数,size 为单个数据的字节数,同时把申请的空间的每个字节初始化为全为0。


#include<stdio.h>
#include<stdlib.h>
int main()
{//在堆区申请10个整形空间int* p = (int*)calloc(10, sizeof(int));if (p == NULL){perror("calloc");return 1;}//使用空间int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(p + i));}//释放free(p);p = NULL;return 0;
}

在这里插入图片描述

三. realloc

void* realloc (void* ptr, size_t size);

解释:调整动态内存开辟的空间,ptr 是那块空间的起始地址,size 是调整后的那块空间的字节的个数,返回指向这块空间的起始地址。

#include<stdio.h>
#include<stdlib.h>
int main()
{//在堆区申请10个整形空间int* p = (int*)malloc(10 * sizeof(int));if (p == NULL){perror("malloc");return 1;}//调整空间——变成20个整形空间int* ptr = (int*)realloc(p, 20 * sizeof(int));//注意:要用新的指针来接收if (ptr != NULL){p = ptr;}else{//开辟失败return 1;}int i = 0;for (i = 0; i < 20; i++){*(p + i) = i + 1;}for (i = 0; i < 20; i++){printf("%d ", *(p + i));}//释放free(p);p = NULL;return 0;
}

在这里插入图片描述

注意:也许有些人有疑问为什么要用新的指针接收返回的地址,直接用原来的指针接收不行吗?答案是不行的,在realloc调整动态内存开辟的空间有3中情况,代码如下:

int main()
{int* p = (int*)malloc(10);//...if (p != NULL){int* ptr = (int*)realloc(p, 20);//...}return 0;
}

情况1:

  1. 开辟的空间后面有足够且连续的空间,只需返回空间的起始地址即可。
    在这里插入图片描述

情况2:

  1. 如果后续的空间不够,realloc 函数直接在堆区找一块新的满足大小的空间,将旧的地址,拷贝到新的地址。
  2. 自动释放旧的地址指向的空间,不需要手动 free,返回新的空间的起始地址。

在这里插入图片描述

情况3:

  1. 堆区已经没有满足情况的连续空间了,返回NULL。
    在这里插入图片描述

realloc函数也能开辟空间,代码如下:

#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)realloc(NULL, 10 * sizeof(int));//等价于malloc(40)if (p == NULL){//...}return 0;
}

四.动态内存的错误

1.对NULL指针的解引用操作

  1. 如果将一个空指针(NULL)进行解引用操作,程序会遇到未定义行为,会导致程序崩溃。这是因为空指针并不指向任何有效的内存地址,尝试解引用它会导致访问非法内存,从而导致程序崩溃。
  2. 因此,在解引用指针之前,应该始终先检查指针是否为空。

错误代码如下:

#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)malloc(10 * sizeof(int));//可能会开辟失败导致,p等于NULL//if (p == NULL)//{//	  perror("malloc");//	  return 1;//}//使用int i = 0;for (i = 0; i < 10; i++){*(p + i) = i + 1;//如果p等于NULL,对其进行解引用操作,程序会崩溃}free(p);p = NULL;return 0;
}

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

#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)malloc(10 * sizeof(int));if (p == NULL){perror("malloc");return 1;}//使用int i = 0;for (i = 0; i < 40; i++)//越界访问,程序崩溃{*(p + i) = i + 1;}free(p);p = NULL;return 0;
}

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

#include<stdio.h>
int main()
{int a = 10;int* p = &a;//...free(p);//程序崩溃p = NULL;return 0;
}

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

#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)malloc(10 * sizeof(int));if (p == NULL){perror("malloc");return 1;}//使用int i = 0;for (i = 0; i < 5; i++){*p = i;p++;//修改了指针p}free(p);//free释放一块动态开辟内存的一部分,程序崩溃p = NULL;return 0;
}

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

#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)malloc(10 * sizeof(int));if (p == NULL){perror("malloc");return 1;}//使用free(p);//p为野指针//...free(p);//对同一块动态内存多次释放,程序崩溃p = NULL;return 0;
}

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

  • 内存泄漏:在程序执行过程中,动态分配的内存空间在程序不再需要时没有被正确释放的情况。这会导致程序在运行过程中持续耗费内存空间而不释放,最终可能导致系统性能下降,甚至导致程序崩溃。
#include<stdio.h>
#include<stdlib.h>
void test()
{int flag = 1;int* p = (int*)malloc(10 * sizeof(int));if (p == NULL)return;//使用if (flag)return;//未释放,函数提前结束,就找不到那块空间,导致内存泄漏free(p);p = NULL;
}
int main()
{test();//......//只有程序结束了,空间才被释放return 0;
}
  1. 在一些服务器上(腾讯,阿里…),可能7*7=49天一直在运行,若一直申请内存而不释放,内存迟早有一天会耗尽的,这会造成巨大损失。
  2. 动态内存管理是一把双刃剑:提供灵活的内存管理方式,但是会带来风险。
  3. 切记:动态开辟的空间一定要释放,并且正确释放。

五.动态内存经典笔试题分析

例题1:

在这里插入图片描述
解决办法:

  1. 传递 str 的地址通过地址修改 str ,同时可以释放动态内存开辟的空间。
  2. 返回动态内存开辟的空间的地址,可以释放动态内存开辟的空间。
    在这里插入图片描述

例题2:

在这里插入图片描述

例题3:

在这里插入图片描述

解决办法:
在这里插入图片描述

创作不易,如果能帮到你的话能赏个三连吗?感谢啦!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/345979.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ROS 获取激光雷达数据(C++实现)

ROS 获取激光雷达数据&#xff08;C实现&#xff09; 实现思路 在机器人ROS系统中&#xff0c;激光雷达通常会有一个对应的节点&#xff0c;这个节点一般是由雷达的厂商提供&#xff0c;我们只需要简单的配置以下端口参数&#xff0c;就能和激光雷达的电路系统建立连接&#…

“安全生产月”专题报道:AI智能监控技术如何助力安全生产

今年6月是第23个全国“安全生产月”&#xff0c;6月16日为全国“安全宣传咨询日”。今年全国“安全生产月”活动主题为“人人讲安全、个个会应急——畅通生命通道”。近日&#xff0c;国务院安委会办公室、应急管理部对开展好2024年全国“安全生产月”活动作出安排部署。 随着科…

单臂路由的配置(思科、华为)

#交换设备 不同vlan属于不同广播域&#xff0c;不能互相通信&#xff0c;他们配置的是不同网段的IP地址&#xff0c;针对不同网段的IP地址进行通信&#xff0c;就需要用到路由技术 实现不同vlan之间的通信技术有两种 单臂路由三层交换 单臂路由 一、思科设备的单臂路由配…

AutoCAD Mechanical机械版专业的计算机辅助设计软件安装包下载安装!

AutoCAD机械版作为一款专业的计算机辅助设计软件&#xff0c;不仅具备卓越的二维绘图功能&#xff0c;更是拥有令人瞩目的3D建模工具&#xff0c;为机械设计师们提供了前所未有的创作空间。 在AutoCAD机械版的3D建模环境中&#xff0c;用户可以借助一系列简洁明了的命令&#…

【EDA】SSTA中最慢路径与最快路径统计计算

假设(X1,X2)为二元高斯随机向量,均值(μ1,μ2),标准差(σ1,σ2),相关系数ρ 定义:X=max(X1,X2),Y=min(X1,X2) SSTA中计算setup/hold的worst delay时即求X、Y,路径N对应维度为N维。 X的概率密度函数PDF为f(x)=f1(-x)+f2(-x),f1和f2为: 其中小Φ和大Φ…

在Linux上的Java项目导出PDF乱码问题

在Linux上的Java项目导出PDF乱码问题 场景&#xff1a;一个Java项目导出PDF&#xff0c;在我本地导出是没有问题&#xff0c;但是部署上Linux上后&#xff0c;导出就出现了乱码了。 处理方案 我这里使用的处理方案是在Linux服务器上安装一些PDF需要使用的字体 1.把字体上传到…

Dell服务器根据GPU温度调整风扇转速

前言 dell服务器自动风扇是根据CPU温度来调速的&#xff0c;我跑AI的时候cpu温度不高但是GPU温度很高导致显卡卡死PVE虚拟机直接挂起无法运行&#xff0c;我看了下也没有基于显卡温度调速的脚本&#xff0c;于是我就自己写了一个 基于ipmi工具 乌班图等linux先安装ipmi apt …

Springboot结合redis实现关注推送

关注推送 Feed流的模式 Timeline:不做内容筛选&#xff0c;简单的按照内容发布时间排序。常用于好友与关注。例如朋友圈的时间发布排序。 优点:信息全面&#xff0c;不会有缺失。并且实现也相对简单 缺点:信息噪音较多&#xff0c;用户不一定感兴趣&#xff0c;内容获取效率…

Transparent 且 Post-quantum zkSNARKs

1. 引言 前序博客有&#xff1a; SNARK原理示例SNARK性能及安全——Prover篇SNARK性能及安全——Verifier篇 上图摘自STARKs and STARK VM: Proofs of Computational Integrity。 上图选自&#xff1a;Dan Boneh 斯坦福大学 CS251 Fall 2023 Building a SNARK 课件。 SNARK…

如何在npm上发布自己的包

如何在npm上发布自己的包 npm创建自己的包 一、一个简单的创建 1、创建npm账号 官网&#xff1a;https://www.npmjs.com/创建账号入口&#xff1a;https://www.npmjs.com/signup 注意&#xff1a;需要进入邮箱验证 2、创建目录及初始化 $ mkdir ufrontend-test $ cd ufron…

Java程序设计————从控制台输入

向控制台输入信息可以借助Scanner扫描器类来实现 语法&#xff1a; Scanner input new Scanner(System.in); 提示 &#xff08;1&#xff09;在使用Scanner类型之前&#xff0c;需要首先指明Scanner类所在的位置&#xff0c;既通过代码 import java.util.Scanner; &…

WordPress 高级缓存插件 W3 Total Cache Pro 详细配置教程

说起来有关 WordPress 缓存插件明月已经发表过不少文章了,但有关 W3 Total Cache Pro 这个 WordPress 高级缓存插件除了早期【网站缓存插件 W3 Total Cache,适合自己的才是最好的!】一文后就很少再提及了,最近因为明月另一个网站【玉满斋】因为某些性能上的需要准备更换缓存…

OpenGauss数据库-5.数据更新

第1关&#xff1a;插入数据 gsql -d postgres -U gaussdb -W "passwd123123" create table student (id integer primary key,name char(20),age integer ); insert into student values(1,"lily",20),(2,lily,21),(3,marry,19); 第2关&#xff1a;删除数…

Nginx | 正向代理与Proxy插件整合

写在前面 &#x1f341;个人主页&#xff1a;微枫Micromaple 在企业开发环境中&#xff0c;局域网内的设备通常需要通过正向代理服务器访问互联网。正向代理服务器充当中介&#xff0c;帮助客户端请求外部资源并返回结果。局域网内也就是我们俗称的内网&#xff0c;局域网外的互…

Qt——控件

目录 概念 QWidget核心属性 enabled geometry WindowFrame的影响 windowTitle windowIcon qrc的使用 windowOpacity cursor font toolTip focusPolicy ​编辑 styleSheet 按钮类控件 PushButton RadioButton CheckBox 显示类控件 Label textFormat pixm…

Flink的简单学习四

一 有状态计算 1.1 概念 1.状态;上一次计算的结果 2.需要基于上一个结果来进行计算&#xff0c;被称为有状态计算 1.2 未使用有状态计算 1.下面这个代码将相同的key发送到同一个task任务里面计算。就是因为这个导致了&#xff0c;明明之前没有输入b&#xff0c;但是输入b之…

Linux 安装ab测试工具

yum -y install httpd-tools ab -help #10个并发连接&#xff0c;100个请求 ab -n 200 -c 100 http://www.baidu.com/

【最新鸿蒙应用开发】——总结ArkUI生命周期

鸿蒙ArkUI相关的生命周期都有哪些? 1. UIAbility生命周期 onCreate、onWindowStageCreate、onForeground、onBackground、onWindowStageDestroy、onDestroy。 onCreate&#xff1a;Create状态为在应用加载过程中&#xff0c;UIAbility实例创建完成时触发&#xff0c;系统会调…

面试官:Spring如何解析配置类

你好&#xff0c;我是柳岸花开。 大家好&#xff0c;今天我们来深入探讨一下Spring框架中的配置类解析与扫描过程的源码。Spring作为Java开发中最为广泛使用的框架之一&#xff0c;其核心机制一直是开发者关注的焦点。本文将带领大家从源码角度&#xff0c;详细剖析Spring配置类…

自动化测试-Selenium-元素定位

一.元素定位 因为使用selenium进行自动化测试&#xff0c;元素定位是必不可少的&#xff0c;所以这篇文章用于自动化测试中的selenium中的元素定位法。 1.根据id属性进行定位&#xff08;id是唯一的&#xff09; id定位要求比较高&#xff0c;要求这个元素的id必须是固定且唯…