变量的作用域和生命周期

news2024/9/21 2:49:30

大家好我是清墨,欢迎收看本期文章。

1. 数据存储的 3 要素

计算机程序在存储数据时必须跟踪 3 个基本属性:

  1. 信息存储在何处,在什么地方定义变量,决定了信息存储在何处
  2. 存储的值是多少,值是多少是通过赋值语句(或者初始化语句)决定的
  3. 存储的信息是什么类型,定义变量的时候会提供数据类型

2. 全局变量和局部变量

我们先看下面的程序例子

#include<bits/stdc++.h>
using namespace std;
int a; // 在 函数以外的地方定义的变量就是全局变量
int func(int t)
{
    int b=t*10+a;  // 在函数内定义的就是局部变量
    return b;
}
int main(){
    int c;  //在 main 函数内定义的变量是局部变量
    cin >>c>>a;
    cout << func(c);

    for(int i=1;i<=10;i++) // 循环变量 i 是局部变量,离开了 for 语句的范围
    {
        bool ok=false; // 局部变量 ok ,它的声明周期仅仅限于 本轮 for 循环。
        if(i%2==0) ok = true;
        if(ok) cout<<i<<endl;
    }
    return 0;
}

 

上面程序中有 5 个变量,都是 int 类型,名字分别是 a, b, c, i, ok 。 这 5 个变量的作用域和生命周期各不相同。

作用域指的是这个变量能被访问到的范围,在这个范围以内就能访问到,超出了这个范围就访问不到,就好像这个变量不存在一样。

生命周期讲的是这个变量什么时候被创建,什么时候被销毁。就好像人会有生老病死一样,变量也一样有。当变量被销毁之后,它就不复存在,你再都不能把它找回来了。这和作用域不太一样的,一个变量可以还存在,只是你在作用域之外访问不到它而已,就好比你和你的朋友被各自隔离在两个海岛上,没电话,没通信,你和你的朋友都是这个世界的客观存在,但是你没办法和你的朋友沟通。但是如果变量已经被销毁,那么在任何地方都访问不到了,那就不仅仅是隔离的问题,是压根就没有这个东西。

  1. a 是全局变量。这意味着在整个程序的任何一个地方都可以访问到全局变量 a;除非是在某个局部范围内,你又另外定义了一个局部变量也叫 a ,那么在这个局部范围内你引用的 a 就是局部变量的 a,也就是说同名的时候,局部变量会屏蔽全局变量。全局变量都是在程序开始运行的时候就创建,到程序结束的时候被销毁,你的程序有多长的生命,全局变量就有多长的生命。

  2. c、b、i、ok 都是局部变量。c 是在 main 函数内定义的,所以,在 main 函数范围内,都可以引用(访问)c; b 是 func 函数内定义的,所以,在整个 func 范围内,都能访问 b 。上面的内容都比较好理解,但是,大家还需要理解反过来的一层意思局部变量值能在定义它的那个小范围(作用域)内被访问,离开了这个作用域,这个变量就没办法访问到,比方说,如果你在 main 函数里试图访问 func 函数里的 b ,那是要出错的,在 func 里面想访问 main 函数里面的 c 也是会出错的。

  3. i 和 ok 同样是局部变量,但是它们 2 个更特殊一些。i 是在 for 语句的圆括号里定义的,那么 i 的生命周期仅仅限于 for 语句之内,这个 for 语句结束了之后,i 就被销毁了,再都没有 i 了。即便你后面再写一个 for,继续用 i 来做循环变量,那个 i 也是另外一个 i 了。就好比你家有一条宠物狗叫 Boby,它死了,然后你又买了一条新的狗,你为了怀念以前的狗,给新的狗也起了个名字叫 Boby,但是此 Boby 非彼 Boby。

  4. ok 变量是在 for 的循环体里面定义的,那么它的作用域就仅限于 for 内部,而且,它的生命周期是本轮循环。也就是说,每循环一遍,这个程序就定义一次 ok,本轮循环结束,就销毁 ok,所以循环了 10 次,就先后定义了 10 个 ok ,也销毁了 10 次 ok,每一个 ok 都是一个不一样的 ok,只不过名字相同而已。如果你的程序要循环非常多次的,那就一定要避免这种变量定义方式,因为变量的定义和销毁是会产生开销的,这个开销要比做加减乘除大得多,如果循环 107107 次,执行 107107 次变量定义和销毁,会花很多时间。

3. 合理利用全局变量和局部变量的特性

可能会有同学提出,既然全局变量能在整个程序范围都被访问,那我把变量都定义成全局变量,那岂不是更好?这个问题非常复杂,因为评判这样做的好坏是有很多个角度的。

如果单单从参数传递的角度来看,把变量定义成全局变量,那就不需要传参,所以会减少模块之间的接口复杂性。请看下面的例子

求最大公约数,版本 1

#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
    int c;
    while(a%b!=0)
    {
        c = a % b;
        a = b;
        b = c;
    }
    return b;
}
int main(){
    int a,b;
    cin>>a>>b;
    cout<<gcd(a,b);
}

 

