1.10 C语言之外部变量与作用域

1.10 C语言之外部变量与作用域

  • 一、外部变量概述
  • 二、练习

一、外部变量概述

  • 我们说,函数(不管是main函数还是其他函数)内部定义的变量,其作用范围都只在函数内部,我们把这些变量叫做自动变量或者局部变量。
  • 除了局部变量外,还可以定义位于所有函数外部的变量,也就是说,在所有函数中都可以通过变量名访问这种类型的变量。由于外部变量可以在全局范围内访问,因此,函数间可以通过外部变量交换数据,而不必使用参数表。再者,外部变量在程序执行期间一直存在,而不是像局部变量一样在函数调用完成之后消失,即使在对外部变量赋值的函数返回后,这些变量仍将保持原来的值不变。
  • 外部变量必须定义在所有函数之外,并且只能定义一次,定义后编译程序将为它分配存储单元。
  • 在每个需要访问外部变量的函数中,必须声明相应的外部变量,并说明它的类型。声明时可以通过extern语句显式声明,也可以通过上下文隐式声明。

我们先改写之前的打印最长文本行的程序,把line、longest、max声明为外部变量,再做详细描述

#include <stdio.h>
#define MAXLINE 1000 //最大行长度限制
char longest[MAXLINE];
char line[MAXLINE];
int max;
int getline(void); // 读取一行
void copy(void); // 数组拷贝

// 打印所有输入行中长度最长的行
main()
{
	int len; // 当前行长度
	extern int max; // 最大长度
	extern char longest[MAXLINE]; // 保存最长的行

	max = 0;
	while ((len = getline()) > 0) {
		if (len > max) {
			max = len;
			copy();
		}
	}

	if (max > 0)
		printf("%s", longest);
	return 0;
}

