数据结构(Day13)
一、学习内容
-
内存空间划分
-
1、一个进程启动后,计算机会给该进程分配4G的虚拟内存
2、其中0G-3G是用户空间【程序员写代码操作部分】【应用层】
3、3G-4G是内核空间【与底层驱动有关】
4、所有进程共享3G-4G的内核空间,每个进程独立拥有0G-3G的用户空间
5、内存分区的目的是:专人专项、提高效率-
栈区特点
-
运行时自动分配和回收: 栈是自动管理的,程序员不需要手工干预,使用起来方便简单。
-
反复使用: 栈内存在程序中其实就是那一块空间,程序反复使用这一块空间。
-
脏内存: 栈内存由于反复使用,每次使用后程序不会去清理,因此分配到时如果没有初始化会保留原来的值。
-
临时性: 函数不能返回栈变量的指针,因为这个空间是临时的。
-
栈会溢出: 因为操作系统事先给定了栈的大小,如果在函数中无穷尽的分配栈内存总会消耗完。
-
栈空间是向下增长的
-
-
堆区特点
-
大块内存: 堆内存管理是总量很大的操作系统内存块,各进程可以按需申请使用,使用完释放。
-
程序手动申请和释放: 手工意思是需要写代码去申请malloc()和释放free()。
-
脏内存: 堆内存也是反复使用的,而且使用者用完释放前不会清除,因此也是脏的。
-
临时性: 堆内存只在申请malloc()和释放free()之间属于这个进程,可以访问。在释放free()之后不能再访问,否则会有不可预料的后果。
-
不可直接操作: 需要通过指针操作。
-
堆空间是向上增长的
-
-
堆和栈的区别
-
管理分配效率不同。栈编译器自动管理,无需程序员手工控制;而堆空间的申请释放工作由程序员控制,容易产生内存泄漏。堆的效率比栈要低
-
空间大小不同。栈是向低地址扩展的数据结构,是一块连续的内存区域。堆是向高地址扩展的数据结构,是不连续的内存区域。
-
是否产生碎片。对于堆来讲,频繁的malloc/free(new/delete)势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低(虽然程序在退出后操作系统会对内存进行回收管理)。对于栈来讲,则不会存在这个问题。
-
增长方向不同。堆的增长方向是向上的,即向着内存地址增加的方向;栈的增长方向是向下的,即向着内存地址减小的方向。
-
-
-
-
动态内存分配和回收(申请和释放)
-
malloc函数
-
功能:在堆区开辟指定字节的空间
-
头文件:#include <stdlib.h>
-
原型:void *malloc(size_t size);
-
分析:返回值是void *【通用型指针】——可以转换成任意类型的指针
-
参数是size_t size 【数据类型 size_t 64位是long int——%ld 32位是int——%d】 【size表示的是索要开辟的空间的大小】
-
-
-
free函数
-
功能:手动释放堆区空间
-
头文件:#include <stdlib.h>
-
原型:void free(void *ptr); //无返回值函数 参数是void *ptr 【通用型指针,传参直接传指针名即可】
-
-
常见的内存错误
-
野指针
-
原因
-
指向动态分配内存的指针在释放后,没有NULL
-
指向被删除的对象或无效对象的指针
-
接收了函数返回的局部变量的指针
-
-
解决方法
-
malloc() free()后及时NULL
-
及时更新指针
-
编码时明确变量的作用域,不要接收返回的局部变量的指针
-
-
-
内存越界
-
原因
-
访问到野指针指向的区域,越界访问
-
数组下标越界访问
-
向缓冲区写入超过其容量的数据【strcpy、strcat的例子】
-
-
解决方法
-
使用数组时确保下标的范围,使用循环计数或条件判断控制范围
-
使用指针时,进行if(NULL==p)的检查
-
使用strncat 和 strncpy可以确保不会溢出目标缓冲区 strcpy(dest , src); strncpy(dest , src , strlen(dest))
-
-
-
内存泄漏
-
如果没有适时释放被动态分配的内存,会导致内存泄露问题。未释放的内存一直占用系统资源,使得系统变慢并最终导致崩溃。
-
原因
-
丢失了分配的内存的首地址,导致无法释放
-
每循环一次,泄露一次内存
-
非法访问常量区
-
-
解决方法
-
及时使用free()释放不再使用的内存
-
合理设计数据结构和算法,避免内存无线增长
-
设置合理的变量【作用域】,减少内存占用
-
-
-
-
-
-
脑图
二、作业
-
p 和 "hello,world"存储在内存哪个区域?( ) (鲁科安全)
int main()
{
char *p = "hello,world";
return 0;
}
解析:
字符串 "hello,world"
是一个字符串字面量,在编译时会存储在程序的 常量区(或者叫做只读数据段) 中。该区域通常是只读的,不能被修改。
变量 p
是一个指针变量,它指向字符串 "hello,world"
。因为 p
是在 main()
函数中定义的局部变量,所以它存储在 栈区 中。
解答:
*p在栈区 "hello,world"在静态区中的.ro段
-
一个由C/C++编译的程序,会将占用的内存分为几个部分:堆、栈、代码段、数据段、BSS段。请问以下程序中的变量a、b、c、d,分别被存在内存的哪个部分?(泰华智慧)
int a = 0;
char *b;
int main()
{
int c;
static char d = 'a';
b = malloc(10);
*b = d;
return 0;
}
解析:
变量
a
:变量
a
是一个全局变量并且初始化为0
。存储区域:数据段(已初始化的全局变量存储在数据段)。
变量
b
:变量
b
是一个全局指针变量,但它没有初始化。存储区域:BSS 段(未初始化的全局变量和静态变量存储在 BSS 段中)。
变量
c
:变量
c
是在main
函数内部定义的局部变量。存储区域:栈区(局部变量存储在栈区)。
变量
d
:变量
d
是一个静态局部变量并初始化为'a'
。存储区域:数据段(静态局部变量也存储在数据段中,因为它已初始化)。
解答:
变量a在数据段、b在bss段、c在栈区、d在数据段
-
如下代码:变量g_iA,g_iB,g_iC,iD,iE, iF, piG,iH 分别在内存中的什么区( ) (H3C)
int g_iA = 1;
int g_iB;
static int g_iC = 1;
void func1(){
static int iD=2;
iD++;
int iE=2;
iE++;
}
void func2(){
int iF=3;
int *piG = (int*) malloc(4);
}
int main(){
int iH = 100;
}
解析:
g_iA
:这是一个已初始化的全局变量。
存储区域:data段(已初始化的全局变量存储在数据段中)。
g_iB
:这是一个未初始化的全局变量。
存储区域:BSS 段(未初始化的全局变量存储在 BSS 段中)。
g_iC
:这是一个已初始化的静态全局变量。
存储区域:data段(已初始化的静态全局变量也存储在数据段中)。
iD
:这是在
func1
函数中定义的已初始化的静态局部变量。存储区域:data段(静态局部变量存储在数据段中,无论函数是否被调用)。
iE
:这是在
func1
函数中定义的局部变量。存储区域:栈区(局部变量存储在栈中,每次函数调用时都会分配新的内存)。
iF
:这是在
func2
函数中定义的局部变量。存储区域:栈区(局部变量存储在栈中)。
piG
:这是在
func2
函数中定义的指针,malloc(4)
动态分配了 4 字节的内存,piG
指向这块内存。存储区域:栈区(指针
piG
本身) 和 堆区(malloc(4)
动态分配的内存)。
iH
:这是在
main
函数中定义的局部变量。存储区域:栈区(局部变量存储在栈中)
解答:
g_iA在静态区中的.data段、g_iB在静态区的.bss段、g_iC在静态区的.data段、iD在静态区的.data段、iE在栈区、iF在栈区、piG在栈区、iH在栈区
-
有关内存的思考题 (山东山大电力技术有限公司,登虹科技,昆腾微电子)
void GetMemory(char *p)
{
p =(char *)malloc(100);
}
void Test(void)
{
char *str=NULL;
GetMemory(str);
strcpy(str,"hello world");
printf(str);
}
请问运行 Test 函数会有什么样的结果?
char * GetMemory(void)
{
char pl[] = "hello world"; //char *p = "hello world"
return p1;
}
Void Test(void)
{
char *str=NULL;
str = GetMemory();
printf(str);
}
请问运行 Test 函数会有什么样的结果?
void GetMemory(char **p,int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello world");
printf(str);
}
请问运行 Test 函数会有什么样的结果?
void Test (void)
{
char *str = (char *)malloc(100);
strcpy(str,"hello");
free(str);
if(str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
请问运行 Test 函数会有什么样的结果?
解析:
1、第一段
在
GetMemory
函数中,参数p
是一个局部指针变量,当malloc(100)
动态分配内存时,只是将地址赋值给局部的p
,而不会影响调用者Test
中的str
。换句话说,str
仍然是NULL
。随后在Test
中调用strcpy(str, "hello world")
时,会试图向NULL
指针中写入数据,这会导致 段错误(Segmentation Fault)。2、第二段
GetMemory
函数中,p1[]
是一个局部数组,存储在栈区。当GetMemory
函数返回时,栈帧将被释放,局部变量p1
将变为无效。虽然GetMemory
返回p1
的地址,但是这个地址指向已经被释放的栈空间,尝试访问该地址的内容是未定义行为。3、第三段
在GetMemory
中,传递的是str
的地址(&str
),因此函数可以正确地分配内存并将其赋值给str
。随后strcpy(str, "hello world")
将字符串拷贝到分配的内存中,并调用printf(str)
输出字符串。
4、第四段malloc(100)
分配了 100 字节的内存,随后strcpy(str, "hello")
将字符串"hello"
拷贝到这块内存。free(str)
释放了str
指向的内存。虽然在C
中,调用free
并不会自动将指针置为NULL
,但在if (str != NULL)
语句中,str
依然保持其原来的值(它指向已释放的内存)。由于内存已经被释放,再次尝试strcpy(str, "world")
将会向一块已经释放的内存写入数据,这是未定义行为。
解答:
第一段:段错误
第二段:段错误
第三段:"hello,world"
第四段:程序崩溃
-
堆和栈的区别是什么? (矩阵软件)
解答:
管理分配效率不同。栈编译器自动管理,无需程序员手工控制;而堆空间的申请释放工作由程序员控制,容易产生内存泄漏。堆的效率比栈要低
空间大小不同。栈是向低地址扩展的数据结构,是一块连续的内存区域。堆是向高地址扩展的数据结构,是不连续的内存区域。
是否产生碎片。对于堆来讲,频繁的malloc/free(new/delete)势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低(虽然程序在退出后操作系统会对内存进行回收管理)。对于栈来讲,则不会存在这个问题。
增长方向不同。堆的增长方向是向上的,即向着内存地址增加的方向;栈的增长方向是向下的,即向着内存地址减小的方向。
-
什么是内存泄漏?面对内存泄漏和指针越界,你有哪些方法?(山大华天,智洋创新)
解答:
1、如果没有适时释放被动态分配的内存,会导致内存泄露问题。未释放的内存一直占用系统资源,使得系统变慢并最终导致崩溃。
2、
及时使用free()释放不再使用的内存
合理设计数据结构和算法,避免内存无线增长
设置合理的变量【作用域】,减少内存占用
三、总结
1. 学习内容概述
内存管理
通过对堆和栈的详细讨论,讲解了内存分配的过程。栈用于自动变量分配,堆用于动态内存分配.
动态内存分配与回收
使用 `malloc`、`free` 等函数来分配和释放内存。
重点包括 `malloc()` 函数的使用方法、返回指针的类型、以及如何合理使用 `free()` 函数来释放动态内存,避免内存泄漏。
内存优化
结合了动态分配的方式和内存碎片问题,指出合理的内存使用和优化内存分配策略的重要性。
高性能与低性能
介绍了高效的内存使用方法以及可能导致低效的内存管理方式,提醒避免内存碎片和滥用动态内存分配。
2. 学习难点
指针的正确使用
在 `malloc()` 函数中分配内存时,返回的指针类型需要转换为适当的类型。初学者容易犯错的地方在于未进行正确的类型转换,或者忘记 `free()` 导致内存泄漏。
内存泄漏
在动态内存分配中,忘记释放不再使用的内存会导致内存泄漏问题,尤其是在大型程序中,内存泄漏将对程序性能产生严重影响。
内存碎片化
不合理的内存分配会导致内存的碎片化问题,影响程序的执行效率,理解并优化内存分配策略具有一定难度。
3. 主要事项
内存分配时需要注意内存对齐
在某些平台上,内存分配需要根据特定的对齐要求进行,否则可能导致性能问题或程序崩溃。
动态内存分配的错误处理
如果 `malloc()` 返回 `NULL`,应及时处理以避免空指针引用。
合理使用 `free()` 释放内存
避免在释放后继续使用已释放的内存,使用悬空指针可能会导致未定义行为。
优化程序的内存使用
避免频繁的内存分配和释放操作,减少内存碎片问题。
4. 未来学习的重点
深度理解内存分配的机制
更深入地理解堆栈的使用区别,尤其在不同平台上的表现差异。
内存调试工具的使用
掌握调试工具(如 `valgrind`)用于检测内存泄漏和内存管理错误,帮助排查问题。
进一步研究复杂数据结构中的内存管理
学习如何在链表、树、图等复杂数据结构中进行有效的动态内存分配和释放。
多线程程序中的内存管理
在并发编程中,了解内存管理的挑战,尤其是当多个线程共享内存时的同步问题。
相关文章:

数据结构(Day13)
一、学习内容 内存空间划分 1、一个进程启动后,计算机会给该进程分配4G的虚拟内存 2、其中0G-3G是用户空间【程序员写代码操作部分】【应用层】 3、3G-4G是内核空间【与底层驱动有关】 4、所有进程共享3G-4G的内核空间,每个进程独立拥有0G-3G的用户空间 …...

链表的快速排序(C/C++实现)
一、前言 大家在做需要排名的项目的时候,需要把各种数据从高到低排序。如果用的快速排序的话,处理数组是十分简单的。因为数组的存储空间的连续的,可以通过下标就可以简单的实现。但如果是链表的话,内存地址是随机分配的…...
css总结(记录一下...)
文字 语法说明word-wrapword-wrap:normal| break-word normal:使用浏览器默认的换行 break-word:允许在单词内换行 text-overflow clip:修剪文本 ellipsis:显示省略符号来代表被修剪的文本 text-shadow可向文本应用的阴影。能够规定水平阴影、垂直阴影、模糊距离,以…...

SpringBoot 处理 @KafkaListener 消息
消息监听容器 1、KafkaMessageListenerContainer 由spring提供用于监听以及拉取消息,并将这些消息按指定格式转换后交给由KafkaListener注解的方法处理,相当于一个消费者; 看看其整体代码结构: 可以发现其入口方法为doStart(),…...
Spring Boot-API版本控制问题
在现代软件开发中,API(应用程序接口)版本控制是一项至关重要的技术。随着应用的不断迭代,API 的改动不可避免,如何在引入新版本的同时保证向后兼容,避免对现有用户的影响,是每个开发者需要考虑的…...
Git 提取和拉取的区别在哪
1. 提取(Fetch) 操作说明:Fetch 操作会从远程仓库下载最新的提交、分支信息等,但不会将这些更改合并到你当前的分支中。它只是将远程仓库的更新信息存储在本地,并不会自动修改你当前的工作区。 使用场景: …...
【数据结构与算法 | 每日一题 | 力扣篇】力扣2390, 2848
1. 力扣2390:从字符串中删除星号 1.1 题目: 给你一个包含若干星号 * 的字符串 s 。 在一步操作中,你可以: 选中 s 中的一个星号。移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。 返回移除 所有 星号之…...

破解信息架构实施的密码:常见挑战与最佳解决方案全指南
信息架构的成功实施是企业数字化转型的关键步骤,但在实际操作中,企业往往会遇到各种复杂的挑战。这些挑战包括 技术整合的难度、数据管理的复杂性、合规性要求的变化 以及 资源限制 等。《信息架构:商业智能&分析与元数据管理参考模型》为…...
CodeChef Starters 151 (Div.2) A~D
codechef是真敢给分,上把刚注册,这把就div2了,再加上一周没打过还是有点不适应的,好在最后还是能够顺利上分 今天的封面是P3R的设置菜单 我抠出来做我自己的游戏主页了( A - Convert string 题意 在01串里面可以翻转…...

Redis学习——数据不一致怎么办?更新缓存失败了又怎么办?
文章目录 引言正文读写缓存的数据一致性只读缓存的数据一致性删除和修改数据不一致问题操作执行失败导致数据不一致解决办法 多线程访问导致数据不一致问题总结 总结参考信息 引言 最近面试快手的时候被问到了缓存不一致怎么解决?一开始还是很懵的,因为…...

跨境电商代购新纪元:一键解锁全球好物,系统流程全揭秘
添加图片注释,不超过 140 字(可选) 在全球化日益加深的今天,跨境电商代购成为了连接消费者与世界各地优质商品的桥梁。本文将在CSDN平台上,深入剖析跨境电商代购系统的功能流程,带您一窥其背后的技术奥秘与…...

Mac 上终端使用 MySql 记录
文章目录 下载安装终端进入 MySql常用操作查看数据库选择一个数据库查看当前选择的数据库Navcat 打开提示报错参考文章 下载安装 先下载社区版的 MySql 安装的过程需要设置 root 的密码,这个是要进入数据库所设定的,所以要记住 终端进入 MySql 首先输…...

461. 汉明距离
一:题目: 两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。 给你两个整数 x 和 y,计算并返回它们之间的汉明距离。 示例 1: 输入:x 1, y 4 输出:2 解释: 1 (0 0…...
开发指南061-nexus权限管理
平台后台服务的核心是组件,管理组件的软件有: Apache的Archiva、JFrog的Artifactory、Sonatype的Nexus。 本平台选择nexus。nexus的权限模型是用户-角色-权限体系:通过组合权限定义角色,通过给用户赋角色来赋权限。有关nexus的权…...

Qt 弹出菜单右键菜单 QMenu 设置不同颜色的子项
概述 在Qt中,可以使用样式表(StyleSheet)来自定义 QMenu 的外观,包括其子项(如菜单项QAction)的颜色。但是,这通常可以设置 QMenu 的整体样式,而不能单独设置某个子项的颜色。不过&…...
Git换行符自动转换参数core.autocrlf的用法
core.autocrlf 是 Git 中用于控制换行符自动转换的配置选项。它有以下几个可能的值: 1. true 作用:在 checkin 时将 CRLF 转换为 LF,在 checkout 时将 LF 转换为 CRLF。适用场景:适用于 Windows 用户,希望在本地文件…...

C语言的结构体类型
在我们使用C语言进行编写代码时,常常会使用已经给定的类型来创建变量,比如int型,char型,double型等,而当我们想创建一些较为复杂的东西时,单单用一个类型变量是没办法做到的,比如我们想创建一个…...
illustrator 收集字体插件VBscript
这是早些年从俄罗斯网站上看到的一个收集字体插件,语言是用VBscript写的,能用,但个别字体不能收集完成,现在Adobe也在illustrator中加入了收集字体打包功能,所以这个也很少用啦。 使用方法: 下好插件,或把下面的代码存入到本地侯后缀名改为.vbs,然后把.ai文件往.vbs文…...

【LLM多模态】文生视频评测基准VBench
note VBench的16个维度自动化评估指标代码实践(待完成)16个维度的prompt举例人类偏好标注:计算VBench评估结果与人类偏好之间的相关性、用于DPO微调 文章目录 note一、相关背景二、VBench评测基准概述:论文如何解决这个问题&…...

通过覆写 url_for 将 flask 应用部署到子目录下
0. 缘起 最近用 flask 写了一个 web 应用,需要部署到服务器上。而服务器主域名已经被使用了,只能给主域名加个子目录进行部署,比如主域名 example.org ,我需要在 example.org/flask 下部署。这时 flask 应用里的内部连接们就出现…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...