你真的了解C语言吗 (深度剖析C语言第一期)_c语言深度 剖析第一

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注go)
img

正文

由此,我们可以提出两个问题:🥳

1.在没有加载到内存之前,程序在哪?

2.为什么所有的程序运行都要加载到内存当中?

通过学习我们可以知道,程序在没有加载到内存的时候放在硬盘,至于为什么程序运行的时候都必须放入硬盘是因为能提高运行效率,让程序更快运行。在此,我们需要了解一些硬件知识。**数据在传输的过程中大体要经历四个步骤,先由输入设备加载到内存,再通过CPU的处理后放到内存,最后刷新至输出设备。**我们先做了解,后续会再次学习冯诺依曼。

🥳🥳🥳变量的声明和定义

变量的本质就是在内存中开辟一块空间用内存保存数据,处于代码块内的变量都是临时变量,运行的时候在内存栈区开辟。为什么定义变量本质都在内存开辟?因为变量在运行的时候才会开辟,而在程序运行之前都会加载到内存。当开辟变量的时候程序已经被加载到内存了。

定义是开辟空间,声明可以理解为告知。定义就是开辟变量,只能定义一次,声明可以声明多次。

🥳🥳🥳关键字auto

通常用来修饰局部变量,该变量只在该代码块内有效,但是随着编译器的进步,auto已经可以被省略了。同样,我们通过程序来验证一下。

由此可见,当auto修饰局部变量的时候,程序是可以运行的,此时auto可以省略。由于auto关键字是年代很久远,我们现阶段基本不用,了解一下即可。

关键字register

什么是存储分级

首先我们需要了解具有存储能力的设备,寄存器,cache,内存,硬盘,软盘……距离CPU越近的存储单元,效率越高,单价成本越高。距离CPU越远的存储单元,效率越低,单价成本越低。对于任何一种硬件而言,它都充当这自己上游硬件的缓存,因此,CPU访问数据的时候以最小的成本达到最高的效率。

register修饰变量

register修饰变量就是尽量将该变量放入CPU的寄存器中,从而达到提高效率的目的。 哪些变量适合用register修饰呢?

1.局部变量,之所以不使用全局变量是一旦将全局变量放入寄存器中,它的作用域是整个工程,生命周期很长使得CPU寄存器被长时间占用。

2.不会被写入的变量。由之前所提及的冯诺依曼规则我们可以知道,数据写入将会被重新回写到内存中,然后重新加载。这样register就没有太大的意义。

3.高频被读取的变量。如果一个变量开辟空间时放在CPU的寄存器里面,那么我们读取变量的时候直接通过寄存器读取,直接通过CPU寄存器读取的效率是极高的。

那我们来思考一下,当我们用register修饰变量的时候,是在寄存器里面开辟的,能找到它的地址吗?想法归想法,写个程序测试一下。

实践证明,编译器报错,register修饰的变量在很多时候是在寄存器中开辟了一块空间而并非是在内存中开辟,而地址是内存上的地址,由此该变量是没有地址的,也是就不能通过取地址符号来找地址。

static关键字

多文件工程

首先我们可以思考一个问题,如果我们在一个工程里面创建两个源文件并将一个源文件里调用存放在另一个文件里的函数,会怎么样呢?是否会打印“别睡啦,快来和小生一起学习吧”呢?我们来测试一下:

程序运行可以发现,在同一个工程的两个不同源文件中,在一个文件里调用另一个文件中的函数是完全可以的,全局变量的作用域是整个工程,那我们如果在一个文件中使用另一个文件中的全局变量可以吗?我们来试一下。

**在此,我们需要用一个extern关键字来声明变量,注意我们这里是声明,并没有开辟空间。**因此我们在重拾C语言.c文件中只能用extern int num;声明该变量来自其他源文件。而不能用extern int num = 5;根本上说声明是没有开辟空间的但是存放变量是需要空间,因此这种写法是错误的。

但是如果项目比较大,文件一多,难道我们每个文件之前都需要声明外部变量或者函数吗?这样维护成本会变得极高,因此我们可以把所需外部函数、全局变量等放入一个新的头文件,可以减少维护成本。头文件基本上是被多个源文件包含,头文件可能会被重复包含,我们需要防止头文件被包含,我们可以在头文件之前加入#pragma once,那我们头文件一般包括什么呢?可以包含所有变量的声明,所有函数的声明,所有所需要的系统自带的头文件,#define ,typedef ,struct结构体等。

之前我们调用其他文件的函数时系统并未报错,但是为了让程序更加严谨,我们应该给来自外部的函数同样进行声明,那函数应该如何声明呢?函数的声明就是把函数的返回值函数的名称和函数的形参列表全部写上,不用写函数体。函数的定义本质也是在内存里开辟空间,变量保存的是数据,函数保存的就是代码,在上面这个问题,我们也可以用extern void show();来声明来自外部的函数。我们通过一个图来看一下:

通过上面的学习,我们知道,全局变量可以跨文件访问,函数也可以跨文件访问。但是在实际的应用当中,我们可能在某些时候不想让全局变量或者函数跨文件访问。这里我们就正式进入我们的主题——关键字:static。当我们用static修饰之前的全局变量num的时候我们改一下程序运行一下:

我们发现vs编译器报错,由此我们可以得出,static修饰全局变量的时候表示该变量只在本文件内被访问,不能被外部其他文件直接访问。那我们也可以猜想,当static修饰函数的时候,该函数是否也只是在该文件内可以被直接调用呢?我们可以试一下。

和原来的想法一样,直接报错哈哈,由此我们也可以得出一个结论,当static修饰函数的时候,该函数只能在本文件访问,不能在其他的文件内直接访问。但是可以通过嵌套的方式来访问。哈哈,是不是挺有趣的,我们来看一下:

因此我们以上的陈述是不能直接访问,但是可以通过函数嵌套的模式来间接访问。哈哈,确实挺有意思的。通过这个程序往深里面剖析,static是一个提供安全保护和项目维护的关键字。我们可以通过static把我们写的东西封装起来,用一个大函数包含, 这样就限制了他人对我们程序的修改,降低了暴露的接口,提高了程序的安全性,是不是很有意思呢?

我们再来看看下面这两个程序的对比:

**先看程序1:**🏃🏃🏃

//程序1
#include <stdio.h>
static void fun()
{
int i = 0;
i++;
printf("%d ",i);
}
int main()
{
for(int i = 0 ; i <= 10; i++)
{
fun();
}
return 0;
}

直接看结果:🚕🚕🚕

**再看程序2:**🏃🏃🏃

//程序2
#include <stdio.h>
static void fun()
{
static int i = 0;
i++;
printf("%d ",i);
}
int main()
{
for(int i = 0;i <= 10 ;i++)
{

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
尝辄止,不再深入研究,那么很难做到真正的技术提升。**

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-VECASGxx-1713458943643)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值