// 读取一行数据到数组s中,并返回该行的长度
int getline(void) {
	int c, i;
	extern char line[MAXLINE]; // 保存当前输入行
	for (i = 0; i < MAXLINE - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
		line[i] = c;
	if (c == '\n') {
		line[i] = c;
		++i;
	}
	line[i] = '\0';
	return i;
}

// 返回值类型为void,显式说明该函数不返回任何值
void copy(void) {
	int i;
	extern char line[MAXLINE], longest[MAXLINE];
	i = 0;
	while ((longest[i] = line[i]) != '\0')
		++i;
}
  • 上面的程序,在最前面的几行中定义了外部变量,line、longest、max,并声明了变量的类型,这样编译器会为他们分配存储单元。从语法角度看,外部变量的定义和局部变量的定义是相同的,但由于它们位于各函数的外部,因此这些变量是外部变量。

  • 如果要在函数中使用外部变量,一种显式声明的方式是external 外部变量名

  • 某些情况下可以省略extern声明:在源文件中,如果外部变量的定义出现在使用它的函数之前,那么在那个函数中就没有必要使用extern声明。因此main,getline,copy函数中的几个extern声明是多余的(这里存疑,经验证:数组类型的变量去掉extern会出错)。在通常的做法中,所有的外部变量都放在源文件的开始处,这样就可以省略extern的声明。

  • 如果程序包含在多个源文件中,而某个变量在file1文件中定义,在file2和file3文件中使用,那么在file2和file3中就需要使用extern声明来建立该变量与其定义之间的联系。人们通常把变量和函数的声明放在一个单独的文件中(习惯上称之为头文件),并在每个源文件中使用#include语句把所要用到的头文件包含进来。后缀名为.h约定为头文件名的扩展名。比如标准库中的函数就是在类似于<stdio.h>的头文件中声明的。
    如果使用vs调试,#include找不到自定义的头文件,可以点击项目->属性->VC++目录->包含目录,把自己的头文件所在路径加进去试试
    在这里插入图片描述

  • 在ANSI C中,如果函数的参数为空,则必须使用void显式声明,以区分老版本C语言

二、练习

  1. 编写程序detab,将输入中的制表符替换成适当数目的空格,使空格充满到下一个制表符终止位的地方。假设制表符终止位的位置是固定的,比如每隔n列就会出现一个制表符终止位。n应该作为变量还是符号常量呢?
  2. 编写程序entab,将空格串替换为最少数量的制表符和空格,但要保持单词之间的间隔不变。假设制表符终止位的位置与练习1的情况相同,当使用一个制表符或者一个空格都可以到达下一个制表符终止位时,选用哪一种替换字符比较好?
  3. 编写一个程序,把较长的输入行折成短一些的两行或多行,折行的位置在输入行的第n列之前的最后一个非空格之后。要保证程序能够智能的处理输入行很长以及在指定的列前没有空格或制表符时的情况。
  4. 编写一个删除c语言程序中所有的注释语句。要正确处理带引号的字符串与字符常量,在c语言中,注释不允许嵌套。
  5. 编写一个程序,查找c 语言程序中的基本语法错误,如圆括号、方括号、花括号不配对等。要正确处理引号(包括单引号和双引号)、转义字符序列与注释。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从文字到使用,一文读懂Kafka服务使用

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

【UE5】瞬移+马赛克过渡效果

效果 步骤 1. 新建一个工程&#xff0c;创建一个Basic关卡 2. 添加第三人称游戏资源到内容浏览器 3. 新建一个材质&#xff0c;这里命名为“M_Pixel” 打开“M_Pixel”&#xff0c;设置材质域为“后期处理” 在材质图表中添加如下节点 此时效果如下&#xff0c;已经有马赛克的…

Textual Inversion

参考博客1:https://www.bilibili.com/read/cv25430752/

数据结构和算法-栈

数据结构和算法-栈 1. 栈的介绍 栈的介绍&#xff1a; 栈的英文为(stack)栈是一个先入后出的有序列表栈是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端&#xff0c;为变化的一端&#xff0c;称为栈顶&#xff0c;另一端为固…

2024 年前端技术发展大趋势一览

随着技术的不断演进&#xff0c;前端开发领域也在不断变化和发展。AI、Vue、Web3等都是当前前端开发的新趋势&#xff0c;它们为开发者提供了更多的机会和挑战。今天这篇文章&#xff0c;咱们就来聊一聊&#xff0c;最新前端技术趋势。 1.AI 年初的 ChatGPT 火爆全网&#xff0…

MongoDB的连接数据库,创建、删除数据库,创建、删除集合命令

本文主要介绍MongoDB的连接数据库&#xff0c;创建、删除数据库&#xff0c;创建、删除集合命令。 目录 MongoDB连接数据库连接到本地 MongoDB 实例连接到远程 MongoDB 实例 MongoDB创建和删除数据库MongoDB创建和删除集合创建集合删除集合 MongoDB连接数据库 连接 MongoDB 数…

SuperMap iObject.NET三维场景拖拽框选实现详解及完整源代码(一)——环境准备及项目配置

作者&#xff1a;超图研究院技术支持中心-于丁1 SuperMap iObject.NET三维场景拖拽框选实现详解及完整源代码&#xff08;一&#xff09;——环境准备及项目配置   三维场景框选是一种在三维空间中进行选择和操作的功能&#xff0c;它可以让使用者通过鼠标拖动来创建一个矩形…

kafka C++实现消费者

文章目录 1 Kafka 消费者的逻辑2 Kafka 的C API2.1 RdKafka::Conf2.2 RdKafka::Event2.3 RdKafka::EventCb2.4 RdKafka::TopicPartition2.5 RdKafka::RebalanceCb2.6 RdKafka::Message2.7 RdKafka::KafkaConsumer&#xff08;核心&#xff09; 3 Kafka 消费者客户端开发3.1 必要…

springboot监听器模式源码精讲

1.前言 很多时候我们看源码的时候看不下去&#xff0c;其中一个原因是系统往往使用了许多设计模式&#xff0c;如果你不清楚这些设计模式&#xff0c;这无疑增加了你阅读源码的难度。 springboot中就大量使用了设计模式&#xff0c;本文主要介绍其中的一种监听器模式&#xf…

谈谈 .NET8 平台中对 LiteDB 的 CRUD 操作

哪个啥&#xff01;纯 C# 编写的 LiteDB 你还不会操作&#xff1f; LiteDB 简介LiteDB 安装1、同步版 LiteDB2、异步版 LiteDB.Async LiteDB StudioLiteDB CRUD 操作举例1、.net cli 命令创建项目2、项目添加相关 nuget 包3、改造项目结构4、改造项目代码 LiteDB vs SQLite 对比…

泳道图绘制全攻略,一图胜千言,快速上手

泳道图是一种流程图的形式&#xff0c;通过在不同的泳道中展示不同的参与者&#xff0c;帮助我们更好地理解和分析流程。它是一种非常有用的工具&#xff0c;可以帮助我们在团队协作、流程管理和问题解决等方面取得更好的效果。 1. 泳道图的定义 泳道图是一种以泳道为基础的流程…

postgresql从入门到精通 - 第37讲:postgres物理备份和恢复概述

PostgreSQL从小白到专家&#xff0c;是从入门逐渐能力提升的一个系列教程&#xff0c;内容包括对PG基础的认知、包括安装使用、包括角色权限、包括维护管理、、等内容&#xff0c;希望对热爱PG、学习PG的同学们有帮助&#xff0c;欢迎持续关注CUUG PG技术大讲堂。 第37讲&#…

提高工厂能源效率的关键:工厂能耗监测平台

工业做为能源消耗的重要场所&#xff0c;所以节能减排对工业来讲是一个亟需解决的问题。除了对设备进行更新换代外&#xff0c;还需要能源管理消耗监测平台&#xff0c;帮助企业实现节能减排的目标。 工厂能源消费量非常庞大&#xff0c;能源比较难以监测与控制。传统能源的管…

路径规划之RRT算法

系列文章目录 路径规划之Dijkstra算法 路径规划之Best-First Search算法 路径规划之A *算法 路径规划之D *算法 路径规划之PRM算法 路径规划之RRT算法 路径规划之RRT算法 系列文章目录前言一、RRT算法1.起源2.流程3. 优缺点3.1 优点3.2 缺点 4. 实际效果 前言 PRM方法相比于传…

正则表达式(3):入门

正则表达式&#xff08;3&#xff09;&#xff1a;入门 小结 本博文转载自 从这篇文章开始&#xff0c;我们将介绍怎样在Linux中使用”正则表达式”&#xff0c;如果你想要学习怎样在Linux中使用正则表达式&#xff0c;这些文章就是你所需要的。 在认识”正则表达式”之前&am…

图像处理之把模糊的图片变清晰

1.图片如果是有雾化效果的对图像产生影响的,要先进行图形增强,Retinex是基于深度神经网络了,我在之前图形处理的文章一路从神经网络(概率统计)—>积卷神经网络(对区域进行概率统计,对图片进行切割多个识别对象)–>深度积卷神经网络(RetinexNet也是模拟人脑的处理过程,增加…

挑选分支中某一个提交进行合并

复制提交的哈希(sha-1)值 挑选提交 git cherry-pick 复制过来的哈希值 若有冲突&#xff0c;解决冲突&#xff0c;没有冲突&#xff0c;即合并完成

C语言普里姆(Prim)算法实现计算国家建设高铁运输网最低造价的建设方案

背景&#xff1a; 描述&#xff1a;为促进全球更好互联互通&#xff0c;亚投行拟在一带一路沿线国家建设高铁运输网&#xff0c;请查阅相关资料 画出沿线国家首都或某些代表性城市的连通图&#xff0c;为其设计长度最短或造价最低的高铁建设方案。 要求&#xff1a;抽象出的图…

Linux-进程之间的通信

目录 ​编辑 一.什么是进程之间的通信 二.进程之间的通信所访问的数据 三.进程之间的通信是如何做到的 四.基于内存文件级别的通信方式——管道 1.什么是管道 2.管道的建立过程——匿名管道 a.什么是匿名管道 b.匿名管道特点&#xff1a; c.使用匿名管道的…

Peter算法小课堂—贪心算法

课前思考&#xff1a;贪心是什么&#xff1f;贪心如何“贪”&#xff1f; 课前小视频&#xff1a;什么是贪心算法 - 知乎 (zhihu.com) 贪心 贪心是一种寻找最优解问题的常用方法。 贪心一般将求解过程分拆成若干个步骤&#xff0c;自顶向下&#xff0c;解决问题 太戈编程第…