初识C语言----完结篇(一)

简介: 初识C语言----完结篇(一)

🦖作者:学写代码的恐龙

🦖博客主页:学写代码的恐龙博客主页

🦖专栏:【初级c语言】

🦖语录:❀未来的你,一定会感谢现在努力奋斗的自己❀

7dfdca43effc4fc699e34a25c6fe3531.png

十一:关键字

11.1:register–寄存器

在计算机中我们可以把数据存放在网盘、硬盘、内存、高速缓存、寄存器里。

382f5ee46fd94f3799d1ff997e968f51.png

他们之间结构成了上图的金字塔结构。越往金字塔的顶端,存储空间越小,访问速度也越来越快,这也导致他们的价格越来越贵。

在计算机中有一个叫CPU的东西,他也被叫做中央处理器,是用来处理数据的,所有的运算都是通过CPU来进行的。最早的时候CPU的运算速度不算快,内存的访问速度也还可以,CPU就会从内存里面拿取数据来进行运算。但随着硬件的发展,CPU的运行速度越来越快,而内存中数据的读取速度没怎么提升,这时尽管CPU的处理速度特别快,但读取数据的速度却显得很慢,这时就诞生了寄存器和高速缓存区,此时CPU直接从寄存器中读取数据,在CPU处理数据的同时,寄存器也会从高速缓存区读取即将要用到的数据,高速缓存区则从内存中读取即将要要用到的数据,这样他们同时工作,大大提升了计算机的工作效率。其中寄存器的单位是字节,我们一般都说有几个寄存器,它集成在CPU上。高速缓存又分为一级缓存,二级缓存,三级缓存等等。

register的作用就是建议编译器把创建的变量值放到寄存器里面,未来对变量的访问就是访问寄存器,从寄存器里面取值,当大量使用到此变量时,从寄存器里面拿效率就会高一些。但register的仅仅起到建议作用,最终是否把变量的值放到寄存器里完全取决于编译器。但现在的编译器都比较聪明,即使不加register他也会对程序进行分析,把一些值放到寄存器里面。

int  main()
{
   register  a  =  10;//仅仅是建议
   return 0;
}

11.2:typedef

type翻译为:类型,def是英文define的缩写翻译为:定义。顾名思义:typedef叫做类型定义。这里应该理解为类型重命名。

当我们想定义一个无符号的整型变量是需要写unsigned int ,这显得非常的长,不方便,此时我们就可以通过typedef给unsigned int重新取一个名字来代替它。

typedef unsigned int uint;
int main()
{
  unsigned int a;
  uint b;
  return 0;
}

此时我们把unsigned int重新命名为uint,这里的a和b具有相同的数据类型。

11.3:static–静态的

主要有三种用法:

    修饰局部变量

    修饰全局变量

    修饰函数

11.3.1:static修饰局部变量

void text()
{
  int a = 0;
  a++;
  printf("%d\n", a);
}
int main()
{
  int i = 0;
  while (i < 10)
  {
    text();
    i++;
  }
  return 0;
}

这里我么们写了一个循环,当i<10的时候调用text函数,可见一共调用了10次。每调用一次text函数就会打印一个值。

eccd8c45eba8434db27a67c75614c4e7.png


从结果看出这里一共打印了10个1,那为什么呢?

void text()
{
  int a = 0;
  a++;
  printf("%d\n", a);
}

text是一个函数,这里的大括号是一个局部范围,每次进入这个函数都会创建一个局部变量a,a的生命周期是进入这个局部范围时创建,出这个局部范围时销毁当 i=0 循环第一次调用text函数时,进入函数创建a,然后让a++,打印出a的值为1,出这个函数时a就销毁,然后让i++,i变成1,继续执行循环,调用text函数,由于上一次调用结束时,a已经被销毁,所以此时会重新创建一个a=0,然后a++,a变成1,打印出a的值,出text函数,销毁掉a。就这样重复循环十次,所以就会打印出10个1。

接下来我们在局部变量a的前面加上static进行修饰。

