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

C语言【动态内存管理 后篇】

动态内存管理 后篇

  • 🫅经典例题
    • 🤦‍♂️题目1
    • 🤦‍♂️题目2
    • 🤦‍♂️题目3
    • 🤦‍♂️题目4
  • 🫅C/C++程序的内存开辟

前面的一篇文章动态内存管理 前篇,我们已经了解过了动态内存管理的相关信息,接下来,让我们来一起来踩“坑”。当然,今天的踩坑,是为了面试不踩坑哦

🫅经典例题

🤦‍♂️题目1

void GetMemory(char* p)
{p = (char*)malloc(100);
}void Test(void)
{char* str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}int main()
{Test();return 0;
}

我们来找一找上面的代码有什么问题?
好了,不绕弯子了,来看看到底错了哪些地方

  1. GetMemory(str)中是传值,而不是传址。当出了GetMemory函数,p指向的地址发生了变化,但str依旧是NULL,然后就进入了strcpy函数,这样就形成了非法访问内存(NULL是操作系统的,我们用户没有权限访问)
  2. 在GetMemory函数内部,动态申请了内存,直到程序结束也没有释放内存,这样会导致内存泄漏

🐉🐉🐉🐉🐉
printf(str)???这样写也能行???为什么吗??
我们来看看下面的代码:

#include<stdio.h>int main()
{char ptr[] = "hehehe";char* p = "hehehe";printf("%s\n", ptr);printf("%s\n", p);printf("hehehe");return 0;
}//运行结果:
*****
hehehe
hehehe
hehehe
*****

纳尼??这是为什么呢?
在解释这个问题前,我们先想一下printf的第一个参数是什么?答案是:必须是指针。那就意味printf(“hehehe”)里面的“hehehe”不是我们所看到的那样,而是一个地址。那么它是谁的地址?下面的代码会给我们答案:

#include<stdio.h>int main()
{char* p = "hehehe";printf("%p\n", "hehehe");printf("%p\n", p);return 0;
}//运行结果:
*****
00AF7B54
00AF7B54*****

奥,那我就明白了:ptr指针指向的是字符串的第一个字符,那么运行结果告诉我们,printf(“hehehe”)里面传的就是第一个字符的地址。

修改:

//修改后
// #include<stdio.h>
#include<stdlib.h>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;
}

🤦‍♂️题目2

#include<stdio.h>
#include<stdlib.h>char* GetMemory(void)
{char p[] = "hello world";return p;
}void Test(void)
{char* str = NULL;str = GetMemory();printf(str);
}int main()
{Test();return 0;
}

这个除了没有释放空间就没有其他的问题了吧。
但真相是这样吗??
让我们看看运行结果是什么吧

嗯??没释放空间也不会导致这种结果吧…

🐉🐉🐉🐉🐉
让我们来全面的分析一下吧:

  1. 关于函数返回信息的问题,这一类问题也叫作“返回栈空间地址的问题”:函数返回地址,地址信息存在,但函数内部的栈空间就还给操作系统了,操作系统可以把此空间作为别的变量的地址
  2. 函数动态申请空间,直到程序结束也没有释放掉空间,会导致内存泄漏

返回栈空间地址的问题???这是什么啊??

栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返
回地址等

那我们就明白了为什么叫做返回栈空间地址,那问题呢??
当函数调用结束(出了函数),在函数里面的空间就会返还给操作系统,我们用户没有操作权限。操作系统会把这个空间重新分配给其他变量,这样我们就不得而知了

修改:

#include<stdio.h>
#include<stdlib.h>char* GetMemory(void)
{char* p = "hello world";  //将第一个字符的地址传给p//static char p[]="hello world";    //被static修饰的变量存放在数据段(静态区),//数据段的特点是在上面创建的变量,直到程序结束才销毁return p;
}void Test(void)
{char* str = NULL;str = GetMemory();printf(str);//释放free(str);str = NULL;
}int main()
{Test();return 0;
}

🤦‍♂️题目3

#include<stdio.h>
#include<stdlib.h>void GetMemory(char** p, int num)
{*p = (char*)malloc(num);
}void Test(void)
{char* str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);
}int main()
{Test();return 0;
}

这个就很简单了,没有释放空间

修改:

#include<stdio.h>
#include<stdlib.h>void GetMemory(char** p, int num)
{*p = (char*)malloc(num);
}void Test(void)
{char* str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);//释放free(str);str = NULL;
}int main()
{Test();return 0;
}

🤦‍♂️题目4

#include<stdio.h>
#include<stdlib.h>void Test(void)
{char* str = (char*)malloc(100);strcpy(str, "hello");free(str);if (str != NULL){strcpy(str, "world");printf(str);}
}int main()
{Test();return 0;
}

