通讯录的进阶

上一篇博客,写了通讯录的简单版本,虽然需要的功能基本都有,但是仍然存在许多问题:

1.当通讯录的实际人数只有几十个时,开辟500个人的信息的内存,显然会浪费,当通讯录人数多于500时,没有足够的内存去存储这么多人的信息;

2.当程序退出时,输入的信息无法保存下来,程序再次打开时,原先输入的数据已经没有了。

鉴于以上两点,对程序进行了改进:一方面,使用malloc,realloc,free等函数动态开辟内存,当人数增加时,可以动态增加内存;另一方面,使用fread,fwritefopen,fclose等函数,在程序退出时将数据写入文件中进行保存,当程序再次打开时,可以将文件中的数据加载到程序中。

在功能上,与上一版一致,包括联系人的添加,删除,修改,查找,展示,排序,清空及退出。

头文件contact.h

#ifndef __CONTACT_H__ 
#define __CONTACT_H__ 

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

#define NAME_MAX 20//姓名能占用的最大空间
#define SEX_MAX 5//性别
#define ADDR_MAX 30//地址
#define TELE_MAX 12 //电话
#define DEFAULT_SZ 3 //默认容量
#define DEFAULT_ADD 2//增容增加的容量
#define FILENAME "contact.dat"//文件名称

typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char addr[ADDR_MAX];
	char tele[TELE_MAX];
}PeoInfo;//struct PeoInfo a; <=> PeoInfo a;

typedef struct Contact
{
	PeoInfo* data;//数据存储区域
	int sz;//有效元素个数
	int capacity;//当前容量
}Contact, *pContact;

//函数声明
void InitContact(pContact pcon);//初始化
void AddContact(pContact pcon);//添加
void ShowContact(const pContact pcon);//浏览
void DelContact(pContact pcon);//删除
void SearchContact(pContact pcon);//查找
void ModifyContact(pContact pcon);//修改
void SortContach(pContact pcon);//排序
void ClearContact(pContact pcon);//清空
void DestroyContact(pContact pcon);//释放动态内存
void SaveContactData(pContact pcon);//保存数据,写入文件
void LoadContactData(pContact pcon);//加载信息
#endif

源文件contact.c

#include "contact.h"

