C语言笔记(第n版):知识清单

news2024/9/21 22:50:19

注:本文参考自【C reference - cppreference.com】和【C 语言参考 | Microsoft Learn】,颇有点借花献佛的意味……

        C 程序是一系列包含声明的文本文件(通常为头文件和源文件)的序列。它们经过转换成为可执行程序,当操作系统调用其主函数时执行(除非它本身就是操作系统或另一个独立程序,在这种情况下入口点由实现定义)。在 C 程序中,某些词具有特殊含义,即关键字。其他词可用作标识符,可用于标识对象函数结构体联合体枚举标签、它们的成类型定义(typedef)名称、标签。每个标识符(除宏外)仅在程序的一部分(称为其作用域)内有效,并属于四种命名空间之一。一些标识符具有链接性,这使得它们在不同的作用域或翻译单元中出现时指向相同的实体。函数的定义包括语句和声明的序列,其中一些包含表达式,这些表达式指定了程序要执行的计算。声明和表达式创建、销毁、访问和操作对象。C 语言中的每个对象、函数和表达式都与一种类型相关联。

一、基本概念

Basic concepts - cppreference.com

(一)翻译阶段

Phases of translation - cppreference.com

C源文件经编译器处理,依次经历以下阶段,实际由具体实现决定

  • Phase 1 的处理:将源文件字节映射到源字符集的字符,替换特定符号,处理三字符序列。
  • Phase 2 的操作:处理行拼接和换行符,明确了非空源文件结束时的要求。
  • Phase 3 的分解:将源文件分解为注释、空格序列和预处理令牌,并对注释进行替换处理。
  • Phase 4 的包含文件处理:对 #include 引入的文件进行递归的 1 至 4 阶段处理,并在阶段结束时移除所有预处理指令。
  • Phase 5 的字符转换:将字符常量和字符串字面量中的字符和转义序列从源字符集转换到执行字符集。
  • Phase 6 的字符串拼接:对相邻字符串字面量进行拼接。
  • Phase 7 的编译:对令牌进行语法和语义分析及翻译。
  • Phase 8 的链接:收集翻译单元和库组件,形成包含执行所需信息的程序图像。

(二)标点符号

序号

符号

描述或用途

1

{ }

结构体或联合体定义中的声明列表,复合语句的界定,初始化中的初始化器。

2

[ ]

下标运算符,数组声明,C99 起在初始化中引入数组元素的设计符,C23 起属性说明符的界定。

3

#

引入预处理指令,字符串化预处理运算符。

4

##

标记粘贴预处理运算符。

5

( )

表达式中的分组指示,函数调用,sizeof_Alignoftypeof 等表达式中的操作数界定,声明或类型标识符中的分组等。

6

;

语句结束,声明或结构声明列表的分隔。

7

:

条件运算符的一部分,标签声明,位字段成员声明中引入宽度,C23 起枚举基的引入。

8

...

函数声明中的可变参数,C99 起宏定义中的可变参数宏。

9

?

条件运算符的一部分。

10

::

C23 起属性的作用域指示,预处理器前缀参数的作用域指示。

11

.

成员访问运算符,C99 起初始化中的结构体/联合体成员的设计符。

12

->

成员访问运算符。

13

~

一元补运算符(位非运算符)。

14

!

逻辑非运算符。

15

+

一元加运算符,二元加运算符。

16

-

一元减运算符,二元减运算符。

17

*

间接运算符,乘法运算符,指针运算符,C99 起函数声明中可变长数组的长度占位符。

18

/

除法运算符。

19

%

模运算符。

20

^

位异或运算符。

21

&

地址运算符,位与运算符。

22

|

位或运算符

23

=

简单赋值运算符,初始化中的对象和初始化器列表的界定,枚举定义中的枚举常量值的引入。

24

+=

复合赋值运算符。

25

-=

复合赋值运算符。

26

*=

复合赋值运算符。

27

/=

复合赋值运算符。

28

%=

复合赋值运算符。

29

^=

复合赋值运算符。

30

&=

复合赋值运算符。

31

|=

复合赋值运算符。

32

==

等式运算符。

33

!=

不等式运算符。

34

<

小于运算符,C23 起 #include__has_include#embed__has_embed 指令和预处理表达式中的头文件名引入。

35

>

大于运算符,C23 起上述指令和表达式中头文件名的结束。

36

<=

小于等于运算符。

37

>=

大于等于运算符。

38

&&

逻辑与运算符。

39

||

逻辑或运算符。

40

<<

位左移运算符。

41

>>

位右移运算符。

