C语言实现自己的动态数组库

本文介绍了一个动态数组库的实现,包括头文件ArrayLib.h和源文件ArrayLib.c。该库提供了初始化、追加、插入、查找、排序等功能,并详细解释了各函数的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态数组库由两部分构成:头文件 ArrayLib.h 和所有函数方法实现文件 ArrayLib.c 根据头文件所需要的功能直接调用就可以了!


ArrayLib.h

/***********************************************
 * 文件名:arrayLib.h
 * 文件描述:动态数组库函数头文件,包含了动态数组
 * 			 所有功能的函数的声明以及类型定义等
 * 编辑人:王廷云
 * 编辑日期:2017-10-1
 * 修改日期:2018-1-10
************************************************/

#ifndef  _ARRAY_LIB_H_
#define  _ARRAY_LIB_H_

/* 动态数组结构体封装 */
typedef struct {
	int  n;     // 动态数组的元素个数
	int  size;	// 动态数组的元素空间大小
	void *addr; // 动态数组的数据起始地址
} Array_t;

/* 比较函数类型定义 */
typedef int compare_t(const void *data1, const void *data2);

/******************************
 * 以下为所有动态数组库函数声明
*******************************/

/* 
 * 函数名: initArray
 * 函数功能: 初始化动态数组
 * 参数: 数组元素的空间大小
 * 返回值: 成功则返回初始化后的动态数组指针
 * 		   失败返回NULL 
*/
Array_t *initArray(int size);

/*
 * 函数名: appendArrayTail
 * 函数功能: 尾部追加数组元素
 * 参数: 1.需要追加的数组指针 2.需要追加的元素指针
 * 返回值: 成功追加返回0 失败返回-1
*/
int appendArrayTail(Array_t *ar, const void *data);

/*
 * 函数名: appendArrayTop
 * 函数功能: 头部追加数组元素
 * 参数: 1.需要追加的数组指针 2.需要追加的元素指针
 * 返回值: 成功追加返回0 失败返回-1
*/
int appendArrayTop(Array_t *ar, const void *data);

/*
 * 函数名: insertArrayByIndex
 * 函数功能: 指定数组下标插入数组元素
 * 			 <函数会检查下标的合法性>
 * 参数: 1.需要插入数据的数组指针 2.需要插入的数据指针
 * 		 2.数组下标值
 * 返回值: 成功插入返回0 失败返回-1
*/
int insertArrayByIndex(Array_t *ar, const void *data, int idx);

/*
 * 函数名: travelArray
 * 函数功能: 遍历动态数组元素
 * 参数: 1.需要遍历的数组指针 2.回调函数
 * 返回值: 无
*/
void travelArray(Array_t *ar, void (*func)(void *data));

/*
 * 函数名: searchArrayByIndex
 * 函数功能: 根据下标查找数组元素<会检查下标的合法性>
 * 参数: 1.需要查找的数组指针 2.查找的下标
 * 返回值: 数据存在返回数据地址 不存在则返回NULL
*/
void *searchArrayByIndex(Array_t *ar, const int idx);

/*
 * 函数名: searchArrayOneByCond
 * 函数功能: 根据条件查找元素,如果有多个则找第一个
 * 参数: 1.需要查找的数组指针 2.比较回调函数指针 3.条件指针
 * 返回值: 数据存在返回数据地址 不存在则返回NULL
*/
void *searchArrayOneByCond(Array_t *ar, compare_t *func, \
										const void *key);
/*
 * 函数名: searchArrayByCond
 * 函数功能: 根据条件查找元素
 * 参数: 1.需要查找的数组指针 2.比较回调函数指针 3.条件指针
 * 返回值: 数据存在返回数据数组 不存在则返回NULL
*/
Array_t *searchArrayByCond(Array_t *ar, compare_t *func, \
										const void *key);
/*
 * 函数名: deleteArrayByIndex
 * 函数功能: 根据下标删除数组元素
 * 参数: 1.数组指针 2.下标
 * 返回值: 成功删除返回0 失败返回-1
*/
int deleteArrayByIndex(Array_t *ar, const int idx);

/*
 * 函数名: deleteArrayOneByCond
 * 函数功能: 根据条件删除数组元素,如果多个匹配则只删除第一个
 * 参数: 1.数组指针 2.比较回调函数指针 3.条件
 * 返回值: 成功删除返回0 失败返回-1
*/
int deleteArrayOneByCond(Array_t *ar, compare_t *func, \
									 const void *key);
