C语言构造类型、位运算与内存分区核心笔记
前言本文整合C语言三大构造数据类型结构体、共用体、枚举、位运算实用技巧、程序内存布局三大高频考点适配Linux C开发笔试、期末复习全部为工程常用知识点。掌握这些内容是深入理解C语言内存管理、数据结构实现和系统编程的基础。一、构造数据类型1. 结构体struct用于封装一组不同类型、相互关联的数据学生信息、日期、商品属性等。1.1 类型定义模板struct结构体名{类型1成员1;类型2成员2;类型3成员3;};1.2 结构体初始化两种写法顺序初始化严格匹配成员顺序structstudents{zhangsan,m,18,90};指定成员初始化推荐顺序不受限制、可读性更高structstudents2{.namezhangsan,.score60};1.3 成员访问规则普通结构体变量使用.访问成员s.name结构体指针使用-访问成员p-name底层本质无论.还是-最终访问的内存地址由成员自身决定。p-name等价于(*p).name。1.4 结构体存储内存对齐必考两条对齐规则成员对齐每个成员只能存放于自身类型长度整数倍的内存地址结构体对齐结构体整体总大小必须等于内部最大基础类型长度的整数倍不足末尾填充空白字节。示例分析structexample{chara;// 1字节偏移0intb;// 4字节需要对齐到4的倍数偏移4shortc;// 2字节偏移8doubled;// 8字节需要对齐到8的倍数偏移16};// 总大小24字节最大类型double8字节24是8的倍数嵌入式场景可手动修改对齐模数#pragmapack(1)// 按1字节对齐取消对齐structpacked_struct{chara;intb;};// 总大小5字节#pragmapack()// 恢复默认对齐1.5 结构体作为函数参数三种形式// 方式1返回结构体值拷贝structstudentGetStuInfo(void);// 方式2值传递拷贝整个结构体开销大无法修改外部数据voidPutStuInfo(structstudenttmpstu);// 方式3指针传递工程标准写法无拷贝开销可以修改外部结构体voidPutStuInfoByPoint(structstudent*pstu);1.6 结构体数组本质就是数组里每一个元素都是完整结构体传参时传递结构体指针即可遍历。structstudentclass[50];voidprint_students(structstudent*stu_array,intcount){for(inti0;icount;i){printf(Name: %s, Score: %d\n,stu_array[i].name,stu_array[i].score);}}2. 共用体联合体 union核心区别结构体所有成员拥有独立内存空间互不干扰共用体所有成员共用同一块内存空间同一时刻只有一个成员有效。内存布局示例uniondata{inti;floatf;charstr[20];};// 大小20字节按最大成员char[20]对齐uniondata my_data;my_data.i10;// 此时i有效printf(%d,my_data.i);// 输出10my_data.f220.5;// 此时f有效i的值被覆盖主要用途节省内存多个选项互斥时使用解析协议数据包同一内存区域按不同数据类型解释判断系统大小端unionendian_test{intnum;charbytes[4];}test{0x12345678};if(test.bytes[0]0x78){printf(Little Endian\n);}else{printf(Big Endian\n);}3. 大小端模式小端模式x86、ARM PC主流低地址存放数据低位字节高地址存放高位字节大端模式网络协议、嵌入式设备低地址存放数据高位字节高地址存放低位字节。示例整数0x12345678在内存中的存储地址增长方向低地址 → 高地址 小端模式0x78 0x56 0x34 0x12 大端模式0x12 0x34 0x56 0x78网络编程注意网络传输使用大端字节序本地主机字节序需要转换#includearpa/inet.huint32_thtonl(uint32_thostlong);// 主机转网络字节序uint32_tntohl(uint32_tnetlong);// 网络转主机字节序4. 枚举enum用来限定变量取值范围星期、月份、状态码。enumweekday{MONDAY,// 0TUESDAY,// 1WEDNESDAY,// 2THURSDAY,// 3FRIDAY,// 4SATURDAY,// 5SUNDAY// 6};enumstatus{OK0,ERROR-1,TIMEOUT100,RETRY// 自动为101};特性枚举常量本质是int整数默认首个枚举值 0后面依次递增1可手动指定某个枚举的值后续自动递增枚举变量只能赋值为枚举常量增强类型安全性。二、位运算2.1 6种位运算符运算符作用示例a0b1100, b0b1010按位与a b 0b1000(8)按位或^按位异或a ^ b 0b0110(6)~按位取反~a 0b1111111111111111111111111111001132位左移低位补0等价乘以2a 2 0b110000(48)右移正数高位补0等价除以2a 2 0b0011(3)2.2 工业高频位运算操作将变量第 n 位设置为 1num|(1n);// 第n位置1将变量第 n 位清零num~(1n);// 第n位清0检查变量第 n 位是否为 1if(num(1n)){// 第n位为1}切换变量第 n 位的值0变11变0num^(1n);// 第n位取反异或实现两个整数交换无需临时变量aa^b;ba^b;// b (a^b)^b aaa^b;// a (a^b)^a b快速判断奇偶性if(num1){// 奇数}else{// 偶数}快速乘除2的幂次num3;// num * 8num2;// num / 4三、C程序内存分区Linux下布局程序运行时内存自上而下分为5大区域区分系统自动管理与程序员手动管理区域1. 栈区 stackOS自动管理存放局部变量、函数形参、函数返回地址特性函数执行完毕自动释放局部变量未初始化值为随机垃圾值栈空间有限通常8MB溢出风险递归过深、超大局部数组会造成栈溢出。voidfunc(){intlocal_var;// 栈区charbuffer[1024];// 栈区staticintstatic_var;// 不在栈区在.bss段}2. 堆区 heap程序员手动管理存放动态内存依靠malloc()、calloc()、realloc()申请free()释放特性生命周期由程序员控制空间较大受系统物理内存限制分配速度较慢注意事项malloc开辟的内存用完不释放 →内存泄漏释放后继续使用 → 野指针重复释放 → 程序崩溃int*arr(int*)malloc(100*sizeof(int));// 堆区分配if(arr!NULL){// 使用arrfree(arr);// 必须释放arrNULL;// 避免野指针}3. 数据段 data / bss.data段已初始化的全局变量、静态局部变量程序加载时分配内存初始值为开发者设定的值.bss段未初始化全局变量、静态变量程序运行前自动清零不占用可执行文件空间intglobal_init10;// .data段intglobal_uninit;// .bss段staticintstatic_local;// .bss段函数内voidfunc(){staticintstatic_init20;// .data段}4. 只读常量区.rodata存放字符串常量、const修饰的全局常量特性只读不可修改尝试修改会触发段错误char*strHello;// Hello在.rodata段constintMAX_SIZE100;// 在.rodata段str[0]h;// 段错误5. 文本段.text存放二进制代码、函数指令特性只读保护防止篡改分区核心总结栈自动分配释放速度快堆手动管理生命周期自由全局变量无论初始化与否都不在栈上字符串常量存在只读段修改字符串字面量会触发段错误static局部变量在数据段生命周期与程序相同。四、知识点区分对照表类型内存特点典型用途大小计算struct 结构体成员各自独占内存封装实体属性学生、日期各成员大小之和 对齐填充union 共用体成员共享同一块内存节省内存、判断大小端、协议解析最大成员的大小enum 枚举限定有限整型取值状态标记、星期月份、错误码通常为int大小4字节五、开发避坑总结结构体传参一律用指针避免值拷贝带来的性能损耗共用体不要同时读写多个成员数据会互相覆盖位修改推荐「或置1、与清零」标准写法避免直接赋值破坏其他位堆内存遵循malloc和free成对书写杜绝内存泄漏字符串常量位于只读段切勿尝试修改局部数组过大考虑使用堆内存避免栈溢出跨平台开发注意大小端问题网络传输必须转换字节序枚举增强代码可读性替代魔法数字。六、实战应用场景6.1 结构体在链表中的应用typedefstructNode{intdata;structNode*next;}Node;// 创建链表节点Node*create_node(intvalue){Node*new_node(Node*)malloc(sizeof(Node));if(new_node){new_node-datavalue;new_node-nextNULL;}returnnew_node;}6.2 位运算在标志位管理中的应用// 定义标志位#defineFLAG_A(10)// 0001#defineFLAG_B(11)// 0010#defineFLAG_C(12)// 0100#defineFLAG_D(13)// 1000unsignedintstatus0;// 设置标志位status|FLAG_A|FLAG_C;// 0101// 清除标志位status~FLAG_A;// 0100// 检查标志位if(statusFLAG_C){printf(FLAG_C is set\n);}// 切换标志位status^FLAG_B;// FLAG_B取反6.3 内存分区在项目中的实际体现#includestdio.h#includestdlib.h#includestring.h// 全局变量 - 数据段intglobal_var100;// .datastaticintstatic_global;// .bssvoidprocess_data(){// 局部变量 - 栈区intlocal_var10;charbuffer[64];// 静态局部变量 - 数据段staticintstatic_local20;// .data// 动态内存 - 堆区char*dynamic(char*)malloc(256);strcpy(dynamic,Heap memory);// 字符串常量 - 只读段char*messageRead-only string;free(dynamic);}// 函数代码 - 文本段intmain(){process_data();return0;}结尾以上内容是Linux C入门核心骨架结构体内存布局是链表、文件操作、网络协议解析的基础位运算广泛用于硬件寄存器操作、标志位管理。掌握这些知识点可以应对笔试面试覆盖80%以上的C语言基础考点提升代码质量写出更安全、高效、可维护的C代码深入系统编程为学习操作系统、网络编程、嵌入式开发打下坚实基础理解底层原理从内存角度理解程序运行机制建议结合实际代码练习通过调试器观察变量地址、内存布局加深对知识点的理解。这些内容不仅是考试重点更是工程实践中必须掌握的核心技能。

相关新闻