42

<<=

位左移赋值运算符。

43

>>=

位右移赋值运算符。

44

++

递增运算符。

45

--

递减运算符。

46

,

逗号运算符,用于分隔声明列表、初始化器列表、函数调用参数列表、枚举器列表、宏参数列表、属性列表等。

(三)标识符

Identifier - cppreference.com

  • 标识符的定义:是由数字、下划线、大小写拉丁字母和特定的 Unicode 字符组成的任意长序列,需以非数字字符开头,且区分大小写,必须符合标准化形式 C。
  • 保留标识符:如关键字、以特定格式开头的外部标识符、标准库定义的外部标识符等均为保留标识符,在程序中不能声明使用。
  • 潜在保留标识符:包括函数名、typedef 名、宏名、枚举常量等多种类型,它们可能在未来被使用。
  • 翻译限制:虽然标识符长度无具体限制,但早期编译器和链接器对标识符有初始字符数量和数量等方面的限制,C 语言标准规定了一些最低支持的限制。

(四)作用域

Scope - cppreference.com

        在 C 程序中出现的每个标识符仅在源代码中被称为其作用域的某些可能不连续的部分可见(即可以被使用)。在一个作用域内,只有当实体处于不同的命名空间时,一个标识符才可以表示多个实体

  • C 语言有四种作用域:包括块作用域、文件作用域、函数作用域、函数原型作用域。
  • 块作用域的规则:在复合语句、函数体、特定表达式和语句内声明的标识符,其作用域从声明点开始到所在块或语句结束。C99 之前,选择和迭代语句自身无块作用域。默认情况下,块作用域变量无链接且自动存储。
  • 文件作用域的特性:在任何块或参数列表之外声明的标识符,其作用域从声明点开始到翻译单元结束。文件作用域标识符默认具有外部链接和静态存储。
  • 函数作用域:从函数定义开始,到函数块结束而结束。函数内声明的标签且只有标签在函数内任何地方、嵌套块等都有效。
  • 函数原型作用域:在函数声明的参数列表中引入的名称的作用域在函数声明符结束时结束。
  • 其他作用域规则:结构体、联合体和枚举标签以及枚举常量的作用域有特定的起始点。标识符的作用域通常在声明符结束和初始化器之前开始。
  • 嵌套作用域:如果两个由相同标识符命名的不同实体同时处于作用域内,并且它们属于相同的命名空间,那么这些作用域就是嵌套的(不允许有其他形式的作用域重叠),并且出现在内部作用域中的声明会隐藏外部作用域中的声明。

(五)生存期

Lifetime - cppreference.com

        在C语言中,对象的生命周期是指对象存在于内存中的时间段,在此期间它可以被程序访问和修改。生命周期的开始和结束时间取决于对象的存储类型。

对象的生命周期定义

  • 生命周期: 在这个时间段内,对象保持其地址不变,并且保留其最后一次有效存储的值(除非该值由于某种原因变得不确定)。对于可变长数组(VLA),它还保留其大小。
  • 可变长数组 (VLA): 这种类型的数组是在运行时确定其大小的数组。自C99标准以来,VLA成为C语言的一部分。

存储期限与生命周期的关系

  • 自动存储期限: 这类对象通常是在函数调用时创建的局部变量。它们的生命周期从进入作用域开始,到离开作用域结束。
  • 静态存储期限: 静态变量在整个程序执行期间都存在。它们在程序启动时初始化一次,并且在整个程序执行过程中保持其值。
  • 线程存储期限: 这种类型的对象在多线程环境中为每个线程提供独立的存储空间。它们的生命周期也与线程的存在相关联。
  • 分配存储期限: 通过内存分配函数如 malloc 或 calloc 分配的对象。它们的生命周期从分配函数返回开始,到使用 free 函数释放为止。

访问生命周期外的对象

  • 未定义行为: 如果试图访问一个已经超出其生命周期的对象,那么结果是未定义的。这可能导致程序崩溃或其他不可预测的行为。

临时生命周期

  • 结构体和联合体: 当结构体或联合体对象包含数组成员,并且这些对象是通过非左值表达式指定时,它们具有临时生命周期。
  • 开始和结束: 临时生命周期从评估表达式时开始,根据C11标准,在整个表达式评估完成时结束。

例如,考虑下面的代码片段:

1struct Point {
2    int x, y;
3} point = {10, 20};
4
5// 使用非左值表达式
6(int[point.x])[0] = 42;  // 此处point具有临时生命周期

        在这个例子中,point作为数组下标的一部分出现在表达式中,因此它具有临时生命周期。需要注意的是,这种用法可能会导致复杂性和潜在的错误,因为一旦表达式计算完成,对point的引用就不再有效。

