【C语言深度剖析】— 史上最全关键字(爆肝半个月、数万字详解、考试必备)(1)

简介: 【C语言深度剖析】— 史上最全关键字(爆肝半个月、数万字详解、考试必备)(1)

引言:

C语言简洁、紧凑,使用方便、灵活。ANSI C标准C语言共有32个关键字,9种控制语句,程序书写形式自由,区分大小写。把高级语言的基本结构和语句与低级语言的实用性结合起来。 C 语言可以像汇编语言一样对位、字节和地址进行操作,而这三者是计算机最基本的工作单元。


简洁紧凑、灵活方便


ANSI C一共只有32个关键字,9种控制语句,程序书写形式自由,区分大小写。把高级语言的基本结构和语句与低级语言的实用性结合起来。 C 语言可以像汇编语言一样对位、字节和地址进行操作,而这三者是计算机最基本的工作单元。


C是结构式语言


结构式语言的显著特点是代码及数据的分隔化,即程序的各个部分除了必要的信息交流外彼此独立。这种结构化方式可使程序层次清晰,便于使用、维护以及调试。C语言是以函数形式提供给用户的,这些函数可方便的调用,并具有多种循环、条件语句控制程序流向,从而使程序完全结构化。


语法限制不太严格,程序设计自由度大:虽然C语言也是强类型语言,但它的语法比较灵活,允许程序编写者有较大的自由度。


允许直接访问内存地址,对硬件进行操作。由于C语言允许直接访问内存地址,可以直接对硬件进行操作,因此它既具有高级语言的功能,又具有低级语言的许多功能,能够像汇编语言一样对位、字节和地址进行操作,而这三者是计算机最基本的工作单元,可用来写系统软件。


生成目标代码质量高,程序执行效率高:一般只比经过高效优化的汇编程序生成的目标代码效率低10~20%。


适用范围大,可移植性好:C语言有一个突出的优点就是适合于多种操作系统,如DOS、UNIX、windows 98.windows NT;也适用于多种机型。C语言具有强大的绘图能力,可移植性好,并具备很强的数据处理能力,因此适于编写系统软件,三维,二维图形和动画,它也是数值计算的高级语言。


运算符丰富


C语言的运算符包含的范围很广泛,共有34种运算符。C语言把括号、赋值、强制类型转换等都作为运算符处理。从而使C语言的运算类型极其丰富,表达式类型多样化。灵活使用各种运算符可以实现在其它高级语言中难以实现的运算。


数据类型丰富


C语言的数据类型有:整型、实型、字符型、数组类型、指针类型、结构体类型、共用体类型等。能用来实现各种复杂的数据结构的运算。并引入了指针概念,使程序效率更高。另外C语言具有强大的图形功能,支持多种显示器和驱动器。且计算功能、逻辑判断功能强大。


同时对于不同的编译器也有各种强大的扩展功能。


另外C语言如此丰富数据类型及强大指针功能,其对硬件的管控能力极强,所以许多操作系统内核及MCU芯片程序开发都偏爱硬件。

1. 关于变量

1.1 什么是变量

在内存中开辟特定大小的空间,用来保存数据

所有的变量,本质都是要在内存中的某个位置开辟空间的!

1.2 变量的定义与声明

1. 类型 变量名 = 默认值    //定义类型格式
2. char c = 'c';         //初始化
3. c = 'd';              //赋值

赋值的意思就是这个变量c已经存在了,存在的本质就是这个变量对应的空间已经开辟出来了 ,换言之就是将'd'字符直接放到一个已经存在的空间中。


很不幸,在C语言中,初始化和赋值的差别不是很大,唯一可能会出现的差别是在结构体数组那块内容,但是对于一般的内置类型基本上是没什么差别的,但是在C++和Java里面还是有差别的,这里不再赘述。

1.3 为什么要定义变量

计算机是为了进行计算的,而计算就需要数据,但是不是所有的数据都要立马被计算,有的数据是要先保存起来,等待后续处理