void InitContact(pContact pcon)//开辟动态内存并初始化
{
	pcon->sz = 0;
	pcon->data = malloc(DEFAULT_SZ*sizeof(PeoInfo));
	if (pcon->data == NULL)
	{
		perror("use malloc");
		exit(EXIT_FAILURE);
	}
	memset(pcon->data, 0, DEFAULT_SZ*sizeof(PeoInfo));
	pcon->capacity = DEFAULT_SZ;
	LoadContactData(pcon);
}
static void CheckCapacity(pContact pcon)//检查是否需要增容,static修饰的函数只能在本文件中使用
{
	if (pcon->sz == pcon->capacity)
	{
		//增容
		PeoInfo* ptr = realloc(pcon->data, (pcon->capacity + DEFAULT_ADD)*sizeof(PeoInfo));
		if (ptr == NULL)
		{
			perror("use realloc");
			exit(EXIT_FAILURE);//失败退出
		}
		else
			pcon->data = ptr;
		pcon->capacity += DEFAULT_ADD;
		//printf("增容成功\n");
	}
}
void AddContact(pContact pcon)//添加
{
	assert(pcon);//断言,用于检验是否为NULL,便于调试,
	             //若函数错误的接受了一个NULL参数,程序就会停止,并打印出提示信息;
				 //若表达式为真(非零),它不会打印任何东西,程序继续执行。
	CheckCapacity(pcon);
	printf("请输入名字:> ");
	scanf("%s", pcon->data[pcon->sz].name);
	printf("请输入年龄:> ");
	scanf("%d", &pcon->data[pcon->sz].age);
	printf("请输入性别:> ");
	scanf("%s", pcon->data[pcon->sz].sex);
	printf("请输入地址:> ");
	scanf("%s", pcon->data[pcon->sz].addr);
	printf("请输入电话:> ");
	scanf("%s", pcon->data[pcon->sz].tele);

	pcon->sz++;
	printf("\n添加成功!\n");
}
void ShowContact(const pContact pcon)//浏览所有联系人
{
	int i = 0;
	assert(pcon);
	printf("%8s\t%8s\t%8s\t%8s\t%8s\n", "name", "age", "sex", "addr", "tele");
	for (i = 0; i < pcon->sz; i++)
	{
		printf("%8s\t", pcon->data[i].name);
		printf("%8d\t", pcon->data[i].age);
		printf("%8s\t", pcon->data[i].sex);
		printf("%8s\t", pcon->data[i].addr);
		printf("%8s\n", pcon->data[i].tele);
	}
}
static int find(pContact pcon,char *name1)//查找函数,如果找到返回联系人所在的排名,否则返回-1
{
	int i = 0;
	assert(pcon);
	assert(name1);
	for (i = 0; i < pcon->sz; i++)
	{
		if (strcmp(pcon->data[i].name, name1) == 0)
		{
			return i;
		}
	}
	return -1;
}
void DelContact(pContact pcon)//删除
{
	int find_name;
	int i = 0;
	char name1[NAME_MAX];
	assert(pcon);
	printf("请输入删除的人姓名:> ");
	scanf("%s", name1);
	find_name = find(pcon, name1);
	if (find_name != -1)
	{
		for (i = find_name; i < pcon->sz; i++)
			pcon->data[i] = pcon->data[i + 1];//后一个人信息覆盖到前一个
		pcon->sz--;
		printf("删除成功\n");
	}
}
void SearchContact(pContact pcon)//查找联系人
{
	int ret = 0;
	int find_name = 0;
	char name1[NAME_MAX];
	assert(pcon);
	do
	{
		printf("请输入要查找的人名字:> ");
		scanf("%s", name1);
		find_name = find(pcon, name1);
		if (find_name != -1)
		{
			printf("\n");
			printf("姓名:%s\n", pcon->data[find_name].name);
			printf("年龄:%d\n", pcon->data[find_name].age);
			printf("性别:%s\n", pcon->data[find_name].sex);
			printf("地址:%s\n", pcon->data[find_name].addr);
			printf("电话:%s\n", pcon->data[find_name].tele);
		}
		else
			printf("没有找到此人\n");
		printf("是否继续,继续查找请选择1,结束查找请选择0:> ");
		scanf("%d", &ret);
		while (ret != 0 && ret != 1)
		{
			printf("选择错误!请重新选择:> ");
			scanf("%d", &ret);
		}
	} while (ret);
}
void ModifyContact(pContact pcon)//修改信息
{
	int ret = 0;
	int find_name = 0;
	char name1[NAME_MAX];
	assert(pcon);
	do
	{
		printf("请输入要修改的人名字:> ");
		scanf("%s", name1);
		find_name = find(pcon, name1);
		if (find_name != -1)
		{
			printf("\n");
			printf("请输入修改后的姓名:");
			scanf("%s", pcon->data[find_name].name);
			printf("请输入修改后的年龄:");
			scanf("%d", &pcon->data[find_name].age);
			printf("请输入修改后的性别:");
			scanf("%s", pcon->data[find_name].sex);
			printf("请输入修改后的地址:");
			scanf("%s", pcon->data[find_name].addr);
			printf("请输入修改后的电话:");
			scanf("%s", pcon->data[find_name].tele);
		}
		else
			printf("没有找到此人\n");
		printf("是否继续,继续修改请选择1,结束修改请选择0:> ");
		scanf("%d", &ret);
		while (ret != 0 && ret != 1)
		{
			printf("选择错误!请重新选择:> ");
			scanf("%d", &ret);
		}
	} while (ret);
}
void SortContach(pContact pcon)//对联系人按姓名排序
{
	int i = 0;
	int j = 0;
	assert(pcon);
	printf("姓名从A-Z的顺序为:\n");
	for (i = 0; i < pcon->sz; i++)
	{
		for (j = 0; j < pcon->sz - i - 1; j++)
		{
			if (strcmp(pcon->data[j].name, pcon->data[j + 1].name)>0)
			{
				PeoInfo tmp;
				tmp = pcon->data[j];
				pcon->data[j] = pcon->data[j + 1];
				pcon->data[j + 1] = tmp;
			}
		}
	}
	ShowContact(pcon);
}
void ClearContact(pContact pcon)//清空联系人
{
	int ret = 0;
	assert(pcon);
	printf("确定清空?确定选择1,取消选择0:) ");
	scanf("%d", &ret);
	if (ret == 1)
	{
		pcon->sz = 0;//没有显示
		memset(pcon->data, 0, sizeof(pcon->data));
		printf("删除成功\n");
	}
	while (ret != 0 && ret != 1)
	{
		printf("选择错误!请重新选择:) ");
		scanf("%d", &ret);
	}
}
void DestroyContact(pContact pcon)//释放动态内存
{
	free(pcon->data);
	pcon->data = NULL;
	pcon->capacity = 0;
	pcon->sz = 0;
}
void SaveContactData(pContact pcon)//保存数据写入文件
{
	FILE* pfout = fopen(FILENAME, "w");
	int i = 0;
	if (pfout == NULL)
	{
		perror("SaveContactData::fopen");//报错
		exit(EXIT_FAILURE);
	}
	for (i = 0; i < pcon->sz; i++)
	{
		fwrite(pcon->data + i, sizeof(PeoInfo), 1, pfout);
	}
	fclose(pfout);
}
void LoadContactData(pContact pcon)//加载文件中的数据
{
	FILE* pfin = fopen(FILENAME, "r");
	PeoInfo tmp = { 0 };
	if (pfin == NULL)
	{
		perror("LoadContactData::fopen");
		exit(EXIT_FAILURE);
	}
	while (fread(&tmp, sizeof(PeoInfo), 1, pfin))
	{
		CheckCapacity(pcon);
		pcon->data[pcon->sz] = tmp;
		pcon->sz++;
	}
	fclose(pfin);
}

