并非从0开始的c++之旅 day2
并非从0开始的c++之旅 day2
- 一、变量
- 1、 变量名的本质
- 二、程序的内存分区模型
- 1、内存分区
- 运行之前
- 运行之后
- 三、栈区注意事项
- 四、堆区
- 1、堆区使用
- 2、堆区注意事项
- 五、全局变量静态变量
- 1、静态变量
- 2、全局变量
- 六、常量
- 1、全局const常量
- 2、局部const常量
- 七、字符串常量
一、变量
既能读又能写的内存对象,成为变量;
若一旦初始化后不能修改的对象则称为常量。
1、 变量名的本质
变量名的本质:一段连续内存空间的别名
程序通过变量来申请和命名内存空间 int a = 0;
通过变量名访问内存空间
不是向变量名读写数据,而是向变量所代表的内存空间中读写数据;
变量修改方式:直接修改、间接修改
void test01() {int a = 10;///1、直接修改a = 20;//2、间接修改int* p = &a;//*p 解引用*p = 200;printf("a = %d\n", a);
}```自定义数据类型练习```c
struct Person {char a;int b;char c;int d;
};void test02()
{struct Person p1 = { 'a',10,'b',20 };//直接修改d属性p1.d = 100;printf("%d\n", p1.d);//间接修改d属性struct Person* p = &p1;p->d = 200;printf("%d\n", p1.d);
}
这种间接修改太简单了,我们还要学一种
若使指针p加一,p指针会跳过一个结构体的字节数
其中char类型占1个字节,int类型占4个字节,a占用0~3,b从4开始,系统用内存对齐的方式让a也占用了虽然他不使用但是在b之前的字节
结果使用以下代码验证
printf("%d\n", p);
printf("%d\n", p+1);
可得两值差16,同理我们可以用这种方式修改变量
char* p = &p1;printf("%d\n", *(int*)(p + 12));printf("%d\n", *(int*)((int*)p + 3));
将p指针类型改为char *型,这时增加p指针的值会使其会一个一个往前走,在输出时,因为我们需要的是4个字节的int类型的内容,故需要做强制类型转换,将其转换为int *类型
同理如上面的第三行代码
二、程序的内存分区模型
1、内存分区
运行之前
可以简单先分为代码区和数据区
程序执行过程:
1)预处理:宏定义展开、头文件展开、条件编译,这里并不会检查语法
2)编译:检查语法,将预处理后文件编译生成汇编文件
3)汇编:将汇编文件生成目标文件(二进制文件)
4)链接:将目标文件链接为可执行程序
当我们编译完成生成可执行文件之后,我们可以通过linux下size命令可以查看一个可执行文件基本情况:
执行size命令后,系统会给出一下几个数据:
text 代码区
data 静态数据/全局初始化数据区
bss 未初始化初始化数据区
dec 文件十进制总和
hex 文件十六进制总和
filename 文件名
通过以上数据可知,在没有运行程序前,也就是说程序没有加载到内存前,可执行程序内部已经分好了3段信息,分别为代码区、数据区和未初始化数据区3个部分(有些人直接把data和bss合起来叫做静态区或全局区)
- 代码区:存放CPU执行的机器指令。通常代码区是可共享的(即另外的执行程序可以调用它),使其可共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可。代码区通常是只读的,使其只读的原因是防止程序意外地修改了他的指令。另外,代码区还规划了局部变量的相关信息
- 全局初始化数据区\静态数据区:该区包含了在程序中明确被初始化的全局变量、已经初始化的静态变量(包括全局静态变量和t)和常量数据(如字符串常量)
- 未初始化数据区(又叫bss区):存入的是全局未初始化变量和未初始化静态变量。未初始化数据区的数据在程序开始执行之前被内核初始化为0或空(NULL)
运行之后
相比运行之前,多出了栈区和堆区
- 栈区(stack):栈是一种先进后出的内存结构,由编译器自动分配释放,存放函数的参数值、返回值、局部变量等。在程序运行过程中实时加载和释放,因此,局部变量的生存周期为申请到释放该段栈空间
- 堆区(heap):堆是一个大容器,它的容量要远远大于栈,但没有栈那样先进后出的顺序。用于动态内存分配。堆在内存中位于BSS区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。
栈区:先进后出,编译器管理数据开辟,释放,容量有限,不要将大量数据开辟到栈区
堆区:容量远远大于栈区,程序员手动开辟数据,手动释放数据
三、栈区注意事项
int* fun() {int a = 10;//栈上创建的变量return &a;
}void test01() {int* p = fun();//结果依然不重要,因为上面的a早已被释放,再去操作这块数据属于非法操作printf("%d\n", *p);printf("%d\n", *p);
}
栈上的数据在执行完方法就释放了,第一次printf能打出正确结果其实是因为编译器认为你可能会处理错了数据,故保留一次,第二次打印时结果才是正常的,已经是一个随机数了。
char* GetString() {char str[] = "hello world";return str;
}void test02() {char* p = NULL;p = GetString();printf("p = %s\n", p);
}
上述代码中,将p打印后的结果为字符型乱码,因为str是指向字符串的指针,但字符串在函数运行结束后自动释放了,故他指向的地址已经为乱码,打印出来也为乱码
这里的hello world原本在常量区,无法修改,被复制了一份到栈区
两段代码告诉我们,栈上的数据出了函数体后就不要再使用了 ,也即不要返回局部变量的地址,局部变量在函数体执行完毕后会被释放,再次操作就是非法操作,结果未知!
四、堆区
1、堆区使用
int* getSpace() {int * p = malloc(sizeof(int) * 5);if (p == NULL)return NULL;for (int i = 0; i < 5; i++) {p[i] = 100 + i;}return p;
}void test01() {int* p = getSpace();for (int i = 0; i < 5; i++)printf("%d\n", p[i]);//释放数据free(p);p = NULL;
}
使用malloc创建的空间在堆区,printf多少次结果都一样,创建后如果没有使用就是垃圾,需要free
防止free后的指针仍指向原来那块已经被释放的空间,称为野指针,我们需要把它设成NULL
2、堆区注意事项
void allocateSpace(char* p) {char* temp = malloc(100);memset(temp, 0, 100);strcpy(temp, "hello world");p = temp;}void test02() {char* p = NULL;allocateSpace(p);printf("p = %s\n", p);
}
打印出来的结果为NULL,因为test中的p和函数的参数p属于同级指针,test的p为NULL时,同级指针无法改变他的值,若要改需要更高级的二级指针。
修改为以下代码
void allocateSpace2(char** p) {char* temp = malloc(100);memset(temp, 0, 100);strcpy(temp, "hello world");*p = temp;}void test03() {char* p2 = NULL;allocateSpace2(&p2);printf("p2 = %s\n", p2);
}
p一开始为NULL,参数p的值为传入p的地址,temp为堆区开辟的地址,解参数p后赋值temp,也就是将temp所含的地址赋予p,这样p就能直接指向temp所指向的堆
如果给主调函数中,一个空指针分配内存,在被调函数中利用同级指针是分配失败的
解决方式:利用高级指针修饰低级指针
五、全局变量静态变量
1、静态变量
生命周期在程序运行结束时死亡
在程序运行前就分配内存
默认属于内部链接属性,在当前文件中使用
static int a = 10;//全局作用域void test01() {static int b = 19;//局部作用域
}
默认内部链接属性,在文件外是访问不到的,如在同一个项目的另一个类中就访问不到这里的a
2、全局变量
默认在c语言下,全局变量前加了关键字 extern
属于外部链接属性
extern int g_b;g_b = 100;
若在其他类中写了一个全局变量,想在main函数中引用,需要有第一行这个代码
这个代码就是告诉编译器,其他文件中有这么一个变量,链接时要去其他文件中寻找
但是要是找不到这个全局变量,就会报错,报错为1个无法解析的外部命令,该报错是在链接阶段报的
六、常量
1、全局const常量
//const 修饰的常量
const int a = 10;//全局const常量void test01() {//直接修改失败//a = 100;//间接修改int* p = &a;*p = 100;printf("%d\n", a);
}
如果直接修改,则a会有红线,显示语法错误
如果间接修改,vs2019会报错,显示写入访问权限冲突
全局const常量放在常量区中,受到常量区的保护
2、局部const常量
void test02() {const int b = 10;//直接修改失败//b = 100;//间接修改int* p = &a;*p = 100;printf("%d\n", b);
}
直接修改依然语法不行
间接修改正常运行,因为局部常量放在栈区,我们称之为伪常量
伪常量不可以初始化数组
七、字符串常量
void test03() {char* p1 = "hello world";char* p2 = "hello world";char* p3 = "hello world";printf("%d\n", p1);printf("%d\n", p2);printf("%d\n", p3);printf("%d\n", &"hello world");
}
由上述代码结果可知,用字符串指针指向字符串常量,得到的地址都是一样的,可知字符串常量是可以共享的
void test04() {char* p1 = "hello world";p1[0] = "w";printf("%d\n", p1);
}
运行后会报错,字符串常量是不能修改的,虽然ANSIC中规定是不定义的,但vs是不能修改的
vs会把多个相同的字符串常量看成一个
相关文章:
并非从0开始的c++之旅 day2
并非从0开始的c之旅 day2一、变量1、 变量名的本质二、程序的内存分区模型1、内存分区运行之前运行之后三、栈区注意事项四、堆区1、堆区使用2、堆区注意事项五、全局变量静态变量1、静态变量2、全局变量六、常量1、全局const常量2、局部const常量七、字符串常量一、变量 既能…...
Linux进阶(Shell编程学习一)
由于shell脚本在java项目运维方面极其重要,比如服务的启动脚本,日志的分割脚本,文件的管理脚本大多都是shell脚本去实现的。所以作为java开发者懂linux的基本命令,会基本的shell编程是必要的。 Shell 是一个用 C 语言编写的程序&…...
sql 优化
sql 优化1. mysql 基础架构1.1 mysql 的组成2. mysql 存储引擎2.1MyISAM2.2 InnoDB2.3 MyISAM 和 InnoDB 的对比3. mysql 索引3.1 Hash 索引3.2 B-Tree 索引3.3 BTree 索引3.4 R-Tree 索引3.5 Full-Text 索引4. sql 优化4.1 避免 select *4.2 避免在where子句中使用or来连接条件…...
第7篇:Java的学习路径
目录 1、Java学习主要内容概览 1.1 Java基础 1.2 数据库技术 1.3 动态网页技术 1.4中间件技术...
对抗生成网络GAN系列——Spectral Normalization原理详解及源码解析
🍊作者简介:秃头小苏,致力于用最通俗的语言描述问题 🍊专栏推荐:深度学习网络原理与实战 🍊近期目标:写好专栏的每一篇文章 🍊支持小苏:点赞👍🏼、…...
Solon2 开发之插件,一、插件
Solon Plugin 是框架的核心接口,简称“插件”。其本质是一个“生命周期”接口。它可让一个组件类参与程序的生命周期过程(这块看下:《应用启动过程与完整生命周期》): FunctionalInterface public interface Plugin {…...
使用nvm管理node
nvm介紹 node的版本管理器,可以方便地安装&切换不同版本的node 我们在工作中,可以会有老版本的node的项目需要维护,也可能有新版本的node的项目需要开发,如果只有一个node版本的话将会很麻烦,nvm可以解决我们的难点…...
Linux
第一章 Linux 1.1 计算机硬件软件体系 冯诺依曼 (数学家,计算机之父) 冯诺依曼体系 计算机的指令和数据都是二进制存储,并且存放到一起程序和指令都是顺序执行的计算机硬件由输入,输出,存储,运算器与控制器组成 输入设备 比如:键盘,鼠标等. 输出设备 打印机输出࿰…...
GB28181-2022注册注销基本要求、注册重定向解读和技术实现
规范解读GB28181-2022注册、注销基本要求相对GB28181-2016版本,做了一定的调整,新调整的部分如下:——更改了注册和注销基本要求(见 9.1.1,2016 年版的 9.1.1)。1.增加对NAT模式网络传输要求,宜…...
2023年二建报考条件是什么?考试考什么?来考网
2023年二建报考条件是什么?考试考什么?来考网 2023年二建报考条件是什么?考试考什么?来考网 二建报考条件: 1、中专及以上学历 2、工程或工程经济类专业 3、从事施工管理工作满2年 二建考试科目: 《建设工…...
vite+vue3搭建的工程热更新失效问题
前段时间开发新的项目,由于没有技术上的限制,所以选择了vitevue3ts来开发新的项目,一开始用vite来开发新项目过程挺顺利,确实比vue2webpack的项目高效些(为什么选择vite),但是过了一段时间后,不…...
Hazel游戏引擎(001-003)
文章目录前言001.游戏引擎介绍002.什么是游戏引擎003设计我们的游戏引擎本人菜鸟,文中若有代码、术语等错误,欢迎指正 前言 我写的项目地址 https://github.com/liujianjie/GameEngineLightWeight(中文的注释适合中国人的你) 关于…...
耗时一个星期整理的APP自动化测试工具大全
在本篇文章中,将给大家推荐14款日常工作中经常用到的测试开发工具神器,涵盖了自动化测试、APP性能测试、稳定性测试、抓包工具等。 一、UI自动化测试工具 1. uiautomator2 openatx开源的ui自动化工具,支持Android和iOS。主要面向的编程语言…...
算法设计与分析(屈婉玲)视频笔记day2
序列求和的方法 数列求和公式 等差、等比数列与调和级数 求和的例子 二分检索算法 二分检索运行实例 2 n 1个输入 比较 t 次的输入个数 二分检索平均时间复杂度 估计和式上界的放大法 放大法的例子 估计和式渐近的界 估计和式渐近的界 小结 • 序列求和基本公式:…...
14-PHP使用过的函数 131-140
131、session_unset 释放当前会话注册的所有会话变量。 没有返回值。 132、session_destroy 销毁当前会话中的全部数据, 但是不会重置当前会话所关联的全局变量, 也不会重置会话 cookie。 如果需要再次使用会话变量, 必须重新调用 session_…...
【第39天】实现一个冒泡排序
本文已收录于专栏 🌸《Java入门一百例》🌸 学习指引 序、专栏前言一、冒泡排序一、【例题1】1、题目描述2、解题思路3、模板代码三、推荐专栏序、专栏前言 本专栏开启,目的在于帮助大家更好的掌握学习Java,特别是一些Java学习者难以在网上找到系统地算法学习资料帮助自身…...
「2」线性代数(期末复习)
🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀 方阵的行列式 (1) |A^T||A|(2) |ǖ…...
动态规划专题——背包问题
🧑💻 文章作者:Iareges 🔗 博客主页:https://blog.csdn.net/raelum ⚠️ 转载请注明出处 目录前言一、01背包1.1 使用滚动数组优化二、完全背包2.1 使用滚动数组优化三、多重背包3.1 使用二进制优化四、分组背包总结…...
数据的分组聚合
1:分组 t.groupby #coding:utf-8 import pandas as pd import numpy as np file_path./starbucks_store_worldwide.csv dfpd.read_csv(file_path) #print(df.head(1)) #print(df.info()) groupeddf.groupby(byCountry) print(grouped) #DataFrameGroupBy #可以遍历…...
【Airplay_BCT】Bonjour conformance tests苹果IOT
从Airplay开始,接触到BCT,这是什么?被迫从安卓变成ios用户和开发。。。开始我的学习之旅,记录成长过程,不定时更新 Bonjour 下面是苹果官网关于bonjour的解释 Bonjour, also known as zero-configuration networking, …...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