就像是吃饭,不是所有的饭菜都要立马被吃掉,要一口口吃,还没吃到的菜就需要暂时放到盘子里


盘子就如同变量,饭菜就相当于数据。


那么有人可能会说为什么要用“盘子”,直接去锅里不就行了吗?这当然没问题,但是效率太低了

1.4 变量定义的本质

定义就是用来开辟空间的  —  只能有一次

声明是用来告知的             —  声明可以多次

2. 关键字

C语言一共多少个关键字呢?一般的书上,都是32个(包括本书),但是这个都是 C90(C89) 的标准。其实 C99 后又新增了5个关键字。不过,目前主流的编译器,对 C99 支持的并不好,我们后面默认情况,使用 C90 ,即认为32个

image.png

image.png

2.1 最宽宏大量的关键字 - auto

2.1.1 局部变量

包含在代码块中的变量叫做局部变量,局部变量具有临时性。

int x = 10;
if(x == 10)
{
    int y = 20;
    printf("code1: %d,%d",x,y);
}
    printf("code2: %d,%d",x,y);

此时系统会报错:最后一行代码中的y变量没有定义

这是因为y变量是局部变量,只有在if代码块里面才可以使用,y的生命周期和作用域只在代码块内可以使用,出来之后y就被注销,所以code2中的y是没有定义的

2.1.2 全局变量

在所有函数外定义的变量,叫做全局变量,全局变量具有全局性。


全局变量整个程序运行期间都有效,且在任何代码块中的都可以被访问,甚至是修改


下面程序输出的是局部,也就是局部和全部同名的时候,优先局部

int g_val = 100;//全局变量
int main()
{
    int g_val = 200;//局部变量
    printf("%d",g_val);
}
//程序的打印结果为200
//局部优先

2.1.3 概念补充

代码块:用{}括起来的区域,就叫做代码块


作用域:指的是可以被正常访问的代码区域


生命周期:指的是该变量从定义到被释放的时间范围,所谓的释放,指的是曾经开辟的空间“被释放”


局部变量:进入代码块,形成局部变量【开辟空间】,退出代码块,“释放”局部变量


全局变量:定义完成之后,程序运行的整个生命周期内,该变量一直有效


作用域本质上是这个变量从什么地方开始有效,到什么地方开始无效


生命周期本质上是从什么时候开始有效,到什么时候开始无效


作用域更多的是描述影响范围,生命周期更多的是描述生存时间长短的问题

2.1.4 auto相关

如何使用:auto一般修饰代码块内部定义的变量,即局部变量,默认都是auto修饰的,不过一般省略,,但是默认的所有变量并不都是auto,只是一般用来修饰局部变量


局部变量,自动变量,临时变量,都是一回事。我们统称局部变量


auto已经很老,近几年新出的C标准都不使用auto来修饰局部变量了,可以直接省略

2.3 最快的关键字—register

2.3.1 计算机的分级存储

CPU主要是负责进行计算的硬件单元,但是为了方便运算,一般第一步需要先把数据从内存读取到CPU内,那么也就需要CPU具有一定的数据临时存储能力。注意:CPU并不是当前要计算了,才把特定数据读到CPU里面,那样太慢了。

所以现代CPU内,都集成了一组叫做寄存器的硬件,用来做临时数据的保存。

金字塔从上到下容量越来越大、速度越来越慢、价格越来越低


一般距离CPU越近,存储效率越高,单价成本越高且容量一般是比较小的。


其中,快的设备给慢的设备做缓存内存,显示器。


计算机的分级存储让我们用最小的成本,使用上最高效率的计算机。我们现在使用的计算机,就是考虑成本和效率的结果

2.3.2 寄存器

我们可以不关系硬件细节,只要知道CPU内集成了一组存储硬件即可,这组硬件叫做寄存器

寄存器存在的本质:在硬件层面上,提高计算机的运算效率。因为不需要从内存里读取数据

我们知道了寄存器的作用之后再来看看寄存器变量—register吧

2.3.3 register 修饰变量

