C++ 知识要点:变量

一.变量

1. 全局变量与 static 变量(作用域、生存周期)

全局变量
  • 作用域:全局变量的作用域从它被定义的地方开始,一直到程序结束。在定义它的文件内部以及通过 extern 关键字在其他文件中都可以访问。
  • 生存周期:全局变量的生存周期贯穿整个程序执行期间,从程序开始执行到程序结束。
static 变量(在函数外部定义的)
  • 作用域static 变量具有文件作用域,即它只在定义它的文件内部可见,其他文件即使通过 extern 也不能访问。
  • 生存周期:与全局变量相同,static 变量的生存周期也是贯穿整个程序执行期间,从程序开始执行到程序结束。但是,由于它的作用域限制,它只能在定义它的文件内部被访问和修改。

2. static 函数与普通函数的区别

  • 作用域static 函数具有文件作用域,即它只能在定义它的文件内部被调用。而普通函数(非static)则可以在整个程序中通过函数原型声明后,在任何文件中被调用(只要包含了相应的头文件或声明)。
  • 链接性static 函数具有内部链接性(internal linkage),这意味着编译器只为该函数生成一份代码,且该代码仅在该文件内部可见。而普通函数具有外部链接性(external linkage),编译器会为每个调用该函数的文件生成一份指向该函数代码的指针(或类似的机制),以便在链接时解析函数调用。
  • 使用场景static 函数常用于隐藏函数实现细节,减少命名冲突,或当函数只在定义它的文件内部使用时。普通函数则用于实现需要在多个文件中共享的功能。

3. 两个文件中声明两个同名变量?(使用了与未使用 extern?)

在C++中,如果两个文件中声明了同名的全局变量,并且没有使用extern关键字来明确指定它们之间的链接关系,那么这两个变量实际上是两个独立的变量,它们分别属于各自的文件作用域。

  • 未使用 extern:每个文件中的同名全局变量都是独立的,它们之间没有任何关系。每个变量只在定义它的文件内部可见和可访问。

  • 使用 extern:如果在一个文件中定义了全局变量(例如,在file1.cpp中定义了int x;),然后在另一个文件(file2.cpp)中想要访问这个变量,就需要在file2.cpp中使用extern关键字来声明这个变量(extern int x;)。这样,file2.cpp中的x就指向了file1.cpp中定义的那个全局变量,它们实际上是同一个变量。但是,需要注意的是,extern声明不能出现在函数内部,它必须位于所有函数之外的全局作用域中。

总结来说,extern关键字用于在多个文件中共享同一个全局变量的声明,而如果不使用extern,则每个文件中的同名全局变量都是独立的。

4. 全局数组和局部数组的初始化

全局数组
  • 定义位置:全局数组是在函数外部定义的,即它们对整个程序可见。
  • 初始化
    • 如果没有显式初始化,全局数组(包括静态数组)的元素会自动初始化为0(对于基本数据类型,如int, float等)。这是因为全局变量和静态变量的存储区域在程序的数据段(data segment),未初始化的全局变量会被编译器自动初始化为0。
    • 如果显式初始化,则可以指定数组元素的具体值。
  • 生命周期:全局数组的生命周期贯穿整个程序执行期间,从程序开始执行到程序结束。
局部数组
  • 定义位置:局部数组是在函数内部定义的,其作用域限定在定义它的函数内部。
  • 初始化
    • 如果不显式初始化,局部数组不会自动初始化为0,它们的初始值是未定义的(即它们包含垃圾值)。
    • 如果显式初始化,可以指定数组元素的具体值,或者通过初始化列表进行部分或全部初始化。
  • 生命周期:局部数组的生命周期从它被定义时开始,到包含它的函数执行结束时结束。

5. 指针和引用的区别

代表意义
  • 指针:是一个变量,存储的是另一个变量的地址。指针可以指向任何类型的数据,包括数组、结构体、函数等。
  • 引用:是变量的别名,必须在声明时被初始化,且一旦与某个变量绑定后,就不能再改变为另一个变量的引用。
内存占用
  • 指针:占用内存空间,用于存储被指向变量的地址。指针的大小取决于系统架构(如32位系统下通常是4字节,64位系统下通常是8字节)。
  • 引用:不占用独立的内存空间,它仅仅是一个别名,对内存的影响仅限于对引用的变量本身进行操作。