测试函数test.c

#define _CRT_SECURE_NO_WARNINGS
#include "contact.h"
void menu()//菜单
{
	printf("\n");
	printf("******************************************\n");
	printf("***********1.添加       2.浏览  **********\n");
	printf("***********3.删除       4.查找  **********\n");
	printf("***********5.修改       6.排序  **********\n");
	printf("***********7.清空       0.退出  **********\n");
	printf("******************************************\n");
}
enum//枚举
{
	EXIT,//0.退出
	ADD,//1.添加
	SHOW,//2.浏览
	DEL,//3.删除
	SEARCH,//4.查找
	MODIFY,//5.修改
	SORT,//6.排序
	CLEAR,//7.清空
};
void test()
{
	int input = 0;
	Contact my_con;
	InitContact(&my_con);
	do
	{
		menu();
		printf("\n请输入你的选择:> ");
		scanf("%d", &input);
		switch (input)
		{
		case ADD://添加联系人
			AddContact(&my_con);
			break;
		case SHOW://浏览联系人
			ShowContact(&my_con);
			break;
		case DEL://删除联系人
			DelContact(&my_con);
			break;
		case SEARCH://查找联系人
			SearchContact(&my_con);
			break;
		case MODIFY://修改联系人
			ModifyContact(&my_con);
			break;
		case SORT://按姓名排序联系人
			SortContach(&my_con);
			break;
		case CLEAR://清空联系人
			ClearContact(&my_con);
			break;
		case EXIT://退出,写入信息到文件,并释放开辟的动态内存
			SaveContactData(&my_con);
			DestroyContact(&my_con);
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值