尽量将所修饰变量,放入CPU寄存区中,从而达到提高效率的目的


那么什么样的变量,可以采用register呢?

1. 局部的(全局会导致CPU寄存器被长时间占用)

2. 不会被写入的(写入就需要写回内存,后续还要读取检测的话,register的意义在哪呢?)

3. 高频被读取的(提高效率所在)

4. 如果要使用,请不要大量使用,因为寄存器数量有限

register修饰的变量,不能取地址(因为已经放在寄存区中了嘛,地址是内存相关的概念)


最后呢,这个关键字现在可以不用管,因为现在的编译器已经很智能了,能够进行比人更好的代码优化

2.4 最名不符实的关键字 - static

在讲这个关键字之前我们先看一个补充的内容

2.4.1 认识多文件

.h:我们称之为头文件,一般包含函数声明,变量声明,宏定义,头文件等内容(header)

.c: 我们称之为源文件,一般包含函数实现,变量定义等 (.c: c语言)

//test.h
#pragma once //防止头文件被重复包含,现在只需要记住,后面用的多
#include <stdio.h>
#include <windows.h>//包含了其他的windows头文件,调用函数时可以使用
//test.c
#include "test.h" //""里面包含头文件,目前只需要知道是自己写的头文件,就用""包含即可
//main.c
#include "test.h" //""里面包含头文件,目前只需要知道是自己写的头文件,就用""包含即可
int main()
{
    printf("hello files!\n");
    return 0;
}

简单看了上面的多文件调用之后,下面我们来看两个问题:


1. 全局变量可以跨文件吗?


       可以


2. 函数可以跨文件访问吗?


       可以


