C语言变量的作用域,生命周期和链接相关

前言

本文介绍C语言的三个很重要的概念:

  • 变量的作用域
  • 变量的生命周期
  • 变量或者函数的链接

写在前面

先介绍一个概念:翻译单元
C语言中有两种文件,头文件.h代码文件.c
翻译单元指的是包含头文件,并且将头文件展开以后的代码文件.c,而每个翻译单元都有一个文件作用域,实际上,他是编译器编译的完整对象单元

变量的作用域

变量的作用域其实是一个范围,只有在这个范围以内变量才是可用的,作用域是可以嵌套的,变量使用的永远是最内层声明或者定义的那个。注意,声明的变量也算,看下面的例子:

#include <stdio.h>
int main(void)
{float PI = 2.14;printf("PI = %f\n",PI);for(int i = 0;i<1;i++){extern float PI;printf("PI = %f\n",PI);}return 0;
}

这个程序运行的结果如下:

PI = 2.140000
PI = 3.141593

我在另外一个calc.c文件中定义了一个PI值,所以第二次打印的时候这个extern表示这是一个声明,他的定义在另外一个翻译单元中。

#include "calc.h"
const float PI=3.1415926;

块作用域

一对大括号括起来就形成了一个块作用域
在一个块作用域内声明的变量的可用范围是从这个块中变量定义处到包含该定义块的结尾,块作用域需要注意几个问题:

  • 函数的参数虽然在块的外面,但是他也属于函数所在的块
    这个一般的理解其实就是函数参数无论是保存在寄存器还是保存在栈上都是在函数调用(call)开始之后进行的
  • 对于if,while,for等循环或者判断的情况,如果没有用花括号括起来,也算是块的一部分,并且我们可以将这些情况理解为两个块,比如for语句,整个for语句看成是一个块,for后面的循环体执行逻辑作为这个块的子块,这样很多问题的比较容易理解了,看下面的例子:
#include <stdio.h>
int main(void)
{for(int i = 0;i<10;i++){printf("%d|",i);int i = 6;printf("%d, ",i);}printf("\n");return 0;
}

输出结果:

0|6, 1|6, 2|6, 3|6, 4|6, 5|6, 6|6, 7|6, 8|6, 9|6, 

在第一次执行循环体的时候,定义了一个i = 6,但是再一次回到for,执行i++的时候依然是用的在for语句定义的i,我们可以把for语句这样写一下:

{//第一层块int i = 0;执行for循环{//第二层块printf("%d|",i);int i = 6;printf("%d, ",i);}
}

这样每次执行for循环的时候内部定义的i就失效了,使用的还是外部定义的i变量

函数作用域

函数作用域指的是即使在函数的内层块中,也会自动提升作用域到整个函数,这种作用域只用于goto的标签(是不是很没有用!!),也就是即使goto的标签定义在一个函数内层块中,也不能在另一个块中定义相同的标签,因为标签的作用域是整个函数,看下面例子:

#include <stdio.h>
int main()
{goto b;{b:printf("bbb");}return 0;
}

运行会打印字符串bbb,虽然标签b定义在一个函数内层块中,但是他具有函数作用域
否则,我们可以在一个函数的另一个块中定义一个同名的标签跳转,这样我们如果使用goto语句的话就太混乱了。所以C语言才有函数作用域这么个东西

函数原型作用域

函数原型作用域针对函数的声明中形参起作用,形参的作用域从定义开始到函数原型定义结束,一般这种情况是针对于函数声明中有可变数组的情况下,比如下面的声明:

void reset(int m,int n,int arr[m][n],int val);

文件作用域

如果一个变量定义在函数外面,就说该变量具有文件作用域,定义在文件中的函数也具有文件作用域,也就是文件中所有函数都可以直接使用,根据变量或函数定义是否添加static关键字,可以分为具有内部链接的文件作用域和具有外部链接的文件作用域

  • 内部链接的文件作用域:只有当前文件内可以使用
  • 外部链接的文件作用域:外部文件也可以使用,不过外部文件使用时需要使用extern进行声明,这样编译器编译的时候就会在符号表中为该变量或者函数添加符号,链接器在链接的时候就会根据符号去别的文件中寻找定义

变量的生命周期

