对通讯录的升级

这篇文章是对模拟实现通讯录的补充

在之前的模拟实现通讯录中升级了两个功能

1.实现通讯录内存的动态管理

2.以文件的形式保存了通讯录,保证在下一次运行代码时能找到上一次保存的联系人

功能一、通讯录内存的动态管理

在实现动态管理时,就需要使用malloc和realloc函数来实现内存的灵活运用

我们假设初始化通讯录时,通讯录只能存储3个联系人,如果容量不够,就使用realloc函数实现增容。

因为涉及到增容,那么在创建通讯录结构体时就需要改变

//动态通讯录的版本
//创建结构体 (通讯录),成员变量是联系信息和联系人个数
typedef struct Contact
{
	PeoInfo* data;//联系人类型的结构体指针,指向的是calloc函数开辟的空间
	int num;//用来标记存储的联系人个数
	int sz;//用来标记容量
}Contact;

那么初始化通讯录同样做出改变

// 动态版本初始化通讯录
void InitContact(Contact* pc)
{
	pc->num = 0;//开始时通讯录中的联系人个数为0
	pc->sz = 3;//通讯录初始容量为3

	pc->data = (PeoInfo*)calloc(3, sizeof(PeoInfo));//向内存申请3个PeoInfo类型的空间
	if (pc == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
	//初始化通讯录之后,把之前文件中的联系人添加到通讯录中
	LoadContact(pc);
}

在通讯录的功能中涉及到容量文体的还有增加联系人

//检查通讯录是否需要增容
void CheckCapacity(Contact* pc)
{
	//现在的通讯录不会满,但是要判断联系人个数和容量是否相等,相等就增容
	if (pc->num == pc->sz)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * (pc->sz + 2));
		if (ptr != NULL)
		{
			pc->data = ptr;
		}
		else
		{
			perror("CheckCapacity->realloc");
			return;
		}
		pc->sz = (pc->sz) + 2;
		printf("增容成功\n");
	}
}

//动态版本增加联系人
void AddContact(Contact* pc)
{
	//检查通讯录是否需要增容
	CheckCapacity(pc);

	printf("请输入联系人姓名:");
	scanf("%s", pc->data[pc->num].name);
	//pc->data 找到存储联系人信息的数组[pc->num]找到这个数组要添加的联系人的下标
	//在.name访问结构体成员变量

	printf("请输入联系人年龄:");
	scanf("%d", &pc->data[pc->num].age);

	printf("请输入联系人性别:");
	scanf("%s", pc->data[pc->num].sex);

	printf("请输入联系人电话:");
	scanf("%s", pc->data[pc->num].tele);

	printf("请输入联系人住址:");
	scanf("%s", pc->data[pc->num].addr);
	pc->num++;
	printf("添加成功\n");
}

因为涉及到动态内存的申请,所以在退出通讯录之前也要先释放内存

//销毁通讯录
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->num = 0;
	pc->sz = 0;
}

功能二、文件的形式保存通讯录

如果要以文件的形式保存,那么就要在退出通讯录时,也就是销毁通讯录之前先把通讯录保存在文件中