为什么要跨文件?有一定规模的项目,一定是多文件的,多个文件之间,后续一定要进行数据“交互”(#include "test.h" , main.c 里的函数访问 test.c 里的函数)跨文件其实就是使代码模块化,方便别人使用时可以直接看到,所以在写项目的时候,跨文件是刚需。


如果不能跨文件,“交互”成本会比较高


如果我的这个文件比较自私,不想把自己定义的变量和函数给别的文件用,那么有没有可能,我们不让全局变量或者函数跨文件访问,只在本文件内部被访问呢?


我们跨文件的时候总有些代码是不能够开源的,这时就出现了static

2.4.2 static相关

static修饰全局变量和函数时,该全局变量和函数只能在本文件内被使用,是不能够被其他文件直接访问的,就相当于将代码给封装起来了,只给一个接口,这样的话别人在使用我们的程序的时候,就不能直接通过该全局变量来直接修改程序。static是一套很好的项目维护机制,提供了安全保证。

static修饰全局变量,影响的是作用域的概念,函数类似。而生命周期是不变的

static修饰局部变量,变量的生命周期变成全局周期。(作用域不变)

static void fun()
{
    static int i = 0;
    i++;
    printf("i = %d\n", i);
}
int main()
{
    for(int i = 0; i < 10; i++)
    {
        fun();
    }
    return 0;
}
/*不加static时打印结果应全为1
加上static后打印结果应为:
i = 1
i = 2
 ……
i = 10

两次结果不一样,其实是因为fun函数每次被调用之后,都会把内存释放,这样一来下一次进入时就会从i = 0开始执行。而后面加上static之后,i 在fun运行过程中,并没有被释放!!!


所以得到结论:static修饰局部变量,更改局部变量的生命周期,作用域不变


static总结:


i 的初始化动作,永远只会初始化一次,第一次!

2.5 基本数据类型—short、int、 long、char、float、double

C语言常见内置类型:short、int、 long、char、float、double等


什么是内置类型:由C语言给我们定义好的就叫做C语言的内置类型


与C语言相对应的还有一批自定义类型:指针,结构体,联合体,枚举等


前面已经说过,定义变量的本质:在内存中开辟一块空间,用来保存数据。


而定义一个变量,是需要类型的,这个是基本语法决定的。


那么,类型决定了:变量开辟空间的大小。

2.6 变量命名

我们为什么要在关键字这里学变量命名呢?

  • 命名是职业化的表现
  • 面试官会让我们现场写代码,如果我们命名太随意,会表现得很业余,体现了我们的职业素养


1.变量名应由“数字字母下划线”组成,且不能以数字开头


2.见名知义


       命名应当直观且可以拼读,可望文知意,便于记忆和阅读


       标识符最好采用英文单词或其组合,不允许使用拼音。程序中的英文单词一般不要太复

杂,用词应当准确。


3.大小驼峰


       当标识符由多个词组成时,每个词的第一个字母大写,其余全部小写。比如:

               int CurrentVal;

       这样的名字看起来比较清晰,远比一长串字符好得多。


4.避免混淆


       程序中不得出现仅靠大小写区分的相似的标识符。

       例如: int x, X; 变量 x 与 X 容易混淆

                   void foo(int x); 函数 foo 与 FOO 容易混淆


       1(数字 1)和 l(小写字母 l)之间, 0(数字 0)和 o(小写字母 o)之间的区别


5.所有宏定义、枚举常数、只读变量全用大写字母命名,用下划线分割单词。


       一般来说习惯上用 n,m,i,j,k 等表示 int 类型的变量; c, ch 等表示字符类型变量; a 等表示数组; p 等表示指针。当然这仅仅是一般习惯,除了 i,j,k 等可以用来表示循环变量外,别的字符变量名尽量不要使用


C语言关键字命名清楚以上这些就足够了

2.7 最冤枉的关键字----sizeof

求特定一种类型,它对应开辟空间的大小的写法的过程中,下面哪些写法是正确的

int a = 10;
printf("%d\n",sizeof(a));      //1
printf("%d\n",sizeof(int));    //2
printf("%d\n",sizeof a);       //3
printf("%d\n",sizeof int);     //4

4.  err: sizeof作为一个关键字不能直接去求另外一个关键字的大小

其余三个都是可以的,换言之sizeof求一种特定开辟空间的大小时,有三种方法帮我们去求

分别对应上面代码块里的1,2,3 种写法

  • 一种是(变量名)
  • 一种是根据类型
  • 还有是直接加变量名

下面我们通过数组、指针、指针数组这三个概念来理解sizeof

对了,在一般的学校考试,二级考试都会经常性的让你求字符串的空间容量,这里大家要注意的就是sizeof求字符串所占空间容量时,会把字符串结束符‘\0’也当作一个字节算在内

相关文章
|
1月前
|
算法 数据库 C语言
简单谈谈我参加计算机二级C语言的考试感受
计算机二级c语言主要内容是熟练掌握C语言基础语法,了解常用数据结构和算法,能够使用C语言进行程序设计,编写简单的应用程序。 计算机二级C语言试卷类型: + 选择题 + 程序填空题 + 程序改错题 + 程序设计题 这四个部分组成,其中大题目的分数占60分。
27 0
|
1月前
|
存储 安全 C语言
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-2
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-2
|
1月前
|
存储 编译器 C语言
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-1
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-1
|
1月前
|
存储 C语言 C++
C语言------------指针笔试题目深度剖析
C语言------------指针笔试题目深度剖析
19 1
|
1月前
|
程序员 C语言
在C语言中,typedef是一种用来创建新的数据类型名的关键字
在C语言中,typedef是一种用来创建新的数据类型名的关键字
9 0
|
1月前
|
存储 编译器 C语言
C语言的关键字
C语言的关键字
13 0
|
1月前
|
存储 编译器 C语言
c语言中的关键字
c语言中的关键字
9 0
|
1月前
|
存储 小程序 C语言
【深度剖析数据在内存中的存储】C语言
【深度剖析数据在内存中的存储】C语言
|
1月前
|
存储 小程序 C语言
【C语言进阶】深度剖析数据在内存中的存储
【C语言进阶】深度剖析数据在内存中的存储
|
1月前
|
编译器 程序员 Linux
深入理解C语言中的return关键字与函数返回机制
深入理解C语言中的return关键字与函数返回机制