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.xdnf.cn/news/146993.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

proteus仿真学习(1)

一&#xff0c;创建工程 一般选择默认模式&#xff0c;不配置pcb文件 可以选用芯片型号也可以不选 不选则从零开始布局&#xff0c;没有初始最小系统。选用则有初始最小系统以及基础的main函数 本次学习使用从零开始&#xff0c;不配置固件 二&#xff0c;上手软件 1.在元件…

【AcWing】875. 快速幂

#include<iostream> using namespace std; typedef long long LL;LL qmi(int a,int b,int p){LL res1%p;//%p是为了p1的时候&#xff0c;余数是0while(b){if(b&1) resres*a%p;//位数是1的b>>1;aa*(LL)a%p;//a*a再modp是为了防止溢出}return res; }int main(){i…

【动态规划】(三)动态规划——完全背包

动态规划——完全背包 完全背包理论基础零钱兑换Ⅱ组合总和Ⅳ爬楼梯&#xff08;进阶版&#xff09;零钱兑换完全平方数单词拆分背包问题总结 完全背包理论基础 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品…

零食店小程序发展客户转化运营

零食店、折扣店近些年市场中跑出了不少区域性、多地化的品牌&#xff0c;直营及加盟模式&#xff0c;还有各种超市、商场、街边小店等&#xff0c;零食基本没有年龄群体限制&#xff0c;又属于常消费品&#xff0c;线上线下生意都可以进行发展。 线下客户到店&#xff0c;线上…

链表数据结构

链表可以解决顺序表的缺点 我们今天简单引用下链表 这边是代码讲解 头文件 #pragma once #include<stdio.h> #include<iostream> #include<string.h> #include<stdlib.h> using namespace std; typedef struct student {union {int data;int len;};s…

【计网】从零开始掌握序列化与反序列化 --- 基础知识储备与程序重构

从零开始掌握序列化与反序列化 1 初识序列化与反序列化2 再谈Tcp协议3 程序重构3.1 Socket类3.2 回调函数设计3.3 最终的Tcp服务器类 1 初识序列化与反序列化 在刚学习计算机网络时&#xff0c;我们谈到过网络协议栈&#xff0c;其中最上层的就是应用层&#xff0c;那么这个应…

Rosetta 一:手把手教你用Linux安装Rosetta(全网最简洁)

文章目录 1. Rosetta 介绍2.下载2. Rosetta 安装3. 验证安装 1. Rosetta 介绍 很久很久之前就对Rosetta有所耳闻&#xff0c;有一篇文章叫做denovo protein design&#xff0c;说的就是用rosetta来设计蛋白质。 rosetta是david baker团队设计的软件&#xff0c;早期只是一个蛋…

【Godot4.3】胶囊形的偏移获取法

概述 之前用半圆弧拼接的方式求过胶囊形&#xff0c;在逐渐熟练使用Geometry2D的过程中&#xff0c;发现通过线段求端点是圆角类型的偏移多边形&#xff0c;获得的就是胶囊形。 所以我们有了第二种胶囊形求法。 测试代码 tool extends Node2D## 横向宽度 export var width:…

【工具】Windows|两款开源桌面窗口管理小工具Deskpins和WindowTop

总结 Deskpins 功能单一&#xff0c;拖到窗口上窗口就可以置顶并且标记钉子标签&#xff0c;大小 104 KB&#xff0c;开源位置&#xff1a;https://github.com/thewhitegrizzli/DeskPins/releases WindowTop 功能完善全面强大&#xff0c;包括透明度、置顶、选区置顶等一系列功…

SQL server学习01-SQL server环境配置

目录 一&#xff0c;手动下载及安装 microsoft .net framework 3.5 1&#xff0c;下载 2&#xff0c;安装 二&#xff0c;安装SQL server2014 1&#xff0c;下载 2&#xff0c;安装 3&#xff0c;启动SQL server服务 三&#xff0c;下载及安装Microsoft SQL Server…

C Prime Plus 第6章习题