/*
 * 函数名: deleteArrayByCond
 * 函数功能: 根据条件删除所有匹配的数组元素
 * 参数: 1.数组指针 2.比较回调函数指针 3.条件
 * 返回值: 返回成功删除的元素个数
*/
int deleteArrayByCond(Array_t *ar, compare_t *func, \
								   const void *key);
/*
 * 函数名: sortArray
 * 函数功能: 对数组元素进行排序
 * 			<至于按什么顺序排列则由用户的回调函数具体来实现>
 * 参数: 1.数组指针 2.比较回调函数指针
 * 返回值: 排序成功返回0 失败返回-1
*/
int sortArray(Array_t *ar, compare_t *func);

/*
 * 函数名: saveArrayToFile
 * 函数功能: 把数组元素数据保存到文件中
 * 参数: 1.数组指针 2.需要保存的文件
 * 返回值: 保存成功返回0 失败返回-1
*/
int saveArrayToFile(Array_t *ar, const char *file);

/*
 * 函数名: loadArrayFromFile
 * 函数功能: 从文件中加载数组数据
 * 参数: 需要加载的文件
 * 返回值: 成功加载返回数组指针 失败返回NULL
*/
Array_t *loadArrayFromFile(const char *file);

/*
 * 函数名: destoryArray
 * 函数功能: 销毁动态数组线性表
 * 参数: 数组指针
 * 返回值: 无
*/
void destoryArray(Array_t *ar);

/*
 * 函数名: isEmptyArray
 * 函数功能: 判断是否是空数组
 * 参数: 数组指针
 * 返回值: 为空返回1 不为空返回0
*/
int isEmptyArray(Array_t *ar);

/*
 * 函数名: arrayLenth
 * 函数功能: 求数组的长度(元素个数)
 * 参数: 数组指针
 * 返回值: 返回数组的元素个数
*/
int arrayLenth(Array_t *ar);

#endif  /* _ARRAY_LIB_H_ */




ArrayLib.c

/********************************************
 * 文件名:arrayLib.c
 * 文件描述:动态数组库函数所有功能函数的定义
 * 编辑人:王廷云
 * 编辑日期:2017-10-1
 * 修改日期:2018-1-10
*********************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "arrayLib.h"

/* 
 * 函数名: initArray
 * 函数功能: 初始化动态数组
 * 参数: 数组元素的空间大小
 * 返回值: 成功则返回初始化后的动态数组指针
 * 		   失败返回NULL 
*/
Array_t *initArray(int size)
{
	Array_t *ar;
	ar = malloc(sizeof(Array_t));
	if (ar == NULL) return NULL;

	ar->size = size;
	ar->n = 0;
	ar->addr = NULL;

	return ar;
}

/*
 * 函数名: appendArrayTail
 * 函数功能: 尾部追加数组元素
 * 参数: 1.需要追加的数组指针 2.需要追加的元素指针
 * 返回值: 成功追加返回0 失败返回-1
*/
int appendArrayTail(Array_t *ar, const void *data)
{
	void *temp;
#if 0
	/* 分配比原来多一个数据的空间 */
	temp = realloc(ar->addr, (ar->n+1)*ar->size);
	if (temp == NULL)
	{
		return -1;
	}
#else
	/* 分配比原来多一个数据的空间 */
	temp = malloc((ar->n+1) * ar->size);
	if (temp == NULL)
	{
		return -1;
	}
	/* 把原来数据移动到新空间 */
	memmove(temp, ar->addr, ar->n * ar->size);
	/* 释放原来数据空间 */
	free(ar->addr);
#endif
	/* 把新数据复制到新空间的尾部 */
	memmove(temp+(ar->n*ar->size), data, ar->size);
	/* 数据个数加1 */
	ar->n += 1;
	/* 更新数据地址指针 */
	ar->addr = temp;

	return 0;
}

