目录
一、程序结构与执行原理
1、自然语言 vs 计算机语言
自然语言:人类交流工具(汉语/英语)含模糊性与语境依赖
计算机语言:严格语法规则(C/Python)实现精准指令传达
UNIX系统开发工具:C语言最初为UNIX系统开发设计,通过cc hello.c命令编译
编译器 | 适用场景 | 特点 |
MSVC | Windows平台开发 | 深度集成VS,调试功能强大 |
GCC | 跨平台嵌入式开发 | 支持多架构,优化选项丰富 |
Clang | macOS/iOS开发 | 错误提示友好,兼容C++标准 |
2、编译型语言特性
编译过程:源代码(.c) → 目标文件(.obj) → 可执行文件(.exe),执行效率高1
VS2022典型流程:cl.exe → 生成目标文件 → link.exe链接 → 生成可执行程序
GCC对比:gcc -o hello hello.c
直接生成二进制文件
源代码文件 编译器 cl.exe 目标文件 链接器 link.exe ┌─────────┐ ┌───────────────┐ ┌──────────┐ ┌───────────────┐ ┌───────────┐ │ test.c ├───────►│ 编译 ├───► │ test.obj │ │ │ │ │ ├─────────┤ │ (cl.exe) │ ├──────────┤ │ │ │ │ │ add.c ├───────►│ ├───► │ add.obj ├───────►│ 链接 ├─────►│ |xxx.exe │ ├─────────┤ └───────────────┘ ├──────────┤ │ (link.exe) │ │ │ │ xxx.c ├───────► │ xxx.obj │ │ │ │ │ └─────────┘ └──────────┘ └───────────────┘ └───────────┘
1)编译阶段:
每个 .c
源文件(test.c
、add.c
、xxx.c
)通过编译器 cl.exe
独立编译,生成对应的 .obj
目标文件。
2)链接阶段:
所有 .obj
文件(test.obj
、add.obj
、xxx.obj
)通过链接器 link.exe
合并,并可能结合其他链接库,最终生成可执行文件 xxx.exe
。
二、核心语法特性
1、main函数规范
入口唯一性:程序执行从main
开始且唯一存在
参数写法:
// 无参数
int main(void) {...}
// 命令行参数
int main(int argc, char *argv[]) {...}
返回类型对应:必须使用return
指定整型返回值(通常0表示成功
2、浮点数精度控制
3.5f的必要性:默认浮点数为double
(8字节),后缀f
强制为float
(4字节)
精度损失示例:
float a = 0.1; // 可能精度丢失(隐式转换)
float b = 0.1f; // 无精度损失
三、输入输出机制
1、printf函数细节
1)占位符与机器对齐:
格式符 | 类型 | 内存对齐要求 |
%d | int | 4字节边界对齐 |
%lld | long long | 8字节边界对齐 |
2)平台差异:
32/64位系统中long
类型长度不同(需stdint.h
明确类型)
2、标准I/O与低级I/O
1)文件描述符:UNIX系统使用,0(stdin)
, 1(stdout)
, 2(stderr)
2)read/write系统调用:
// 读取最多100字节到缓冲区
ssize_t n = read(0, buffer, 100);
write(1, buffer, n); // 回显到终端
四、关键数据结构与编码
1、ASCII编码体系
特殊字符编码:
'\n' = 10 (0x0A) | '0' = 48 (0x30)
'A' = 65 (0x41) | 'a' = 97 (0x61)
进制表达式转换:
printf("%c", 0x41); // 输出'A'(十六进制)
printf("%c", 0101); // 输出'A'(八进制)
2、字符串与空终止符
隐式添加\0
:字面量字符串char s[] = "abc"
自动补\0
(占4字节)
越界防护机制:
char s[3] = {'a','b','c'}; // 末尾无\0,printf可能越界
char t[4] = "abc"; // 正确带终止符的声明
五、语法规范与安全性
1、转义字符深层作用
三字母词问题(现以用不到):
printf("??!"); // 输出为 |(需转义为\?\?!)
printf("??="); // 输出为 #(需转义为\?\?!)
printf("??("); // 输出为 [(需转义为\?\?!)
printf("??<"); // 输出为 {(需转义为\?\?!)
printf("??'"); // 输出为 ^(需转义为\?\?!)
printf("??-"); // 输出为 ~(需转义为\?\?!)
内存安全应用:
printf("C:\\Program Files\\"); // 正确路径表示
2、标识符命名规则
合法性要求:可包含字母/数字/下划线,不得以数字开头
工程规范:
1)禁止前导双下划线:避免与系统关键字冲突(如__FILE__)3
2)自解释命名:int max_speed优于int a
六、编译器与调试支持
1、类型转换安全策略
1)强制转换风险:
float *p = (float*)# // 内存布局不一致时导致数据错误
2)防御性编程:
优先使用显式类型转换并添加断言验证
2、调试器辅助技巧
1)内存布局观测:
在VS调试器中查看变量实际存储的十六进制值
2)断点分析越界:
通过内存窗口验证字符串是否包含\0
七、printf和库函数
1、printf函数机制
标准输出功能:
通过printf("format", args)在终端打印内容
占位符与类型匹配:
%d→整型,%c→字符,%f→浮点数(%lf用于double),%s→字符串,%p→指针地址
2、库函数的调用规范
1)头文件依赖:使用库函数前需包含对应头文件(如stdio.h支持I/O操作)
2)标准库由编译器厂商按规范实现(如strlen、malloc属于标准库函数)
八、关键字
1、C语言关键字特性
1)保留字分类:系统级(如void、sizeof)、流程控制(如if、for)、类型修饰(如const)
2)不可重定义规则:程序员定义的标识符不能与关键字重复
3)部分C99新增关键字:inline、_Bool、restrict等
九、字符与ASCII编码
1、ASCII编码体系
可打印字符范围:32(空格)~126(~)2
特殊值举例:
A=65(0x41),a=97(0x61),0=48(0x30)\n=10(换行符),\0=0(字符串结束标志)
2、字符处理技巧
大小写转换:通过ASCII差值('a'-'A'=32
)实现:
char lower = 'C' + 32; // 小写'c'
十、字符串与\0
1、字符串存储规则
隐式终止符:"abc"实际存储为[a][b][c][\0](数组长度为4)
内存泄漏风险:未以\0结尾的字符数组可能导致越界访问(如printf意外打印垃圾值)
2、验证示例
char arr1[] = {'a', 'b', 'c'}; // 输出可能包含随机值(缺少\0)
char arr2[] = "abc"; // 正确输出(自动补\0)
十一、转义字符
1、常规转义字符
\n:换行符(ASCII 10)
\t:水平制表符(ASCII 9)
\\:表示单个反斜杠,防止路径冲突(如 C:\\Program Files\\)1
\":在字符串内表示双引号(printf("文\"本");)
\0:空字符,用于终止字符串(如 char s[] = "abc\0def"; 实际输出 abc)
2、ASCII 编码表示
八进制形式:\ddd(十进制取值范围 0~255)
示例:\130 → ASCII 88 → 字符 X
十六进制形式:\xhh(可表示扩展字符)
示例:\x30 → ASCII 48 → 字符 0
3、IO 函数中的转义处理
输入流空白符:\n、\t等均视为空白符,scanf("%s", str)自动跳过前置空白
强制读取非空白符:
scanf("%c", &ch); // 读取任意字符(包括空白符)
scanf(" %c", &ch); // 跳过空白符后读取字符
4、易错示例
(1)无效转义导致未定义行为
问题代码:printf("\z");
后果:编译器可能忽略\z直接输出字符z,也可能报错或输出乱码
(2)跨行连接的反斜杠
行尾续行符:在预处理阶段将续行符\
与换行符合并(适用于长字符串定义):
const char* msg = "This is a very long string \
that spans multiple lines."; // 实际无换行效果
十二、语句分类
1、五类语句详解
空语句:仅包含分号(如;),用于占位或循环体省略
表达式语句:表达式加分号(如a = 5;)
函数调用语句:函数名加参数及分号(如printf("Hello");)
复合语句:{}包裹的代码块(如函数体、循环体)
控制语句:
分支:if/switch
循环:for/while/do-while
跳转:break/continue/return
十三、注释规范
1、注释形式与限制
块注释:/* ... */,可跨行但不能嵌套,/**/ 的这个注释也不⽀持嵌套注释, /* 开始注释后,遇到第
⼀个 */ 就认为注释结束了。
行注释://至行尾(C99支持)
上下文规范:编译后注释被替换为空格(a/*注释*/b等价于a b)
2、注释实践准则
避免冗余:不因简单代码重复注释(如i++; // 自增为无效注释)
定位清晰:注释与代码相邻(上或右),避免下方注释易被忽视
版本声明:文件头部说明版权及版本信息(如// (c) 2023 [Author])
习题
知识点:
1、EOF一般用来作为检测文本文件的末尾
2、typedef是用来给类型取别名的关键字
3、switch:当变量表达式的内容与某个case后的常量相等后,就执行该case下的语句,break表示该case以后的内容不会执行,如果没有跟break,会继续执行当前case之后的case分支。当变量表达式的内容没有与那个case匹配,就会执行default下的内容。switch中常用的关键字:case 、break、default,当然case中语句比较复杂时,可能会用if进行判断。continue是用来结束本次循环的,而switch不是循环,因此其中不能使用continue关键字。
4、C语言关键字:C语言定义的,具有特定含义、专门用于特殊用途的C语言标识符,也称为保留字define不是关键字,是编译器实现的,用来定义宏的预处理指令,不是C语言中的内容。 int、struct和continue都是C语言中包含的关键字。
5、C语言规定,在一个源程序中,main函数的位置( C)
main函数的位置可以在任意位置,但是如果在主函数之中调用了哪些函数,必须在main函数前对其所调用函数进行生命或包含其被调用函数的头文件。
A.必须在最开始
B.必须在库函数的后面
C.可以任意
D.必须在最后
集成开发环境:一般都是将编辑、编译、链接、调试等功能集成在一起的一个开发环境,集成开发环境简称IDE,集成开发环境使用起来方便,大大提升了开发和调试的效率
头文件与源文件:很多C语言编译器就是通过文件的后缀来区分是源文件还是头文件的,一般都是要明确的写出文件后缀的头文件的后缀是.h,是header的意思源文件的后缀是.c,在稍微复杂的C语言程序中,头文件是很有必要的,一般是用来函数声明、类型声明等 。
main函数:一个C语言程序中的main函数,有且仅有一个main函数的名字是固定的,编译器以main函数作为程序的入口,程序是从main函数的第一行开始执行的。
C语言的编译和链接:C语言是一门编译型计算机语言,代码需要经过编译和链接生成可执行程序才能运行的,C语言代码经过编译生成目标文件,目标文件和链接库通过链接生成可执行程序。
下面代码结果:随机值
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = {'b', 'i', 't'};
printf("%d\n", strlen(arr));
return 0;
}
strlen是用来获取字符串的有效长度的,结尾标记'\0'不包含在内。strlen获取的规则非常简单:从前往后依次检测,直到遇到'\0'是就终止检测。
ASCII编码:
小写字母的ASCII码值-32就能得到对应的大写字母的ASCII码值,小写字母的ASCII码值比对应的大写字母的ASCII码值更大的。