用C语言简单实现一个可变数组

我们知道,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,就不用再扩容了。

 

 

 

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页