```c
void text()
{
  static int a = 0;
  a++;
  printf("%d\n", a);
}
int main()
{
  int i = 0;
  while (i < 10)
  {
    text();
    i++;
  }
  return 0;
}

此时打印出来的结果是1-10.

a910d2a36a844ac5a1d3e39b83821424.png

大家可以这样来想原因,当我们第一次调用text函数的时候,起初定义a=0,a++后a变成1,打印出第一个数字1,当第二次调用text函数的时候,如果上一次的a销毁了,那此时重新创建一个a=0,然后a++,打印出来a的值还是1,但实际却打印的是2,那说明分析的有问题,再看第二次调用text函数的时候执行a++了,结果是2,那说明a原来的值一定是1,那这个1是从哪里来的呢?如果第二次循环重新创建a了,那a就是0,所以这里a=1,说明第一次循环调用text函数结束的时候并没有把a销毁,而是继续保存a=1。因此,这里的a从第一次循环调用text函数时被创建,在每次函数调用结束时没有被销毁,这样a就会产生一个累加效果。

这里本质的原因是,被static修饰后的局部变量会被存储在内存中的静态区。这里就需要扩展一点内存方面的知识。内存中被分了3块区域,分别是栈区、堆区和静态区。栈区中一般是用来存储局部变量和函数的参数这类临时变量。堆区里面是用来动态内存分配的,malloc、calloc、realloc、这些函数都是在堆区中申请的空间。静态区存放的是静态变量和全局变量。栈区的特点是,进入作用域创建,出了作用域就释放。里面存放的变量都是临时的。静态区里面的数据创建好后直到程序结束才销毁。

注意:被static修饰是不会影响作用域的。但是生命周期发生了变化,变长了。

a16145bf116048fc8154fb1d5ec47647.png

总结一下,当我们希望保留变量上一次的值,这时我们就可以用static来修饰这个变量。

11.3.2:static修饰的全局变量

在之前介绍全局变量作用域的时候给大家举了个例子,就是我们可以用extern来声明一个外部变量,这样我们就可以在A这个源文件中用同一个工程下B这个源文件中定义的全局变量了。

54bac43ccaee4a2e891ea5bae885768e.png

如上图,我们在add.c中定义了一个全局变量a=1,此时我们要是想在text.c中用a的值,这需要在text.c中用extern声明一下这个外部变量a就可以。

如果我们在add.c中的“int a = 1;”前面加上一个static会发生什么结果呢?

ae47c854866a43ea80015a21fa5c5c13.png

可以看出,此时程序报错了“无法解析的外部符号_a”,也就是程序不认识这个符号。为什么会出现这个原因呢?

原因是:全局变量本身是具有外部链接属性的,也就是在同一个工程下的a源文件中定义的全局变量在b源文件中可以通过链接使用。但是如果全局变量被ststic修饰,这个外部连接属性就变成了内部连接属性,这个全局变量只能在自己所在的源文件内使用。static的修饰会把全局变量的外部链接属性变成内部连接属性。最终使得全局变量的作用域变小。(一个工程最终只能编出一个可执行程序,一个text.c可以通过 编译 + 链接 生成一个可执行程序----- .exe。链接这个阶段回去其他的文件找我们想要的符号。(注意:局部变量没有链接属性)

11.3.3:static修饰函数

我们在B源文件中定义了一个函数,在A中直接调用这个函数程序会发出警告。如下图,在add.c源文件中定义了一个函数add在text.c中调用这个函数,程序报警说:add未定义。此时我们可以像声明一个外部变量那样,用extern来声明一个外部函数。(每一个编译器都是对.c文件进行单独编译的)

9f7a9337cb7640dc994c29652d6b9204.png

修改后的代码为:

90d9d971e819407fa880ad116fc47dbd.png

此时编译器没有报警告。

当我们在add函数的前面加上一个ststic后会发生什么呢?

320515bbab904c52b317ce4c43c755c1.png

是不是很熟悉,这结果和上面static修饰全局变量的结果是一样的。

函数本身是具有外部链接属性的,被static修饰后,外部链接属性变成了内部链接属性,使得这个函数只能在自己的这个源文件里使用,其他源文件无法使用。


目录
相关文章
|
10月前
|
存储 编译器 C语言
初识C语言----完结篇(二)
初识C语言----完结篇(二)
49 0
|
11月前
|
编译器 C语言
【C语言初阶】带你轻松掌握指针基础知识完结篇——野指针,指针运算,指针和数组,二级指针
【C语言初阶】带你轻松掌握指针基础知识完结篇——野指针,指针运算,指针和数组,二级指针
51 0
|
存储 编译器 C语言
初识C语言系列-5-完结篇-#define,指针,结构体(二)
初识C语言系列-5-完结篇-#define,指针,结构体
初识C语言系列-5-完结篇-#define,指针,结构体(二)
|
编译器 C语言
初识C语言系列-5-完结篇-#define,指针,结构体(一)
初识C语言系列-5-完结篇-#define,指针,结构体
初识C语言系列-5-完结篇-#define,指针,结构体(一)
|
C语言
理解C语言——从小菜到大神的晋级之路(15)——完结篇:C编程风格
本期视频链接:点击这里 有人说过:“程序源代码其实是跟人阅读的,只是恰好机器可以编译而已”。
1226 0
|
1天前
|
C语言
C语言---函数---请输入乘法口诀表的行,来打印几几乘法表
C语言---函数---请输入乘法口诀表的行,来打印几几乘法表
|
1天前
|
C语言
C语言--函数递归与迭代
C语言--函数递归与迭代
|
1天前
|
C语言 C++
C语言----C语言内存函数
C语言----C语言内存函数
|
1天前
|
C语言
C语言----字符函数和字符串函数(4)
C语言----字符函数和字符串函数
|
1天前
|
算法 C语言
C语言----字符函数和字符串函数(3)
C语言----字符函数和字符串函数
10 0