/*
 * 函数名: appendArrayTop
 * 函数功能: 头部追加数组元素
 * 参数: 1.需要追加的数组指针 2.需要追加的元素指针
 * 返回值: 成功追加返回0 失败返回-1
*/
int appendArrayTop(Array_t *ar, const void *data)
{
	void *temp;
#if 0
	/* 分配比原来多一个数据的空间 */
	temp = realloc(ar->addr, (ar->n+1)*ar->size);
	if (temp == NULL)
	{
		return -1;
	}
#else
	/* 分配比原来多一个数据的空间 */
	temp = malloc((ar->n+1) * ar->size);
	if (temp == NULL)
	{
		return -1;
	}
	/* 把原来数据移动到新空间 */
	memmove(temp+ar->size, ar->addr, ar->n * ar->size);
	/* 释放原来数据空间 */
	free(ar->addr);
#endif
	/* 把新数据复制到新空间的头部 */
	memmove(temp, data, ar->size);
	/* 数据个数加1 */
	ar->n += 1;
	/* 更新数据地址指针 */
	ar->addr = temp;

	return 0;
}

/*
 * 函数名: insertArrayByIndex
 * 函数功能: 指定数组下标插入数组元素
 * 			 <函数会检查下标的合法性>
 * 参数: 1.需要插入数据的数组指针 2.需要插入的数据指针
 * 		 2.数组下标值
 * 返回值: 成功插入返回0 失败返回-1
*/
int insertArrayByIndex(Array_t *ar, const void *data, int idx)
{
	/* 检查下标合法性 */
	if (idx < 0 || idx > ar->n)
	{
		printf("Error! index is illegal!\n");
		return -1;
	}

	void *temp;
#if 0
	/* 分配比原来多一个数据的空间 */
	temp = realloc(ar->addr, (ar->n+1)*ar->size);
	if (temp == NULL)
	{
		return -1;
	}
	/* 把原来空间idx以及后面的数据移动到新空间的idx之后 */
	memmove(temp+(idx+1)*ar->size, temp+idx*ar->size, \
								(ar->n-idx)*ar->size);
	/* 把新数据插入到新空间的idx处 */
	memmove(temp+idx*ar->size, data, ar->size);
#else
	/* 分配比原来多一个数据的空间 */
	temp = malloc((ar->n+1)*ar->size);
	if (temp == NULL)
	{
		return -1;
	}
	/* 把原来空间idx以前的数据移动到新空间前面 */
	memmove(temp, ar->addr, idx*ar->size);
	/* 把新数据插入到新空间的idx处 */
	memmove(temp+idx*ar->size, data, ar->size);
	/* 把原来空间idx以及后面的数据移动到新空间的idx之后 */
	memmove(temp+(idx+1)*ar->size, ar->addr+(idx*ar->size), \
								(ar->n-idx)*ar->size);
#endif
	/* 数据元素个数加1 */
	ar->n += 1;
	/* 更新数据地址 */
	ar->addr = temp;

	return 0;
}

/*
 * 函数名: travelArray
 * 函数功能: 遍历动态数组元素
 * 参数: 1.需要遍历的数组指针 2.回调函数
 * 返回值: 无
*/
void travelArray(Array_t *ar, void (*func)(void *data))
{
	int i;
	for (i = 0; i < ar->n; i++)
	{
		/* ar->addr + i*ar->size: 每个数据的起始地址 */
		func(ar->addr + i*ar->size);
	}
}

/*
 * 函数名: searchArrayByIndex
 * 函数功能: 根据下标查找数组元素<会检查下标的合法性>
 * 参数: 1.需要查找的数组指针 2.查找的下标
 * 返回值: 数据存在返回数据地址 不存在则返回NULL
*/
void *searchArrayByIndex(Array_t *ar, const int idx)
{
	/* 下标合法性检查 */
	if (idx < 0 || idx >= ar->n)
	{
		fprintf(stderr,"Error! index is illegal!\n");
		return NULL;
	}
	return ar->addr + idx*ar->size;
}

/*
 * 函数名: searchArrayOneByCond
 * 函数功能: 根据条件查找元素,如果有多个则找第一个
 * 参数: 1.需要查找的数组指针 2.比较回调函数指针 3.条件指针
 * 返回值: 数据存在返回数据地址 不存在则返回NULL
*/
void *searchArrayOneByCond(Array_t *ar, compare_t *func, \
										const void *key)
{
	int i;
	for (i = 0; i < ar->n; i++)
	{
 		/* 比较函数条件匹配func返回1 */
		if (func(ar->addr+i*ar->size, key) == 1)
		{
			return ar->addr + i*ar->size;
		}
	}
	return NULL;
}
/*
 * 函数名: searchArrayByCond
 * 函数功能: 根据条件查找元素
 * 参数: 1.需要查找的数组指针 2.比较回调函数指针 3.条件指针
 * 返回值: 数据存在返回数据数组 不存在则返回NULL
*/
Array_t *searchArrayByCond(Array_t *ar, compare_t *func, \
										const void *key)
{
	int i, ret;
	Array_t *result;

	/* 创建用于保存结果的数组 */
	result = initArray(ar->size);
	if (result == NULL)
	{
		return NULL;
	}
	/* 遍历查找 */
	for (i = 0; i < ar->n; i++)
	{
 		/* 比较函数条件匹配func返回1 */
		if (func(ar->addr+i*ar->size, key) == 1)
		{
			/* 把匹配的数据尾部追加到数组里 */
			ret = appendArrayTail(result, ar->addr+i*ar->size);
			if (ret != 0)
			{
				destoryArray(result);
				return NULL;
			}
		}
	}
	return result;
}

