【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’也当作一个字节算在内

目录
打赏
0
0
0
0
2
分享
相关文章
|
3月前
|
【C语言】break 关键字详解
- `break` 关键字用于提前退出循环体或 `switch` 语句的执行。 - 在 `for`、`while` 和 `do-while` 循环中,`break` 可以帮助程序在满足特定条件时退出循环。 - 在 `switch` 语句中,`break` 用于终止 `case` 代码块的执行,避免代码“穿透”到下一个 `case`。 - 注意 `break` 只会退出最内层的循环或 `switch` 语句,确保在嵌套结构中正确使用 `break` 以避免意外的控制流行为。
199 2
【C语言】enum 关键字详解
`enum`关键字在C语言中提供了一种简洁而高效的方法来定义一组相关的常量。通过使用枚举,可以提高代码的可读性、可维护性,并减少错误的发生。在实际应用中,枚举广泛用于表示状态、命令、错误码等,为开发者提供了更清晰的代码结构和更方便的调试手段。通过合理使用枚举,可以编写出更高质量、更易维护的C语言程序。
175 2
【C语言】volatile 关键字详解
`volatile` 关键字在 C 语言中用于防止编译器对某些变量进行优化,确保每次访问该变量时都直接从内存中读取最新的值。它主要用于处理硬件寄存器和多线程中的共享变量。然而,`volatile` 不保证操作的原子性和顺序,因此在多线程环境中,仍然需要适当的同步机制来确保线程安全。
124 2
【C语言】auto 关键字详解
`auto` 关键字用于声明局部变量的自动存储类,其作用主要体现在变量的生命周期上。尽管现代C语言中 `auto` 的使用较少,理解其历史背景和作用对于掌握C语言的存储类及变量管理仍然很重要。局部变量默认即为 `auto` 类型,因此在实际编程中,通常不需要显式声明 `auto`。了解 `auto` 关键字有助于更好地理解C语言的存储类及其在不同场景中的应用。
145 1
|
3月前
|
【C语言】continue 关键字详解
`continue` 关键字在 C 语言中用于跳过当前循环中的剩余代码,并立即开始下一次迭代。它主要用于控制循环中的流程,使程序在满足特定条件时跳过某些代码。
227 1
【C语言】continue 关键字详解
|
3月前
|
【C语言】return 关键字详解 -《回家的诱惑 ! 》
`return` 关键字在 C 语言中用于终止函数的执行,并将控制权返回给调用者。根据函数的类型,`return` 还可以返回一个值。它是函数控制流中的重要组成部分。
153 2
【C语言】一篇通关所有 “关键字”,值得收藏篇!
关键字是编程语言预定义的保留词,代表特定的操作或结构。C语言中的关键字用于定义变量类型、控制语句、存储类、数据类型等。使用这些关键字可以创建函数、控制程序的流程、声明变量和常量等。
438 0
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
97 23
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
21 1
一文彻底搞清楚C语言的函数
|
2月前
|
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
123 15
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等