[C语言]通讯录

目录

基本版本

一、test.c测试文件

main()主函数

菜单menu()函数 

二、contact.h头文件

结构体Peoinfo

结构体Contact

 定义宏

 声明函数

三、contact.c函数实现文件

初始化联系人

添加联系人

 打印通讯录

 寻找指定联系人

 删除指定联系人

查找指定联系人

修改联系人信息

按照年龄排序联系人信息

动态版本

一、contact.h头文件

考虑增容后的结构体Contact 

 新定义的宏

二、concact.c函数实现文件

初始化通讯录

增加联系人

 销毁通讯录

文件版本

 一、contact.h头文件

文件版本的新函数

二、test.c测试文件

三、concact.c函数实现文件

保存联系人信息到文件

初始化通讯录——添加已有联系人到通讯录中

​ Checkcapacity增容函数

基本版本

目标功能:

1.通讯录能够存放1000个联系人的信息

每个联系人的信息包括:名字+年龄+性别+电话+地址

2.增加联系人的信息

3.删除联系人的信息

4.修改指定联系人的信息

5.查找指定联系人的信息

6.排序通讯录

一、test.c测试文件

main()主函数

需要打印通讯录界面

需要接收使用人的指令,并做出对应操作,使用相对应的函数

int main()
{
	int input = 0;
	
	//Peoinfo con[MAX];//一个数组存放MAX数量人的信息
	//int sz = 0;//表明此时通讯录已有多少联系人
	Contact con;

	//初始化联系人信息
	Initcon(&con);
	
	do
	{
		menu();//打印联系人菜单界面
		printf("请选择你要进行的操作:>\n");
		scanf("%d", &input);
		switch (input)
		{
		  case Add:
		  {
			Addcon(&con);
			break;
		  }
		  case Del:
		  {
			Delcon(&con);
			break;
		  }
		  case Mod:
		  {
			  Modifycon(&con);
			 break;
		  }
		  case Sear:
		  {
			  Searcon(&con);
			  break;
		  }
		  case Sort:
		  {
			  Sortcon(&con);
			  break;
		  }
		  case Prin:
		  {
			  Printcon(&con);
			  break;
		  }
          case Exit:
		  {
			  printf("已退出程序并销毁通讯录\n");
			  break;
		  }
		  default:
		  {
			  printf("选择错误,请重新选择\n");
			  break;
		  }
		}
	} while (input);
	return 0;
}

创建一个枚举类型,这样在写代码时,switch语句中可读性更好

enum option
{
	Exit,
	Add,
	Del,
	Mod,
	Sear,
	Sort,
	Prin
};

菜单menu()函数 

void menu()
{
	printf("****  1.Add    2.Del  ******\n");
	printf("****  3.Mod    4.Sear ******\n");
	printf("****  5.Sort   6.Prin ******\n");
	printf("****      0.EXit      ******\n");
}

二、contact.h头文件

结构体Peoinfo

创建用户信息类型包含姓名,电话,性别,住址,年龄

typedef struct Peoinfo
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	int age;
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}Peoinfo;

 为了使用方便,将结构体struct Peoinfo和struct Contract重命名为Peoinfo和Contract,这样便于在源文件中使用

结构体Contact

通讯录由1000个用户组成的,需要创建一个数组

同时在通讯录中操作时,怎么知道已有多少联系人信息,因此需要一个数进行记录

typedef struct Contact
{
	Peoinfo data[MAX];
	int sz;
}Contact;

 定义宏

为了便于修改数组的大小

#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 10

 声明函数

//初始化联系人
void Initcon(Contact* pc);
//添加联系人
void Addcon(Contact* pc);
//打印通讯录信息
void Printcon(Contact* pc);
//删除指定联系人
void Delcon(Contact* pc);
//查找指定联系人
void Searcon(Contact* pc);
//修改联系人信息
void Modifycon(Contact* pc);
//排序联系人信息
void Sortcon(Contact* pc);
//动态版本——销毁通讯录
void Destroycon(Contact* pc);

三、contact.c函数实现文件

初始化联系人

data内的元素全部设置为0;

通讯录初始化为含有0个元素;

//初始化联系人
void Initcon(Contact* pc)
{
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}

添加联系人

如果已满,就不能再添加;

每加一个联系人信息,就要将sz++;