(六)命名空间

Lookup and name spaces - cppreference.com

名字空间的定义

        当C程序解析标识符时,它需要确定该标识符所代表的内容。为了做到这一点,C语言为不同的标识符类别定义了不同的命名空间。每个命名空间都是独立的,这意味着可以在不同的命名空间中使用相同的标识符名称而不会产生冲突。

(七)类型

Type - cppreference.com

        对象、函数和表达式具有一种称为类型的属性,该属性决定了存储在对象中或由表达式计算的二进制值的解释。

类型分类

兼容类型

         在C语言中,兼容类型的概念很重要,因为它决定了不同翻译单元(Translation Units, TU)之间如何引用同一对象或函数。在 C 程序中,在不同的翻译单元中指向相同对象或函数的声明不必使用相同的类型。它们只需要使用足够相似的类型,称为兼容类型。如果两个声明引用同一个对象或函数但类型不兼容,则程序的行为是未定义的。

类型名称

类型名称在C语言中可以用于以下情况:

  • 类型转换 (cast)
  • 类型大小查询 (sizeof)

类型名称还可以用来引入新的类型,例如通过typedef或者在类型转换表达式中。

(八)对象

Objects and alignment - cppreference.com

C语言中的对象是指程序执行环境中的一段数据存储区域,这段区域的内容可以表示一定的值。

整数类型的字节使用

  • 当整数类型占据多个字节时,这些字节的使用方式由实现定义。
  • 主要有两种实现:大端和小端。
    • 大端实现将最高有效字节存储在最低地址处。
    • 小端实现将最低有效字节存储在最低地址处。

二、执行单元

(九)主函数

main_function - cppreference.com

C语言中的main函数是程序的入口点,它是程序启动后第一个被调用的函数。

main函数的形式

main函数可以有不同的形式,常见的形式如下:

  1. 无参数形式:

    1int main(void) {
    2    // body
    3}

    这种形式的main函数没有参数,适用于不需要命令行参数的简单程序。

  2. 带参数形式:

    1int main(int argc, char *argv[]) {
    2    // body
    3}

    这种形式的main函数接收两个参数:argcargvargc是一个整数,表示命令行参数的数量(包括程序名称)。argv是一个指向字符串数组的指针,这些字符串是命令行参数。

  3. 其它扩展实现形式:

    1int main(int argc, char *argv[], char *envp[]) {
    2    // body
    3}

    这种形式的main函数接收三个参数:argcargvenvp。除了argcargv外,envp是一个指向环境变量字符串数组的指针。

参数说明

  • argc:

    • 表示传入程序的命令行参数的数量(包括程序名称)。
    • 是一个非负整数。
  • argv:

    • 是一个指向字符串数组的指针,其中每个字符串都是一个命令行参数。
    • argv[0]通常指向程序名称。
    • 如果argv[0]非空指针(即argc > 0),它指向一个表示程序名称的字符串;如果程序名称无法获取,则argv[0][0]保证为零。
    • argv[argc]是空指针。

返回值

main函数的返回值具有特殊的意义:

  • 如果main函数的返回类型与int兼容,那么从main函数的初始调用返回相当于调用了exit函数,并将main函数返回的值作为参数传递给exit函数。
  • 返回值为0或EXIT_SUCCESS表示成功终止。
  • 返回值为EXIT_FAILURE表示失败终止。

特殊性质

  1. 原型不可提供:

    • main函数的原型不能由程序提供。
  2. 退出行为:

    • 如果main函数的返回类型与int兼容,那么从main函数返回的行为等同于调用exit函数,并传递main函数返回的值作为参数。这会触发一系列标准清理操作,比如调用atexit注册的函数、关闭和刷新所有输出流、删除通过tmpfile创建的文件,并将控制权返回给执行环境。
  3. 未定义的行为:

    • 如果main函数执行了一个未指定返回值的return语句,或者到达了函数结尾而没有执行return,则返回给执行环境的终止状态是未定义的(直到C99标准)。
    • 如果main函数的返回类型与int不兼容(例如void main(void)),返回给执行环境的值是未指定的。如果main函数的返回类型与int兼容,但是控制流到达了函数结尾而没有执行return,则行为等同于执行return 0;(自C99标准起)。

(十)语句

Statements - cppreference.com

(十一)表达式

Expressions - cppreference.com

(十一)初始化、声明与定义

(十二)函数

 