这个问题是啥?感觉没问题啊??不会是str没有置空吧?
哈哈,其实这个问题很隐蔽,不注意看是看不出来的

free的动作是将该内存块返还给操作系统,我们没有操作权限,故str是野指针,造成了非法访问内存

修改:

#include<stdio.h>
#include<stdlib.h>void Test(void)
{char* str = (char*)malloc(100);strcpy(str, "hello");free(str);str = NULL;  //在这里置空,也是为了符合下面判断的逻辑//那么也不会进入if里面造成非法访问if (str != NULL){strcpy(str, "world"); printf(str);}
}int main()
{Test();return 0;
}

🫅C/C++程序的内存开辟

在在这里,终于把C语言中的动态内存管理的知识讲解完了。想必大家大概的框架是有的,但是对一些专业术语跟底层逻辑不是很清楚。比如:什么是堆区,什么又是栈区?内存中的每一个区域的作用是什么?等等

在这里插入图片描述
C/C++程序内存分配的几个区域:

  1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结
    束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是
    分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返
    回地址等。
  2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分
    配方式类似于链表。
  3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
  4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。字符串常量就在其中
  • 实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。
    但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序
    结束才销毁。所以生命周期变长。

在这里插入图片描述
码文不易,各位看官一键三连哦 💕💕💕
各位的鼓励与支持是我前进最大的动力

相关文章:

C语言【动态内存管理 后篇】

动态内存管理 后篇&#x1fac5;经典例题&#x1f926;‍♂️题目1&#x1f926;‍♂️题目2&#x1f926;‍♂️题目3&#x1f926;‍♂️题目4&#x1fac5;C/C程序的内存开辟前面的一篇文章动态内存管理 前篇&#xff0c;我们已经了解过了动态内存管理的相关信息&#xff0c…...

四大步骤,教你彻底关闭Win10自动更新

文章目录一、禁用Windows Update服务二、在组策略里关闭Win10自动更新相关服务三、禁用任务计划里边的Win10自动更新四、在注册表中关闭Win10自动更新参考资料一、禁用Windows Update服务 1、同时按下键盘 Win R&#xff0c;打开运行对话框&#xff0c;然后输入命令 services…...

通信算法之一百零四:QPSK完整收发仿真链路

1.发射机物理层基带仿真链路 1.1 % Generates the data to be transmitted [transmittedBin, ~] BitGenerator(); 2.2 % Modulates the bits into QPSK symbols modulatedData QPSKModulator(transmittedBin); 2.3 % Square root Raised Cosine Transmit Filter %comm…...

时间复杂度(超详解+例题)

全文目录引言如何衡量一个算法的好坏时间复杂度时间复杂度的定义时间复杂度的大O表示法实例test1test2test3test4test5总结引言 如何衡量一个算法的好坏 我们在写算法的时候&#xff0c;对于实现同样的作用的不同算法&#xff0c;我们如何判断这个算法的好坏呢&#xff1f; …...

【Java面试总结】Maven篇

【Java面试总结】Maven篇1.Maven坐标是啥2.Maven常见的依赖范围有哪些?3.多模块如何聚合4.对于一个多模块项目&#xff0c;如果管理项目依赖的版本5.maven怎么解决版本冲突6.Maven常用命令有哪些&#xff1f;1.Maven坐标是啥 一般maven使用groupID&#xff0c;artifactId&…...

【每日一题Day123】LC1792最大平均通过率 | 堆

最大平均通过率【LC1792】 一所学校里有一些班级&#xff0c;每个班级里有一些学生&#xff0c;现在每个班都会进行一场期末考试。给你一个二维数组 classes &#xff0c;其中 classes[i] [passi, totali] &#xff0c;表示你提前知道了第 i 个班级总共有 totali 个学生&#…...

[安装之5] Mac pro更换大内存固态硬盘实践教程

近由于mac电脑内存吃紧&#xff0c;安装大的软件&#xff0c;是不是要提示一下内存不够&#xff0c;内心非常的不爽。作为一款A1502版的mac&#xff0c;128G固态硬盘通常被称为“乞丐版”。提前做好准备工作后&#xff0c;我周末花了一天的时间搞定这件事&#xff0c;为了能够帮…...

04 Python变量的声明与使用

基本上,在所有的计算机编程语言中,都会用到变量,变量将数据存储在计算机内存中。 变量是指存储数据的内存地址,通过变量名,我们可以找到这个变量名对应的内容。 命名变量时不允许使用数字、特殊字符、连字符开头。 变量可以有一个短名称(如 x、y、z),但强烈建议使用更具…...

