引言:动态数组在C/C++、Java、Python等语言中应用广泛,高级语言一般通过调用类或接口等可以快捷使用,C语言实现动态数组需要手动构造,以下为实现过程。
1 结构体构造动态数组
typedef struct Array
{
void **p; //维护在堆区创建的指针(后续函数入参为传址调用,节省内存,对void*操作,因此构造void **p)
size_t capacity; //动态数组容量
size_t size; //动态数组实际大小
} Array;
2 动态数组初始化
Array *initArray(size_t capacity)
{
Array *array = (Array *)malloc(sizeof(Array));//在堆区申请array的内存
array->capacity = capacity;//将动态数组容量初始化为函数入参
array->size = 0;//将动态数组实际大小初始化为0
array->p = (void **)malloc(sizeof(void *) * capacity); //在堆区申请二级指针p的内存
return array;
}
3 动态数组在索引index处插入数据data
/**
* @brief 向动态数组插入一个数据
* @param array 动态数组
* @param index 插入索引
* @param data 插入数据,data为传址
* @return int 插入成功返回1,失败返回0
*/
#define RATIO 2 //扩容倍数
int insertArrayByIndex(Array *array, int index, void *data)
{
if (array == NULL || data == NULL)//空指针判断
return 0;
if (index < 0 || index >= array->size) //插入索引不在[0,size)内时,选择尾插
index = array->size;
if (array->capacity == array->size) // array数组已满,需要申请更大空间,并将源数据copy到新空间
{
size_t newCapacity = array->capacity * RATIO; //动态数组新容量
void **newP = (void **)malloc(sizeof(void *) * newCapacity);//重新申请堆内存
memcpy(newP, array->p, sizeof(void *) * array->capacity);//源数据copy至新的堆内存中
free(array->p); //释放旧空间
array->p = newP; //更新新指向
array->capacity = newCapacity; //更新新容量
}
for (int i = array->size - 1; i >= index; i--) //新数据插入在index,先后移index及其以后数据
array->p[i + 1] = array->p[i]; // p[i]相当于*(p+i),p原为二级指针,解引用操作了void *;使得一级地址后移
array->p[index] = data;
array->size++; //更新大小
return 1;
}
4 动态数组移除数据,可分为通过索引index移除或通过数据data移除,
4.1 通过索引index移除
int removeArrayByIndex(Array *array, int index) //从动态数组移除一个数据
{
if (array == NULL || index < 0 || index >= array->size)//空指针或非法索引会导致移除失败
return 0;
for (int i = index + 1; i < array->size; i++)
array->p[i - 1] = array->p[i];//移除index对应的data后,需将index后的数据前移
free(array->p[array->size-1]);
array->p[array->size - 1] = NULL;//原末位数据置空
array->size--;//原实际数组大小减1
return 1;
}
4.2 通过数据data移除,为方便理解,以下代码构造了动态数组存储的数据类型
typedef struct Student // 以动态数组存储的数据类型为Student*为例分析
{
char name[10];
int age;
} Student;
int compare(void *s1, void *s2) //根据结构体Student设计比较规则,返回1表示相等
{
Student *stu1 = (Student *)s1;//指针类型转换
Student *stu2 = (Student *)s2;
if (strcmp(stu1->name, stu2->name) == 0 && stu1->age == stu2->age)
return 1;
return 0;
}
int removeArrayByData(Array *array, void *data, int (*compare)(void *s1, void *s2)) //移除data函数,仅考虑不重复情况下
{
if (array == NULL || data == NULL)//空指针
return 0;
for (int i = 0; i < array->size; i++)
{
if (compare(array->p[i], data))//利用函数回调找出与data相同时的索引index
{
for (int index = i; index < array->size - 1; index++)//思路与通过索引删除数据一致
array->p[index] = array->p[index + 1];
free(array->p[array->size - 1]);
array->p[array->size - 1] = NULL;
array->size--;
return 1;//删除成功返回1
}
}
return 0;//删除失败返回0
}
5 动态数组遍历
void listArray(Array *array, void (*printfdArray)(void *)) //利用函数回调遍历
{
if (array == NULL || printfdArray == NULL)
return;
for (int i = 0; i < array->size; i++)
printfdArray(array->p[i]);
puts("\n");
}
void printfStudent(void *data) //为Student*类型数据写遍历函数
{
Student *s = (Student *)data;
printf("%s->%d\t", s->name, s->age);
}
6 动态数组销毁
void destoryArray(Array *array)//释放占用的内存即可
{
if (array != NULL)
{
free(array);
array = NULL;
}
if (array->p != NULL)
{
free(array->p);
array->p = NULL;
}
}
7 动态数组简单演示
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define RATIO 2 //动态数组扩展系数
#define SHOW_CAPACITY_SIZE_AND_LIST \
printf("容量->%d\t大小->%d\t\n", array->capacity, array->size); \
listArray(array, printfStudent);
int main()
{
Array *array = initArray(5);
Student s1 = {"jakes1", 16};
Student s2 = {"jakes2", 17};
Student s3 = {"jakes3", 18};
Student s4 = {"jakes4", 19};
Student s5 = {"jakes5", 20};
Student s6 = {"jakes6", 21};
insertArray(array, 0, &s1);
SHOW_CAPACITY_SIZE_AND_LIST
insertArray(array, 0, &s2);
SHOW_CAPACITY_SIZE_AND_LIST
insertArray(array, 1, &s3);
SHOW_CAPACITY_SIZE_AND_LIST
insertArray(array, 0, &s4);
SHOW_CAPACITY_SIZE_AND_LIST
insertArray(array, 1, &s5);
SHOW_CAPACITY_SIZE_AND_LIST
insertArray(array, 2, &s6);
SHOW_CAPACITY_SIZE_AND_LIST
removeArrayByIndex(array, 2);
SHOW_CAPACITY_SIZE_AND_LIST
printf("-----%d\n", removeArrayByData(array, &s3, compare));
SHOW_CAPACITY_SIZE_AND_LIST
return 0;
}
运行结果如下
--如有错误,欢迎大家指出交流,共同学习--