C语言实现通讯录(静态版本+动态版本)

当前使用VS2019编译器

首先建立2个源文件test.c和contect.c以及1个头文件contect.h

一.通讯录操作菜单

void menu()
{
	printf("********  1.Add     2.Del    ***********************\n");
	printf("********  3.Search  4.Modify ***********************\n");
	printf("********  5.Sort    6.Print  ***********************\n");
	printf("********  7.Destroy 0.Exit   ***********************\n");
	printf("****************************************************\n");
}

1. 定义结构体变量以及枚举常量

typedef struct PeoInfo//该结构体变量用来存储个人的信息
{
	char name[NAME_MAX];//以下数组中的值为#define的宏定义
	char sex[SEX_MAX];
	int age;
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
}PeoInfo;
typedef struct Contect//静态版本
{
	PeoInfo data[MAX];//用来储存MAX个PeoInfo类型的数据
	int sz;//用来记录当前通讯录人数的个数
}Contect;//重命名
typedef struct Contect//动态版本
{
	PeoInfo* data;
	int sz;
	int capacity;
}Contect;
enum Select {//该枚举常量为通讯录菜单中的选择
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SORT,
	PRINT,
	DESTROY
};
enum Modify {//该枚举常量为通讯录中修改函数中菜单的选择
	NAME=1,
	SEX,
	AGE,
	TELE,
	ADDR
};

2.选择操作

void test()
{
	int input = 0;
	Contect con;//定义一个Contect类型的变量
	InitContect(&con);//初始化
	do {
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)//下面的case语句中的常量为枚举常量
		{
		case ADD:
			AddContect(&con);
			break;
		case DEL:
			DelContect(&con);
			break;
		case SEARCH:
			SearchContect(&con);
			break;
		case MODIFY:
			ModifyContect(&con);
			break;
		case SORT:
			SortContect(&con);
			break;
		case PRINT:
			PrintContect(&con);
			break;
		case DESTROY:
			DestroyContect(&con);
			break;
		case EXIT:
			printf("退出程序");
			break;
		default:
			printf("选择错误");
			break;
		}
	} while (input);
}

二.函数的声明

//初始化
void InitContect(Contect* pc);
//增加内容
void AddContect(Contect* pc);
//打印
void PrintContect(Contect* pc);
//删除内容
void DelContect(Contect* pc);
//查找内容
void SearchContect(const Contect* pc);
//修改内容
void ModifyContect(Contect* pc);
//排序内容
void SortContect(Contect* pc);
//销毁
void DestroyContect(Contect* pc);

三.函数的定义

 1.通讯录的初始化

//静态版本
void InitContect(Contect* pc)
{
	assert(pc);//判断是否为NULL
	memset(pc->data, 0, sizeof(pc->data));
	pc->sz = 0;
}

 memset的作用是将缓冲区设置为指定的字符'0'

//动态版本
void InitContect(Contect* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;//设置初始化能存DEFAULT_SZ个数据,其中DEFAULT_SZ为宏定义的内容
	pc->data = (PeoInfo*)malloc(pc->capacity * sizeof(PeoInfo));//用malloc动态分配内存给data数组
	if (pc->data==NULL)
	{
		perror("InitContect::malloc");//显示动态分配内存出错的信息
		return;
	}
	memset(pc->data, 0, pc->capacity * sizeof(PeoInfo));
}

malloc用来分配内存,单位为字节

2.通讯录内容的添加

