Days15 构造数据类型及内存储存
前言前面我们学习了C语言基础数据类型、数组、函数、指针本篇聚焦构造数据类型及之后的位运算、内存管理核心知识点这部分是C语言项目开发、底层编程、嵌入式开发的高频考点包含结构体 struct 、共用体 union 、枚举 enum 、位运算、动态堆内存管理配套大量代码示例与原理图解适合面试复习、期末备考。一、构造数据类型基础数据类型 int/char/float 只能存储单一数据构造类型可以组合多种不同类型数据分为结构体、共用体、枚举三类。1.1 结构体 struct结构体用于封装一组不同类型的关联数据比如学生信息、日期、坐标每个成员拥有独立内存空间。1.1.1 结构体类型定义cstruct 结构体名 {数据类型1 成员名1;数据类型2 成员名2;数据类型3 成员名3;}; // 末尾分号不可省略示例定义学生结构体cstruct Student {char name[20]; // 姓名char sex; // 性别int age; // 年龄float score; // 分数};1.1.2 结构体变量定义与初始化1. 顺序初始化cstruct Student s1 {zhangsan, m, 18, 90.5f};2. 指定成员初始化推荐可读性高cstruct Student s2 {.name lisi,.score 88.0f,.age 19};1.1.3 结构体成员访问两种访问运算符1. . 结构体普通变量访问成员cprintf(姓名%s 分数%.2f, s1.name, s1.score);2. - 结构体指针访问成员cstruct Student *pstu s1;printf(姓名%s, pstu-name);1.1.4 结构体内存对齐核心考点对齐规则1. 每个成员存储地址必须是自身类型字节数的整数倍2. 结构体总大小必须是内部最大基础类型字节的整数倍3. 可通过 #pragma pack(n) 手动修改对齐字节嵌入式开发常用。示例cstruct Test {char a; // 1字节int b; // 4字节};// 内存布局a占1字节填充3字节对齐再存int b总大小8字节1.1.5 结构体数组 结构体传参1. 结构体数组批量存储多个对象cstruct Student class[4] {{zhangsan,m,18,90},{lisi,f,17,85}};2. 函数传参- 值传递拷贝整个结构体开销大- 指针传递仅传地址效率高工程开发首选c// 值传递void ShowStu(struct Student tmp) {}// 指针传递推荐void ShowStuByPoint(struct Student *pstu) {}1.2 共用体联合体union结构体成员各自独立内存共用体所有成员共享同一块内存空间同一时间只有一个成员有效。1. 定义格式cunion Data {int num;char ch;float f;};2. 内存特点共用体大小等于内部最大成员的字节数修改任意一个成员其余成员数据会被覆盖。3. 拓展大小端判断经典笔试题cunion Endian {int a;char b;};void CheckEndian() {union Endian u;u.a 0x0102;if(u.b 0x02) printf(小端模式);else printf(大端模式);}- 小端低地址存数据低位大端低地址存数据高位。1.3 枚举 enum枚举用于限定变量只能取预设的固定常量本质是 int 类型适合状态、月份、星期等固定场景。1. 基础定义cenum Week {MONDAY, // 默认0TUESDAY, // 1WEDNESDAY, // 2SUNDAY 6 // 手动指定值};2. 特性- 枚举常量默认从0自增- 可手动给某个常量赋值后续常量自动1- 枚举变量只能赋值枚举内常量代码可读性远优于魔数。二、位运算普通运算符操作完整数值位运算直接操作二进制bit位底层驱动、硬件寄存器、权限掩码场景必备。2.1 六大位运算符运算符 名称 功能 按位与 两位均为1结果才为1 按位或^ 按位异或 两位不同为1相同为0~ 按位取反 0变11变0单目运算符 左移 高位舍弃低位补0等价乘2 右移 有符号数补符号位无符号补0等价除22.2 高频实用位运算技巧1. 将数字第n位置1cnum | (1 n);2. 将数字第n位置0cnum ~(1 n);3. 异或交换两个变量不引入第三方临时变量ca a ^ b;b a ^ b;a a ^ b;三、C语言内存分区与动态内存管理3.1 程序五大内存分区图解1. 文本区(.text)存放编译后的代码、函数指令只读2. 数据区- .data 已初始化全局变量、static静态变量- .bss 未初始化全局/静态变量程序启动自动置0- .rodata 字符串常量只读3. 栈区(stack)操作系统自动管理存储局部变量、函数形参、函数返回地址- 局部变量未初始化值随机函数执行完毕自动释放空间4. 堆区(heap)程序员手动管理通过 malloc/free 申请释放- 不主动释放会造成内存泄漏5. 寄存器CPU高速存储 register 变量优先存放于此。3.2 堆区动态内存函数头文件 #include stdlib.h1. malloc(size_t size) 申请指定字节堆内存未初始化返回void*指针2. free(void *ptr) 释放malloc/calloc/realloc申请的堆内存释放后指针置空避免野指针3. calloc(int num, int size) 申请num个size大小内存自动初始化为04. realloc(void *p, size_t newSize) 扩容/缩容已申请的堆空间。示例动态数组c#include stdio.h#include stdlib.hint main() {int *arr NULL;int len 5;arr (int *)malloc(len * sizeof(int));if(arr NULL) { // 必须判断内存申请失败perror(malloc fail);return -1;}// 使用数组for(int i0; ilen; i) arr[i] i;// 释放内存free(arr);arr NULL; // 防止野指针return 0;}3.3 内存泄漏与野指针1. 内存泄漏 malloc 申请堆内存程序结束前未 free 长期运行程序占用内存持续上涨2. 野指针未初始化指针、已释放堆内存的指针解引用会导致程序崩溃3. 空指针 NULL 指向地址0只读禁止 *NULL 操作。四、综合实战作业配套练习题练习1结构体综合日期工具集封装 struct date 实现闰年判断、计算当天是年内第几天、计算年内剩余天数c#include stdio.hstruct date {int year;int month;int day;};// 输入年月日void GetCurDate(struct date *pday);// 判断闰年int IsLeepYear(int tmpyear);// 计算当前是一年第几天int GetDayOfYear(struct date day);// 计算当年剩余天数int GetLeftDayOfYear(struct date day);练习2数字累加 aaaaaa...输入a和n计算 3 33 333 3333 33333cint CalcSum(int a, int n) {int sum 0, tmp 0;for(int i0; in; i) {tmp tmp * 10 a;sum tmp;}return sum;}练习33*3二维数组对角线最值输入9个数字存入3行3列数组返回主对角线最大值、辅对角线最小值cvoid InputMatrix(int a[3][3]);void GetDiagonal(int a[3][3], int *max_main, int *min_second);练习4手写字符串库函数不使用string.h自行实现 mystrlen/mystrcpy/mystrcat/mystrcmp 、字符串倒置c// 自定义字符串长度int mystrlen(char *str) {int len 0;while(str[len] ! \0) len;return len;}五、总结1. 构造数据类型分工- struct 多类型独立内存存储复合实体- union 多类型共享内存大小端、数据复用场景- enum 限定常量取值优化代码可读性2. 位运算操作二进制底层硬件开发必备熟记置1、置0、交换变量经典用法3. 内存分区分清栈、堆、数据区、文本区堆内存必须手动free规避内存泄漏、野指针4. 结构体指针动态内存是C语言项目核心组合所有工程开发都会高频使用。