变量的生命周期就是变量在程序运行过程中可用的时间段,主要有四种:

  • 静态变量
  • 线程变量
  • 局部变量或者叫自动变量
  • 动态变量

静态变量

静态变量也叫全局变量,是指在程序运行过程中一直存在的变量,所谓静态变量,就是指变量不是存储在运行栈或者运行堆上,而是放在固定的内存位置,比如.data数据块等地方。C语言有如下几种静态变量:

  1. 定义在函数外面的变量,也就是具有文件作用域的变量,无论是否使用static修饰,都是全局变量
  2. 使用extern声明的变量,虽然定义在别的地方,但是也是静态变量
  3. 在函数内部使用static关键字定义的变量,该变量虽然作用域只限于当前定义的函数内部,但是在整个程序运行期间都存在,并且我们通过指针使用该变量,看下面例子:
#include <stdio.h>
int* get();
int main(void)
{int c = *get();printf("%d\n",c);return 0;
}int* get()
{static int a = 10;return &a;
}

运行结果

10

线程变量

线程变量是通过使用关键字_Thread_local声明的变量,每个线程都会获取变量的一个单独的备份,看下面的例子:

#include <stdio.h>
#include <pthread.h>
_Thread_local int threadVar = 10;
void threadHandle();
int main(void)
{int c = 0;for(int i = 0;i<6;i++){pthread_t threadNo;if((c = pthread_create(&threadNo, NULL, threadHandle, NULL)) != 0){printf("thread create failed. errno:%d",c);continue;}}return 0;
}void threadHandle()
{threadVar++;printf("threadHandle::%d\n",threadVar);pthread_exit(0);
}

输出

threadHandle::11
threadHandle::11
threadHandle::11
threadHandle::11
threadHandle::11

局部变量或者叫自动变量

局部变量是指在块内部定义的变量,该变量或者在函数执行期间通过寄存器保存,或者保存在程序栈上。该变量在块结束后就失效。
注意:自动变量不会自动初始化,所以一定要初始化自动变量,不然值是不确定的

动态变量

动态变量是指变量的定义和内存分配是通过用户控制,在程序运行期间动态执行的,动态变量一般分配在程序堆上,通过制定的函数接口来分配和释放
使用动态函数需要引用头文件

#include <stdlib.h>

malloc

该函数接受一个参数:所需的内存字节数,然后去找合适的空闲内存块,返回内存的地址。

void	*malloc(size_t __size)

注意:
这个函数分配的内存是未初始化的
如果分配内存失败,返回NULL

free

该函数接受一个参数,就是前面malloc返回的内存指针,该函数的作用是释放分配的内存

可以看出动态内存非常灵活,比如我们可以在程序运行过程中动态创建数组,链表等数据结构,但是动态分配的内存在程序运行期间会一直增加,除非你用free函数释放内存。并且,有些操作系统,即使应用程序结束,动态分配的内存也不会释放,所以,使用动态内存需要注意一下几点:

  1. 需要维护好动态分配的内存指针,并且在不使用的时候用free释放
  2. 释放后的指针需要设置成NULL,避免free多次

calloc

calloc和malloc一样,也是用于动态分配内存,但是calloc是按照存储单元分配内存,该函数接受两个参数,第一个参数是所需的存储单元的数量,第二个参数是存储单元占用的字节数。比如下面的例子:

long* newmem = (long*)calloc(100,sizeof(long));

这种分配方式有个好处就是即使一个系统上long类型占用的字节数不是四个字节,该函数分配的内存依然够用。

free函数也可用于释放calloc分配的内存

变量或者函数的链接

链接的原因

之所以要有链接的概念,是因为我们为了编写大型应用程序,需要将程序进行模块化,分成一个个的翻译单元,比如我们创建一个游戏引擎的程序,需要

  • 日志模块
  • 内存管理模块
  • 音视频解码
  • 图像解码
  • 数学库
  • 材质管理
  • 多媒体播放
  • 事件系统
  • 动画系统
  • 渲染模块
  • 等等
    但是各个模块之间还会相互调用,比如我在数学库中定义的一个矩阵相乘的方法,可能在很多别的模块也需要,但是函数的定义在数学库中,别的模块怎么找到呢,这就是链接的目的,链接就是寻找在外部定义的变量或者函数的地址

