一看就懂-【c语言】可变数组的实现与缺陷分析
目录
0.引言
1.完整代码
2.可变数组的创造
3.可变数组的长度
4.可变数组的写入
5.可变数组的增长
6.可变数组的自动增长
7.可变数组的缺陷
7.1 效率极低
7.2 浪费内存空间
8.总结
0.引言
当我们在使用数组的时候,要提前初始这个数组的大小,所以使用数组时,我们总是提心吊胆害怕出现数组越界的情况,那么利用可变数组就可以轻松解决这个问题了(妈妈再也不用担心我的数组越界了) 本文主要详细介绍如何实现可变数组(创造,写入,增长,自动增长,清空),以及可变数组的缺陷。
【本文出现的任何疑惑或者问题都可以私信博主,一起交流讨论,随时回复!】
1.完整代码
#include<stdio.h> #include<stdlib.h>typedef struct array{int size;int *array; }Array;//可变数组的初始创造 Array array_creat(int init_size);//得到可变数组的大小(封装) int array_size(Array a);//可变数组的写入 void array_write(Array *a,int index,int number);//可变数组的读取 int array_get(Array *a,int index);//可变数组的增大 void array_bigger(Array *a,int more_size);//可变数组的清空 void array_free(Array *a);int main() {Array a=array_creat(5);int i;for(i=0;i<10;i++){int x;scanf("%d",&x);array_write(&a,i,x);}for(i=0;i<10;i++){printf("%d ",a.array[i]);}array_free(&a);return 0;} Array array_creat(int init_size){Array a;a.size=init_size;a.array=(int*)malloc(sizeof(int)*a.size);return a;}int array_size(Array a){return a.size;}void array_write(Array *a,int index,int number){if((index+1)>a->size){int block_size=20;array_bigger(a,block_size);}a->array[index]=number;}int array_get(Array *a,int index) {return a->array[index]; }void array_bigger(Array *a,int more_size){int *another_array=(int*)malloc(sizeof(int)*(a->size+more_size));int i;for(i=0;i<a->size;i++){another_array[i]=a->array[i];}free(a->array);a->array=another_array;a->size=a->size+more_size;}void array_free(Array *a){free(a->array);a->array=NULL;a->size=0;}
2.可变数组的创造
首先我们需要定义一个结构,包含你要创造这个可变数组的大小和一个指针(用于储存数据)
typedef struct array{int size;int *array; }Array;
接下来我们要写一个函数,进行可变数组的初始创造,目的在于给主函数中新定义的Array a
初始的size和动态内存分配指针a->array的空间。
Array array_creat(int init_size){Array a;a.size=init_size;a.array=(int*)malloc(sizeof(int)*a.size);return a;}
这个函数只有一个参数,就是给定size的大小。
int main() {Array a=array_creat(5);return 0; }
这样就在主函数中初始化了一个可变数组,这个可变数组的初始大小为5
3.可变数组的长度
这里可能显得多次一举了,因为我们要专门写一个函数去得到我们初始化可变数组的size
int array_size(const Array a) {return a.size;}
我们不是直接a.size就可以了吗,为什么还需要一个函数去return a.size?这里其实是对数据的封装(其实就是对数据的一种保护,可能在现在这个程序中看不出来它的作用,但是当在大程序用作是,就避免了很多麻烦)
4.可变数组的写入
前面我们创造了一个大小为5个int的可变数组,也就是给a->array动态分配了五个int空间,那么这个时候我们要将数据写入到这个指针中【具体指针应用可看我的博文《【超详解】浅入指针剖析》】
void array_write(Array *a,int index,int number){a->array[index]=number;}
这个函数有三个参数,一个是Array *a的指针,要把初始化的可变数组已指针的形式传进来进行数据的储存,int index就是储存指针的位置,int number就是你要在这个指针位置储存的数据。
int main() {array_write(&a,0,10);return 0; }
就将10这个值写入进可变数组,那么我们就是读取这个数了!
int array_get(Array *a,int index) {return a->array[index]; }
这里同样做的是封装,而不是直接输出a.array[index]。
实例:
int main() { array_write(&a,0,1); printf("%d",array_get(&a,0)); return 0; }
output:10
5.可变数组的增长
我们之所以需要可变数组关键就在于要让他发生变化,不让它越界,那么最为关键就在于如何让已经初始化的数组进行增长,而且要保持已经写入的数据不发生改变!那么实现这个函数就需要做三件事情:1.分配一个更大空间给新的指针 2.拷贝原来的数据给新的指针 3.把新创造的指针赋值给原来的指针
void array_bigger(Array *a,int more_size) {int *next_array=(int*)malloc(sizeof(int)*(a->size+more_size));int i;for(i=0;i<a->size;i++){next_array[i]=a->array[i];}free(a->array);a->array=next_array;a->size=a->size+more_size;}
这里需要清空原来分配给a->array的空间,同时给定新的a->array和a->size。
6.可变数组的自动增长
现在我们知道了如何增长可变数组,但是还是只是人为的增长,我们一般的数组也可以做到人为增长啊。这里我们就需要让它进行自动增长!我们要实现,当我们要写入的数据位置超过了初始化的数组大小事,程序会帮我自动分配相应的空间大小,这里我们就需要在可变数组的写入函数中进行修改
void array_write(Array *a,int index,int number){if((index+1)>a->size){int block_size=20;int t=index+1;block_size=((t-a->size)/20+1)*block_size;array_bigger(a,block_size);}a->array[index]=number;}
这里定义了一个block_size=20,表明已20为一个单位进行扩增。block_size=((t-a->size)/20+1)*block_size;是确定要扩增多少个block_size。
所以在内存足够的清况下,写入储存数据时就不会存在越界的问题,程序会自动进行数组大小的扩增
int main() {Array a=array_creat(5);array_write(&a,250,100);printf("%d",array_get(&a,250));return 0; }
output:100 (没有任何问题,即使初始定义数组大小为5)
7.可变数组的缺陷
7.1 效率极低
每一次可变数组的增长都要进行数据的全部复制,那么假设有几百万个数据,每次增长都重新复制,那在很大程度上降低了程序的效率
7.2 浪费内存空间
如图所示:一开始假设我们Array a可以储存100个int数据,现在要进行增大一个block_size(20个数据),我们可以看出整个内存中还剩160个内存空间,理论上是可行的,但是当我清空a后,要创造一个可以储存120个连续空间的指针,但是已经找不出来这个位置了,也就浪费了160个内存空间位置。那么我们怎么处理这个问题呢?答案是:使用链表!【查看我的博文《一看就懂-c语言单向链表【初阶】》】
8.总结
可变数组的实现,解决了我们一直害怕的越界问题,但是它的缺点也是非常致命的。链表的出现就不仅解决了越界问题,同时还提高了效率,充分利用内存空间。
如果这篇文章对您有一丝丝帮助的话,请帮博文点个关注点个赞!
一看就懂-【c语言】可变数组的实现与缺陷分析相关推荐
- 《零基础看得懂的C语言入门教程 》——(八)了解基本数组还不是那么简单
一.学习目标 了解数组的使用方法 目录 C语言真的很难吗?那是你没看这张图,化整为零轻松学习C语言. 第一篇:(一)脱离学习误区 第二篇:(二)C语言没那么难简单开发带你了解流程 第三篇:(三)轻轻松 ...
- 【C语言】数组详解,初学者一看就懂
你每天都在做很多看起来毫无意义的决定,但某天你的某个决定就能改变你的一生.--<西雅图不眠夜> 目录 什么是C语言数组? 1.一维数组的创建与初始化 1.1数组的创建格式 1.2数组的初 ...
- C语言0长度数组(可变数组/柔性数组)详解
CSDN GitHub C语言0长度数组(可变数组/柔性数组)详解 AderXCoding/language/c/zero_length_array 本作品采用知识共享署名-非商业性使用-相同方式共享 ...
- c++ 结构体赋值_《零基础看得懂的C语言入门教程》—(十二)结构体是这么回事
一.学习目标 了解C语言的结构体的使用方法 了解C语言结构体的结构的赋值 了解多种C语言结构体变量的赋值方法和取值方法 目录 <零基础看得懂的C语言入门教程>--(二)简单带你了解流程 & ...
- 搞懂C语言指针,看这篇就够了!
点击上方"大鱼机器人",选择"置顶/星标公众号" 福利干货,第一时间送达! ID:技术让梦想更伟大 整理:李肖遥 说到指针,估计还是有很多小伙伴都还是云里雾里的 ...
- 《零基础看得懂的C++入门教程 》——(8)搞定二维数组与循环嵌套
一.学习目标 了解二维数组的使用方法 了解循环嵌套的使用方法 目录 预备第一篇,使用软件介绍在这一篇,C++与C使用的软件是一样的,查看这篇即可:<软件介绍> 想了解编译原理和学习方法点这 ...
- 《零基础看得懂的C++入门教程 》——(7)小数组玩起来
一.学习目标 了解数组的使用方法 了解一维数组的使用方法 了解一维数组与循环的使用方法 目录 预备第一篇,使用软件介绍在这一篇,C++与C使用的软件是一样的,查看这篇即可:<软件介绍> 想 ...
- 为什么学习C语言这么久,看的懂代码,做不出题,写不出来项目?
前言 我看得懂别人的程序,可是我自己却写不出来,我应该怎么办啊? 你了解这些嘛? 你只是能从别人书写的代码知道每一步都做些什么吧? 你明白别人的解题思路吗? 你知道别人为什么要用那样的算法吗? 如果你 ...
- C语言,谁都能看得懂的归并排序
喜欢看排序算法动态效果的,可以看看这个网站 https://visualgo.net/zh/sorting 里面很多算法的动画解释,可以看到算法的排序效果,而且还附带了伪代码的实现过程. 本来想录制几 ...
最新文章
- ML之回归预测:以某个数据集为例从0到1深入理解科学预测之回归(实数值评分预测)问题的思路框架
- Spring 核心容器类BeanFactory
- C# 获取打开的EXCEL中某列的行数
- 什么是运行时Runtime、运行时库Runtime Library、运行时环境Runtime environment
- 房地产项目动态计划管理系统
- SURF算法python实现
- Java实现地固坐标与经纬度转换
- 什么是脏读、不可重复读、幻读? (数据库相关)
- 制作favicon图标
- word 尾注后边加致谢
- 华盛顿道格拉斯县计划建立区块链创新园区
- 锁仓怎么解_[期货知识]期货锁仓后怎么解锁?期货锁仓解锁技巧介绍 - 南方财富网...
- 如何录屏?电脑屏幕录制软件哪个好?
- 大班线描机器人_大班线描画-有趣的巨人
- 抖音数据分析工具pc端_用于分析Windows PC上硬盘空间的四个最佳免费工具
- 最好用的文字锁屏APP的使用教程
- C# 从做早餐看同步异步
- KB/s和Kbps是完全不同的概念
- 铁血丹心 歌词粤语转汉语谐音
- 搜狗浏览器升级,给“红海”市场“火上浇油”