初识C语言 | 第5篇 文章目录链表什么是链表链表 vs 数组核心区别为什么要用链表关键字typedefvoid 关键字笔记核心含义三种基本用法常见禁忌static核心总思想浮点数舍入指针内存的核心作用地址的概念内存容量与寻址能力关键总结指针变量的大小结构体核心作用代码定义示例关键点实战链表什么是链表形象比喻“寻宝游戏”。核心逻辑数据不需要挤在一起只要每个人手里拿着“下一张纸条的地址”就能顺藤摸瓜找到所有数据。节点构成数据 ( data )宝藏线索实际内容。指针 ( next )下一个地点的导航指向下一个节点的地址。链表 vs 数组核心区别内存布局数组像电影院座位必须紧挨着坐连续内存位置固定。链表像手拉手的小朋友可以分散站在操场各处离散内存只要手拉着就行。插入/删除效率数组慢插队需要后面所有人挪位置移动元素。链表快只需改变“拉手”的对象修改指针其他人不用动。查找/访问效率数组快直接报座号就能找到随机访问。链表慢必须从第一个人开始一个一个顺着问过去顺序访问。为什么要用链表灵活不要求大块连续内存利用零碎空间即可存储。动态大小可随时伸缩不需要预先定义长度。高效增删适合频繁插入、删除数据的场景如音乐播放列表、消息队列。关键字typedeftypedef unsigned int uint;//本质为unsigned int无符号整型创建了一个简短的别名unit。目的用uint来代替unsigned int使代码更简洁。typedef struct Node{int data;//数据站用来存储节点所承载的实际数据struct Node* next;//指针域一个指向同类型结构体Node的指针}Node;//重命名为Nodeint main(){unsigned int num 0;uint num2 1;struct Node n;Node n2;return 0;}void 关键字笔记核心含义void 意为“无类型”本身不能用来定义变量或分配内存。三种基本用法无返回值 void func() 表示函数不返回数据。无参数 void func(void) 表示函数不接受任何参数C 语言中必须写 void C 中留空即可。通用指针 void *p 可指向任意类型但不能直接解引用使用前必须强制转换为具体类型。常见禁忌不能定义 void 变量如 void a; 。不能定义 void 数组。static核心总思想static 的本质只有两个作用延长生命周期、缩小作用域。static 修饰局部变量原本普通局部变量的特点1.函数调用时创建​2.函数结束立刻销毁​3.每次调用都会重新初始化//每完成一次循环a都会被初始化故每次输出2222222222void test(){int a 1;a;printf(“%d”, a);}int main(){int i 0;while (i 10){test();i;}return 0;}加 static 之后的变化静态局部变量1.只初始化一次后续调用保留上一次的值不会清零​2.生命周期变长程序运行期间一直存在不随函数结束销毁​3.作用域不变依然只能在当前函数内部使用//完成循环后无需初始化延用上一循环最后的取值生命周期和程序的生命周期相同。输出234567891011void test(){static int a 1;a;printf(“%d”, a);}int main(){int i 0;while (i 10){test();i;}return 0;}为什么要用想让函数多次调用可以记忆数据又不想定义全局变量污染整个程序。static 修饰全局变量原本普通全局变量的特点1.所有文件都能访问、修改​2.容易出现重名冲突、被误改加 static 之后的变化静态全局变量生命周期不变全程程序有效作用域缩小仅限当前 .c 文件别的文件无法引用、无法修改为什么要用私有化变量只给本文件自己用防止跨文件篡改、变量重名冲突。代码//当另外一个源文件定义nint n 99,输出99//当另外一个源文件定义nstatic int n 99,程序错误。static修饰全局变量的狮虎extern int n;int main(){printf(“%d\n”, n);return 0;}static 修饰函数普通函数特点全局可见所有文件都可以调用加 static 之后的变化静态函数仅限当前 .c 文件调用外部文件无法调用代码extern int Add(int x, int y);int main(){int a 10;int b 20;int z Add(a, b);printf(“%d\n”, z);return 0;}1.当另外一个源文件这样定义Add(int x, int y){return x y;}//可正常调用输出30//若在Add(int x, int y)前加static修饰则程序错误。为什么要用1.本文件的工具函数不需要对外暴露2.不同文件可以写同名函数互不冲突3.减少全局符号避免编译链接报错浮点数舍入默认规则遵循IEEE 754标准采用“四舍六入五成双”遇5取偶。核心逻辑尾数 5直接舍去。尾数 5向前进位。尾数 5看前一位奇数进位偶数舍去。设计目的抵消传统“四舍五入”在海量计算中产生的单向积累误差。触发时机主要发生在浮点运算的对阶与规格化阶段尾数右移或溢出时。避坑指南浮点数底层为二进制存在精度丢失严禁直接用 比较浮点数。指针内存的核心作用内存是计算机中程序运行的“工作台”所有正在执行的程序和数据都必须加载到内存中才能被CPU处理。为了高效管理内存被划分为一个个最小单位1字节的存储单元。地址的概念每个内存单元都有一个唯一的编号这个编号就是内存地址。通过地址CPU可以精确定位并访问任意一个内存单元就像通过门牌号找到具体的房间一样。内存容量与寻址能力常见内容容量如4G、8G、16G、32G代表可划分的内存单位总数。32位系统地址总线为32根理论上最大寻址空间为2*32字节即4G。64位系统地址总线更宽可支持远超4GB的内存空间实际受限于硬件和操作系统。关键总结指针的本质就是存储内存地址的变量。理解内存的地址化结构是掌握指针操作如取地址、解引用*的前提。指针变量的大小指针变量的大小取决于地址的大小32位平台下地址是32个bit位即4个字节64位平台下地址是64个bit位即8个字节代码int main(){//int* p;//char* p2;//不管是什么类型的指针都是在创建指针变量//指针变量用来存放地址//指针变量的大小取决于一个地址存放的时候需要多大的空间//32位机器上的地址32bit位 - 4byte所以指针变量的大小是4个字节//64位机器上的地址64bit位 - 8byte所以指针变量的大小是8个字节printf(“%zu\n”, sizeof(char*));//8printf(“%zu\n”, sizeof(short*));//8printf(“%zd\n”, sizeof(int*));//8printf(“%zd\n”, sizeof(char*));//8printf(“%zd\n”, sizeof(double*));//8return 0;}int main(){char* p;intp1,p2,* p3;//p1,p2,p3全是指针int* q1, q2, q3;//只有q1是指针q2,q3是整型return 0;}结构体核心作用描述复杂类型基本数据类型如int char)只能存单一数据。聚合数据结构体能够将不同类型的数据组合在一起用来描述现实中的对象如学生、书本。代码定义示例以“学生”为例包括名字、年龄、性别、学号struct Stu {Char name[19];//名字字符数组int age;//年龄整型char sex[5];//性别字符数组char id[15];//学号字符数组}关键点关键字使用struct定义。成员多样性内部可以包括数组、整型、浮点型等不同类型的数据。语法细节每个成员变量后面必须加分号结束、实战//定义图纸结构体定义创建一种新的数据类型//用struct关键字定义内部可包括多种类型成员。//成员变量以分号结尾不可省略。struct Stu{char name[20];//名字int age;//年龄char sex[10];//性别char tele[12];//电话};//加工工具定义打印函数专门用来输出学生信息的工具函数void print(struct Stu* ps){printf(“%s %d %s %s\n”, (*ps).name,(*ps).age,(*ps).sex,(*ps).tele);//箭头运算符 - 用于结构体指针//ps-name等价于(*ps).name更简洁常用。printf(“%s %d %s %s\n”, ps-name, ps-age, ps-sex, ps-tele);//-//结构体指针变量-成员名}//总指挥主函数入口程序的起点和总指挥//输出总共打印三行。//直接访问s.name)打一行main里只写了一次所以直接打印一次。//指针访问(ps-name)打两行你在print函数里为了演示写了两种方式(*ps)和-写了两遍printf所以它打了两行。int main(){//结构体对象初始化//1.直接在定义时按照成员顺序赋值//2.字符串需要双引号整型直接写数字。struct Stu s { “xiaoli”,26,“nan”,“11111111111” };//点运算符 . 用于结构体变量本身//输出一行xiaoli 26 nan 11111111111//房间一main函数的地盘//场景这是程序的“总指挥室”。//动作在这里你手里直接拿来结构体变量s。//视野在这个房间里只有main函数里的代码时可见的。当你写printf…时电脑只执行这一句指令。//结论它完全不知道外面还有一个叫print的函数更不知道那个函数里写了两种访问方式。它只负责把自己手里的活干完打印一行然后继续往下走。printf(“%s %d %s %s\n”,s.name,s.age,s.sex,s.tele);//房间二print函数的地盘//场景这是一个独立的“加工车间”。//触发只有当main函数执行到print(s)这一行时程序的“控制权”才会瞬间跳转到这个房间。//动作在这个房间里电脑才开始逐行阅读你写的代码//1.看到第一行(*ps).name -执行打印。//2.看到第二行ps-name -执行打印。//视野这里的代码只有在进行这个函数后才会被“看到”和执行。print(s);return 0;}上述代码中的void的作用含义明确告诉编译器print函数执行完打印操作后不会返回任何数据给调用者main函数。原因该函数的唯一目的是输出内容副作用不需要计算结果供后续使用。语法对应C语言规定若函数不返回任何值必须用void占位作为返回类型。简而言之表示该函数只负责“干活”打印不负责“交货”返回数值。