ps->data找到数组,ps->size的数值相当于表示下标,data[ps->size]找到数组里面的某一个结构体Peoinfo了,data[ps->size].name给结构体里名字成员变量赋值

//添加联系人
void Addcon(Contact* pc)
{
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法添加\n");
		return;
	}
	//增加一个人的信息
	printf("请输入名字:>\n");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:>\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:>\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入电话:>\n");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:>\n");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("增加成功\n");
}

 打印通讯录

根据通讯录内元素的个数遍历打印

//打印通讯录的信息
void Printcon(Contact* pc)
{
	int i = 0;
	printf("%-20s\t%-5s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");

	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[i].name,
			    pc->data[i].age, pc->data[i].sex,
			    pc->data[i].tele, pc->data[i].addr);
	}
}

 寻找指定联系人

 这个函数不需要声明在头文件里,因为不需要给用户使用,这个函数是为了服务查询名字而出现的;

加上static,代码更安全,只给contact.c文件内函数使用;

找到返回对应下标,找不到返回-1;

//寻找指定联系人
static int Findname(Contact* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name,name) == 0)
		{
			return i;
		}
	}
	return -1;
}

 删除指定联系人

找到相应的元素,就将其后面的元素逐个前移覆盖,同时大小减一,同时使for循环的判断数值更加合理

//删除指定联系人
void Delcon(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,不需要删除\n");
		return;
	}
	printf("请输入需要删除人的姓名:>\n");
	scanf("%s", name);
	int ret = Findname(pc,name);
	if (ret == -1)
	{
		printf("未找到指定人姓名\n");
		return;
	}
	int i = 0;
	for (i = ret; i < pc->sz-1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

查找指定联系人

void Searcon(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,不需要查找\n");
		return;
	}
	printf("请输入需要查找人的姓名:>\n");
	scanf("%s", name);
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("未找到指定人姓名\n");
		return;
	}
	printf("找到目标联系人:>\n");
	printf("%-20s\t%-5s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[ret].name,
		pc->data[ret].age, pc->data[ret].sex,
		pc->data[ret].tele, pc->data[ret].addr);
	
}

修改联系人信息

void Modifycon(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,不需要修改\n");
		return;
	}
	printf("请输入需要修改人的姓名:>\n");
	scanf("%s", name);
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("未找到指定人姓名\n");
		return;
	}
	printf("请重新输入名字:>\n");
	scanf("%s", pc->data[ret].name);
	printf("请重新输入年龄:>\n");
	scanf("%d", &(pc->data[ret].age));
	printf("请重新输入性别:>\n");
	scanf("%s", pc->data[ret].sex);
	printf("请重新输入电话:>\n");
	scanf("%s", pc->data[ret].tele);
	printf("请重新输入地址:>\n");
	scanf("%s", pc->data[ret].addr);
	printf("修改成功\n");
}

按照年龄排序联系人信息

使用qsort函数,因为是根据年龄排序,所以需要传递结构体Peoinfo的指针来找到年龄数值

static cmp_age(const void* e1, const void* e2)
{
	return ((Peoinfo*)e1)->age - ((Peoinfo*)e2)->age;
}
//排序联系人信息
void Sortcon(Contact* pc)
{
	if (pc->sz <= 1)
	{
		printf("不需要进行排序\n");
		return;
	}
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_age);
	printf("排序成功\n");	
}

动态版本

目标功能:

1.通讯录初始化后,最先只能存放3个人的信息

2.如果要添加更多人的信息,每次添加可以存放2个人信息的空间

一、contact.h头文件

考虑增容后的结构体Contact 

由于存放联系人的空间是动态变化的,所以此时需要PeoInfo* 的指针指向那片空间即可

sz依旧表示存放了几个有效信息,确定是否需要增容

新参数capacity表示当前通讯录的最大容量

//动态版本
typedef struct Contact
{
	Peoinfo* data;//存放联系人的信息
	int sz;//已经存放了几个联系人信息
	int capacity;//表示当前通讯录的最大容量
}Contact;

 新定义的宏

//动态版本——增加的参数
#define DEFAULT_SZ 3//默认通讯录容量
#define INC_SZ 2//每次增容的数量

二、concact.c函数实现文件

初始化通讯录

申请一块连续的空间在堆区上,data指针指向的动态空间

通讯录中含有0个联系人

