提出问题
请问在c语言里如何实现动态大小的数组啊,比如说int a[N];当数组a[N]中容量满了,怎样再扩大容量呢?或者有什么方法可以实现类似的功能?总之只要在编译时不用再考虑数组大小就行。
我们知道,C语言中数组一旦被创建容量就是固定的,而当我们需要使用数组时,就必须要去考虑数组容量这个问题。一些人可能会说我直接在创建数组时把容量设置成很大不就可以了吗?比如:我创建数组的时候初始容量为10000,但是我最后只使用了100个。这样会浪费大量的内存。所以接下来才有动态数组。
什么是动态数组?
从字面意思上理解是:可变的数组。但是这种理解真的对吗?
我们知道,数组一旦被创建就是固定的,那为什么还会有动态数组这个东西呢?
动态数组之所以叫做动态数组,并不是因为数组可变,而是我们创建了一个新的数组,再原有数组的基础上扩容,再把原本的数据copy到新数组中。
如何去写一个可扩展的数组
第一步:创建一个结构体,里面有int类型的指针、最大长度和实际长度,指针的目的就是为了扩展数组,最大长度是为了初始化数组,实际长度是为了判断什么时候需要扩容。
第二步:我们创建完一个结构体,紧接着就需要对数组做一些操作(创建,初始化),初始化的时候别忘记设置初始长度=0
第三步:当数组容量到达最大长度的时候,需要扩容——创建了一个新的数组,再原有数组的基础上扩容,再把原本的数据copy到新数组中。最后释放之前malloc获得的空间,还需要我们把结构体int类型的指针所指的地址变成新建的数组。
下面是我的代码:
#include<stdlib.h>
#include<stdio.h>
typedef struct {
int* arr;
int max;
int len;
} ArrList;
void initial(ArrList* a, int max);
void addlen(ArrList* a, int len);
int main() {
ArrList a;//定义一个顺序表
ArrList* p = &a; //定义一个ArrList的指针=&a
printf("请输入数组初始容量:");
int len;
scanf("%d", &len);
initial(p, len); //传入ArrList的指针,可以更改p->arr数组地址
for (int i = 0; i < len; i++ ) {
int num;
scanf("%d", &num);
a.arr[i] = num;
a.len++;//每添加一个数据,len就要+1
}
printf("现在数组满了,请输入要扩充的大小:");
scanf("%d", &len);
addlen(p, len); //扩容len长度
while (a.len < a.max) {
int num;
scanf("%d", &num);
a.arr[a.len] = num;
a.len++;
}
printf("下面输出一下写入的数据:");
for (int i = 0; i < a.len; i++) {
printf("%d\t", a.arr[i]);
}
return 0;
}
void initial(ArrList* a, int max) {
(*a).arr = (int*)malloc(sizeof(int) * max);
(*a).max = max;
(*a).len = 0;
}
void addlen(ArrList* a, int len) {
int* l = (*a).arr; //先把原本的数组地址传递给l,等会释放内存
int max =(*a).max + len;
(*a).arr = (int*)malloc(sizeof(int) * max);
(*a).max = max;
for (int i = 0; i < max - len; i++) {
(*a).arr[i] = l[i];
}
free(l);//释放l所指的那块内存
(*a).len = max - len;
}
下面的运行的截图:
这样子的数组还是有局限性的:比如在扩容的时候,需要重新copy数据(非常的浪费时间)。所以后面还会更新链表。链表的话扩容的时候就不是这样子的了,会极大地提高时间效率。但是会牺牲一部分空间。
有兴趣的可以去了解一下Java的集合,也是通过数组实现的。还有一些方法,有能力的也可以尝试去写写。
总结
这里只演示了如何扩容,你自己也可以尝试写一下增删改查等一系列对动态数组的操作。以后也会持续更新!!!
以上均是个人的理解,如果有不对的地方请各位大佬帮忙斧正。