//把通讯录信息保存在文件上
void SaveContact(Contact* pc)
{
	//打开文件
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContact fopen");
		return;
	}

	//向文件写入信息
	size_t ch = 0;
	int i = 0;
	for (i = 0; i < pc->num; i++)//向文件中一个一个的写入信息
	{
		fwrite(pc->data+i, sizeof(PeoInfo), 1, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

同时我们也要对初始化通讯录做出改变,在以保证在下一次运行代码时,已经把文件中的信息读到通讯录当中

//把文件中的联系人添加到通讯录中
void LoadContact(Contact* pc)
{
	//先检查是否需要增容
	CheckCapacity(pc);
	//打开文件
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact->fopen");
		return;
	}
	//从文件读出
	size_t ch = 0;
	PeoInfo ex={0};
	while (ch = fread(&ex, sizeof(PeoInfo), 1, pf) != 0)
	{
		//先检查是否需要增容
		CheckCapacity(pc);
		pc->data[pc->num] = ex;
		pc->num++;
	}

	//关闭文件
	fclose(pf);
	pf = NULL;
}


// 动态版本初始化通讯录
void InitContact(Contact* pc)
{
	pc->num = 0;//开始时通讯录中的联系人个数为0
	pc->sz = 3;//通讯录初始容量为3

	pc->data = (PeoInfo*)calloc(3, sizeof(PeoInfo));//向内存申请3个PeoInfo类型的空间
	if (pc == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
	//初始化通讯录之后,把之前文件中的联系人添加到通讯录中
	LoadContact(pc);
}

如图

在第一次运行时添加了四位联系人胡英俊、牛爷爷、胡图图、和壮壮,

并输入0退出通讯录以保证四位联系人被写到文件中

关闭运行窗口,第二次运行时直接输入5,显示联系人就可以看到联系人,说明联系人被从文件读出

总体代码如下

test.c文件

#include"contact.h"


void menu()
{
	printf("************************\n");
	printf("***   1.add  2.del   ***\n");
	printf("***3.search  4.modify***\n");
	printf("***  5.show  6.sort ***\n");
	printf("***    0.exit       ****\n");
	printf("************************\n");
}

enum Option //用枚举列举出所有的功能,并且EXIT的默认值为0,依次往上递增,与菜单一致
{
	EXIT,//退出通讯录
	ADD,//添加联系人
	DEL,//删除联系人
	SEARCH,//查找联系人
	MODIFY,//修改联系人
	SHOW,//显示所有联系人
	SORT//对所有联系人排序
};



int main()
{
	int input = 0;
	//创建通讯录变量
	Contact con;
	//对通讯录变量初始化
	InitContact(&con);
	//当文件中写入了联系人后,在下一次加载通讯录时一个把文件中的联系人读到通讯录中,所以在初始化时加载出来
	do
	{
		menu();
		printf("请输入选择\n");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SEARCH:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			//在释放内存之前,要先把信息保存到文件上
			SaveContact(&con);
			//释放内存
			DestroyContact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}

	} while (input);
	return 0;
}

contact.h文件

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

//创建结构体(联系人),成员变量是联系人的各种信息
typedef struct PeoInfo
{
	char name[20];
	int age;
	char sex[5];
	char tele[15];
	char addr[30];
}PeoInfo;



////静态通讯录的版本
////创建结构体 (通讯录),成员变量是联系信息和联系人个数
//typedef struct Contact
//{
//	PeoInfo data[100];//结构体数组,
//	int num;//用来标记存储的联系人个数
//}Contact;



//动态通讯录的版本
//创建结构体 (通讯录),成员变量是联系信息和联系人个数
typedef struct Contact
{
	PeoInfo* data;//联系人类型的结构体指针,指向的是calloc函数开辟的空间
	int num;//用来标记存储的联系人个数
	int sz;//用来标记容量
}Contact;



//初始化通讯录
void InitContact(Contact* pc);

//增加联系人
void AddContact(Contact* pc);

//显示联系人
void ShowContact(Contact* pc);

//删除联系人
void DelContact(Contact* pc);

//查找联系人
void SearchContact(Contact* pc);

//修改联系人
void ModifyContact(Contact* pc);

//给联系人排序
void SortContact(Contact* pc);


//将通讯录保存在文件上
void SaveContact(Contact* pc);

//销毁通讯录
void DestroyContact(Contact* pc);

contact.c文件

#include"contact.h"


//// 静态版本初始化通讯录
//void InitContact(Contact* pc)
//{
//	pc->num = 0;
//	memset(pc->data, 0, sizeof(pc->data));//pc->data就是数组名data,是指针
//}

//检查通讯录是否需要增容
void CheckCapacity(Contact* pc);


//把文件中的联系人添加到通讯录中
void LoadContact(Contact* pc)
{
	//先检查是否需要增容
	CheckCapacity(pc);
	//打开文件
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact->fopen");
		return;
	}
	//从文件读出
	size_t ch = 0;
	PeoInfo ex={0};
	while (ch = fread(&ex, sizeof(PeoInfo), 1, pf) != 0)
	{
		//先检查是否需要增容
		CheckCapacity(pc);
		pc->data[pc->num] = ex;
		pc->num++;
	}

	//关闭文件
	fclose(pf);
	pf = NULL;
}


