当前位置: 首页 > news >正文

C语言-数据结构-1-动态数组

        本章为数据结构初学过程,通过实现动态数组,初步了解数据结构这一门课常见的代码

动态数组,就是能自动扩容的数组,当数组满的时候能够实现高效的扩容,节省系统空间

        那么,在正式学习动态数组之前,我们需要先来了解以下四个常用的内存管理函数

(1)malloc()

函数原型:

(类型说明符*) malloc(unsigned int size);

功能:在内存的动态存储区中分配一块长度为size字节的连续区域。

(2)calloc()

函数原型:

(类型说明符*) calloc(n,size);

功能:在内存的动态存储区中分配n块长度为size字节的连续区域

(3)realloc

函数原型:

(类型说明符*) realloc(void *p,int size);

功能:重新分配堆上的任意指针变量类型所指的空间,使其长度为size个字节,同时会复制原有内容到新分配的堆上存储空间。
注意,size可大可小(如果新的大小大于原内存大小,则新分配部分不会被初始化;如果新的大小小于原内存大小,可能会导致数据丢失)

(4)free()

函数原型:

void  free(void* p);

功能:释放void*p所指的内存空间

以上四个常用的内存管理函数介绍来源于https://blog.csdn.net/jianbai_/article/details/109728592?fromshare=blogdetail&sharetype=blogdetail&sharerId=109728592&sharerefer=PC&sharesource=Mondie4387&sharefrom=from_link

那么,初略了解完四个常用的内存管理函数malloc、calloc、realloc、free函数之后,让我们正式进入数据结构&动态数组的学习

一、头文件引入

stdio.h文件包含了标准输入输出函数,这个大家都非常熟悉

stdlib.h文件包含了四个常用的动态内存分配函数(内存管理函数)(malloc, calloc, realloc, free)

#include <stdio.h>   // 标准输入输出函数
#include <stdlib.h>  // 动态内存分配函数(malloc, calloc, realloc, free)

二、结构体定义

有了头文件,接下来我们定义一个结构体,这个结构体封装了三个元素(data指向动态分配的数组内存,size当前实际存储的元素个数,capacity数组的总容量)

通俗来讲,data就是一个指针,指向了我们要实际存储数据的位置,而size和capacity是用来辅助程序动态改变data的内存大小。

typedef struct {int* data;      // 指向动态分配的数组内存int size;       // 当前实际存储的元素个数int capacity;   // 数组的总容量
} DynamicArray;

三、创建动态数组函数

有了这个前提,在后面的程序中,会经常用到DynamicArray这个结构体别名,用于创建新的结构体变量。

接下来我们来创建动态数组函数。其中,以DynamicArray为模板创建一个新的结构体变量arr,并使用malloc函数为其分配一个内存地址、使用calloc函数为arr的成员arr->data分配一个内存,initial_capacity在main函数中用来接收初始容量。

DynamicArray* create_array(int initial_capacity) {DynamicArray* arr = (DynamicArray*)malloc(sizeof(DynamicArray));  // 分配结构体内存arr->data = (int*)calloc(initial_capacity, sizeof(int));          // 分配数组内存并初始化为0arr->size = 0;                    // 初始时没有元素arr->capacity = initial_capacity; // 设置初始容量return arr;
}

完成了动态数组函数的初步创建,接下来让我们进行下一步

四、添加元素函数

需要实现的功能有:

(1)检查data是否需要扩容,该步骤可通过比较size当前元素数量和capacity总容量来进行判断。

需要扩容的话,我们就要创建new_capacity和*new_data这两个变量来临时存储改变的总容量和新地址,因为扩容的时候不能破坏原有的数据,所以使用了realloc函数来进行扩容。

(2)需要检查内存是否分配成功,通过判断new_data是否为NULL来进行检查,若new_data为空的话,表示分配失败,需要结束整个程序,若成功,在后续就可以把new_data和new_capacity赋值给arr->data和arr->capacity了。

(3)无论是否需要扩容,在本函数的最后一步,需要对arr->data[arr->size]进行赋值,因为本函数的作用就是在data中增加新的数据。当数据增加完之后,要对size进行更新,即加一