致读者:

        本文略显潦草地总结了C的一些知识点,难免有疏漏之处,本人知识有限也无法提供足够专业的知识分析,仅仅是作为一个参考,概览一些C的语法面貌。本文的目的,是作为一个小总结和再回顾。虽然是总结,但是可以发现的是,对于C的整体语法体系,这里仅仅是探明了一部分,至少本人没有去完全了解C的语法体系。即使是作为技术的纯粹者和热爱者,完全熟练一门语言也需要时间,更何况C的灵活性和变化的应用环境。所以倘若有读者能在这里得到点什么,这篇文章也算有点意义了。对于较为庞大的思维导图,本文提供了相应文件,读者可以自行修改。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1964915.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Bugku ---Web---全题目解析 超详细步骤 持续更新

目录 1.Simple_SSTI_1 2.Simple_SSTI_2 3.滑稽 4.计算器 5.矛盾 6.GET ————————————————————分割线———————————————————— 1.Simple_SSTI_1 SSTI是服务器端模板注入 F12查看下源码 在 Flask 中&#xff0c;双大括号 {{ }} 用…

ElasticSearch父子索引实战

关于父子索引 ES底层是Lucene,由于Lucene实际上是不支持嵌套类型的,所有文档都是以扁平的结构存储在Lucene中,ES对父子文档的支持,实际上也是采取了一种投机取巧的方式实现的. 父子文档均以独立的文档存入,然后添加关联关系,且父子文档必须在同一分片,由于父子类型文档并没有…

Oracle LiveLabs实验:Improve application performance with True Cache

此实验申请地址在这里&#xff0c;时间为120分钟。 帮助见这里。 简介 参加本次动手实践研讨会&#xff0c;了解如何使用 True Cache 通过卸载查询和减少对主数据库的请求和连接数量来提高可扩展性。本次研讨会基于连接到配置了 True Cache 的主数据库的计算实例&#xff08…

从零手写实现 mybatis 系列(零)mybatis 核心特性

拓展阅读 第一节 从零开始手写 mybatis&#xff08;一&#xff09;MVP 版本 中我们实现了一个最基本的可以运行的 mybatis。 第二节 从零开始手写 mybatis&#xff08;二&#xff09;mybatis interceptor 插件机制详解 第三节 从零开始手写 mybatis&#xff08;三&#xff0…

最低工资标准数据(2001-2023年不等)、省市县,整理好的面板数据(excel格式)

时间范围&#xff1a;2001-2022年 具体内容&#xff1a;一&#xff1a;最低工资数据标准时间&#xff1a;2012-2021包含指标&#xff1a; 省份城市/区县小时最低工资标准&#xff08;非全日制&#xff09;月最低工资标准实施日期 样例数据&#xff1a; 二&#xff1a;各省最低…

Spring Cloud Gateway网关的高级特性之GatewayFilter Factories(路由过滤器)

1、GatewayFilter Factories&#xff08;路由过滤器&#xff09; 官方访问地址&#xff1a;点击这里 来自官方的解释如下图所示&#xff1a; 简单来说就是&#xff1a; 客户端向 Spring Cloud Gateway 发送请求。如果请求与某个路由匹配&#xff0c;则该请求会被传递给 Ga…

OpenEuler安装部署教程

目录 OpenEuler安装部署教程 MobaXterm一款全能的远程工具 yum安装软件 vim编辑器&#xff08;了解&#xff09; 防火墙 常用命令 网络工具netstat & telnet 进程管理工具top ps 磁盘free、fdisk 用户、组&#xff08;了解&#xff09; 权限&#xff08;了解&am…

实验3-9 三天打鱼两天晒网

//实验3-9 三天打鱼两天晒网/* 中国有句俗语叫“三天打鱼两天晒网”。 假设某人从某天起&#xff0c;开始“三天打鱼两天晒网”&#xff0c; 问这个人在以后的第N天中是“打鱼”还是“晒网”&#xff1f; */#include<stdio.h> #include<math.h> int main(){int n; …

Photoshop的下载和安装教程

找到Adobe 的官网 https://www.adobe.com/cn/ 创建一个新的账户,如果你没有账户的话 后面安装步骤来注册 下载和安装 登录之后 点击 点击 点击 然后进行下载和安装 然后就是漫长的等待 安装完成 点击 这只是一个安装Photoshop的教程,也可以根据别人的安装包来进行安装

ThreadPoolExecutor工作原理及源码详解

