《c语言修炼内功之第二种境界(看代码就是内存)之关键字系列二》
前言:这个系列内容我会深入讲解一下c语言中的重点内容,会把每一个知识点讲的更加底层些,会增强大家的c语言内功,从内存维度看代码你会有不同的理解。
这一节我主要讲一下多文件的知识,static修饰全局变量和局部变量,函数的作用及一些结论,函数命名的规则以及sizeof的用法。(在这里我们所用测试的编译器为vs2019)
多文件
多文件的介绍
什么是多文件呢?我们在进入编译器(我们这里说vs)中都会有解决资源管理器。具体看图
我们这里有头文件,资源文件还有源文件,这里资源文件暂且不说。
我们在创建某一个工程(我们在写c语言代码时候)一定在添加源文件时候后面一定是.c文件(我们的源文件是用来定义的,也就是代码的具体实现)。
我们在创建头文件时候后面一定是.h文件(头文件用来声明的)。
在我们进行写代码的时候,我们会写函数和变量,那我们可不可以在外部的源文件实现函数,而在我们本文件进行调用呢?(我们的本文件为main.c,测试文件为test.c,头文件为test。h)我们接下来观察一下
我们声明变量以后的情况
现象总结:
- 我们在既没有给变量又没给函数声明的时候,我们结果都会报错
- 我们给变量声明后,函数和变量的值都可以打印出来
结论:
我们可以通过多文件的形式在其他外部文件进行定义,在自己的主源文件进行调用,但是我们必须给变量和函数进行声明。虽然有时候(比如在有些编译器)没有给函数声明的时候不会出现报错的情况,但是为了确保警告,我们在声明外部变量和函数的时候我们要进行外部声明加上外部声明符号extern.
我们再来思考一个问题,我们可以在声明的时候进行定义变量么?
我们再这样写代码的时候编译器就会自动给你报错,解释不允许对外部变量的局部声明使用初始化设定项。
那为什么不可以在进行外部声明的时候进行定义变量呢?
我们来回忆一下什么是变量,变量就是在内存的某个位置开辟的空间,既然需要开辟空间,我们在进行声明的时候只是声明没有进行定义(也就是初始化和赋值),所以我们没有在内存上开辟空间。
总结:
我们在进行声明变量的时候,不能设置初始化和赋值也就是内存并没有给开辟空间,所以我们在变量声明的时候必须加上extern(变量和函数都要加上extern)。
头文件
我们为啥会有头文件呢?
首先,我们未来肯定在某一个公司上班(这里祝咱们都进大厂),我们在未来公司写代码,我们又两种方式,第一种方式是把所有的代码都写在main函数里,第二种方式就是分多个文件(也就是我们常说的模块化)来写代码。我想每个人都知道是分多个文件写代码不仅清晰而且便于后面别人看你的代码(可读性高)和修改代码更好一些。而相反你要把代码都写在main函数里,你要修改一处代码,可能都要改多处(甚至都有可能找不到),我们单纯的使用源文件在进行组织项目结构时,项目越大越复杂时,维护成本就越高,而当我们利用头文件,在组织项目时,就会减少大型项目的维护成本的问题。
我们头文件都会包含哪些内容呢?
1.进行头文件的包含(c的库文件)
2.所有变量的声明
3.所有函数的声明
4.#define(宏),类型,typedef,struct,等等。
我们可以创建一个头文件,把这些内容都放在头文件里,而在源文件里要包含这个你创建的头文件 我们一般将c语言库的头文件用<>来包含,我们自己定义的头文件用" "(双引号)包含。
头文件重复包含问题
头文件一定会被多个源文件包含,这个时候就会出现重复包含的问题
这里我们的解决方案就是加上#pragma once
两个结论
- 全局变量可以跨文件访问
- 全局函数可以跨文件访问
这里又有个问题为啥可以跨文件访问呢?
在一定规模的项目一定是多文件的,在多文件之间后语一定要进行数据交互(比如我们的 main.c ,test.c ,test.h的内容要进行交互),如果我们没有跨文件,进行交互的成本就会变得很高。
关键字——static
static修饰全局变量
所以static修饰局部变量时只能在本文件内部访问,不能被外部其他文件直接访问。
既然不可以直接访问那可不可以间接访问呢?
虽然使用static不能访问外部文件的变量内容,但我们可以使用函数嵌套调用的方式来进行间接访问。
总结:
static修饰局部变量时只能在本文件内部访问,不能被外部其他文件直接访问。由于调用变量具有临时性,函数调用的时候开辟空间并初始化,函数结束的时候,变量被释放。而这里static改变了全局变量的作用域,生命周期没有改变。
static修饰局部变量
没有static修饰的时候
void fun1() { int i = 0; i++;printf("no static: i=%d\n", i); }int main() {for (int i = 0; i < 10; i++){fun1();}return 0; }
我们来观察一下没有static修饰的时候输出的全是1,那这是为什么呢?大家应该还记得上节课我们讲的变量只在代码块内部有效,出了代码块,变量会被销毁,所以每调用一次就会加一,然后出了代码块又变成0.
有static修饰局部变量的时候
void fun2() { static int i = 0;i++; printf("has static: i=%d\n", i); } int main() {for (int i = 0; i < 10; i++){fun2();}return 0; }
我们再来观察一下没有static的情况,随着循环依次增加,那这又是为啥呢?这肯定就是static的作用了,与上次没有static的对比可以知道我们这里加1之后没有被销毁,而是直接保存上次计算的结果,依次累加。
总结:static修饰局部变量时变量只会初始化一次,在执行函数时变量没有被释放。这里static修饰局部变量的时候生命周期改变,而作用域没有被改变。
这里我们说static修饰局部变量的时候,将临时变量变成了全局的生命周期,但作用域没有被改变。
函数地址空间图
从这张图可以说明我们的局部变量时存放在栈区的,而当我们用static修饰局部变量的时候,我们将局部变量的位置由栈区变成了全局数据区,而全局数据区在整个“进程”运行生命周期都是有效的,所以static修饰局部变量只初始化一次当调用函数时不被释放具有了全局的生命周期,但并不是说它就是全局变量。全局变量和全局数据区是两回事。在全局数据区只能说明它的生命周期是全局的。
static修饰函数
static修饰函数与全局变量一样。
static修饰局部变量时只能在本文件内部访问,不能被外部其他文件直接访问。
深入理解数据类型
数据类型
我们这里讲一下c语言的内置数据类型
为啥要有数据类型呢?
我们都知道这些数据类型,但为啥要存在它们呢?我们有内存,一整块内存拿去用不可以么?比如我们来统计班级内的各学科成绩,最高也就不超过1000分,就这么小的数据我们用一个字节就可以存下去,如果把整个内存拿去用的话是不就会大量的浪费内存了。
好我们总结一下:
c语言中为啥要出现数据类型呢? 本质上讲对内存进行合理的划分,合理地进行划分,按需所求,那类型为啥要分为那么多种呢?分这么多的类型是因为应用场景不同,为了解决应用场景对应得计算方式不同,需求空间的大小也是不同的。所以本质上就是用最小的成本解决各种多样化的场景问题。
变量命名规则
按照c语言深度解剖这本书规则我们选择最优的规则来进行书写,但这些规则对于我们新手也不用时刻记在心里,因为每个公司都有这自己的命名规范到时候在按照公司的命名规范学习也不迟,我们这里推荐一些,便于后期复习用
1 . 命名应当直观且可以拼读,可望文知意,便于记忆和阅读。标识符最好采用英文单词或其组合,不允许使用拼音。程序中的英文单词一般不要太复杂,用词应当准确。2 . 命名的长度应当符合“min-length && max-information”原则。C 是一种简洁的语言 , 命名也应该是简洁的。例如变量名 MaxVal 就比MaxValueUntilOverflow 好用。标识符的长度一般不要过长,较长的单词可通过去掉 “ 元音 ” 形成缩写。另外,英文词尽量不缩写,特别是非常用专业名词,如果有缩写,在同一系统中对同一单词必须使用相同的表示法,并且注明其意思。3 . 当标识符由多个词组成时,每个词的第一个字母大写,其余全部小写。比如:int CurrentVal ;这样的名字看起来比较清晰,远比一长串字符好得多。尽量避免名字中出现数字编号,如 Value1,Value2 等,除非逻辑上的确需要编号。比如驱动开发时为管脚命名,非编号名字反而不好。4 . 对在多个文件之间共同使用的全局变量或函数要加范围限定符 ( 建议使用模块名( 缩写 ) 作为范围限定符 ) 。 (GUI_ , etc)程序中不得出现仅靠大小写区分的相似的标识符。例如: int x, X; 变量 x 与 X 容易混淆void foo(int x); 函数 foo 与 FOO 容易混淆void FOO(float x);这里还有一个要特别注意的就是 1 (数字 1 )和 l (小写字母 l )之间, 0 (数字 0 )和 o(小写字母 o )之间的区别。这两对真是很难区分的,我曾经的一个同事就被这个问题折腾了一次5 . 一个函数名禁止被用于其它之处6 . 所有宏定义、枚举常数、只读变量全用大写字母命名,用下划线分割单词。7 . 考虑到习惯性问题,局部变量中可采用通用的命名方式,仅限于 n 、 i 、 j 等作为循环变量使用。一般来说习惯上用 n,m,i,j,k 等表示 int 类型的变量; c , ch 等表示字符类型变量; a 等表示数组; p 等表示指针。当然这仅仅是一般习惯,除了 i,j,k 等可以用来表示循环变量外,别的字符变量名尽量不要使用。8 . 定义变量的同时千万千万别忘了初始化。定义变量时编译器并不一定清空了这块内存,它的值可能是无效的数据
关键字——sizeof
sizeof:是求变量所占空间大小单位是字节
sizeof注意事项
虽然sizeof()用括号但sizeof不是函数,sizeof是运算符
int main()
{int a;int* pa = NULL;printf("%d\n", sizeof(int));printf("%d\n", sizeof(a));printf("%d", sizeof int);//其中这个是错误的sizeof和int都是关键字,关键字不能计算关键字的大小printf("%d\n", sizeof a );return 0;
}
好啦,今天就讲到这里再见!!bye bye
《c语言修炼内功之第二种境界(看代码就是内存)之关键字系列二》相关推荐
- ComeFuture英伽学院——2020年 全国大学生英语竞赛【C类初赛真题解析】(持续更新)
视频:ComeFuture英伽学院--2019年 全国大学生英语竞赛[C类初赛真题解析]大小作文--详细解析 课件:[课件]2019年大学生英语竞赛C类初赛.pdf 视频:2020年全国大学生英语竞赛 ...
- ComeFuture英伽学院——2019年 全国大学生英语竞赛【C类初赛真题解析】大小作文——详细解析
视频:ComeFuture英伽学院--2019年 全国大学生英语竞赛[C类初赛真题解析]大小作文--详细解析 课件:[课件]2019年大学生英语竞赛C类初赛.pdf 视频:2020年全国大学生英语竞赛 ...
- 信息学奥赛真题解析(玩具谜题)
玩具谜题(2016年信息学奥赛提高组真题) 题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业.有一天, 这些玩具小人把小南的眼镜藏了起来.小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的 ...
- 信息学奥赛之初赛 第1轮 讲解(01-08课)
信息学奥赛之初赛讲解 01 计算机概述 系统基本结构 信息学奥赛之初赛讲解 01 计算机概述 系统基本结构_哔哩哔哩_bilibili 信息学奥赛之初赛讲解 02 软件系统 计算机语言 进制转换 信息 ...
- 信息学奥赛一本通习题答案(五)
最近在给小学生做C++的入门培训,用的教程是信息学奥赛一本通,刷题网址 http://ybt.ssoier.cn:8088/index.php 现将部分习题的答案放在博客上,希望能给其他有需要的人带来 ...
- 信息学奥赛一本通习题答案(三)
最近在给小学生做C++的入门培训,用的教程是信息学奥赛一本通,刷题网址 http://ybt.ssoier.cn:8088/index.php 现将部分习题的答案放在博客上,希望能给其他有需要的人带来 ...
- 信息学奥赛一本通 提高篇 第六部分 数学基础 相关的真题
第1章 快速幂 1875:[13NOIP提高组]转圈游戏 信息学奥赛一本通(C++版)在线评测系统 第2 章 素数 第 3 章 约数 第 4 章 同余问题 第 5 章 矩阵乘法 第 6 章 ...
- 信息学奥赛一本通题目代码(非题库)
为了完善自己学c++,很多人都去读相关文献,就比如<信息学奥赛一本通>,可又对题目无从下手,从今天开始,我将把书上的题目一 一的解析下来,可以做参考,如果有错,可以告诉我,将在下次解析里重 ...
- 信息学奥赛一本通(C++版) 刷题 记录
总目录详见:https://blog.csdn.net/mrcrack/article/details/86501716 信息学奥赛一本通(C++版) 刷题 记录 http://ybt.ssoier. ...
- 最近公共祖先三种算法详解 + 模板题 建议新手收藏 例题: 信息学奥赛一本通 祖孙询问 距离
首先什么是最近公共祖先?? 如图:红色节点的祖先为红色的1, 2, 3. 绿色节点的祖先为绿色的1, 2, 3, 4. 他们的最近公共祖先即他们最先相交的地方,如在上图中黄色的点就是他们的最近公共祖先 ...
最新文章
- 《评人工智能如何走向新阶段》后记(再续9)
- golang中的strings.Split
- 第一章 Oracle 11g 数据库——在Windows 上安装部署
- html语言把字变大,css怎么让字体变大?
- 如何用CS07进行BOM工厂分配
- ubuntu Mysql乱码解决
- 你可能不需要 jQuery!使用原生 JavaScript 进行开发
- Spring Security Oauth2 (五) 密码码模式 整合jwt
- 我的Linux生涯之Mysql:Day01[Mysql基本使用]例
- php判断get和post请求,PHP:6种GET和POST请求发送方法
- 拿来吧你! | 从入门到精通docker ,都在这里了
- 交互式甘特图控件VARCHART XGantt教程:如何打印和导出图表(.NET版)
- PSF 点扩展函数 (from WikiPedia)
- 机器学习 | 交叉验证
- 国庆节发个国庆直播的小软件
- 手机cpu什么型号支持鸿蒙系统,华为鸿蒙2.0系统支持的手机型号(图文)
- weblogic常见问题QA
- getElementById 用法的一个技巧
- 能否比较一下华为路由器和TPLINK路由器的优缺点?
- 系统学习NLP(七)--词语相似度