void add_element(DynamicArray* arr, int value) {if (arr->size >= arr->capacity) {  // 检查是否需要扩容int new_capacity = arr->capacity * 2;  // 容量翻倍int* new_data = (int*)realloc(arr->data, new_capacity * sizeof(int));if (new_data == NULL) {  // 检查内存分配是否成功printf("内存分配失败!\n");return;}arr->data = new_data;      // 更新数据指针arr->capacity = new_capacity; // 更新容量printf("数组已扩容至 %d\n", new_capacity);}arr->data[arr->size] = value;  // 在末尾添加新元素arr->size++;                   // 元素计数加1
}

五、打印数组函数

void print_array(const DynamicArray* arr) {  // const保护参数不被修改printf("数组元素[大小=%d, 容量=%d]: ", arr->size, arr->capacity);for (int i = 0; i < arr->size; i++) {printf("%d ", arr->data[i]);  // 遍历打印所有元素}printf("\n");
}

六、销毁数组函数

void destroy_array(DynamicArray* arr) {free(arr->data);  // 先释放数组内存free(arr);        // 再释放结构体内存
}

注意:释放顺序很重要,如果先释放结构体,arr->data指针就会丢失。

七、主函数调试

int main() {DynamicArray* arr = create_array(3);  // 创建初始容量为3的数组printf("动态数组演示\n");// 添加10个元素测试自动扩容for (int i = 1; i <= 10; i++) {add_element(arr, i * 10);  // 添加元素10, 20, 30, ..., 100print_array(arr);          // 每次添加后打印状态}destroy_array(arr);  // 释放内存return 0;
}

八、程序编译结果:

动态数组演示
数组元素[大小=1, 容量=3]: 10
数组元素[大小=2, 容量=3]: 10 20
数组元素[大小=3, 容量=3]: 10 20 30
数组已扩容至 6
数组元素[大小=4, 容量=6]: 10 20 30 40
数组元素[大小=5, 容量=6]: 10 20 30 40 50
数组元素[大小=6, 容量=6]: 10 20 30 40 50 60
数组已扩容至 12
数组元素[大小=7, 容量=12]: 10 20 30 40 50 60 70
数组元素[大小=8, 容量=12]: 10 20 30 40 50 60 70 80
数组元素[大小=9, 容量=12]: 10 20 30 40 50 60 70 80 90
数组元素[大小=10, 容量=12]: 10 20 30 40 50 60 70 80 90 100C:\Users\34088\source\repos\数据结构\x64\Debug\数据结构.exe (进程 31832)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

完整代码如下

#include <stdio.h>
#include <stdlib.h>typedef struct {int* data;//指向动态分配数组的指针,本处指针的用处就是将数组存储区域独立出结构体,因此本处位置只存储了一串定长的地址int size;//当前数组中实际存储的元素个数int capacity;//数组的总容量(最多能存储的元素个数)
} DynamicArray;// 创建动态数组//本代码中,调用该函数,先分配3个int大小的地址
DynamicArray* create_array(int initial_capacity) {DynamicArray* arr = (DynamicArray*)malloc(sizeof(DynamicArray));//先为结构体分配地址arr->data = (int*)calloc(initial_capacity, sizeof(int));//后为结构体成员arr->data分配地址arr->size = 0;arr->capacity = initial_capacity;return arr;
}// 添加元素
void add_element(DynamicArray* arr, int value) {if (arr->size >= arr->capacity) {//当实际个数大于总容量时,要进行扩容int new_capacity = arr->capacity * 2;int* new_data = (int*)realloc(arr->data, new_capacity * sizeof(int));if (new_data == NULL) {printf("内存分配失败!\n");return;}arr->data = new_data;arr->capacity = new_capacity;printf("数组已扩容至 %d\n", new_capacity);}arr->data[arr->size] = value;//在数组末尾添加新元素arr->size++;// 增加元素计数
}// 打印数组
void print_array(const DynamicArray* arr) {//其中const的用处是保护arr使其无法被修改printf("数组元素[大小=%d, 容量=%d]: ", arr->size, arr->capacity);for (int i = 0; i < arr->size; i++) {printf("%d ", arr->data[i]);}printf("\n");
}// 销毁数组
void destroy_array(DynamicArray* arr) {//内存释放顺序:必须先释放data指向的内存,再释放结构体内存free(arr->data);free(arr);
}int main() {DynamicArray* arr = create_array(3);  // 初始容量为3printf("动态数组演示\n");// 添加元素测试自动扩容for (int i = 1; i <= 10; i++) {add_element(arr, i * 10);print_array(arr);}destroy_array(arr);return 0;
}

http://www.dtcms.com/a/577431.html

相关文章:

  • iOS 审核 上架 被拒 4.3a 【改革】【灾难来袭】
  • 从0开始学算法——第二天(时间、空间复杂度)
  • Jenkins使用指南1
  • 在 macOS 上使用 Homebrew 安装 MySQL 8.0 完整指南
  • redis 在网站开发中怎么用江西网站建设销售电话
  • AIoT | 软件:Astra MCP边缘算力构建详解
  • Apache Paimon 查询全流程深度分析
  • 网站中英文切换代码企业服务器配置方案
  • 专业的内蒙古网站建设160外发加工网
  • 团队学习与企业破局
  • 编程语言|前端开发——WebAssembly 和 JavaScript 该怎么选?
  • 佛山美容网站建设广州旅游网站建设设计公司
  • 深入理解HTTPS协议:从密码学基础到TLS 1.3实战
  • rhcse----DNS
  • 苍穹外卖资源点整理+个人错误解析-Day05-Redis、店铺营业状态设置
  • Vue 3.5 新API解析:响应式革命、SSR黑科技与开发体验飞跃
  • 【tips】项目中 package.json的 “type“对于文件的导入导出的区别
  • 【科研绘图系列】R语言绘制曲线图(curve plot)
  • 骏域网站百度信息流是什么
  • 【科研绘图系列】R语言绘制地图(map plot)
  • 【C 语言面试】高频考点深度解析
  • 【AI】拆解神经网络“技术高墙”:一条基于“根本原理-补丁理论-AI部署”哲学的学习路径
  • 让 Elasticsearch Delete By Query 请求立即生效
  • HarmonyOS开发-系统AI能力-语音转文字
  • 巨鹿企业做网站儋州网站建设培训学校
  • 建站优化收费下载网页图片
  • Docker搭建Ngnix、php5.6、php8、postgresql、redis
  • php基础-系统函数-第15天
  • CSP-J教程——第一阶段——第五课:程序流程控制 - 选择结构
  • 【Go微服务框架深度对比】Kratos、Go-Zero、Go-Micro、GoFrame、Sponge五大框架