赋值最开始的最大容量

//动态版本——初始化联系人
void Initcon(Contact* pc)
{
	pc->data = (Peoinfo*)calloc(DEFAULT_SZ,sizeof(Peoinfo));
	if (pc->data == NULL)
	{
		printf("无法初始化通讯录\n");
		return;
	}
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	
}

增加联系人

当通讯录中已有联系人个数达到最大容量,就需要增容

如果增容成功,则最大容量也需增加

//动态版本——添加联系人
void Addcon(Contact* pc)
{
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法添加\n");
		return;
	}
	//当有效元素个数和通讯录最大容量相等时就要扩容
	if (pc->sz == pc->capacity)
	{
		Peoinfo* ptr = (Peoinfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(Peoinfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += INC_SZ;
			printf("增容成功\n");
		}
		else
		{
			printf("无法增容\n");
			return;
		}
	}
	//增加一个人的信息
	printf("请输入名字:>\n");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:>\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:>\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入电话:>\n");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:>\n");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("增加成功\n");
}

 销毁通讯录

注意我们申请了动态内存却没有释放,则我们需要在程序结束也就是程序退出的时候释放,也就是Exit选项

//动态版本——销毁通讯录
void Destroycon(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;//指针别忘了置为空指针
	pc->sz = 0;
	pc->capacity = 0;
}

文件版本

目标功能:

1.退出程序后能保存已输入的联系人的信息到一个Contact.txt文件中

2.初始化通讯录后,能默认将之前的联系人信息加载进来

 一、contact.h头文件

文件版本的新函数

由于之前已经存放的联系人信息,可能会大于初始化通讯录后的容量,所以也需要进行增容

增容功能由于在初始化和添加联系人时都需要使用,所以不如封装为一个函数更方便

//文件版本——保存已有联系人信息
void Savecon(Contact* pc);
//文件版本——加载已有联系人信息
void Loadcon(Contact* pc);
//文件版本——判断是否增容
void Checkcapacity(Contact* pc);

二、test.c测试文件

在Exit选项销毁通讯录前增加一个保存联系人信息到文件的函数

case Exit:
		  {
			  //退出前保存已有联系人信息
			  Savecon(&con);
			  //销毁通讯录
			  Destroycon(&con);
			  printf("已退出程序并销毁通讯录\n");
			  break;
		  }

三、concact.c函数实现文件

保存联系人信息到文件

以只写的方式打开文件,可以修改其中的数据

将已输入的联系人信息用遍历的方式全部输入到文件中

//文件版本——保存已有联系人信息
void Savecon(Contact* pc)
{
	//打开文件
	FILE* pf = fopen("Contact.txt", "w");
	if (NULL == pf)
	{
		perror("Savecon");
		return;
	}
	//写文件
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data+i, sizeof(Peoinfo), 1, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

假设先输入3个联系人数据,分别是全1、全2、全3,可以看见联系人数据以二进制方式保存到了Contact.txt文件中

初始化通讯录——添加已有联系人到通讯录中

fread函数若没有读取到数据,则会返回0,因此可以作为while循环的判断依据

//文件版本——加载已有联系人信息
void Loadcon(Contact* pc)
{
	//打开文件
	FILE* pf = fopen("Contact.txt", "r");
	if (NULL == pf)
	{
		perror("Loadcon");
		return;
	}
	//读文件
	Peoinfo tmp = { 0 };//需要初始化变量存放数据
	while (fread(&tmp, sizeof(Peoinfo),1, pf))
	{
		//考虑已有联系人数量大于初始通讯录的容量,则需要增容
		Checkcapacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

//动态版本——初始化联系人
void Initcon(Contact* pc)
{
	pc->data = (Peoinfo*)calloc(DEFAULT_SZ,sizeof(Peoinfo));
	if (pc->data == NULL)
	{
		printf("无法初始化通讯录\n");
		return;
	}
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	//加载已有联系人信息
	Loadcon(pc);
}

 当关闭程序,再次打开文件,我们可以选择先打印看是否有之前的联系人信息

 Checkcapacity增容函数

//是否增容
void Checkcapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		Peoinfo* ptr = (Peoinfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(Peoinfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += INC_SZ;
			printf("增容成功\n");
		}
		else
		{
			printf("无法增容\n");
			return;
		}
	}
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值