C语言实现 动态数组 处理任意类型数据

引言:动态数组在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;
}

运行结果如下

 --如有错误,欢迎大家指出交流,共同学习--

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jakerc

原创不易,您的奖励将是我最大的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值