链接的方式

C语言中能被外部函数或者内存函数使用的变量或者函数只有两种,前面讲过,就是具有文件作用域的变量或函数:

  • 外部链接:函数外部声明的函数或者变量,没有使用static修饰符,具有外部链接。外部使用时必须使用extern进行声明我们通常把一个翻译单元的外部链接变量或者函数使用extern在头文件中集中进行声明,别的翻译单元只需要引用该头文件即可使用
  • 内部链接:函数外部声明的函数或者变量,使用static修饰符,具有内部链接。内部链接的变量或函数只能供当前翻译单元使用。

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

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

相关文章

分布式数据库HBase

文章目录 前言 一、HBase概述 1.1.1 什么是HBase HBase是一个分布式的、面向列的开源数据库HBase是Google BigTable的开源实现HBase不同于一般的关系数据库, 适合非结构化数据存储HBase是一种分布式、可扩展、支持海量数据存储的 NoSQL数据库。HBase是依赖Hadoop的。为什么HBa…

Linux中的输入输出重定向

目录 1.输出重定向 > 2.追加重定向 >> 3.标准 正确/错误 输出重定向 4.输入重定向 < 5.标准输入 0 1.输出重定向 > 将命令执行之后的结果不打印出来&#xff0c;可以输入在另外一个文件当中。 如&#xff0c;我查看文件a.txt 的前3行&#xff0c;然后不显…

如何从eureka-server上进行服务发现,负载均衡远程调用服务

在spring cloud的maven的pom文件中添加eureka-client的依赖坐标 <!--eureka-client依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependen…

gitLab 和Idea分支合并

以下二选1即可完成分支合并建议第一种简单有效 Idea合并方式 切换到被合并的分支&#xff0c;如我想把0701的内容合并到dev&#xff0c;切换到dev分支&#xff0c;然后再点击merge然后选择要合并的分支&#xff0c;即可,此时git上的代码没有更新只是把代码合到本地需要pull才…

【Flink on k8s】- 5 - 简要介绍 Flink

目录 1、了解流计算框架 1.1 分代 1.2 流计算框架对比 2、Flink 的应用场景 2.1 Data anal

互联网大规模数据挖掘的目录

目录 目  录 第1章  数据挖掘基本概念  1 1.1  数据挖掘的定义  1 1.1.1  统计建模  1 1.1.2  机器学习  1 1.1.3  建模的计算方法  2 1.1.4  数据汇总  2 1.1.5  特征抽取  3 1.2  数据挖掘的统计限制  4 1.2.1  整体情报预警  4 1.2.2 …

盲盒小程序搭建:实现盲盒消费新体验

近几年来&#xff0c;潮玩市场中的盲盒逐渐席卷了年轻一代人的生活&#xff0c;吸引了不少消费者。盲盒的不确定性给消费者带来了惊喜和快乐&#xff0c;盲盒的商业价值也是逐渐增加&#xff0c;预计2024年盲盒市场规模将突破300亿元。 但在当下互联网快速发展的时代下&#x…

python/matlab图像去雾/去雨综述

图像去雾和去雨是计算机视觉领域的两个重要任务&#xff0c;旨在提高图像质量和可视化效果。本文将综述图像去雾和去雨的算法、理论以及相关项目代码示例。 一、图像去雾算法 基于暗通道先验的方法&#xff1a; 这是广泛应用于图像去雾的经典算法之一。该方法基于一个观察&…

Ubuntu22.04通过Maas和Juju部署openstack charm

目录 官方文档材料准备软件硬件 模板机和虚拟网络安装MAAS官方文档MAAS节点配置安装MAAS浏览器登录MAAS进行配置 激活DHCP 官方文档 https://docs.openstack.org/project-deploy-guide/charm-deployment-guide/2023.1/ 这是一个通过Maas面板即可部署openstack的方式&#xff0…

利用 Python进行数据分析实验(一)

一、实验目的 使用Python解决简单问题 二、实验要求 自主编写并运行代码&#xff0c;按照模板要求撰写实验报告 三、实验步骤 本次实验共有5题&#xff1a; 有四个数字&#xff1a;1、2、3、4&#xff0c;能组成多少个互不相同且无重复数字的三位数&#xff1f;各是多少&…