初始化
  • 指针:必须显式初始化,否则它可能指向一个随机的内存地址,导致不可预测的行为。
  • 引用:必须在声明时通过另一个变量来初始化,且初始化后不能改变其指向。
指向是否可改
  • 指针:指向可以改变,可以指向另一个变量的地址。
  • 引用:一旦与某个变量绑定,其指向不能改变。
能否为空
  • 指针:可以指向nullptr(或NULL,在C++11之前),表示它不指向任何有效的内存地址。
  • 引用:不能为空,必须在声明时被初始化指向一个有效的对象。

6. C/C++中的强制转换

在C和C++中,强制类型转换用于显式地将一种数据类型的表达式转换成另一种类型。C++引入了更安全的类型转换操作符,而C语言中的类型转换主要通过类型转换运算符(如(type)expression)实现。

C风格类型转换
  • (type)expression:这是C语言风格的类型转换,它在C++中仍然有效,但不够安全,因为它不会检查类型之间是否存在合理的转换路径。
C++风格类型转换

C++提供了四种类型转换操作符,它们提供了更明确和安全的类型转换方式:

  • static_cast(expression):用于基本数据类型之间的转换,以及有明确定义转换路径的类之间的转换。
  • dynamic_cast(expression):主要用于类的层次结构中的安全向下转换(即派生类到基类指针或引用的转换)。它只适用于含有虚函数的类。
  • const_cast(expression):用于去除或添加变量的const或volatile限定符。
  • reinterpret_cast(expression):允许进行几乎任何类型的指针或引用之间的转换,包括不相关的类型之间的转换。这种转换是不安全的,因为它仅仅是对位模式进行重新解释。

每种转换都有其特定的用途和限制,使用时应根据具体需求和上下文选择适当的转换方式。

7. 如何修改 const 变量、constvolatile

如何修改 const 变量

在C++中,const 关键字用于声明一个变量为常量,这意味着一旦变量被初始化后,其值就不应该被修改。因此,从常规编程的角度来看,直接修改一个 const 变量的值是不被允许的,也是不符合C++设计初衷的。然而,在某些特定情况下(如调试或学习目的),我们可以通过一些“hack”的方式来实现,但这些方法并不推荐在生产代码中使用。

  • 通过指针的强制类型转换:虽然不推荐,但你可以通过将 const 变量的地址赋给一个指向非 const 类型的指针,然后通过这个指针修改值。这违反了 const 的设计意图,可能导致未定义行为。
const int x = 10;
int* px = const_cast<int*>(&x); // 强制类型转换
*px = 20; // 现在x的值被修改了,但这是未定义行为
constvolatile
  • const:表明变量的值不应该被修改。编译器会检查对 const 变量的修改,确保它们不被意外修改。const 主要用于优化和提供代码的语义清晰性。

  • volatile:表明变量的值可能会意外地被改变,即该变量的值可能在程序的控制流之外被修改(例如,由硬件或并发运行的另一个线程)。使用 volatile 告诉编译器不要对这样的变量进行优化(比如缓存其值),而是每次直接从内存中读取它的值。

volatileconst 可以一起使用,例如 const volatile int* ptr;,这表示指针指向的值是常量,但这个值可能会被外部因素改变,因此每次访问都需要直接从内存读取。

8. 静态类型获取与动态类型获取(typeiddynamic_cast:转换目标类型必须是引用类型)

静态类型获取
  • typeid:用于在运行时获取对象的类型信息。typeid 可以用于任何类型的表达式,包括基本数据类型、指针、用户定义类型等。对于多态类型,typeid 会在运行时确定对象的实际类型(通过RTTI,运行时类型信息)。对于非多态类型,typeid 在编译时就已经确定了类型。
动态类型获取
  • dynamic_cast:主要用于安全地将基类指针或引用转换为派生类指针或引用。它要求基类必须含有虚函数(即多态类型),因为 dynamic_cast 在运行时检查转换的安全性。如果转换不安全(即对象不是目标类型的实例),则指针类型的 dynamic_cast 会返回 nullptr,而引用类型的 dynamic_cast 会抛出 std::bad_cast 异常。注意,dynamic_cast 的目标类型必须是引用类型或指针类型。

9. 如何比较浮点数大小?

