【C语言航路】第一站:初识C语言(四)

简介: 【C语言航路】第一站:初识C语言(四)

十一、关键词

1.常见关键词总结及分类

c语言中提供了丰富的关键词,这些关键词都是事先设定好的,用户是不能自己创造的

这是我们常见的关键词,那么我们对其进行分类一下。

(1)类型

auto 这个关键词解释一下,这个是自动的意思,我们们在使用局部变量的时候,有这样一个特点,局部变量都是自动创建自动销毁的,所以局部变量也叫做自动变量,只不过后来由于局部变量都是auto 类型的,后来没有人这样写了

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
  {
    auto int a;
  }
  return 0;
}

char

int

short

long

float

double

signed有符号的

unsigned无符号

static

void

const

enum

union

struct

typedef

(2)循环

break 打破循环时候使用(也可在switch选择语句中使用)

continue 终结本次循环,执行下一轮循环

do

while

for

(3)选择分支

if

else

switch

case

break

default

goto

(4)其他

extern 声明外部符号

register 寄存器

return 函数返回

sizeof 计算所占内存大小

volatile 后面详细讲

2.关键词register

register意思是寄存器

在提到寄存器的时候,我们先思考一个问题,计算机中,数据都可以存储在哪里?

如图所示,是我们计算机中的存储器,从上到下,依次是寄存器,高速缓存,内存,硬盘,网盘(网盘一般不在电脑上,就跟我们的百度网盘一样)

为什么是一个金字塔的分布呢?我们会发现这些存储器的大小有很大的区别,网盘一般几个T,硬盘一般500G,内存一般8G/16G,高速缓存一般是xxM,寄存器一般是几个字节。读到这里,我们貌似懂了,原来是按照内存大小才把他看作金字塔的分布了

那么为什么存储大小这么这么多区别呢?

其实最核心的原因就是造价的高低,就比如我们网盘,一般只要注册了就会送1T的空间,而硬盘就需要买了,内存更贵了,从下往上越来越贵,所以上面的存储大小就很小了,下面的存储大小就比较大了。而且呢,网盘的速度,相信大家也都懂吧,硬盘的速度肯定是比网盘快的,内存的速度大于硬盘,高速缓存更快了,寄存器是最快的。

所以我们得出一个结论,越往上,存储大小越小,速度越快,造价越高

那么为什么我们的存储是这样的分配呢。在这里我们不得不提一下CPU,也就是中央处理器

在早期呢,我们CPU的数据都是从内存里面获取的,因为那时候的CPU还不是这么快,内存的速度也还不错,两者之间可以完美搭配

     但是后来呢,随着CPU的快速发展,而我们的内存速度并没有得到快速提升,这就导致了,CPU再快也带不动内存的拖后腿,于是我们就设计出了更快的高速缓存,寄存器,虽然他们的数据存储的少,但是问题不大。我们只需要让我们的CPU数据都从寄存器里拿,寄存器剩余的字节都从高速缓存里获取,高速缓存从内存中获取,内存最后再从硬盘中获取就可以了。这样刚好完美的搭配了起来,使我们计算机的数据得到有效的提高。

那么我们现在聊了这么多,那寄存器到底该怎么用呢?

#include<stdio.h>
int main()
{
  register int a = 10;
  return 0;
}

这段代码的意思是,建议将a放在寄存器中,注意,仅仅是建议,具体是否放在寄存器中取决于编译器,当然,我们如今的编译器已经是相当聪明了,他在编译的时候就会考虑到这个是否该放在寄存器中,使我们的效率大幅度提高。

3.关键词typedef

typedef顾名思义是类型定义,这里应该理解为类型重命名

我们用一段代码来理解一下

typedef unsigned int uint;
#include<stdio.h>
int main()
{
  unsigned int a = 10;
  uint b = 5;
  return 0;
}

这段代码中使用typedef对unsigned int重定义成uint,这时候,unsigned和uint是同一种类型,这样的好处是可以简化一些复杂的类型,上面代码中a和b的类型就是相同的。

4.关键词static

static意思是静态的,有三种用法

1.修饰局部变量

2.修饰全局变量

3.修饰函数

(1)修饰局部变量

我们先看这样一段代码,并思考一下输出结果为什么呢