/*
 * 函数名: deleteArrayByIndex
 * 函数功能: 根据下标删除数组元素
 * 参数: 1.数组指针 2.下标
 * 返回值: 成功删除返回0 失败返回-1
*/
int deleteArrayByIndex(Array_t *ar, const int idx)
{
	/* 检查下标合法性 */
	if (idx < 0 || idx >= ar->n)
	{
		fprintf(stderr, "Error! index is illegal!\n");
		return -1;
	}
	/* 通过数据搬运达到删除目的 */
	void *temp;
	temp = malloc((ar->n-1)*ar->size);
	if (temp == NULL)
	{
		return -1;
	}
	/* 把idx之前的数据移到新空间 */
	memmove(temp, ar->addr, idx*ar->size);
	/* 把idx之后的数据移到新空间 */
	memmove(temp+idx*ar->size, ar->addr+(idx+1)*ar->size, \
					              (ar->n-idx-1)*ar->size);
	/* 释放原来数据空间 */
	free(ar->addr);
	/* 更新元素个数 */
	ar->n -= 1;
	/* 更新数组元素地址 */
	ar->addr = temp;

	return 0;
}

/*
 * 函数名: deleteArrayOneByCond
 * 函数功能: 根据条件删除数组元素,如果多个匹配则只删除第一个
 * 参数: 1.数组指针 2.比较回调函数指针 3.条件
 * 返回值: 成功删除返回0 失败返回-1
*/
int deleteArrayOneByCond(Array_t *ar, compare_t *func, \
									 const void *key)
{
	int i;
	for (i = 0; i < ar->n; i++)
	{
		/* 比较函数条件匹配返回1 */
		if (func(ar->addr+i*ar->size, key) == 1)
		{
			return deleteArrayByIndex(ar,i);
		}
	}
	return -1;
}

/*
 * 函数名: deleteArrayByCond
 * 函数功能: 根据条件删除所有匹配的数组元素
 * 参数: 1.数组指针 2.比较回调函数指针 3.条件
 * 返回值: 返回成功删除的元素个数
*/
int deleteArrayByCond(Array_t *ar, compare_t *func, \
								   const void *key)
{
	int i;
	int count = 0;
	for (i = 0; i < ar->n; i++)
	{
		/* 比较函数条件匹配返回1 */
		if (func(ar->addr+i*ar->size, key) == 1)
		{
			if (deleteArrayByIndex(ar,i) == 0)
			{
				count++;
				i--; /* 弥补按下标删除元素后的下标变化 */
			}
		}
	}
	return count;
}
/*
 * 函数名: sortArray
 * 函数功能: 对数组元素进行排序
 * 			<至于按什么顺序排列则由用户的回调函数具体来实现>
 * 参数: 1.数组指针 2.比较回调函数指针
 * 返回值: 排序成功返回0 失败返回-1
*/
int sortArray(Array_t *ar, compare_t *func)
{
	int i, j;
	void *temp;
	temp = malloc(ar->size);
	if (temp == NULL) return -1;
	for (i = 0; i < ar->n; i++)
	{
		for (j = 1; j < ar->n-i; j++)
		{
		    /* 比较函数条件匹配返回1 */
		    if (func(ar->addr+i*ar->size, \
					ar->addr+j*ar->size) == 1)
		    {
		    	memmove(temp, ar->addr+i*ar->size, ar->size);
				memmove(ar->addr+i*ar->size, \
						ar->addr+j*ar->size, ar->size);
				memmove(ar->addr+j*ar->size, temp, ar->size);
		    }
		}
	}
	free(temp);
	return 0;	
}

