C 程序编译完整流程C源文件(.cASCII文本) → 预处理 → 编译 → 目标文件 (.obj Windows / .o Linux) → 链接 → 可执行文件 (.exe)(.c源文件属于文本文件代码里的字符字母、分号等都是以 ASCII 码保存不是二进制机器码)GCC编译过程通常分为以下几个阶段预处理预处理器如cpp会处理源代码中的宏定义、文件包含#include、条件编译等指令将它们展开并生成一个纯粹的C语言代码文件。编译编译器将经过预处理的源代码转换成汇编语言代码。这个阶段主要是语法分析、语义分析和生成汇编代码。汇编汇编器将汇编代码转换为机器代码也就是目标文件.o文件。链接链接器将目标文件和库文件连接生成最终的可执行文件。结构体和联合体结构体 (struct) 是一种聚合数据结构它能够将不同类型的数据组合在一起每个成员都有独立的内存空间。联合体 (union) 也是一种聚合数据结构它与结构体类似但联合体的所有成员共享同一块内存空间即所有成员共用同一内存地址只有一个成员能够在任何时刻存储值。结构体适用于需要同时存储多个不同数据类型的情况而联合体适用于在同一内存空间中存储不同类型的数据但一次只能使用其中一个成员。const 和 static 的区别一句话表述:const 用来修饰【只读】static 用来修饰【作用域 / 生命周期】1. const只读常量属性作用限定变量的值不能被修改本质还是变量只是只读。1.修饰局部变量该变量在栈上不能赋值修改const int a 10;a 20; // 编译报错不能修改2.修饰指针区分 const int *p / int * const p3.修饰全局变量全局只读变量2. static静态控制生命周期 作用域两个作用分场景1.修饰局部变量函数内部生命周期程序整个运行期间都存在不再是函数调用时创建、退出销毁只初始化一次作用域仍然只能在本函数内部访问voidfunc(){staticinta0;// 只初始化1次a;printf(%d,a);}2.修饰全局变量 / 函数外部作用域限制只能在当前.c 源文件内使用其他文件extern也无法访问内部链接属性生命周期全局程序运行全程存在static不限制读写不加 const 的 static 变量可以正常修改。## 运算符小技巧 用一个char控制8个开关 #define OPEN_FILE 0x1; #define DROP_FILE 0x2; #define OFFICE_FILE 0x4; 定义一个char, char pro 0000 0000; 打开一个开关 pro pro | DROP_FILE; 打开多个开关 pro pro |(DROP_FILE|OFFICE_FILE); 关闭一个开关 pro pro ~DROP_FILE; 关闭多个开关 pro pro ~(DROP_FILE|OFFICE_FILE); ## 数组 1.数组的基本 数组的名字的含义是指数组第一个元素的地址, int arr[5]; arr 和 arr什么区别 arr是第一个元素的地址 arr整个数组的首地址 数据是相同的; 2.二维数组 二维数组的每一项都是一个数组 arr[2][3] {1,2,3},{4,5,6}; arr[1][1] 5; 同理为 *(*(arr1)1) 3.字符数组和字符串的区别字符串一定是\0结尾 strcpy //字符串复制 strcmp //字符串比较函数 strcat //字符串拼接函数 以上三个函数能够自己编码实现使用都有风险 建议使用strncpy strncat strncmp strlen //计算字符串长度 memset //内存设置函数一般用来置零 memset(buf, 0, sizeof(buf)); 4.聚合数据类型 结构体多个类型打包成一个整体用来表示复杂类型 定义结构体 struct Student { char name[20], int age, int id; }st2, *st3; struct Student st; 结构体名字: Student 结构体类型struct Student 结构体变量st、st2、st3 st3是指针类型 typedef struct Student { char name[20], int age, int id; }St, *St2; St stu; St2 stu2 结构体名字Student 结构体类型1、struct Student 2、St 3、St2 指针类型 结构体变量stu、stu2 //stu2是指针 结构体大小计算 1、结构体的总大小一定是结构体内最大的内置类型的倍数; 2、结构体的每个元素位置一定是元素类型大小的倍数,要求起始位置是最大的内置类型的倍数; 联合体多个成员共享同一个内存空间大小按最大的算 枚举整数从0开始递增 ## 函数 组成返回值 函数名 参数列表 函数体 函数名函数的入口地址 函数的设计 1、函数的执行结果 1、返回值带回 2、出参 2、函数需要的参数 1、入参 3、函数是否运行成功 1、返回值带回 2、出参 递归函数: 自己调用自己要有明确的返回 如果函数一直调用自己不反回会发生段错误栈溢出 ## 指针 概念保存地址的变量 指针的运算指针1 实际加的数 是指针指向类型的字节大小 野指针保存的地址不知道是谁 使用野指针的后果不可预计的后果严重的内存运行问题 野指针规避使用完指针后置 NULL》(void *)0 定义指针要初始化 二级指针保证指针的地址 指针函数返回值是指针的函数 少见概念 函数指针保存函数的地址 int Show(int); int (*funcP)(int) Show;//定义函数指针funcP保存Show函数地址 funcP(20); //等价于Show(20); 指针数组数组的每一项都是一个指针 int *p[5]; 数组指针指向数组的指针 int (*p)[5]; 指针的用法 1、堆区内存管理 malloc/calloc申请空间 free释放 2、管理数组 函数传递数组首地址遍历数组 3、函数的地址传递 用于出参 4、函数指针 调用未知函数名但已知地址的函数 代替switch菜单选择