// 动态版本初始化通讯录
void InitContact(Contact* pc)
{
	pc->num = 0;//开始时通讯录中的联系人个数为0
	pc->sz = 3;//通讯录初始容量为3

	pc->data = (PeoInfo*)calloc(3, sizeof(PeoInfo));//向内存申请3个PeoInfo类型的空间
	if (pc == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
	//初始化通讯录之后,把之前文件中的联系人添加到通讯录中
	LoadContact(pc);
}


//销毁通讯录
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->num = 0;
	pc->sz = 0;
}


////静态版本增加联系人
//void AddContact(Contact* pc)
//{
//	//增加前判断通讯录是否满了
//	if (pc->num == 100)
//	{
//		printf("通讯录满了,无法增加\n");
//		return;
//	}
//	//没满就开始增加
//	printf("请输入联系人姓名:");
//	scanf("%s", pc->data[pc->num].name);
//	//pc->data 找到存储联系人信息的数组[pc->num]找到这个数组要添加的联系人的下标
//	//在.name访问结构体成员变量
//
//	printf("请输入联系人年龄:");
//	scanf("%d", &pc->data[pc->num].age);
//
//	printf("请输入联系人性别:");
//	scanf("%s", pc->data[pc->num].sex);
//
//	printf("请输入联系人电话:");
//	scanf("%s", pc->data[pc->num].tele);
//
//	printf("请输入联系人住址:");
//	scanf("%s", pc->data[pc->num].addr);
//	pc->num++;
//	printf("添加成功\n");
//}


//检查通讯录是否需要增容
void CheckCapacity(Contact* pc)
{
	//现在的通讯录不会满,但是要判断联系人个数和容量是否相等,相等就增容
	if (pc->num == pc->sz)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * (pc->sz + 2));
		if (ptr != NULL)
		{
			pc->data = ptr;
		}
		else
		{
			perror("CheckCapacity->realloc");
			return;
		}
		pc->sz = (pc->sz) + 2;
		printf("增容成功\n");
	}
}

//动态版本增加联系人
void AddContact(Contact* pc)
{
	//检查通讯录是否需要增容
	CheckCapacity(pc);

	printf("请输入联系人姓名:");
	scanf("%s", pc->data[pc->num].name);
	//pc->data 找到存储联系人信息的数组[pc->num]找到这个数组要添加的联系人的下标
	//在.name访问结构体成员变量

	printf("请输入联系人年龄:");
	scanf("%d", &pc->data[pc->num].age);

	printf("请输入联系人性别:");
	scanf("%s", pc->data[pc->num].sex);

	printf("请输入联系人电话:");
	scanf("%s", pc->data[pc->num].tele);

	printf("请输入联系人住址:");
	scanf("%s", pc->data[pc->num].addr);
	pc->num++;
	printf("添加成功\n");
}




//显示联系人
void ShowContact(Contact* pc)
{
	//先判断通讯录是否有联系人
	if (pc->num == 0)
	{
		printf("通讯录无联系人,无法显示\n");
		return;
	}
	//有联系人,显示
	int i = 0;
	printf("%-20s %-4s %-5s %-15s %-30s\n", "name", "age", "sex", "telephone", "address");
	for (i = 0; i < pc->num; i++)
	{
		printf("%-20s %-4d %-5s %-15s %-30s\n",
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}

}


int Find_by_name(Contact* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->num; i++)
	{
		if (*name == *(pc->data[i].name))
		{
			return i;
		}
	}
	//出了循环就是没有找到
	return -1;
}