直接使用 == 来比较浮点数的大小是不安全的,因为浮点数的表示可能受到精度限制和舍入误差的影响。这意呀着,即使两个数学上不相等的浮点数,也可能在内存中表示为相同的值。

正确的做法是使用一个小的容差(epsilon)来比较两个浮点数是否“足够接近”:

#include <cmath>
#include <iostream>bool isEqual(double a, double b, double epsilon = 1e-9) {return std::fabs(a - b) < epsilon;
}int main() {double a = 0.1 + 0.2;double b = 0.3;if (isEqual(a, b)) {std::cout << "a and b are equal within epsilon." << std::endl;} else {std::cout << "a and b are not equal." << std::endl;}return 0;
}

在这个例子中,isEqual 函数通过比较两个数的差的绝对值是否小于一个小的容差(epsilon)来判断这两个数是否足够接近,从而可以认为它们是相等的。选择适当的 epsilon 值取决于你的具体应用场景和所需的精度。

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

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

相关文章

TCP 和 UDP 协议的区别?

参考TCP 和 UDP的区别_tcp和udp的区别-CSDN博客

Acwing DFS

DFS&#xff1a;深度优先搜索 DFS与BFS的对比 DFS使用栈来实现&#xff0c;BFS使用队列来实现 DFS所需要的空间是 O ( h ) O(h) O(h),而BFS需要的空间是 O ( 2 h ) O(2^h) O(2h),其中h是树的高度&#xff1b; DFS不具有最短路的特性&#xff0c;BFS有最短路的特性 DFS回溯…

102.SAPUI5 sap.ndc.BarcodeScannerButton调用摄像头时,localhost访问正常,使用IP访问失败

目录 原因 解决办法 1.修改谷歌浏览器的setting 2.在tomcat中配置https访问 参考 使用SAPUI5的sap.ndc.BarcodeScannerButton调用摄像头时&#xff0c;localhost访问正常&#xff0c;使用IP访问时&#xff0c;一直打不开摄像头&#xff0c;提示getUserMedia()问题。 原因…

2024 “华为杯” 中国研究生数学建模竞赛(D题)深度剖析|大数据驱动的地理综合问题|数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题&#xff01; CS团队倾注了大量时间和心血&#xff0c;深入挖掘解…

elasticsearch同步mysql方案

文章目录 1、1. 使用数据库触发器2. 使用定时任务3. 监听MySQL二进制日志&#xff08;binlog&#xff09;4. 使用数据管道5. 使用第三方工具或服务6. 编写自定义脚本注意事项 2、1. 使用Logstash步骤&#xff1a;示例配置&#xff1a; 2. 使用Debezium步骤&#xff1a; 3. 自定…

828华为云征文 | 解锁企业级邮件服务,在华为云fFlexus x实例上部署Mailcow开源方案

前言 华为云Flexus X实例携手Mailcow开源邮件方案&#xff0c;为企业打造了一个既高效又安全的邮件服务解决方案。Flexus X实例的柔性算力与高性能&#xff0c;是这一方案的坚实基石。它提供CPU内存的灵活定义&#xff0c;以经济型价格实现旗舰级性能&#xff0c;确保邮件服务的…

【Python实战】---- 爬取 CSDN 专栏文章列表

1. 场景 需求就是专栏中文章随着时间写的越多,如果后边需要去查找的时候比较麻烦,比如一些不常用的 git 命令,或者有些开发场景的细节,在之前已经开发完了,现在忘记部分细节,需要在之前的输出文章中去查找,当几十几百篇文章时,查找就比较麻烦,但是如果没发布一篇文章,…

js中的条件控制语句

下面是 JavaScript 流程控制语句的介绍&#xff0c;包括实例和一些应用场景。 1. 条件语句 1.1 if...else 根据条件执行不同的代码块。可以使用多个 if 语句进行复杂的判断。 示例&#xff1a; let age 18; if (age < 18) {console.log("未成年"); } else i…

【MySQL】库的相关操作

目录 1. 库的创建1.1 创建语法1.2 编码问题1.3 查看系统默认的字符集和校验集1.4 查看数据库的字符集和校验集1.2 指定编码规则创建数据库 2. 库的删改查2.1 数据库的删除2.2 选择数据库2.3 查看自己所处的数据库2.4 修改字符集或者校验集 3. 库的备份与恢复3.1 备份3.2 恢复3.…

