C语言常见概念:从编译链接到字符串与注释

C语言常见概念:从编译链接到字符串与注释
Lichermione前言
C 语言的基础语法并不复杂,但初学阶段有很多概念非常容易混淆:
- 编译器和 IDE 是一回事吗?
.c文件如何变成可执行程序?- 一个工程为什么只能有一个
main函数? - 字符
'a'和字符串"a"有什么区别? - 字符串末尾为什么必须有
'\0'? sizeof("abc")为什么是4,而strlen("abc")是3?printf中的%f和%lf有什么区别?- 一个单独的分号为什么也是语句?
本文从 C 语言的基本定位出发,依次介绍开发环境、编译链接、源文件与头文件、第一个 C 程序、main 函数、标准库、关键字、ASCII、字符串、转义字符、语句和注释。
一、C 语言是什么
1.1 计算机语言
人与人交流可以使用汉语、英语等自然语言;人与计算机交流,则需要使用计算机语言。
程序员通过计算机语言描述:
- 要处理的数据;
- 要执行的操作;
- 操作执行的顺序;
- 不同条件下应该采取的行为。
C、C++、Java、Go 和 Python 都属于计算机语言,只是它们的设计目标、执行方式和使用场景不同。
1.2 C 语言的特点
C 语言具有以下典型特点:
- 语法相对精简;
- 执行效率高;
- 可以进行接近底层的内存操作;
- 具有良好的可移植性;
- 适合系统软件和性能敏感程序;
- 许多现代语言的语法都受到 C 语言影响。
C 语言常见于:
- 操作系统;
- 编译器;
- 数据库;
- 嵌入式设备;
- 驱动程序;
- 网络服务;
- 高性能基础库。
1.3 C 语言与 Unix
C 语言最初与 Unix 系统的发展密切相关。它既能提供接近机器的控制能力,又比汇编语言更容易编写、维护和移植。
学习 C 语言不仅是在学习语法,也是在逐步理解:
- 程序怎样被编译;
- 数据怎样存入内存;
- 函数怎样调用;
- 源文件怎样协作;
- 操作系统怎样运行程序。
二、编译器与集成开发环境
2.1 什么是编译器
C 语言是一门编译型语言。.c 文件本质上是文本,处理器不能直接执行这些源代码。
编译器及相关工具需要把源代码转换为机器能够执行的程序。
常见的 C/C++ 编译器包括:
- MSVC;
- GCC;
- Clang。
2.2 什么是 IDE
IDE 是 Integrated Development Environment 的缩写,中文称为集成开发环境。
一个 IDE 通常集成:
- 代码编辑器;
- 编译工具;
- 调试器;
- 项目管理;
- 代码补全;
- 静态检查;
- 图形化界面。
常见 IDE 包括 Visual Studio、CLion、Xcode、Code::Blocks 和 Dev-C++。
2.3 编译器和 IDE 的区别
| 对比项 | 编译器 | IDE |
|---|---|---|
| 主要作用 | 将源代码转换为目标代码 | 提供完整开发环境 |
| 是否负责编辑代码 | 通常不负责 | 负责 |
| 是否包含调试功能 | 不一定 | 通常包含 |
| 典型例子 | GCC、Clang、MSVC | Visual Studio、CLion、Xcode |
Visual Studio 是 IDE,MSVC 是它常用的编译工具链,二者不能简单地看成同一个概念。
2.4 VS2022 的特点
Visual Studio 2022 适合 Windows 平台上的 C/C++ 学习和开发,主要优点包括:
- 编辑、编译和调试功能完整;
- 安装完成后通常不需要复杂配置;
- 图形化调试功能强大;
- 可以观察变量、内存和调用栈;
- 社区版可以免费用于学习。
它的主要缺点是安装体积和磁盘占用相对较大。
2.5 在 VS 中确保使用 C 语言
Visual Studio 会根据文件扩展名决定编译语言:
.c通常按 C 语言编译;.cpp通常按 C++ 编译。
如果想学习纯 C 语言,应当把源文件保存为:
1 | main.c |
而不是:
1 | main.cpp |
否则某些只能在 C++ 中通过的语法可能掩盖 C 语言问题。
三、C 程序如何变成可执行文件
3.1 总体过程
一个 C 程序从源代码到可执行文件,通常经历:
1 | 源文件 |
日常交流中,人们也经常把预处理、编译和汇编统称为“编译阶段”,再与链接阶段进行区分。
3.2 预处理
预处理器主要处理:
#include;#define;- 条件编译;
- 注释移除;
- 宏替换。
例如:
1 |
使用 GCC 可以观察预处理结果:
1 | gcc -E main.c -o main.i |
3.3 编译
狭义的编译阶段负责词法和语法分析、类型检查、语义分析、优化以及生成汇编代码。
1 | gcc -S main.i -o main.s |
如果变量未声明、括号不匹配或者类型使用错误,通常会在这一阶段报错。
3.4 汇编
汇编器将汇编代码转换成目标文件:
1 | gcc -c main.s -o main.o |
目标文件已经包含机器指令,但其中可能仍有尚未解析的函数或全局符号,因此通常不能直接作为完整程序运行。
3.5 链接
链接器把多个目标文件、库文件和运行时支持代码组合成最终可执行文件:
1 | gcc main.o -o main |
如果代码中调用了一个只声明却没有定义的函数,源文件可能编译成功,但链接时会报告未定义符号。
3.6 多文件工程
假设工程中包含:
1 | main.c |
它们会先分别编译:
1 | main.c → main.o |
再共同链接:
1 | main.o + add.o + 库文件 → 可执行程序 |
对应命令:
1 | gcc -c main.c -o main.o |
也可以让 GCC 驱动程序一次完成:
1 | gcc main.c add.c -o app |
3.7 Windows 与 Linux 文件扩展名
| 文件类型 | Windows 常见扩展名 | Linux 常见扩展名 |
|---|---|---|
| C 源文件 | .c |
.c |
| 头文件 | .h |
.h |
| 目标文件 | .obj |
.o |
| 可执行文件 | .exe |
通常没有固定扩展名 |
| 静态库 | .lib |
.a |
| 动态库 | .dll |
.so |
3.8 编译错误与链接错误
编译错误
常见原因:
- 语法错误;
- 类型不匹配;
- 标识符未声明;
- 缺少分号;
- 函数声明不可见。
链接错误
常见原因:
- 函数只有声明,没有定义;
- 忘记链接某个目标文件;
- 库文件没有加入;
- 同一个全局符号被重复定义;
- 函数名称或参数不一致。
判断错误发生在编译阶段还是链接阶段,是调试多文件工程的基本能力。
四、项目、源文件和头文件
4.1 源文件
C 语言通常把 .c 文件称为源文件,主要保存函数定义、全局变量定义和具体实现。
1 | // add.c |
4.2 头文件
.h 文件称为头文件,通常保存函数声明、类型声明、结构体定义、宏定义和外部变量声明。
1 | // add.h |
4.3 使用头文件
1 | // main.c |
这里:
add.h告诉编译器Add的函数签名;add.c提供Add的真正实现;- 链接器最终把
main.o和add.o连接起来。
4.4 尖括号与双引号
1 |
一般约定:
<...>用于标准库或配置的系统头文件;"..."用于当前项目中的自定义头文件。
具体搜索路径由编译器和项目配置决定。
4.5 不要直接包含 .c 文件
不推荐:
1 |
源文件应当独立编译,接口通过头文件共享。直接包含 .c 文件容易导致重复定义,也会破坏正常的模块边界。
五、第一个 C 语言程序
1 |
|
运行结果:
1 | hello C |
5.1 逐行解释
包含标准输入输出头文件
1 |
stdio.h 中声明了 printf 等标准输入输出函数。
定义 main 函数
1 | int main(void) |
main 是程序入口,返回类型是 int。
调用 printf
1 | printf("hello C\n"); |
这条语句把字符串输出到标准输出,\n 表示换行。
返回程序状态
1 | return 0; |
返回 0 通常表示程序正常结束。
六、main 函数
6.1 main 是程序入口
操作系统启动程序后,C 运行时完成必要初始化,然后调用 main 函数。
一个可执行程序只能有一个入口,因此正常工程中只能定义一个 main 函数。即使工程包含多个 .c 文件,也只能有一个 main 定义。
6.2 main 的常见标准形式
不接收命令行参数:
1 | int main(void) |
接收命令行参数:
1 | int main(int argc, char* argv[]) |
其中:
argc表示命令行参数数量;argv保存各个参数字符串。
6.3 不要写 void main
下面的写法不属于可移植的标准形式:
1 | void main() |
推荐始终使用:
1 | int main(void) |
6.4 int main() 与 int main(void)
在 C 语言中,int main() 的空参数列表表示参数信息未指定;int main(void) 则明确表示函数不接收参数。
因此,在 C 代码中推荐使用 int main(void)。
需要注意,这一点与 C++ 不同。在 C++ 中,空参数列表表示没有参数。
6.5 main 的常见错误
- 把
main写成mian; - 漏掉参数列表的括号;
- 使用中文括号、引号或分号;
- 忘记函数体大括号;
- 一个工程定义多个
main; - 把源文件误建成
.cpp; - 写成非标准的
void main。
七、printf 与标准库
7.1 printf 是什么
printf 是 C 标准库中的格式化输出函数,声明在:
1 |
它通常把结果写到标准输出。
7.2 常用格式说明符
1 | int age = 20; |
| 格式 | 对应参数 | 说明 |
|---|---|---|
%d |
int |
有符号十进制整数 |
%u |
unsigned int |
无符号十进制整数 |
%c |
int |
输出一个字符 |
%s |
char* |
输出以 '\0' 结尾的字符串 |
%f |
double |
输出浮点数 |
%zu |
size_t |
输出 sizeof 等结果 |
%p |
void* |
输出地址 |
%% |
无参数 | 输出百分号 |
7.3 printf 中的 %f 与 %lf
调用可变参数函数时,float 会发生默认参数提升,转换成 double。
因此,在 printf 中:
1 | printf("%f\n", 3.14); |
%f 与 %lf 对浮点输出具有相同效果,通常推荐写 %f。
但在 scanf 中二者不同:
1 | float f = 0.0f; |
%f需要float*;%lf需要double*。
不要把 printf 与 scanf 的规则混在一起。
7.4 格式与参数必须匹配
错误示例:
1 | double value = 3.14; |
printf 根据格式字符串解释后面的参数。如果格式说明符与实际参数类型不匹配,行为可能未定义。
推荐开启编译器警告:
1 | gcc -std=c11 -Wall -Wextra -Wpedantic main.c |
7.5 为什么必须包含 stdio.h
头文件中包含 printf 的函数声明。声明让编译器知道函数名称、参数形式和返回值类型。
现代 C 语言不允许依赖隐式函数声明。使用库函数前,应包含对应头文件。
7.6 什么是标准库
为了避免重复实现输入输出、字符串处理和内存管理等常见功能,C 标准规定了一组标准库接口。
| 头文件 | 典型功能 |
|---|---|
stdio.h |
输入输出 |
stdlib.h |
内存分配、转换、程序控制 |
string.h |
字符串和内存块处理 |
math.h |
数学函数 |
ctype.h |
字符分类和转换 |
time.h |
时间和日期 |
assert.h |
断言 |
标准规定函数行为,各编译器和平台提供具体实现。编译器厂商还可能提供扩展函数,但扩展函数不一定能跨平台使用。
八、C 语言关键字
8.1 什么是关键字
关键字是被 C 语言保留并赋予特殊语法意义的单词,例如 int、if、return 和 sizeof。
程序员不能把关键字用作变量名、函数名或其他普通标识符。
8.2 C90 的 32 个关键字
1 | auto break case char const continue |
8.3 按用途分类
基本类型与复合类型
1 | char short int long signed unsigned |
存储类别与类型限定
1 | auto register static extern |
流程控制
1 | if else switch case default |
其他
1 | sizeof typedef |
sizeof 是运算符,不是普通函数。
8.4 后续标准新增关键字
C99 增加了:
1 | inline restrict _Bool _Complex _Imaginary |
C11 又增加了与原子操作、泛型选择、静态断言和线程存储等相关的关键字。
学习初期不必一次记住所有关键字。随着类型、循环、函数、结构体和内存管理等内容逐步展开,再理解它们更有效。
九、字符与 ASCII
9.1 字符常量
C 语言使用单引号表示字符常量:
1 | 'A' |
双引号表示字符串:
1 | "A" |
| 写法 | 含义 |
|---|---|
'A' |
字符常量 |
"A" |
包含 'A' 和 '\0' 的字符串 |
在 C 语言中,普通字符常量 'A' 的类型是 int,但它通常可以安全地存入 char。
9.2 为什么需要字符编码
计算机最终保存的是数字。字符编码负责建立“字符与数值”之间的对应关系。
ASCII 是常见的字符编码基础。现代系统通常使用 ASCII 兼容编码表示基础英文字符。
9.3 常见 ASCII 范围
| 字符范围 | ASCII 十进制值 |
|---|---|
'0' 到 '9' |
48 到 57 |
'A' 到 'Z' |
65 到 90 |
'a' 到 'z' |
97 到 122 |
| 换行 LF | 10 |
| 空字符 NUL | 0 |
大小写英文字母在 ASCII 中相差 32。不过,编写字符转换代码时更推荐使用 <ctype.h> 中的 tolower 和 toupper,而不是手动加减 32。
9.4 字符与整数可以互相观察
1 |
|
在 ASCII 环境下输出:
1 | Q |
9.5 输出可打印 ASCII 字符
ASCII 中通常把 32 到 126 视为可打印字符,127 是 DEL 控制字符,不属于普通可打印字符。
1 |
|
9.6 数字字符转换为整数
数字字符在字符集中连续排列,因此可以写:
1 | char ch = '7'; |
十、字符串与空字符
10.1 C 语言中的字符串
C 语言没有独立的内置字符串类型。字符串通常表示为:
一段连续字符,并以空字符
'\0'作为结束标志。
例如 "abcdef" 在内存中实际包含:
1 | 'a' 'b' 'c' 'd' 'e' 'f' '\0' |
10.2 sizeof 与 strlen
1 |
|
输出:
1 | 4 |
区别是:
sizeof("abc")计算整个字符数组所占字节数,包含'\0';strlen("abc")统计'\0'之前的字符数量,不包含'\0'。
10.3 两种字符数组初始化
1 | char arr1[] = {'a', 'b', 'c'}; |
它们的内存内容不同:
1 | arr1: 'a' 'b' 'c' |
因此:
1 | sizeof(arr1) == 3 |
10.4 没有 \0 时不能使用 %s
下面的代码是错误的:
1 | char arr1[] = {'a', 'b', 'c'}; |
%s 会不断读取字符,直到遇到 '\0'。但 arr1 中没有结束标志,函数可能继续访问数组边界之外的内存。
它有时会打印“随机字符”,也可能崩溃。正式说法不是“必然打印乱码”,而是:
访问越界导致未定义行为。
正确写法:
1 | char arr1[] = {'a', 'b', 'c', '\0'}; |
10.5 字符串中间的 \0
1 | printf("%s\n", "abc\0def"); |
输出 abc。字符串字面量实际包含:
1 | 'a' 'b' 'c' '\0' 'd' 'e' 'f' '\0' |
因此:
1 | sizeof("abc\0def") == 8 |
10.6 字符数组与字符串字面量指针
1 | char arr[] = "hello"; |
arr是一份可以修改的字符数组副本;ptr指向字符串字面量;- 修改字符串字面量会导致未定义行为。
1 | arr[0] = 'H'; // 正确 |
实践中应使用 const char* 接收字符串字面量,避免误修改。
10.7 ‘\0’、’0’、0 和 NULL
| 写法 | 含义 |
|---|---|
'\0' |
数值为 0 的空字符 |
'0' |
数字字符,在 ASCII 中值为 48 |
0 |
整数常量零 |
NULL |
空指针常量宏 |
'\0' 的数值为 0,但它与字符 '0' 完全不同。NULL 用于指针语境,不应该拿来表示普通字符串结束字符。
十一、转义字符
11.1 什么是转义字符
反斜杠 \ 会改变后续字符的含义:
1 | printf("abc\ndef"); |
其中 \n 不是反斜杠和字母 n 两个普通字符,而是一个换行转义序列。
11.2 常见转义序列
| 转义序列 | 含义 |
|---|---|
\n |
换行 |
\r |
回车 |
\t |
水平制表 |
\v |
垂直制表 |
\b |
退格 |
\f |
换页 |
\a |
警报 |
\\ |
反斜杠 |
\' |
单引号 |
\" |
双引号 |
\? |
问号 |
\0 |
数值为 0 的空字符 |
不同终端对 \a、\b、\f 和 \v 的显示效果可能不同。
11.3 输出引号和反斜杠
1 |
|
输出:
1 | ' |
11.4 八进制转义
八进制转义形式为 \ddd,最多使用三个八进制数字。
1 | printf("%c\n", '\130'); |
八进制 130 等于十进制 88,在 ASCII 中对应字符 X。\0 也可以看成八进制转义的一种特殊形式。
11.5 十六进制转义
十六进制转义以 \x 开始,后面会继续读取十六进制数字,并不严格限制为两个数字。
1 | printf("%c\n", '\x30'); |
十六进制 30 等于十进制 48,在 ASCII 中对应字符 0。
如果后面紧跟的字符仍然属于十六进制数字,可能被继续吞入同一个转义序列。必要时可以拆分字符串字面量:
1 | const char* text = "\x41" "BC"; |
相邻字符串字面量会在编译阶段自动连接。
11.6 Windows 路径中的反斜杠
字符串 "C:\test\new" 中的 \t 会被解释为制表符,\n 会被解释为换行。
正确写法:
1 | "C:\test\new" |
或者在部分场景使用正斜杠:
1 | "C:/test/new" |
十二、C 语言中的语句
12.1 什么是语句
C 程序由声明、表达式和语句等结构组成。语句用于描述程序执行的动作和流程。
入门阶段常见语句包括:
- 空语句;
- 表达式语句;
- 复合语句;
- 选择语句;
- 循环语句;
- 跳转语句。
需要注意,函数调用通常属于表达式,后面加分号后构成表达式语句,并不是与表达式语句完全独立的标准语法类别。
12.2 空语句
一个单独的分号就是空语句:
1 | ; |
例如:
1 | while (getchar() != '\n') |
循环体就是空语句。
12.3 空语句造成的常见错误
1 | if (score >= 60); |
if 后面的分号已经构成完整的空语句,因此后面的大括号不受 if 控制,会无条件执行。
同样要警惕:
1 | for (int i = 0; i < 10; ++i); |
12.4 表达式语句
表达式后面添加分号,就构成表达式语句:
1 | int a = 10; |
12.5 函数调用语句
函数调用表达式后面加分号:
1 | printf("hello\n"); |
从标准语法角度看,它们属于表达式语句。
12.6 复合语句
一对大括号中的零条或多条内容构成复合语句,也叫代码块:
1 | { |
代码块还会形成作用域,块内声明的普通局部变量在块外不可见。
12.7 控制语句
选择语句
1 | if (condition) |
1 | switch (value) |
循环语句
1 | while (condition) |
跳转语句
break:结束循环或switch;continue:跳过本轮循环剩余部分;goto:跳转到函数内标签;return:结束函数并返回。
十三、注释
13.1 注释的作用
注释用于帮助人理解代码,编译器不会把注释当作正常程序逻辑执行。
好的注释应该重点解释:
- 为什么这样设计;
- 有什么特殊边界;
- 为什么不能采用看似更简单的方案;
- 参数和返回值有什么约束;
- 哪些行为容易误用。
不需要为一眼就能看懂的代码逐行翻译。
不推荐:
1 | ++count; // count 加一 |
更有价值:
1 | // 跳过下标 0,因为它保存的是协议头而不是有效数据。 |
13.2 块注释
1 | /* 这是一条注释 */ |
块注释可以跨行:
1 | /* |
13.3 块注释不能嵌套
下面的写法有问题:
1 | /* |
编译器遇到第一个 */ 就会结束块注释,后面的代码可能产生语法错误。
13.4 单行注释
1 | // 这是一条单行注释 |
// 注释从双斜杠开始,一直延伸到当前行末尾。它从 C99 开始成为标准 C 语法。
13.5 字符串中的注释符号
1 | printf("// hello /* world */\n"); |
双引号内部的 // 和 /* */ 都只是普通字符串内容,不具有注释作用。
13.6 注释会被替换为空白
在翻译过程中,注释会被替换为空白字符。
1 | min/* comment */Value |
不会连接成 minValue,而会形成近似于 min Value 的两个记号。
13.7 临时屏蔽大段代码
因为块注释不能嵌套,使用 /* */ 临时包住本身含有块注释的代码很容易出错。
可以考虑条件编译:
1 |
|
正式代码仍应及时删除无用逻辑,并依靠版本控制保存历史,而不是长期保留大量注释掉的代码。
十四、完整示例
下面的程序综合演示 main、printf、字符和整数、字符串、sizeof 与 strlen、转义字符、语句和代码块。
1 |
|
运行结果:
1 | age: 20 |
十五、常见错误汇总
15.1 文件扩展名写成 .cpp
文件可能被当成 C++ 编译,导致学习环境与目标语言不一致。
15.2 main 拼写错误
把 main 写成 mian 时,链接器找不到程序入口。
15.3 使用中文符号
错误:
1 | printf(“hello”); |
正确:
1 | printf("hello"); |
15.4 忘记分号
编译器可能在下一行附近报错,因此要同时检查报错位置的上一行。
15.5 格式说明符不匹配
printf 格式字符串与参数类型不匹配可能导致未定义行为。
15.6 字符数组没有 \0
不带 '\0' 的字符数组不能直接交给要求 C 字符串的接口。
15.7 if 或 for 后误写分号
这个分号会形成空语句,使后续代码块脱离原来的控制结构。
15.8 使用库函数却不包含头文件
编译器无法获得正确函数声明,可能产生诊断或错误的调用行为。
15.9 认为块注释可以嵌套
/* */ 遇到第一个结束符就结束,不能直接嵌套。
15.10 把转义序列当成两个字符
'\n' 是一个字符转义序列,不是反斜杠和字母 n 两个独立字符。
十六、常见面试与复习问题
16.1 编译器和 IDE 有什么区别?
编译器负责把源代码转换为目标代码;IDE 提供代码编辑、项目管理、编译和调试等完整开发环境。
16.2 C 程序生成可执行文件经过哪些阶段?
通常包括预处理、编译、汇编和链接。多个源文件分别生成目标文件,再由链接器组合成可执行程序。
16.3 头文件和源文件分别放什么?
头文件主要放声明和公共类型,源文件主要放定义和实现。
16.4 为什么一个程序只能有一个 main?
main 是程序入口。一个可执行程序必须具有唯一、明确的入口。
16.5 printf 为什么需要包含 stdio.h?
stdio.h 提供 printf 的声明,让编译器能够检查和生成正确调用。
16.6 sizeof 是函数吗?
不是。sizeof 是 C 语言运算符。
16.7 字符常量 ‘A’ 在 C 中是什么类型?
普通字符常量在 C 中的类型是 int,其值对应执行字符集中的编码。
16.8 字符串为什么必须以 \0 结尾?
C 字符串接口通常不额外保存长度,而是通过 '\0' 判断字符串终点。
16.9 sizeof(“abc”) 和 strlen(“abc”) 分别是多少?
1 | sizeof("abc") == 4 |
前者包含字符串结尾的 '\0',后者不统计 '\0'。
16.10 char arr[] = {‘a’,’b’,’c’} 是字符串吗?
严格来说,它只是一个包含三个字符的数组,不是合法的以 '\0' 结尾的 C 字符串。
16.11 ‘\0’ 和 ‘0’ 有什么区别?
'\0' 的数值是 0,表示空字符;'0' 是数字字符,在 ASCII 中数值是 48。
16.12 printf 中 %f 和 %lf 有什么区别?
在 printf 中通常没有实际区别,二者都用于输出 double。在 scanf 中有区别:%f 对应 float*,%lf 对应 double*。
16.13 为什么 %s 输出无 \0 数组是未定义行为?
%s 会继续向后读取,直到找到 '\0'。如果数组内没有终止符,就可能越界访问不属于该数组的内存。
16.14 注释可以嵌套吗?
标准块注释 /* */ 不能嵌套;// 只持续到当前行末尾。
16.15 函数调用语句是不是独立语法类别?
函数调用本身是表达式,函数调用表达式加分号后构成表达式语句。“函数调用语句”是便于初学者理解的常用教学分类。
十七、总结
本文需要重点掌握以下内容:
- C 源代码需要经过预处理、编译、汇编和链接才能运行;
- 编译器负责翻译代码,IDE 提供完整开发环境;
- 多个
.c文件分别编译,再链接成一个程序; - 头文件主要放声明,源文件主要放实现;
- 一个可执行程序只能有一个
main; - 推荐使用标准形式
int main(void); - 使用标准库函数前要包含对应头文件;
printf的格式说明符必须与实际参数匹配;- C 关键字不能用作自定义标识符;
- 字符使用单引号,字符串使用双引号;
- C 字符串以
'\0'作为结束标志; sizeof计算对象大小,strlen统计首个'\0'前的字符数量;- 没有
'\0'的字符数组不能直接作为%s参数; - 转义字符使用反斜杠改变字符含义;
- 一个分号也可以构成空语句;
- 函数调用加分号后属于表达式语句;
- 块注释不能嵌套,字符串中的注释符号只是普通字符;
- 注释应该解释设计意图和特殊约束,而不是逐行翻译代码。