LeetCode 2418. 按身高排序

给你一个字符串数组 names &#xff0c;和一个由 互不相同 的正整数组成的数组 heights 。两个数组的长度均为 n 。 对于每个下标 i&#xff0c;names[i] 和 heights[i] 表示第 i 个人的名字和身高。 请按身高 降序 顺序返回对应的名字数组 names 。 示例 1&#xff1a; 输…...

一文了解Hotspot虚拟机下JAVA对象从创建到回收的生命周期

Java虚拟机是Java的核心和基础&#xff0c;他是Java编译器和操作系统平台之间处理器&#xff0c;能实现跨平台运行Java程序。本文主要讲解的是虚拟机如何管理对象&#xff0c;即Java对象在JVM虚拟机中被创建到回收的流程 Java对象从创建到回收的生命周期对象创建流程1.类加载检…...

【Java基础】Java对象创建的几种方式

先上关键内容&#xff0c;所用到的代码请参考文末示例代码。一、使用new关键字创建对象这是一种最常用的创建对象的方式。Student student1 new Student();二、使用Class的newInstance()方法创建对象需要有一个无参构造方法&#xff0c;这个newInstance()方法调用无参的构造函…...

社保缴费满15年就可以不缴了?6个很多人最关心的问题权威解答来了

一、社保缴费满15年就可以不缴了&#xff1f; 上海市政府新闻办公室2022年在微信号发文表示&#xff0c;社会保险是由国家通过立法强制建立的社会保障制度&#xff0c;用人单位和劳动者都必须依法参加社会保险。即使职工与用人单位商议签订了不参加社保的所谓“协议”&#xf…...

关于HDFS

目录 一、HDFS概述 二、HDFS架构与工作机制 三、HDFS的Shell操作 四、Hdfs的API操作 一、HDFS概述 HDFS&#xff1a;Hadoop Distributed File System&#xff1b;一种分布式文件管理系统&#xff0c;通过目录树定位文件。使用场景&#xff1a;一次写入&#xff0c;多次读出…...

C++入门:类 对象

C 在 C 语言的基础上增加了面向对象编程&#xff0c;C 支持面向对象程序设计。类是 C 的核心特性&#xff0c;通常被称为用户定义的类型。类用于指定对象的形式&#xff0c;它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员。函数在一个类中被称为类的成…...

Python生日系统

#免费源码见文末公众号# 录入生日 def write():keyvar1.get()valuevar2.get()with open(d:\\生日系统.pickle,rb) as file:dictspickle.load(file)dicts[key]valuewith open(d:\\生日系统.pickle,wb) as file:pickle.dump(dicts,file)file.close() 查询生日 def read():namev…...

< CSDN周赛解析:第 28 期 >

CSDN周赛解析&#xff1a;第 27 期&#x1f449; 第一题&#xff1a; 小Q的鲜榨柠檬汁> 题目解析> 解决方案&#x1f449; 第二题&#xff1a; 三而竭> 解析> 解决方案> 拓展知识&#x1f449; 第三题&#xff1a; 隧道逃生> 解析> 解决方案&#x1f449;…...

【题外话】如何拯救小米11Pro这款工业垃圾

1 背景媳妇用小米11Pro手机&#xff0c;某日不慎摔落&#xff0c;幸好屏幕未碎&#xff0c;然而WiFi却怎样都无法打开&#xff0c;初以为是系统死机&#xff0c;几天依旧故障无法使用。现在的手机没有WiFi功能&#xff0c;就无法刷抖音、看视频&#xff0c;就是鸡肋了。后抽空去…...

Python中有哪些常用操作?这20个你都会吗

Python 是一个解释型语言&#xff0c;可读性与易用性让它越来越热门。 正如 Python 之禅中所述&#xff1a; 优美胜于丑陋&#xff0c;明了胜于晦涩。 在你的日常编码中&#xff0c;以下技巧可以给你带来意想不到的收获。 1、字符串反转 下面的代码片段&#xff0c;使用 P…...

【LeetCode】剑指 Offer(4)

目录 写在前面&#xff1a; 题目&#xff1a;剑指 Offer 10- I. 斐波那契数列 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 题目&#xff1a;剑指 Offer 10- II. …...

庄懂的TA笔记(十二)<>

庄懂的TA笔记&#xff08;十二&#xff09;&#xff1c;&#xff1e;一、作业展示&#xff0c;答疑&#xff1a;1、作业&#xff1a;2、答疑&#xff1a;二、作业示范&#xff0c;分析&#xff1a;1、文档分析&#xff1a;2、资源分析&#xff1a;3、资源优化&#xff1a;4、光…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

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

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

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...