求最大公约数,版本 2

#include<bits/stdc++.h>
using namespace std;
int a,b,c;
void gcd()
{
    while(a%b!=0)
    {
        c = a % b;
        a = b;
        b = c;
    }
    c = b;
}
int main(){
    cin>>a>>b;
    gcd();
    cout<<c;
}

 

上述两个版本,要做的事情都类似,第一个版本中,main 函数内调用 gcd ,通过 参数 把要两个数传给 gcd 函数。gcd 函数算完之后通过返回值把结果送回给 main。

第二个版本,a, b 都是全局变量,计算结果放在 c,c 也是全局变量。所以,main 函数和 gcd 函数之间不需要传递和会送任何的数据,换一句话说,这两个部分之间的相互配合是很简单的。但是,简单未必是好事。如果这个程序要计算的东西很复杂,我们算最大公约数的时候不希望破坏原来的 a 和 b,它们后面还有别的地方要用到,改了就反而不行的,那么第一个版本显然就是更合理的。

在工作中,用于生产、商业运作的程序往往都是很严肃的程序,程序的可靠性、代码的可管理性都是很重要的考量因素,如果代码简单了但是牺牲了程序的可靠性、稳健性、可管理性,那么这样换回来的简单是不会被采纳的。

但是,在比赛的时候,程序往往就是一个简单的问题,解题有时间限制,写一个非常漂亮、规范的程序并不给你加分,只要你能掌控得住,这个程序或许不是那么规范,节省了时间可能会给你带来分数上的帮助。所以的的确确很多时候会依赖全局变量来简化程序的模块接口。我们看一些牛人写的程序,你可能会挑剔他有各种毛病,并不是那个牛人不知道这些问题,而是而是他们掌控得住你说的那些问题。

再讲大一点,ACM 的比赛和 OI 的比赛因为规则不一样,代码风格都不太一样。ACM 是比时间的,解题速度和最终的分数关系非常大,所以,ACM 会有一些自己的代码风格,能节省 10 秒就是 10 秒。我们过去一直是基于 OI 的比赛规则来训练的,过去的区赛也是 OI 模式。这种模式下,对解题时间没有考量。因此我们会更加注意把代码写好一点,严谨一点。

这个世界很大,非常复杂,当你知道的东西越多,你越是会觉得有趣。

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

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

相关文章

图片压缩格式自适应,真的很省流量!

导语 图片&#xff0c;作为信息传递的重要载体&#xff0c;其格式日益多样化。不管是 PC 端还是移动端&#xff0c;图片一直都是流量消耗的大户。在互联网的应用中&#xff0c;用户会上传大量的图片&#xff0c;而且访问频繁&#xff0c;如果这些图片都以传统方式存在服务器磁盘…

用AI制作专属欧美漫画头像!FLUX大模型-漫画情侣lora应用教程

​ ​ 新上线了一个漫画风格的lora《漫画情侣&#xff08;欧美黄金时代风&#xff09;v1.0》 感兴趣的朋友可以去下载使用&#xff0c;下载是免费的。 下面跟大家说一下这个lora的特点、使用方法以及这个lora的延伸应用&#xff1a;欧美漫画头像制作 lora风格特点 欧美漫画/人…

Leetcode面试经典150题-97.交错字符串

给定三个字符串 s1、s2、s3&#xff0c;请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。 两个字符串 s 和 t 交错 的定义与过程如下&#xff0c;其中每个字符串都会被分割成若干 非空 子字符串 &#xff1a; s s1 s2 ... snt t1 t2 ... tm|n - m| < 1交错 是…

C++入门基础知识八

1.介绍new与delete 1.malloc和free是函数&#xff0c;new和delete是操作符 2.malloc申请的空间不会初始化&#xff0c;new可以初始化 3.malloc申请空间失败时&#xff0c;返回的是NULL&#xff0c;因此必须判空&#xff0c;new不需要&#xff0c;但是new需要捕获异常 4.申请…

【例题】lanqiao4403 希尔排序模板题

插入排序每次只能将数据移动一位。 已知插入排序代码为&#xff1a; def insert_sort(a):for i in range(1,len(a)):ji-1while j>0 and a[j]>a[i]:a[j1]a[j]j-1a[j1]a[i]return a希尔排序在插入排序的基础上&#xff0c;将数据移动n/2,n/4,…,1位。 for i in range(ga…

某东不固定大小旋转验证码识别

注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路 如有侵犯,请联系作者下架 旋转验证码基本是旋转小图到一定的角度去匹配大图的,通常的旋转验证码,中间缺口图部分大小固定,但是在某东上,大小不固定,部分数据集如下: 结合之前的旋转验证…

09.20 C++对C的扩充以及C++中的封装、SeqList

SeqList.h #ifndef SEQLIST_H #define SEQLIST_H#include <iostream> #include<memory.h> #include<stdlib.h> #include<string.h>using namespace std;//typedef int datatype; //类型重命名 using datatype int;//封装一个顺序表 class Seq…

.ipynb 图解介绍,轻松入门,提升效率

