当前位置: 首页 > 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 hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...

Pydantic + Function Calling的结合

1、Pydantic Pydantic 是一个 Python 库&#xff0c;用于数据验证和设置管理&#xff0c;通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发&#xff08;如 FastAPI&#xff09;、配置管理和数据解析&#xff0c;核心功能包括&#xff1a; 数据验证&#xff1a;通过…...

文件上传漏洞防御全攻略

要全面防范文件上传漏洞&#xff0c;需构建多层防御体系&#xff0c;结合技术验证、存储隔离与权限控制&#xff1a; &#x1f512; 一、基础防护层 前端校验&#xff08;仅辅助&#xff09; 通过JavaScript限制文件后缀名&#xff08;白名单&#xff09;和大小&#xff0c;提…...

GraphRAG优化新思路-开源的ROGRAG框架

目前的如微软开源的GraphRAG的工作流程都较为复杂&#xff0c;难以孤立地评估各个组件的贡献&#xff0c;传统的检索方法在处理复杂推理任务时可能不够有效&#xff0c;特别是在需要理解实体间关系或多跳知识的情况下。先说结论&#xff0c;看完后感觉这个框架性能上不会比Grap…...

渗透实战PortSwigger Labs指南:自定义标签XSS和SVG XSS利用

阻止除自定义标签之外的所有标签 先输入一些标签测试&#xff0c;说是全部标签都被禁了 除了自定义的 自定义<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 当元素获得焦点时&#xff08;如通过点击或键盘导航&…...