目录
14.1.1 可变数组
首先我们想一想这个问题需要的特点(功能):
- 可增长
- 能获得当前大小
- 可以访问其中的单元
解决方法:设立函数库,几个函数分别实现不同功能
array.h
#ifndef _ARRAY_H
#define _ARRAY_H
typedef struct{
int *array;
int size;
}Array;//重命名结构为ARRAY
}*Array
很多人第三方库会设定成一个指针,下方的参数表里经常用到,
可以将参数表里的*去掉了,但是这样的坏处是你之后就不能访问
本地变量array(会动态创建一个),而且可读性也不好
Array array_create(int init_size);//创建数组
void array_free(Array *a);//释放数组的内存空间
int array_size(const Array *a);//获得数组空闲大小
int* array_at(Array *a, int index);//访问数组某个单元
void array_inflate(Array *a,int more_size);//让数组变大
array.c
#include"array.h"
//typedef struct{
// int *array;
// int size;
//}Array;
const BLOCK_SIZE = 20;//设自己觉得合适的大小
Array array_create(int init_size)
{
Array a;//创建结构变量a
a.size = init_size;
a.array = (int*)malloc(sizeof(int)*a.size);
//初始化大小和指针
return a;
//返回a本身而不是指针,此时制作的是本地变量,因此可以在main函数中灵活使用
}
void array_free(Array *a)//上个函数中的结构里的*array需要释放
{
free(a->array);
//为了保险起见,防止free两次(freeNULL是无害的),把这两个也初始化为0
a->array = NULL;
a->size = 0;
}
//既然只是想获得size,为什么不干脆printf里return a.size?还写函数干什么
//实际上,我们用函数将内部的实现细节封装起来,防止在大体量程序里直接调用带来的问题
//因为可能根本无法调用
int array_size(const Array *a)
{
return a->size;
}
//为什么返回指针?因为这样做可以同时做到对指针的读和写
eg:*array_at(&a,0) = 10;//写入
printf("%d\n",*array_at(&a,0));//读取
当然,写两个分开的函数也是可以的
int* array_at(Array *a, int index)
{
return a->array[index];
这样对吗?并不,注意这个函数的返回类型是个int指针,我们这样写返回的是int
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];
}
//这个循环可以用库函数里的memcpy代替,理论效率更高
free(a->array);
a->array = p;
a->size += more_size;
}
array.c main
int main()
{
Array a = array_create(100);//创建结构a,数组大小为100
printf("%d\n",array_size(&a));//打印数组大小
*array_at(&a,0) = 10;//设置a[0]=10
printf("%d\n",*array_at(&a,0));//打印a[0]
int number = 0;
int cnt = 0;
//设置输入-1为退出条件
while(number != -1){
scanf("%d",&number);
if(number != -1){
*array_at(&a,cnt++) = number;
}
}
array_free(&a);
return 0;
}
此时可以实现不断输入数值填满数组,但是当数组越界时,还需要对程序进行一些修改
int* array_at(Array *a, int index)
{
if(index >= a->size){
array_inflate(a, index - a->size + 1);
//因为每次读入一个数,所以就让数组上标增长1,
//然而每次增长1都要重新申请,然后完整复制之前的数据,
//因此我们定一个单位,每次越界都增长一个单位的大小,这样更加高效
array_inflate(a, (index/BLOCK_SIZE + 1)*BLOCK_SIZE - a->size);
//比如我要访问102,block大小为20,现在只有100,也就是5个block,
//那么102/20=5,5+1=6,6*20=120,120-100=20,于是函数知道要增长20
//如果越界更多,用这个公式也可以一次性算好
}
return &(a->array[index]);
}