你该逆袭了 红色标注的是&#xff1a;错误的答案 蓝色标注的是&#xff1a;正确的答案 绿色标注的是&#xff1a;做题时有疑问的地方 橙色标注的是&#xff1a;答案中需要着重注意的地方 练习题 一、复习题1、2、3、4、5、我的答案&#xff1a;错误正确答案&#xff1a; 6、7、…

ubuntu 安装minikube,并拉取k8s镜像

不要使用最新版&#xff0c;重要的事情说三遍&#xff0c;刚开始也是最求新一点的版本&#xff0c;但问题很多&#xff0c;主要是版本之间的依赖问题&#xff0c;不是某个依赖的版本不支持某些功能&#xff0c;就是依赖之间的版本不能对应上&#xff0c;所以就降低几个版本&…

行业人工智能研究-Python自监督方式学习图像表示算法

学术界人工智能研究落后于工业界 摘要 行业或工业界在人工智能研究上超出学术界&#xff0c;并占据着大量的计算力&#xff0c;数据集和人才诱人的薪水和明朗的预期吸引大量人才离开学术界&#xff0c;涌入行业或工业界即使&#xff0c;比如Meta开源其人工智能模型&#xff0…

实验:WLAN无线综合实验

无线综合实验的概述&#xff1a; WLAN无线综合实验是一种针对无线网络技术的综合性实验&#xff0c;旨在通过实践操作加深对无线局域网&#xff08;WLAN&#xff09;技术的理解和应用能力。以下是对该实验的详细概述&#xff1a; 实验目的 掌握认证AP上线的配置方法&#xff…

[SAP ABAP] 创建域

我们可以使用事务码SE11创建域 输入要创建的域的名称&#xff0c;然后点击创建 输入简短描述&#xff0c;选择数据类型和输入字符数 激活并保存域&#xff0c;创建的域才能够生效

pg入门18—如何使用pg gis

1. 下载postgre gis镜像 2. 运行镜像 docker run -p 15432:5432 -d -e POSTGRES_PASSWORDAb123456! postgis/postgis:12-3.4-alpine 3. 使用gis # 进入容器&#xff0c;登录pgdocker exec -it bash# 登录数据库psql -U postgres# 创建数据库CREATE DATABASE mygeotest;# 使用…

Spring Boot 入门:解锁 Spring 全家桶

前言 Spring 全家桶是现代 Java 开发者不可或缺的工具集&#xff0c;它提供了从轻量级的框架到微服务架构的完整支持。本文将带你快速了解 Spring 框架、核心概念如 IoC&#xff08;控制反转&#xff09;和 AOP&#xff08;面向切面编程&#xff09;&#xff0c;并深入介绍 Sp…

YOLOv10多模态 结合Transformer与NMS-Free 融合可见光+红外光(RGB+IR)双输入【附代码】

文章目录 前言视频效果代码获取文章概述必要环境一、模型训练1、 定义数据1.1、数据集结构1.2、定义data.yaml 2、 运行方法运行效果 二、模型验证运行方法运行效果 三、模型推理3.1. 推理图像1. 参数定义2. 运行方法运行效果 3.2. 推理视频1. 参数定义2. 运行方法运行效果 四、…

构建高可用和高防御力的云服务架构第一部分:深入解析DDoS高防(1/5)

引言 在数字化时代&#xff0c;网络安全已成为全球关注的焦点。随着互联网技术的快速发展和应用的广泛深入&#xff0c;网络安全形势日益严峻。特别是分布式拒绝服务&#xff08;DDoS&#xff09;攻击&#xff0c;以其破坏性强、难以防范的特点&#xff0c;对个人、企业乃至国…

Go-知识-定时器

Go-知识-定时器 1. 介绍2. Timer使用场景2.1 设定超时时间2.2 延迟执行某个方法 3. Timer 对外接口3.1 创建定时器3.2 停止定时器3.3 重置定时器3.4 After3.5 AfterFunc 4. Timer 的实现原理4.1 Timer数据结构4.1.1 Timer4.1.2 runtimeTimer 4.2 Timer 实现原理4.2.1 创建Timer…