云计算课程作业1

作业1 Xmanager连接 rhel连接 作业2 首先确认你的虚拟机设置的是NAT 1-3 然后打开这篇blog&#xff0c;并完成第一步和第二步 因为我们是NAT&#xff0c;所以不需要连接网桥&#xff0c;即跳过第三步&#xff0c;但是这里ping一下测试网络连接 2- 如果到这里你发现提示yum…

Stylized Smooth Clouds 卡通风格化云朵包

下载:​​Unity资源商店链接资源下载链接 效果图:

flutter widget 设置GestureDetector点击无效

有可能是被上层的widget挡住了&#xff0c;虽然你看得到这个widget&#xff0c;但是操作不到。使用相对布局Stack要特别注意&#xff0c;这种布局会和Android一样&#xff0c;先写的布局放在下层&#xff0c;后写的&#xff0c;如果范围较大的话&#xff0c;会盖在之前的widget…

828华为云征文|Flexus X实例Docker+Jenkins+gitee实现CI/CD自动化部署-解放你的双手~

目录 前言 实验步骤 环境准备 安装Portainer 拉取镜像 更换镜像源 启动容器 安装jenkins 拉取镜像 获取管理员密码 新建流水线项目 Portainer配置 gitee配置WebHooks 构建 修改代码&#xff0c;自动部署 前言 &#x1f680; 828 B2B企业节特惠来袭&#xff0c;…

如何通过蜂巢(容器安全)管理内部部署数据安全产品与云数据安全产品?

本文将探讨内部部署和云数据安全产品之间的主要区别。在思考这个问题之前&#xff0c;首先了解内部部署和云数据安全产品之间的主要区别。 内部部署数据安全产品意味着管理控制台位于企业客户的内部部署&#xff0c;而德迅云安全则在云中托管云数据安全产品。德迅云安全供应商通…

gin集成jaeger中间件实现链路追踪

1. 背景 新业务线带来新项目启动&#xff0c;需要改进原有项目的基础框架和组件能力&#xff0c;以提升后续开发和维护效率。项目搭建主要包括技术选型、框架搭建、基础服务搭建等。这其中就涉及到链路追踪的内容&#xff0c;结合其中的踩坑情况&#xff0c;用一篇文章来说明完…

编译 Android 11源码

参考小米6 lineageos官方编译文档&#xff1a;https://wiki.lineageos.org/devices/sagit/build 单独编译 framework 以LineageOS18.1&#xff08;Android 11&#xff09;为例&#xff1a; 1、在源码根目录执行&#xff1a; make framework-minus-apex 2、用生成的framewo…

【第十三章:Sentosa_DSML社区版-机器学习聚类】

目录 【第十三章&#xff1a;Sentosa_DSML社区版-机器学习聚类】 13.1 KMeans聚类 13.2 二分KMeans聚类 13.3 高斯混合聚类 13.4 模糊C均值聚类 13.5 Canopy聚类 13.6 Canopy-KMeans聚类 13.7 文档主题生成模型聚类 13.8 谱聚类 【第十三章&#xff1a;Sentosa_DSML社…

54.【C语言】 字符函数和字符串函数(strncpy,strncat,strncmp函数)

和strcpy,strcat,strcmp函数对应的是strncpy,strncat,strncmp函数 8.strncpy函数 *简单使用 cplusplus的介绍 点我跳转 翻译: 函数 strncpy char * strncpy ( char * destination, const char * source, size_t num ); 从字符串中复制一些字符 复制源(source)字符串的前num个…

MySQL高阶1890-2020年最后一次登录

目录 题目 准备数据 分析数据 题目 编写解决方案以获取在 2020 年登录过的所有用户的本年度 最后一次 登录时间。结果集 不 包含 2020 年没有登录过的用户。 返回的结果集可以按 任意顺序 排列。 准备数据 Create table If Not Exists Logins (user_id int, time_stamp …

JavaSE--集合总览02:单列集合Collection的体系之一:List

Collection体系的特点 分为 list 和set集合&#xff0c;这篇文章主要讲述List&#xff0c;下篇讲述Set。 简单认识单列集合collection集合的特点 : list集合的特点&#xff1a; 有序 可重复 有索引 set集合的特点&#xff1a;无序 不重复 无索引 其中LinkedHashSet有序 TreeS…