//删除联系人
void DelContact(Contact* pc)
{
	//先判断通讯录有没有联系人
	if (pc->num == 0)
	{
		printf("通讯录无联系人,无法删除\n");
		return;
	}

	char name[20];
	printf("请输入想要删除的联系人姓名\n");
	scanf("%s", name);
	//先遍历通讯录,看有没有这个人的名字
	int rst1 = Find_by_name(pc, name);
	if (rst1 == -1)
	{
		printf("通讯录无该联系人\n");
		return;
	}

	// 为了不改变通讯录联系人顺序,要把后面的联系人依次往前放
	int i = 0;
	//这样只能改变存在的前num-1个联系人的,如果要删除联系人是最后一个,也就不用改变顺序了
	for (i = rst1; i < pc->num - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];

	}
	//删除后联系人数量减一
	pc->num--;
	printf("删除成功\n");

}


//查找联系人
void SearchContact(Contact* pc)
{
	//判断通讯录不为空
	if (pc->num == 0)
	{
		printf("通讯录无联系人,无法查找\n");
		return;
	}

	char name[20];
	printf("请输入要查找的联系人姓名");
	scanf("%s", name);
	//先遍历通讯录,看有没有这个人的名字
	int rst = Find_by_name(pc, name);

	if (rst == -1)
	{
		printf("通讯录无该联系人\n");
		return;
	}
	//有这个联系人就显示这个联系人的所有信息
	printf("%-20s %-4s %-5s %-15s %-30s\n", "name", "age", "sex", "telephone", "address");

	printf("%-20s %-4d %-5s %-15s %-30s\n",
		pc->data[rst].name, pc->data[rst].age, pc->data[rst].sex, pc->data[rst].tele, pc->data[rst].addr);
}


//修改联系人
void ModifyContact(Contact* pc)
{
	//判断通讯录不为空
	if (pc->num == 0)
	{
		printf("通讯录无联系人,无法查找\n");
		return;
	}

	char name[20];
	printf("请输入要修改的联系人姓名");
	scanf("%s", name);
	//先遍历通讯录,看有没有这个人的名字
	int rst = Find_by_name(pc, name);
	if (rst == -1)
	{
		printf("通讯录无该联系人\n");
		return;
	}

	//有这个联系人就开始修改
	printf("请输入联系人姓名:");
	scanf("%s", pc->data[rst].name);

	printf("请输入联系人年龄:");
	scanf("%d", &pc->data[rst].age);

	printf("请输入联系人性别:");
	scanf("%s", pc->data[rst].sex);

	printf("请输入联系人电话:");
	scanf("%s", pc->data[rst].tele);

	printf("请输入联系人住址:");
	scanf("%s", pc->data[rst].addr);

	printf("修改成功\n");
}




//e1和e2是数组的相邻的两个元素,结构体数组的一个元素就有多个成员变量
int my_compar(const char* e1, const char* e2)
{
	return strcmp(((Contact*)e1)->data->name, ((Contact*)e2)->data->name);
}

//给联系人排序
void SortContact(Contact* pc)
{
	//判断通讯录不为空
	if (pc->num == 0)
	{
		printf("通讯录无联系人,无法查找\n");
		return;
	}

	//按名字的首字母的顺序排序
	size_t sz = sizeof(pc->data[0]);
	qsort(pc->data, pc->num, sz, my_compar);
}



//把通讯录信息保存在文件上
void SaveContact(Contact* pc)
{
	//打开文件
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContact fopen");
		return;
	}

	//向文件写入信息
	size_t ch = 0;
	int i = 0;
	for (i = 0; i < pc->num; i++)//向文件中一个一个的写入信息
	{
		fwrite(pc->data+i, sizeof(PeoInfo), 1, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值