顺序表的动态分配
文章目录代码代码解读类型定义InitList ()含义IncreaseSize()含义流程规范说明注意代码#includestdlib.h#defineInitSize10//默认的最大长度typedefstruct{int*data;// 指示动态分配数组的首地址intMaxSize;// 顺序表的最大容量intlength;// 顺序表的当前有效长度}SeqList;// 顺序表的类型定义// 初始化动态顺序表voidInitList(SeqListL){// malloc申请连续堆内存L.data(int*)malloc(InitSize*sizeof(int));L.length0;L.MaxSizeInitSize;}// 扩容函数增加动态数组的长度voidIncreaseSize(SeqListL,intlen){int*pL.data;// 先保存旧数组首地址// 开辟更大的新空间L.data(int*)malloc((L.MaxSizelen)*sizeof(int));// 把旧数据拷贝到新空间for(inti0;iL.length;i){L.data[i]p[i];}L.MaxSizeL.MaxSizelen;// 更新最大容量free(p);// 释放旧数组内存防止内存泄漏}intmain(){SeqList L;// 栈上创建顺序表结构体InitList(L);// 初始化IncreaseSize(L,5);// 扩容5个int空间return0;}和静态顺序表核心区别静态int data[MaxSize]数组空间固定在栈无法扩容动态int *data 空间在堆可重新 malloc 扩容。代码解读类型定义结构体里存的是指向堆中动态分配的数组不是固定数组相当于是一张“门牌号纸条”typedefstruct{int*data;// ① 这是一个指针变量将来存放堆区数组的起始地址intMaxSize;// ② 记录当前总共分配了多少个坑位容量intlength;// ③ 记录当前实际用了多少个坑位有效长度}SeqList;栈区 (Stack)SeqList L[ data ] 0x1000 (指向堆区的门牌号)[ MaxSize ] 10[ length ] 0堆区 (Heap)地址 0x1000 → [ 坑0 ][ 坑1 ] … [ 坑9 ] (共 10 个 int40 字节)InitList ()含义可以理解为在堆区“盖房子”把门牌号写在便利贴上voidInitList(SeqListL){// L 是 SeqList 类型变量L.data 就是访问这个自定义成员。L.data(int*)malloc(InitSize*sizeof(int));L.length0;L.MaxSizeInitSize;}malloc(InitSize * sizeof(int))向操作系统申请10 * 4 40字节的连续堆内存。假设返回的起始地址是 0x1000。(int *)强制转换告诉编译器“这块地以后要按 int 的步长4字节来切割”。L.data ...把 0x1000 这个门牌号复制到结构体 L 的 data 这个格子中。** 作用在堆内存开辟一块能存InitSize个int的连续空间返回首地址赋值给L.data**L.length 0; L.MaxSize 10;设置当前有效个数为 0空表记录总容量为 10。IncreaseSize()含义这是整段代码的灵魂操作。当MaxSize不够用时C 语言没有像 JS 那样的自动扩容必须手动实现“找新家、搬家具、拆旧房”。voidIncreaseSize(SeqListL,intlen){int*pL.data;// 步骤1L.data(int*)malloc((L.MaxSizelen)*sizeof(int));// 步骤2for(inti0;iL.length;i){L.data[i]p[i];// 步骤3}L.MaxSizeL.MaxSizelen;// 步骤4free(p);// 步骤5}流程步骤代码物理内存行为通俗类比解释①int *p L.data;临时新建一张便利贴 p把原来的门牌号 0x1000 抄下来。(假设的动态数组首地址)在旧房子被推倒前先拿手机拍下门牌号。②L.data malloc((MaxSizelen)*sizeof(int));在堆区另找一块更大的地皮比如 0x2000把新门牌号 0x2000 写入 L.data。找搬家公司在别处租了更大的新房子。③for… L.data[i]p[i];挨个访问旧地址 0x1000 i4 读取数据写入新地址 0x2000 i4。把旧房子里的家具一件件搬到新房子。④L.MaxSize L.MaxSize len;把容量记录从 10 更新为 15。房产证上更新新家的面积。⑤free(p);把地址 0x1000 的 40 字节彻底归还给操作系统。旧房子产权注销彻底拆掉。规范说明备份旧数组地址int *p L.data;一旦给L.data赋新地址旧内存地址会丢失无法释放造成内存泄漏开辟更大的新堆空间总容量 原有 MaxSize 新增 len循环拷贝所有有效数据只复制0~length-1有效元素垃圾值不用复制更新最大容量L.MaxSize L.MaxSize lenfree 释放旧数组必须写 free。为什么必须有第⑤步极重要如果不写free(p旧的 40 字节内存就永远被占着且由于 L.data 已经指向了 0x2000再也找不到 0x1000 的门牌号首地址了。这就造成了内存泄漏。注意代码中需要提示的是L 是 SeqList 类型变量L.data 就是访问这个自定义成员。