void test()
{
  int a = 0;
  a++;
  printf("%d\n", a);
}
#include<stdio.h>
int main()
{
  int i = 0;
  for (i = 0; i < 10; i++) {
    test();
  }
  return 0;
}

不难得出,运行结果为十个1,因为a是一个局部变量,当他离开他的函数以后,就被销毁了,然后再一次进入的时候a又重新创建了,所以a一直都是1

然后我们在思考一下这个代码

void test()
{
  static int a = 0;
  a++;
  printf("%d\n", a);
}
#include<stdio.h>
int main()
{
  int i = 0;
  for (i = 0; i < 10; i++) {
    test();
  }
  return 0;
}

这段代码结果为什么呢?还是十个1吗?

我们运行一下

运行结果为1~10,这个结果挺令人震惊的,为什么是这个结果呢,这段代码和上段代码的不同点就是static,static修饰了a后,貌似a不在被销毁了,a活下来了。事实上,static确实使得a的生命周期延长了,那如果static的作用是使得a的生命周期延长,使得他不会被销毁,那又为什么将他叫做静态呢?static在计算机中做了什么事情,使得他不会被销毁了呢?在这里我们得拓展一个知识。

我们先画一下内存的各个区域,如图所示,我们一般将内存分为三块,分别是栈区,堆区,静态区

每个区域中都存储着不同的变量

如图所示,栈区存储着局部变量,函数参数等临时的变量,函数本身是不占用内存空间的,他就是一段二进制代码,只有在调用他的时候才会占用空间

堆区存储着动态内存分配,比如malloc,calloc,realloc,free

静态区存储着静态变量,全局变量

堆区我们放在后面的文章中讲解

那么栈区与静态区有什么区别呢?

如图所示

栈区的数据,进了作用域就创建,出了作用域就销毁

而我们静态区的数据创建后,直到程序结束后才释放

在我们第二段代码中,我们使用static修饰了a,也就是将a放在了静态区,这样的话,那我们的a就创建后,直到程序结束后才会被释放,当我们第一次创建好静态的a后,他会活到程序结束的那一刻。我们循环进行第二次第三次第n次时候,经过下图中蓝色区域的代码时,则会自动跳过,他会自动忽略掉这行代码,因为他只创建一次a就可以了。

听起来貌似跟全局变量很像,但并非如此,这是一个经典的错误标准的零分,static修饰的局部变量后,最终的结果仅仅只是延长了a的生命周期,但是他的作用域没有发生变化,作用域仍然是之前的局部的,而我们的全局变量的作用域和生命周期都是整个程序。

这里总结一下static修饰局部变量:

1.普通的局部变量是放在栈区上的,这种局部变量进入作用域后创建,出了作用域释放

2.但是局部变量被static修饰后,这种变量就放在静态区,放在静态区的变量,创建好后,直到程序结束后才释放

3.本质上:static的修饰改变了局部变量的存储位置,因为存储位置的差异,使得执行效果不一样。

4.被static修饰是不影响作用域的!!!但是生命周期发生了变化,变长了。

(2)修饰全局变量

我们先通过阅读这两段代码来回顾一下我们之前的全局变量的两种用法

int a = 5;
#include<stdio.h>
int a = 5;
int main()
{
  printf("%d", a);
  return 0;
}

这两段代码都是全局变量的正常使用,一种是在一个.c文件内的,另外一种是两个.c文件之间使用同一个全局变量时,需要extern,这两种方式都可以使我们的程序正常运行。

但是如果我给第二种形式的全局变量加上static呢,这会发生什么呢?

我们打出这段代码并尝试编译。

已经报错了,那么我们应该就能猜到,static修饰全局变量后会使这个a不能被其他文件的使用,相当于把a给隔离到他自己的文件里面了,不让他人使用了。

那么我们现在来解释一下static修饰全局变量的作用

全局变量本身是具有外部链接属性的

在A文件中定义的变量,在B文件中可以通过【链接】使用

但是如果全局变量被static修饰,这个外部链接属性就变成内部链接属性,这个全局变量只能在自己所在的源文件内部使用

static的修饰,会把外部链接属性变成内部链接属性,最终使得全局变量的作用域变小了

