C语言程序设计 学习笔记 可变数组(链表基础)

用C语言实现一个可以变大小的数组(动态数组)
需求:
1.当数据量不够的时候,它能自动扩张
2.我能够随时看到其目前的size
3.能够访问它的单元
在这里插入图片描述
1.创建数组
2.释放数组
3.求数组目前大小
4.读取指定位置
5.inflate 膨胀 -> 扩张数组
代码+笔记:

#include <iostream>
#include "array.h" 
#include <stdlib.h>
#include <cstring> 
using namespace std;
//typedef struct{
//	int *array;
//	int size;
//} Array;
#define BLOCK_SIZE = 20; 
//PS:对于结构体,使用其内部变量可以用a.xx,但如果这个结构体是指针形式,那就只能用a->xx  
 
//create:希望的数组size,返回一个array,返回类型不是指针,因为array是本地变量,返回出去就无效了 
Array array_create(int init_size){
	Array a;
	a.size = init_size;//保存这个大小 
	a.array = (int*)malloc(sizeof(int)*a.size);
	return a;
}

//free:释放该array,并且将size置0;以防万一可以再让array = null(防止别人调2次,free(0、null)是无害的 
void array_free(Array *a){
	free(a->array);
	a->array = NULL;
	a->size = 0; 
} 

//想求size可以用a.size,但是用array_size更安全(这个操作叫封装) 
//一般地,在c++中为了保护用户权限,size和array是保存在private中的,用户不好直接读取 
int array_size(const Array *a){
	return a->size; 
} 

//指向数组的index的位置,返回类型是指针(地址)
//也就是说,返回的是地址,我们可以对其进行读写 
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]);//返回是指针,所以要加&(取地址) 
} 

//当然也可以分别设置set、get函数,这两个功能等于一个array_at 
void *array_set(Array *a, int index, int value){
	a->array[index] = value;
} 
//这里用const的原因是我不会对其进行写入操作,所以const更安全 
int array_get(const Array *a, int index){
	return a->array[index];
}

//理论上,malloc是不能长大的,所以对其扩张就是需要扩张的空间加上原空间大小 
//然后要将原数组a.array的数据,逐个添加入inflate后的新数组*p 
void array_inflate(Array *a, int more_size){
	int *p = (int*)malloc(sizeof(int)*(a->size + more_size));
//	for(int i = 0; i<a.size; i++){
//		p[i] = a.array[i];
//	} 
	memcpy(p,a->array,a->size); //比for更高效的复制,需string头文件 
	free(a->array);
	a->array = p;
	a->size = a->size + more_size;
} 

int main(int argc, char** argv) {
	Array a = array_create(100);
	cout<<"size = "<<array_size(&a)<<endl;
	*array_at(&a,0) = 10;//赋值
	cout<<"a.array[0] = "<<*array_at(&a,0)<<endl;//读值
	
	//inflate扩张实例:
	//持续输入数据 
	int number;
	int cnt = 0;
	while( number != -1){//number == -1退出循环 
		cin>>number;
		*array_at(&a,cnt++) = number; //迟早cnt会大于目前的size,这时候需要在array_at上操作 
	} 
	array_free(&a);
	return 0;
}

如果我每次inflate都只是inflate1个,每次都要开一个新数组,然后memset,然后free旧数组,再循环,这样效率非常低,所以每次inflate一个BLOCK,效率更高
(但不知道为什么不直接inflate20个,而是以BLOCK为单位,希望有人明白的话能为我解答一下,非常感谢!)

对于BLOCK,首先最好有一个BLOCK的概念
每一个BLOCK可以设定为是数组的一个大单位,1BLOCK = 20size之类
这样每一次inflate都是以1BLOCK为单位,每次膨胀20个size,这样效率会更高
对于

array_inflate(a,(index/BLOCK_SIZE + 1)*BLOCK_SIZE - a->size);

当输入到最大值的时候会调用它,设置的时候size=100,BLOCK_SIZE = 20
此时index = 100,BS = 20那么index/BS = 5,就是说此时我们里面有5个BLOCK,然后再+1,那就是我们要有6个BLOCK,乘上20(最小单位)就是我们所需要的size,再减去目前的size就是要inflate的size大小

可变数组的缺陷:
缺陷主要是内存使用上存在的缺陷
在这里插入图片描述
假设最左边是内存起点,申请的第一个数组(ar1)在后,然后通过inflate膨胀,在ar1后面申请出来ar2,再将ar1释放
在这里插入图片描述
后来再inflate,申请出ar3,随后将ar2释放,继续申请ar4,只要ar1+ar2的size不比ar4小,那么ar4会在他们俩所在的那个内存位置创建(在起点),随后释放ar3
但是以此类推下去,总会有一次
在这里插入图片描述
当数组size为n,之前释放的是n-BS,然后我们需要再次inflate,这样就inflate不了了,因为你没有足够的空间再进行申请,但实际上是n+BS这个容量内存还是能够接收的,就是因为申请和释放之间的关系导致无法申请

但如果我们可以使用BLOCK,将其都拼接在一起,并不是用上面的方法复制粘贴。每一个BLOCK会有一个单元指向的是下一个BLOCK的地址,这样就不会有上述的问题了
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/a656418zz/article/details/84196929