转载:https://blog.csdn.net/melody_1016/article/details/81948809
我们知道,C语言的数组是固定大小的,尽管可以用一个变量来定义数组大小,但是一旦定义了,在大小在运行过程中无法改变。如果一开始就定义一个容量较大的数组,那么由于不知道实际要存放多少元素,可能会造成空间浪费或者还是不够用。所以,本篇博客,我们就用C语言实现一个可以变大小的数组。
先上代码:
头文件array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_
const int BLOCK_SIZE = 2;
typedef struct
{
int*array;
int size;
}Array;
Array array_creat(int init_size);//创建一个数组
void array_free(Array *a);//回收空间
int array_size(Array *a);//目前有多少个空间可以用
int*array_at(Array*a, int index);//访问数组当中某个单元:可以读也可以写(即可以做左值也可以做右值)
void array_inflate(Array*a, int more_size);//数组增容
void array_set(Array*a, int index, int value);//向数组中写入东西
#endif
array.cpp
#include"array.h"
#include<stdio.h>
#include<stdlib.h>
//创建一个数组
Array array_creat(int init_size)
{
Array a;
a.array = (int*)malloc(sizeof(int)*init_size);
a.size = init_size;
return a;
}
//回收空间
void array_free(Array *a)
{
free(a->array);
a->array = NULL;
a->size = 0;
}
//目前有多少个空间可以用
int array_size(Array *a)
{
return a->size;
}
//访问数组当中某个单元:可以读也可以写(即可以做左值也可以做右值)
int*array_at(Array*a, int index)
{
if (index >= a->size)
{
array_inflate(a, (index / BLOCK_SIZE + 1)*BLOCK_SIZE - a->size);
}
return &(a->array[index]);
}
//数组增容
void array_inflate(Array*a, int more_size)
{
int*p = (int*)malloc(sizeof(int)*(a->size + more_size));//新开辟一段空间
int i;
//将原空间的内容全部拷贝至新空间
for (i = 0; i < a->size; i++)
{
p[i] = a->array[i];
}
//array_free(a);
free(a->array);
a->array = p;
a->size += more_size;
}
void array_set(Array*a, int index, int value)
{
a->array[index] = value;
}
int main()
{
Array a;
a=array_creat(3);
//array_free(&a);
*array_at(&a, 0) = 10;
*array_at(&a, 1) = 20;
*array_at(&a, 2) = 30;
*array_at(&a, 3) = 40;
*array_at(&a, 4) = 50;
*array_at(&a, 5) = 60;
//array_set(&a, 0, 10);
//array_set(&a, 1, 20);
//array_set(&a, 2, 30);
//array_inflate(&a, 2);
//array_set(&a, 3, 40);
//array_set(&a, 4, 50);
for (int i = 0; i < 4; i++)
{
printf("%d ", a.array[i]);
}
//printf("%d\n", array_size(&a));
array_free(&a);
//Array *pa= array_creat(NULL, 3);
//pa = array_creat(&a, 3);
//array_free(&a);
//array_free(&a);
system("pause");
return 0;
}
下面对代码的设计思路和重点部分讲解一下:
一、Array array_creat(int init_size)//创建一个数组,这里返回值为什么是Array的变量本身而不是Array*呢?
如果返回的的是指向结构体的指针,即函数定义为Array* array_creat(Array*a,int init_size),那么在函数内部,应该就是这样
Array* array_creat(Array*a,int init_size)
{
a->size=init_size;
a->array=(int*)malloc(sizeof(int)*a->size);
return a;
}
但是,这里就有一个潜在的风险:如果传进来的a为null,那么直接通过空指针访问它的数据,必然程序崩溃;如果传进来的a已经指向一块开辟好的内存,那么要先free掉原来的空间,再把a指向新空间才可以,用上面的代码,明显会出问题。而如果按照原来的做法(即返回的是Array),则我们可以在main()函数中定义一个Array类型的结构体变量来接收array_creat(int init_size)函数返回的结构体:即Array=array_creat(3);这处理起来就比较简单了。
二、void array_inflate(Array*a, int more_size);//数组增容,具体是怎么进行增容呢?
三、BLOCK_SIZE的引入目的?
当初始容量写满后,如果再要写入数据,必须进行增容,我们的 array_inflate函数只单纯负责增容,不进行检测容量的大小;那么如何判断空间已满,需要扩容呢?这里是在array_at函数中进行判断的,因为array_at函数的作用是访问数组单元和写入数值的,可以通过它的参数index与当前size大小比较,判断是否已满,如果原内存已满,则调用array_inflate函数进行扩容。
这里引入BLOCK_SIZE是为了扩容方便。如果写成以下方式,则原内存空间满后,每再写入一个数据,都要重新申请比原来多一个数据大小的空间,再进行数据的拷贝。这样反复的开空间和拷贝数据降低了效率。
int*array_at(Array*a, int index)
{
if (index >= a->size)
{
array_inflate(a, index-a->size+1);//每次扩充一个大小
}
return &(a->array[index]);
}
所以我们寻求一种方式,可以每次都扩充固定大小,比如20个,那么原内存空间满(假设原内存空间可以存放100个数据)后,再插入一个数据,即index=100时,系统一次性扩充20个(即新申请120个数据大小),这样后续插入数据时,只要index没有到120,就不用再扩容了。