目录 01 使用jupyter遇到的问题1.1 Python requires ipykernel installed or requires an update 1.1.1 查询所有内核 1.1.2 选择对应的Python版本 02 理解jupyter规则 2.1 系统命令 01 使用jupyter遇到的问题 1.1 Python requires ipykernel installed or requires an up…

MyBatis 基本操作 - XML版

目录 配置xml文件 一&#xff0c;查询 - Select 1.1 全列查询 1.2 赋值问题 二&#xff0c;新增 - insert 2.1 使用对象插入 2.2 获取主键 三&#xff0c;删除 - delete 四&#xff0c;修改 - update 配置xml文件 <?xml version"1.0" encoding"U…

全国自闭症寄宿学校:为孩子提供全方位关怀

在自闭症儿童教育的广阔领域中&#xff0c;全国范围内的寄宿学校如同一座座灯塔&#xff0c;照亮了这些特殊孩子前行的道路。它们不仅提供了专业的教育服务&#xff0c;更以无微不至的关怀&#xff0c;为孩子们构建了一个温暖的家。在广州这座充满温情的城市&#xff0c;星贝育…

【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL20

数据选择器实现逻辑电路 描述 请使用此4选1数据选择器和必要的逻辑门实现下列表达式。 数据选择器的逻辑符号如下图&#xff1a; 数据选择器代码如下&#xff0c;可在本题答案中添加并例化此数据选择器。 module data_sel(input S0 ,input S1 …

2024.9.20 Python模式识别新国大EE5907,PCA主成分分析,LDA线性判别分析,GMM聚类分类,SVM支持向量机

1.PCA 主成分分析用于特征提取、可视化和分类 根据要求&#xff0c;我在第一个代码框中完成了从指定路径提取图像数据&#xff0c;将其转换为灰度图像并将其展平。在这里&#xff0c;我将数字 88 设置为我的照片的标签&#xff0c;然后将所有 10 张照片传入代码。然后我定义了…

java之杨辉三角问题

给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 如何实现呢&#xff1f; 思路&#xff1a;首先&#xff0c;我们可以将杨辉三角视作i行j列的二维数组。除了第一行和第二行之外&am…

✨机器学习笔记(五)—— 神经网络,前向传播,TensorFlow

Course2-Week1: https://github.com/kaieye/2022-Machine-Learning-Specialization/tree/main/Advanced%20Learning%20Algorithms/week1机器学习笔记&#xff08;五&#xff09; 1️⃣神经网络&#xff08;Neural Network&#xff09;2️⃣前向传播&#xff08;Forward propaga…

最短路: Djikstra

最短路: Djikstra 适用于边权非负 如果存在负边权, 则当前距离dist最小的点, 不一定就是实际离源点最近的点,可能有负边导致其它路径离当前点更近 如下图所示, 如果存在负边, y点距离S点最近, 所以选中y点进行松弛, 贪心思想 当边权非负,离起点S最近的点,不能被更新, 如果在…

PointNet++改进策略 :模块改进 | SPVConv, 体素和点云特征融合提升小目标检测能力

论文题目&#xff1a;Searching Efficient 3D Architectures with Sparse Point-Voxel Convolution发布期刊&#xff1a;ECCV通讯地址&#xff1a;麻省理工 & 清华大学代码地址&#xff1a;https://github.com/mit-han-lab/spvnas 介绍 这篇论文的主题是如何为自驾车等应…

[译] Go语言的源起,发展和未来

本篇内容是根据2019年9月份Creating the Go programming language音频录制内容的整理与翻译, 两位主持人与Go 的创始人 Rob Pike 和 Robert Griesemer谈论了 Go 的起源、发展、影响和未来。这是一个史诗般的剧集&#xff0c;深入探讨了 Go 的历史和详细信息&#xff0c;以及他们…

手动部署并测试内网穿透(ssh 和 nginx)

原理回顾 首先需要一台连接了公网的云服务器&#xff0c;然后我们要访问的内网穿透对象最好是Linux服务器&#xff0c;比如虚拟机&#xff0c;然后我们通过向云服务器发送指令&#xff0c;云服务器再将指定发送给指定对象&#xff0c;让其能够执行命令。 总结就是&#xff1a…

数据结构与算法——Java实现 6.递归

要学会试着安静下来 —— 24.9.17 一、递归的定义 计算机科学中&#xff0c;递归是一种解决计算问题的方法&#xff0c;其中解决方案取决于同一类问题的更小子集 说明: ① 自己调用自己&#xff0c;如果说每个函数对应着一种解决方案&#xff0c;自己调用自己意味着解决方案是…

数据建模无法满足复杂业务需求?别慌,数据开发平台可以完美互补!

前言 数据可视化建模无论是对于企业的数字化转型&#xff0c;还是对数据资源的价值开发来说&#xff0c;都是至关重要的工具&#xff0c;小兵在前文《数据可视化建模平台介绍》。中有详细介绍过他的能力&#xff0c;包括面向多源异构的企业数据&#xff0c;为企业提供数据集成…