解决IDEA Failed to connect to github.com port 443: Timed out 问题

1. Timed out 报错 fatal: unable to access https://github.com/xxxx/xxxx.git/: Failed to connect to github.com port 443: Timed out解决 设置代理 git config --global http.proxy 127.0.0.1:1080 #为全局的 git 项目都设置代理git config --local http.proxy 127.…

java面试题-ArrayList 和 LinkedList 的区别是什么

远离八股文&#xff0c;面试大白话&#xff0c;通俗且易懂 看完后试着用自己的话复述出来。有问题请指出&#xff0c;有需要帮助理解的或者遇到的真实面试题不知道怎么总结的也请评论中写出来&#xff0c;大家一起解决。 java面试题汇总-目录-持续更新中​​​​​​​ ArrayLi…

大数据生态架构:探索未来科技的无限可能。

1、大数据生态圈技术框架 大数据生态圈技术是指在大数据领域中&#xff0c;涉及到的技术体系。目前大数据生态圈中的核心技术总结下来分为以下9类&#xff1a; 数据采集技术框架数据存储技术框架数据处理技术框架数据分析技术框架数据可视化技术框架数据安全技术框架数据治理…

华为数通---使用基本ACL限制Telnet登录权限案例

组网需求 如下图所示&#xff0c;PC与设备之间路由可达&#xff0c;用户希望简单方便的配置和管理远程设备&#xff0c;可以在服务器端配置Telnet用户使用AAA验证登录&#xff0c;并配置安全策略&#xff0c;保证只有符合安全策略的用户才能登录设备。 配置通过Telnet登录设备…

机器学习之布谷鸟搜索算法(Cuckoo Search Algorithm,CSA)剖析

概念 布谷鸟搜索算法(Cuckoo Search Algorithm,CSA)是一种模拟自然界中布谷鸟种群行为的优化算法。这个算法的灵感来自布谷鸟的繁殖行为:布谷鸟会将自己的蛋放入别的鸟巢中,鸟主人可能会发现假蛋并将它们丢弃,而布谷鸟的蛋则有可能得以孵化。 这个算法的基本思想是模拟布…

学习极市开发平台

这是官网的链接&#xff1a;极市开发者平台-计算机视觉算法开发落地平台-极市科技 (cvmart.net) 第一次用这个平台有很多问题&#xff0c;首先在使用这个平台之前&#xff0c;我大部分时候使用的是百度的飞浆平台&#xff0c;也就是BML&#xff0c;去训练一些深度学习的模型。 …

防抖和节流

防抖&#xff08;Debouncing&#xff09;&#xff1a; 防抖是指在事件被触发后&#xff0c;等待一定的时间间隔&#xff0c;如果在这个时间间隔内再次触发该事件&#xff0c;则重新计时。只有当事件停止触发一段时间后&#xff0c;才会执行相应的操作。防抖常用于优化输入框的搜…

Elasticsearch,Kibana集成,x-pack鉴权配置

Elasticsearch,Kibana集成 Java8环境部署[CentOS7] cd /usr/local/src wget https://repo.huaweicloud.com/java/jdk/8u201-b09/jdk-8u201-linux-x64.tar.gztar -xzvf jdk-8u201-linux-x64.tar.gz -C /usr/local#配置环境变量 vim /etc/profile #文末添加 export JAVA_HOME/us…

强敌环伺:金融业信息安全威胁分析——钓鱼和恶意软件

门口的敌人&#xff1a;分析对金融服务的攻击 Akamai会定期针对不同行业发布互联网状态报告&#xff08;SOTI&#xff09;&#xff0c;介绍相关领域最新的安全趋势和见解。最新的第8卷第3期报告主要以金融服务业为主&#xff0c;分析了该行业所面临的威胁和Akamai的见解。我们发…

2023年11月Web3行业月度发展报告区块链篇 |陀螺研究院

11月&#xff0c;在宏观转好以及事件带动下&#xff0c;加密市场逐渐回暖。上月现货ETF带来的市场情绪持续增强&#xff0c;美方监管利好消息不断&#xff0c;零售投资者入场信号明显&#xff0c;持仓在10枚BTC以下的小规模投资者持仓持续上涨&#xff0c;推动BTC保持坚挺。利好…