void AddContect(Contect* pc)
{
	assert(pc);
	//静态版本
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法添加");
		return;
	}
	printf("请输入名字:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);
	pc->sz++;
	printf("添加成功\n");
}
void AddContect(Contect* pc)
{
	assert(pc);
	//动态版本
	CheckCapacity(pc);//该函数用来判断当前通讯录能够存储的内容是否达到最大值
	printf("请输入名字:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);
	pc->sz++;
	printf("添加成功\n");
}
void CheckCapacity(Contect* pc)
{
	assert(pc);
	if (pc->sz == pc->capacity)//sz为当前通讯录中数据的个数,capacity为当前通讯录中最多能存储数据的个数
	{
		PeoInfo* tmp = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));//每次增加2个存储数据的空间
		if (tmp != NULL)
		{
			pc->data = tmp;//tmp不等于空指针说明内存分配成功,将成功分配的内存给data数组
		}
		else
		{
			perror("CheckCapacity::realloc");//内存分配失败的原因
			return;
		}
		pc->capacity += 2;
		printf("增容成功\n");
	}
}

 

realloc 的作用为重新分配内存块,能增能减

3.通讯录内容的删除

void DelContect(Contect* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要删除的姓名:");
	scanf("%s", name);
	int ret = Search_by_name(pc, name);//找到想要删除的对象
	if (-1 == ret)
	{
		printf("无法找到该内容\n");
		return;
	}
	for (int i = ret; i < pc->sz - 1; i++)//将删除对象后面的数据往前移
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

3.通讯录内容的查找

void SearchContect(const Contect* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找的姓名:");
	scanf("%s", name);
	int pos = Search_by_name(pc, name);//通过名字查找
	if (-1 == pos)
	{
		printf("无法找到该内容\n");
	}
	else
	{
		printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr);
	}
}
int Search_by_name(Contect* pc, char name[])
{
	assert(pc);
	for (int i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(name, pc->data[i].name))//strcmp为字符串的比较,不懂的详见上一篇
		{
			return i;
		}
	}
	return -1;
}

4.通讯录内容的修改

修改菜单:

void MENU()
{
	printf("********** 1.name  2.sex  **********\n");
	printf("********** 3.age   4.tele **********\n");
	printf("********** 5.addr  0.exit **********\n");
}
void ModifyContect(Contect* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要修改的人的姓名:");
	scanf("%s", name);
	int ret = Search_by_name(pc, name);//找到要修改的对象
	if (-1 == ret)
	{
		printf("无法找到要修改的人的信息\n");
		return;
	}
	int input = 0;
	do {
		MENU();
		printf("请选择要修改的内容:");
		scanf("%d", &input);
		switch (input)
		{
		case NAME:
			printf("请输入名字:");
			scanf("%s", pc->data[ret].name);
			printf("修改成功\n");
			break;
		case SEX:
			printf("请输入性别:");
			scanf("%s", pc->data[ret].sex);
			printf("修改成功\n");
			break;
		case AGE:
			printf("请输入年龄:");
			scanf("%d", &(pc->data[ret].age));
			printf("修改成功\n");
			break;
		case TELE:
			printf("请输入电话:");
			scanf("%s", pc->data[ret].tele);
			printf("修改成功\n");
			break;
		case ADDR:
			printf("请输入地址:");
			scanf("%s", pc->data[ret].addr);
			printf("修改成功\n");
			break;
		case EXIT:
			printf("退出修改程序\n");
			break;
		default:
			printf("输入错误\n");
			break;
		}
	} while (input);
}

5.通讯录的排序(以名字排序)

void SortContect(Contect* pc)
{
	assert(pc);
	qsort(pc->data, pc->sz, sizeof(PeoInfo), compare);//使用qsort库函数进行排序
	printf("排序成功\n");
}

 该函数最后一个参数内容为自定义函数,以要通过什么内容来进行排序编写函数

int compare(const void* e1, const void* e2)
{
	return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
}

6.通讯录的打印

void PrintContect(Contect* pc)
{
	assert(pc);
	if (0 == pc->sz)
		{
			printf("通讯录中无内容\n");
		}
	else
		printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		
		printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

7.通讯录的销毁

void DestroyContect(Contect* pc)
{
	free(pc->data);/需要通过free函数来进行释放动态分配的内存空间否则会导致内存泄露
	pc->sz = 0;
	pc->capacity = 0;
	pc->data = NULL;
	printf("销毁成功\n");
}

评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

山涧晴岚.

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值