一、前言 创建一个线程可以通过继承Thread类或实现Runnable接口来实现&#xff0c;这两种方式创建的线程在运行结束后会被虚拟机回收并销毁。若线程数量过多&#xff0c;频繁的创建和销毁线程会浪费资源&#xff0c;降低效率。而线程池的引入就很好解决了上述问题&#xff0c;…

万字详解 MapStruct Plus,带你快速上手!

与其明天开始&#xff0c;不如现在行动&#xff01; 文章目录 前言一、为什么要用 MapStruct&#xff08;背景&#xff09;二、MapStruct Plus 的快速开始1. 引入依赖2. 指定对象映射关系3. 编写测试代码4. 运行结果5. 原理解析 三、自定义实体类中的属性转换1. 自定义一个类型…

【IO】使用父子进程完成两个文件的拷贝,父进程拷贝前一半内容,子进程拷贝后一半内容,子进程结束后退出,父进程回收子进程的资源

1、使用父子进程完成两个文件的拷贝&#xff0c;父进程拷贝前一半内容&#xff0c;子进程拷贝后一半内容&#xff0c;子进程结束后退出&#xff0c;父进程回收子进程的资源 #include <myhead.h>int main(int argc, const char *argv[]) {//判断输入的格式是否符合要求i…

预测性维护:一种基于因果技术语言处理 (CTLP) 的智能故障诊断方法

关键词&#xff1a;预测性维护、因果贝叶斯网络、ROX数据 在工业运营和维护领域&#xff0c;资产绩效最大化和风险最小化至关重要。随着工业设备组件的磨损和恶化&#xff0c;系统会表现出一系列变化&#xff0c;这些变化的严重程度会逐渐增加&#xff0c;直到最终发生故障。在…

C++_string_知识总结(初学)

基础认识&#xff1a; string严格意义上不属于STL容器&#xff0c;其出现的时间早于STL&#xff0c;这也导致了string官方库中部分函数冗余。但是这也体现了语言发展中的一个重要现象——向前兼容。和很多STL容器一样&#xff0c;string是一个类&#xff0c;核心是一个顺序表&…

MySQL:GROUP BY 分组查询

分组查询是SQL中一个非常强大的功能&#xff0c;它允许我们将数据按照一个或多个字段进行分组&#xff0c;并对每个分组进行聚合计算&#xff08;如求和、平均值、最大值、最小值等&#xff09;。在MySQL中&#xff0c;我们使用 GROUP BY 关键字来实现分组查询。 核心语法 SE…

笑出腹肌的饼图绘制秘籍:Matplotlib让你秒变数据烘焙大师!

1. 引言 亲们&#xff0c;还在为数据报告里的饼图头疼吗&#xff1f;别怕&#xff0c;Matplotlib来救场啦&#xff01;它不只是个绘图工具&#xff0c;简直是数据界的魔术师&#xff0c;让你的饼图既专业又有趣。跟我学几招&#xff0c;保证让你的观众边吃边看&#xff0c;爱不…

Linux驱动开发—编写第一个最简单的驱动模块

文章目录 开发驱动准备工作1.正常运行的Linux系统的开发板2.内核源码树3.nfs挂载的rootfs4.得心趁手的IDE 第一个Hello world 驱动程序常见模块的操作命令模块的初始化和清理模块的版本信息模块中的各种宏 示例Hello World代码printk函数解析 使用MakeFile编译驱动模块使用insm…

谷歌账号异常,成功通过验证后这个界面操作指引:建议增加辅助手机和邮箱

许多朋友对下面这个界面都很熟悉&#xff0c;通常是账号被停用后的时候输入账号和密码后&#xff0c;还需要再次输入手机号码验证。而且这个时候输入国内的号码或者谷歌账号绑定的辅助手机号码都不管用&#xff0c;提示此电话号码用于验证的次数过多&#xff0c;或者此电话号码…

链表篇:03-合并有序链表

解题思路&#xff1a; 使用双指针&#xff0c;一个指针指向头节点&#xff0c;然后另外一个指针进行移动。让其头节点保持不动&#xff0c;最后循环遍历两个链表&#xff0c;将其挂到头指针所在的节点上。 temp 守卫节点&#xff0c;用于指向头节点&#xff0c;防止头节点丢…

机械学习—零基础学习日志(高数17——极限局部有界性)

零基础为了学人工智能&#xff0c;真的开始复习高数 这里我们更加详细讲解函数极限性质。上一篇文章里有一些内容还需要进一步补充。 局部有界性 这里是局部有界性的需要注意的事项。第3点&#xff0c;如果函数在闭区间内连续&#xff0c;则必定有界。试想一下&#xff0c;如…