C语言动态数组的完整实现

    作者:朱克锋

   

    数组的有点在于随机存取,然而其不足也是明显的,就是一旦建立其大小就不能改变。若用数组存储数据,则必须创建一个可能存放的最大空间的数组,这无疑浪费了空间。动态数组解决了这个问题。动态数组的思路是:先建立一定大小的数组,向这个数组中存放数据,如果数组已满,则重新申请一个更大的空间来存放。每次重新申请时可以指定增量的大小(一般为原来数据的1.5倍),也可以固定大小。这样做的好处是空间浪费不多,其不足是重新申请空间浪费时间,每次重新申请空间时须将原来的数据拷贝到新申请的空间,当数组很大时,这种浪费还是相当可观的。
  
接下来是对动态数组实现的说明:
    先建立动态数组的存储结构:
typedef struct _DArray
{
    int size;
    int count;
    void **data;

}DArray;

接下来定义一个enum来存放程序中函数的返回值,可以不定义
typedef enum _Ret
{
    RET_OK = 1,
    RET_FAIL,
    RET_OOM   
}Ret;
为了使程序更具通用性可以定义一个回调函数原型,用于回调

typedef void (*VisitFunc)(void *ctx, void *data);

定义一个用于测试的宏
#define return_val_if_fail(p, val)/
    if(!(p)){printf("%s:%d"#p" failed./n",__func__,__LINE__); return val;}

下面定义数组的基本操作,包括:

DArray *darray_create();
static Ret darray_expand(DArray *darray, int needone);
Ret darray_preapppend(DArray *darray, void * data);
Ret darray_append(DArray *darray, void * data);
Ret darray_insert(DArray *darray, int index, void * data);
Ret darray_delete(DArray *darray, int index);
Ret darray_shrink(DArray *darray);
int darray_len(DArray * darray);
Ret darray_set_by_index(DArray *darray, int index, void *data);
Ret darray_foreach(DArray *darray, VisitFunc visitfunc, void *ctx);
Ret darray_destroy(DArray *darray);
头文件基本定义结束,保存为darray.h

为了优化一般会在头文件中定义选择编译的宏
#ifndef DARRAY_H
#define DARRAY_H
。。。
。。。
#endif /*DARRAY_H*/
避免重复编译

完整头文件如下(darray.h):

#ifndef DARRAY_H
#define DARRAY_H
#define DEFAULT_A_SIZE 10
/*
* File:   darray.h:动态数组函数实现
*/

typedef struct _DArray
{
    int size;
    int count;
    void **data;

}DArray;

typedef enum _Ret
{
    RET_OK = 1,
    RET_FAIL,
    RET_OOM   
}Ret;

typedef void (*VisitFunc)(void *ctx, void *data);

#define return_val_if_fail(p, val)/
    if(!(p)){printf("%s:%d"#p" failed./n",__func__,__LINE__); return val;}

DArray *darray_create();
static Ret darray_expand(DArray *darray, int needone);
Ret darray_preapppend(DArray *darray, void * data);
Ret darray_append(DArray *darray, void * data);
Ret darray_insert(DArray *darray, int index, void * data);
Ret darray_delete(DArray *darray, int index);
Ret darray_shrink(DArray *darray);
int darray_len(DArray * darray);
Ret darray_set_by_index(DArray *darray, int index, void *data);
Ret darray_foreach(DArray *darray, VisitFunc visitfunc, void *ctx);
Ret darray_destroy(DArray *darray);

#endif /*DARRAY_H*/

以下是函数实现部分(darray.c):
#include "darray.h"
#include <malloc.h>
/*
* File:   darray.c:动态数组函数实现
*/

/*
*功能:实现一个DArray结构体的初始化
*参数:void
*返回:DArray结构体
*/
DArray *darray_create()
{   
    int i = 0;
    DArray *darray = (DArray *)malloc(sizeof(DArray));
    if(darray != NULL)
    {
        darray->count = 0;
        darray->size = 0;
        darray->data = (void **)malloc(sizeof(void *) * DEFAULT_A_SIZE);

        if(darray->data !=NULL)
        {
            darray->size = DEFAULT_A_SIZE;
            for(i = 0; i <darray->size;i++ )
            {
                darray->data[i] = NULL;
            }
        }   
        return darray;
    }
   
    return NULL;
}
/*
*功能:添加(尾)元素
*参数:darray:指定数组  data:插入的数据的指针
*返回:Ret
*/
Ret darray_append(DArray *darray,void * data)
{
    return_val_if_fail(darray != NULL && data != NULL, RET_FAIL);

    if(darray ==NULL || data == NULL)
    {
        return RET_FAIL;
    }

    if((darray->count + 1 ) >= darray->size)
    {   
        darray_expand(darray, 2);

    }

    darray->data[darray->count] = data;
   
    darray->count++;

    return RET_OK;

}
/*
*功能:替换数组指定位置的值
*参数:参数:darray:指定数组 index:插入位置 data:插入的数据的指针
*/
Ret darray_set_by_index(DArray *darray, int index, void *data)
{
    return_val_if_fail(darray != NULL && data != NULL, RET_FAIL);

    if(darray ==NULL || data == NULL)
    {
        return RET_FAIL;
    }
    if(index <0 || index >= darray->count)
    {   
        return RET_FAIL;
    }

    darray->data[index] = data;
    return RET_OK;

}
/*
*功能:增加指定数组的容量
*声明:有可能引起新内存申请,内存拷贝,从而改变指针具体指向
*参数:darray:要操作的数组指针地址 needone:要增加的数量(这里用于选择)
*/
static Ret darray_expand(DArray *darray, int needone)
{
    int newallocsize = 0;

    if(needone == 2)
    {
         newallocsize = darray->count + (darray->count>>1)+DEFAULT_A_SIZE;
    }
    else
    {
        newallocsize = darray->count + 1;
    }
    void **data = (void **)realloc(darray->data, sizeof(void *) * newallocsize);
    if(data != NULL)
    {
        darray->data = data;
        darray->size = newallocsize;

    }
    return RET_OK;

}
/*
*功能:缩减指定数组的容量
*声明:有可能引起新内存申请,内存拷贝,从而改变指针具体指向
*参数:darray:要操作的数组指针地址 (视情况缩减为原来的1.5倍,这样不会不用每次都执行内存分配)
*/
Ret darray_shrink(DArray *darray)
{
    if((darray->count >> 1) < darray->size && (darray->size > DEFAULT_A_SIZE))
    {
        int newallocsize = darray->count +darray->count>>1;
        void **data = (void **)realloc(darray->data, sizeof(void *) * newallocsize);
        if(data != NULL)
        {
            darray->data = data;
            darray->size = newallocsize;

        }
   
    return RET_OK;   
    }
}
/*
*功能:删除元素
*参数:darray:指定数组  index:数据的位置
*返回:Ret
*/
Ret darray_delete(DArray *darray, int index)
{
    int i = 0;

    for(i = index; (i+1) < darray->count; i++)
    {
        darray->data[i] = darray->data[i + 1];       
    }

    darray->count--;

    darray_shrink(darray);

    return RET_OK;
}
/*
*功能:添加(头)元素
*参数:darray:指定数组  data:插入的数据的指针
*返回:Ret
*/
Ret darray_preappend(DArray *darray, void * data)
{
    return_val_if_fail(darray != NULL && data != NULL, RET_FAIL);

    if(darray ==NULL || data == NULL)
    {
        return RET_FAIL;
    }

    if(darray->count + 1 > darray->size)
    {
        darray_expand(darray, 2);
    }
    int i = 0;
    for(i = darray->count; i >  0; )
    {
        darray->data[i] = darray->data[i - 1];
        i--;
    }
    darray->data[0] = data;
    darray->count++;

    return RET_OK;
}
/*
*功能:插入元素
*参数:darray:指定数组 index:插入位置 data:插入的数据的指针
*返回:Ret
*/
Ret darray_insert(DArray *darray, int index, void * data)
{
    return_val_if_fail(darray != NULL && data != NULL, RET_FAIL);

    if(darray ==NULL || data == NULL)
    {
        return RET_FAIL;
    }

    if(darray->count + 1 > darray->size)
    {
        darray_expand(darray, 1);
    }
    int i = 0;
    for(i = darray->count; i >  index; )
    {
        darray->data[i] = darray->data[i - 1];
        i--;
    }
    darray->data[index] = data;
    darray->count++;

    return RET_OK;
}
/*
*功能:遍历数组
*参数:darray:指定数组 visitfunc:回调函数 ctx:上下文
*返回:Ret
*/
Ret darray_foreach(DArray *darray, VisitFunc visitfunc, void *ctx)
{
    int index = 0;

    while(index < darray->count)
    {
        visitfunc(ctx, darray->data[index]);
        index ++;   
    }
   
    return RET_OK;
}
/*
*功能:数组长度
*参数:darray:指定数组
*返回:数组大小
*/
int darray_len(DArray * darray)
{
    return darray->count;
}
/*
*功能:释放指定数组内存
*参数:darray:指定数组
*返回:Ret
*/
Ret darray_destroy(DArray *darray)
{
    if(darray == NULL)
    {
        return RET_OK;
    }

    free(darray->data);   
    darray->data = NULL;

    free(darray);
    darray = NULL;
    return RET_OK;
}
最后把测试也写在下面,供学习者测试(darraytest.c)

#include "darray.h"
#include <assert.h>
#include <stdio.h>
/*
* File:   darraytest.c:动态数组函数实现
*/
/*
*功能:测试的打印函数,用于回调
*/
void print_int(void *ctx, void *data)
{
    printf(".........%d/n",*(int *)data);
}

int main(int argc, char *argv[])
{
   
    int i = 0;
    int a = 8;
    int b = 9999;
    int c = 555;
    int u = 7777;
/*    int i = 0;
    char *a ="aaaaa";
    char *b = "bbbbbbbbb";
    char *c = "ccccccc";
    char *u = "uuuuuuuuuuuu";
*/
    DArray *darray = darray_create();
   
    for(i  = 0;i <23; )
    {
        darray_append(darray, &a);
        i++;
    }

    darray_insert(darray, 3, &b);   
    darray_set_by_index(darray, 20, &u);

    for(i = 0; i < 16; i++)
    {
        darray_delete(darray, 0);
    }

    darray_preappend(darray, &b);
    int j = 0;
    for(j = 0;j < darray->count; )
    {   
        printf("%d/n",*(int*)darray->data[j]);
        j++;
    }


    darray_append(darray,&b);
    darray_append(darray,&b);
    darray_append(darray,&b);
    printf("%d/n",darray->size);
    darray_foreach(darray, print_int, NULL);
    darray_destroy(darray);
}

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值