/*
 * 函数名: saveArrayToFile
 * 函数功能: 把数组元素数据保存到文件中
 * 参数: 1.数组指针 2.需要保存的文件
 * 返回值: 保存成功返回0 失败返回-1
*/
int saveArrayToFile(Array_t *ar, const char *file)
{
	FILE *fout;
	int ret;

	/* 打开文件流 */
	fout = fopen(file, "w");
	if (fout == NULL)
	{
		perror(file);
		return -1;
	}
	/* 写入数组元素个数 */
	ret = fwrite(&ar->n, sizeof(ar->n), 1, fout);
	if (ret != 1)
	{
		/* 写入失败:关闭文件流,关闭文件 */
		fclose(fout);
		remove(file);
		return -1;
	}
	/* 写入数组元素空间大小 */
	ret = fwrite(&ar->size, sizeof(ar->size), 1, fout);
	if (ret != 1)
	{
		/* 写入失败:关闭文件流,关闭文件 */
		fclose(fout);
		remove(file);
		return -1;
	}
	/* 写入数据 */
	ret = 0;
	while (ret != ar->n) /* 保证写完 */
	{
		ret += fwrite(ar->addr+ret*ar->size, \
					ar->size, ar->n-ret, fout);
		/* 如果遇到写文件错误 */
		if (ferror(fout))
		{
			fclose(fout);
			remove(file);
			return -1;
		}
	}

	fclose(fout);
	return 0;
}

/*
 * 函数名: loadArrayFromFile
 * 函数功能: 从文件中加载数组数据
 * 参数: 需要加载的文件
 * 返回值: 成功加载返回数组指针 失败返回NULL
*/
Array_t *loadArrayFromFile(const char *file)
{
	int ret;
	FILE *fin;
	Array_t *ar;

	/* 打开文件 */
	fin = fopen(file, "r");
	if (fin == NULL)
	{
		return NULL;
	}
	/* 成功打开文件 */

	ar = initArray(0);
	if (ar == NULL)
	{
		fclose(fin);
		return NULL;
	}
	/* 成功初始化数组 */
	
	/* 读取数组元素个数 */
	ret = fread(&ar->n, sizeof(ar->n), 1, fin);
	if (ret != 1)
	{
		fclose(fin);
		destoryArray(ar);
		return NULL;
	}
	/* 读取数组元素空间大小 */
	ret = fread(&ar->size, sizeof(ar->size), 1, fin);
	if (ret != 1)
	{
		fclose(fin);
		destoryArray(ar);
		return NULL;
	}
	/* 读取数组元素数据 */
	ar->addr = malloc(ar->n * ar->size);
	if (ar->addr == NULL)
	{
		fclose(fin);
		destoryArray(ar);
		return NULL;
	}
	ret = 0;
	while (ret != ar->n) /* 保证读完 */
	{
		ret += fread(ar->addr + ret*ar->size, \
						ar->size, ar->n-ret, fin);
		if (ferror(fin))
		{
			if (ret > 0) /* 已经读取到了一部分 */
			{
				break;
			}
			else
			{
				fclose(fin);
				destoryArray(ar);
				return NULL;
			}
		}
		/* 有可能文件记录的个数与实际的不一样 */
		else if (feof(fin)) 
		{
			break;
		}
	}
	/* 文件数据丢失,没有之前存储的那么多 */
	if (ar->n != ret)
	{
		void *temp;
		ar->n = ret;
		temp = realloc(ar->addr, ar->n*ar->size);
	}

	fclose(fin);   // 关闭打开的文件
	return ar;
}

/*
 * 函数名: destoryArray
 * 函数功能: 销毁动态数组线性表
 * 参数: 数组指针
 * 返回值: 无
*/
void destoryArray(Array_t *ar)
{
	/* 释放数组元素空间 */
	free(ar->addr);
	/* 释放数组本身空间 */
	free(ar);
	/* 避免再次使用释放的空间 */
	ar = NULL;
}

/*
 * 函数名: isEmptyArray
 * 函数功能: 判断是否是空数组
 * 参数: 数组指针
 * 返回值: 为空返回1 不为空返回0
*/
int isEmptyArray(Array_t *ar)
{
	/* 元素个数为零同时元素地址为NULL */
	return ar->n==0 && ar->addr==NULL;
}

/*
 * 函数名: arrayLenth
 * 函数功能: 求数组的长度(元素个数)
 * 参数: 数组指针
 * 返回值: 返回数组的元素个数
*/
int arrayLenth(Array_t *ar)
{
	return ar->n;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值