这里先解释一下,任何一个变量都是具有内部链接属性的,当具有外部链接属性时,就称作他具有外部链接属性,而使用static后外部链接属性就被剥离了,只剩下内部链接属性了。

补充一个小知识点:我们的test.c文件-------->编译+链接--------->.exe可执行程序

也就是任何一个工程中,我们的所有.c文件编译后加上链接就会形成.exe可执行程序

(3)static修饰函数

static修饰函数其实跟修饰全局变量是很相似的

像这段代码是可以正常运行的

但是加上static以后

下面的报错显示,无法解析的外部符号,说明我们的Add函数无法被test.c文件识别到,static修饰函数的作用与修饰全局变量的作用就显得很类似了,使得外部链接属性变成了内部链接属性。

那么总结一下static修饰函数的作用:

函数本身是具有外部链接属性的

被static修饰后,外部链接属性就变成了内部连接属性

使得这个函数只能子啊自己所在的源文件内部使用,其他源文件无法使用

注:与全局变量不同的是,函数没有生命周期,他一直都在,只不过是能不能调到的问题

十二、#define定义常量和宏

1.#define定义常量

这一块我们其实在前面变量常量时候已经提到过了,那我们这块就在通过这段代码来简单复习一下

#define M 100
#include<stdio.h>
int main()
{
  printf("%d", M);
  return 0;
}

即代码中的所有M都会替换成100

2.宏

与定义常量有点类似又有点不同

我们先看这样一段代码

#define MAX(x,y)  (x>y?x:y)
#include<stdio.h>
int main()
{
  int a = 10;
  int b = 20;
  int m = MAX(a, b);
  printf("%d\n", m);
  return 0;
}

类似的,这段代码就是把MAX(a,b)替换为(x>y?x:y)这也是一种替换,只不过这种是可以传一个参数的,将a传入x,b传入y,然后最终替换为(a>b?a:b)


总结

本节主要讲了几个常见的关键词,以及#define定义常量与宏,如果本节内容对你有帮助的化,不要忘记留下你免费的赞赞和关注哦!!!

本站未完,欲知后事,请看下节

下节预告:它,被人称作c语言精髓,被人称作c语言的噩梦开始,还有另一个它,它的类型由你来掌握,据说,当熟练掌握他们两个后,将他们联合使用,可以真正的了解到c生万物,可开启数据结构的大门,可以获得掌握链表,栈,队列,树,图等很多强大的技能。从而突破瓶颈,成为一方强者。

那么你们猜到下节的内容吗?

下节:第一站,初识C语言(终章)

相关文章
|
6月前
|
编译器 Linux C语言
【C语言航路】第十五站:程序环境和预处理(下)
【C语言航路】第十五站:程序环境和预处理(上)
41 0
|
6月前
|
存储 自然语言处理 编译器
【C语言航路】第十五站:程序环境和预处理(上)
【C语言航路】第十五站:程序环境和预处理
43 0
|
6月前
|
存储 编译器 C语言
【C语言航路】第十四站:文件(下)
【C语言航路】第十四站:文件
42 0
|
6月前
|
存储 编译器 数据库
【C语言航路】第十四站:文件(上)
【C语言航路】第十四站:文件
37 0
|
6月前
|
程序员 C语言 C++
【C语言航路】第十三站:动态内存管理(下)
【C语言航路】第十三站:动态内存管理
35 0
|
6月前
|
编译器 C语言
【C语言航路】第十三站:动态内存管理(上)
【C语言航路】第十三站:动态内存管理
50 0
|
6月前
|
编译器 Linux C语言
【C语言航路】第十二站:自定义类型:结构体、枚举、联合体
【C语言航路】第十二站:自定义类型:结构体、枚举、联合体
41 0
|
6月前
|
存储 编译器 C语言
【C语言航路】第十一站:字符串、字符和内存函数(下)
【C语言航路】第十一站:字符串、字符和内存函数
52 0
|
6月前
|
算法 安全 编译器
【C语言航路】第十一站:字符串、字符和内存函数(中)
【C语言航路】第十一站:字符串、字符和内存函数
57 0
|
6月前
|
IDE 开发工具 C语言
【C语言航路】第十一站:字符串、字符和内存函数(上)
【C语言航路】第十一站:字符串、字符和内存函数
34 0