想起多年前刚毕业去线下面试、笔试时的一件事情。当时有个笔试就一个题目,要求用到动态数组实现某个玩意,当时我直接定义一个main函数的传参x,作为int array[x]数组的动态大小,结果编译时就报错了。哈哈,当时不知道实际上可以用 realloc 来实现动态数组的功能引起的一个小插曲。
希望该文章在某一时刻对你有所帮助。
进入正题,先说下使用realloc实现动态数组的优点:
1、高效的随机访问:动态数值支持通过下标索引随机访问,时间复杂度为O(1)。这对需要频繁访问的场景来说的十分高效的;
2、尾插高效:尾插是高效的,只要在原来的空间追加分配即可。
3、内存空间连续
缺点:
1、插入数据不灵活:没办法在中间插入(如果需要随机插入场景可以考虑使用链表)
一、代码实现
1、代码段分析
①、数据结构的定义
/* 宏定义 */
#define RET_SUCC (0)
#define RET_FAIL (-1)
/* 数据结构 */
typedef struct {
int id;
char name[32];
}Item, *pItem;
typedef struct {
pItem items;
unsigned int items_nr; // items数量
}DataModel;
/* 全局变量 */
static DataModel g_data_model;
/* ******
数据结构说明:
定义 Item 结构体,表示一个具体的实例,包含 id、name。
定义 DataModel(g_data_model) 作为数据库,包含所有的实例信息。items_nr 为实例个数,items 为实例列表。
* ******* /
②、初始化、增、删、查函数实现
/* 函数声明 */
static void initDataModel();
static int addItem(Item *item);
static int delItem(int id);
static int freeDataModel();
static void dumpDataModel();
static int addItemApi(int id, char *name);
/* 局部函数 */
// 初始化函数
static void initDataModel()
{
g_data_model.items = NULL;
g_data_model.items_nr = 0;
}
// ADD: 添加一个item
static int addItem(Item *item)
{
void *p = NULL;
// realloc memory
if(0 == g_data_model.items_nr)
{
p = realloc(NULL, sizeof(Item));
}
else
{
p = realloc(g_data_model.items, (g_data_model.items_nr + 1) * sizeof(Item));
}
if(NULL == p)
{
perror("realloc fail:");
return RET_FAIL;
}
// copy-item-value
g_data_model.items = p;
g_data_model.items[g_data_model.items_nr].id = item->id;
snprintf(g_data_model.items[g_data_model.items_nr].name, \
sizeof(g_data_model.items[g_data_model.items_nr].name), \
"%s", item->name);
g_data_model.items_nr ++;
return RET_SUCC;
}
static int addItemApi(int id, char *name)
{
Item item = {0};
item.id = id;
snprintf(item.name, sizeof(item.name), "%s", name);
return addItem(&item);
}
// DEL: 依据id删除一个item
static int delItem(int id)
{
int i = 0;
unsigned int old_items_nr = g_data_model.items_nr;
void *p = NULL;
Item *item = NULL;
Item item_back = {0};
for(i = 0; i < old_items_nr; i++)
{
item = &g_data_model.items[i];
if(id != item->id)
continue;
// backup
memcpy(&item_back, item, sizeof(item_back));
// 将最后的item节点移至到要删除的节点
item->id = g_data_model.items[old_items_nr-1].id;
snprintf(item->name, sizeof(item->name), \
"%s", g_data_model.items[old_items_nr-1].name);
p = realloc(g_data_model.items, (old_items_nr - 1) *sizeof(Item));;
if(1 != old_items_nr && NULL == p) {
// restore
memcpy(item, &item_back, sizeof(Item));
return RET_FAIL;
}
g_data_model.items_nr--;
return RET_SUCC;
}
// not found
return RET_FAIL;
}
// FREE: 释放data model
static int freeDataModel()
{
if(0 == g_data_model.items_nr || NULL == g_data_model.items)
return RET_SUCC;
free(g_data_model.items);
g_data_model.items = NULL;
g_data_model.items_nr = 0;
return RET_SUCC;
}
// DUMP: 打印data model
static void dumpDataModel()
{
int i = 0;
if(0 == g_data_model.items_nr)
{
printf("data model is empty\n ");
return ;
}
for(i = 0; i < g_data_model.items_nr; i++)
{
printf("\n----- items<%d> -----\n", i);
printf("id = %d\n", g_data_model.items[i].id);
printf("name = %s\n", g_data_model.items[i].name);
}
}
③、main 函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
// main函数
int main(void)
{
int ret = RET_SUCC;
initDataModel();
// ADD
ret += addItemApi(10, "CC1");
ret += addItemApi(20, "CC2");
ret += addItemApi(30, "CC3");
ret += addItemApi(40, "CC4");
ret += addItemApi(50, "CC5");
if(RET_SUCC != ret)
printf("\033[31m[warning]\033[0m ret = %d\n", ret);
dumpDataModel();
// DEL
ret = RET_SUCC;
ret += delItem(10);
ret += delItem(30);
ret += delItem(50);
if(RET_SUCC != ret)
printf("\033[31m[warning]\033[0m ret = %d\n", ret);
dumpDataModel();
// FREE
ret = RET_SUCC;
ret = freeDataModel();
if(RET_SUCC != ret)
printf("\033[31m[warning]\033[0m ret = %d\n", ret);
return 0;
}