通讯录(顺序表的应用)

顺序表思想实现通讯录

实现通讯录前,我们考虑一下,通讯录需要包含什么内容?

联系人,联系人需要包含姓名年龄电话性别这3种基本信息。

我们知道顺序表实质是个数组,如果我们让数组的每个元素都代表一个联系人,每个联系人又需要包含多条信息,所以,我们想到结构体,让数组的每个元素都是结构体,结构体就能很好地描述每一个联系人。

对于这样一个通讯录,我们采用顺序表的思想,但不单独写顺序表的接口,直接实现通讯录的接口,从无到有。

头文件

头文件的书写主要注意以下事项:

  • 结构体的声明
  • 命名的可读性,便于理解
  • 需要哪些对通讯录操作,声明出对应函数
//Contact.h

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

#define MAX_NAME 20
#define MAX_GENDER 10
#define MAX_TELNUM 20

typedef struct personinfo
{
	char name[MAX_NAME];
	size_t age;
	char telnum[MAX_TELNUM];
	char gender[MAX_GENDER];
}peoinfo;

typedef struct Contact
{
	peoinfo* a;
	int size;
	int capacity;
}Contact;

//初始化通讯录
void ContactInit(Contact* con);

//添加联系人
void ContactAdd(Contact* con);

//删除联系人
void ContactDel(Contact* con);

//修改联系人
void ContactModify(Contact* con);

//展示通讯录
void ContactShow(Contact* con);

//查找联系人信息
void ContactFind(Contact* con);

//销毁通讯录
void ContactDestory(Contact* con);

接口函数

注意:

  • 函数实现要包含必要的语句说明
  • 函数主体部分为顺序表的增删查改
//Contact.c

# define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"

void ContactInit(Contact* con)
{
	assert(con);
	con->a = NULL;
	con->size = 0;
	con->capacity = 0;
}


void ContactAdd(Contact* con)
{
	assert(con);
	peoinfo new;
	printf("请输入新联系人的姓名:\n");
	scanf("%s", new.name);
	printf("请输入新联系人的年龄:\n");
	scanf("%zd", &new.age);
	printf("请输入新联系人的电话:\n");
	scanf("%s", new.telnum);
	printf("请输入新联系人的性别:\n");
	scanf("%s", new.gender);
	if (con->size == con->capacity)
	{
		int newcapacity = con->capacity == 0 ? 4 : con->capacity * 2;
		peoinfo* tmp = (peoinfo*)realloc(con->a, sizeof(peoinfo) * newcapacity);
		if (NULL == tmp)
		{
			printf("add error!REASON: realloc function failed!\n");
			exit(-1);
		}
		con->a = tmp;
		con->capacity = newcapacity;
	}
	con->a[con->size] = new;
	con->size++;
}


int FindIndex(Contact* con, char* obj)
{
	for (int i = 0; i < con->size; i++)
	{
		if (0 == strcmp(con->a[i].name, obj))
			return i;
	}
	return -1;
}
void ContactDel(Contact* con)
{
	assert(con);
	char del[MAX_NAME] = { 0 };
	printf("请输入要删除的联系人的姓名:\n");
	scanf("%s", del);
	int ret = FindIndex(con, del);
	if (ret < 0)
	{
		printf("您要删除的联系人不存在!\n");
		return;
	}
	else
	{
		for (int i = ret; i < con->size - 1; i++)
		{
			con->a[i] = con->a[i + 1];
		}
		con->size--;
		printf("删除成功!\n");
	}
}


void ContactModify(Contact* con)
{
	assert(con);
	char mod[MAX_NAME] = { 0 };
	printf("请输入要修改的联系人的姓名:\n");
	scanf("%s", mod);
	int ret = FindIndex(con, mod);
	if (ret < 0)
	{
		printf("您要修改的联系人不存在!\n");
		return;
	}
	else
	{
		char newmod[MAX_NAME] = { 0 };
		size_t newage = 0;
		char newtelnum[MAX_TELNUM] = { 0 };
		char newgender[MAX_TELNUM] = { 0 };

		printf("请输入新的联系人姓名:\n");
		scanf("%s", con->a[ret].name);

		printf("请输入新的联系人年龄:\n");
		scanf("%zd", &con->a[ret].age);

		printf("请输入新的联系人电话:\n");
		scanf("%s", con->a[ret].telnum);

		printf("请输入新的联系人性别:\n");
		scanf("%s", con->a[ret].gender);
		printf("修改成功!\n");
	}

}


void ContactShow(Contact* con)
{
	assert(con);
	if (con->size == 0)
	{
		printf("通讯录为空!\n");
		return;
	}
	else
	{
		printf("----------------------------------------------------------------------------------\n");
		printf("%-11s %-11s %-11s %-11s\n", "姓名", "年龄", "电话", "性别");
		for (int i = 0; i < con->size; i++)
		{
			printf("%-11s %-11zd %-11s %-11s\n", con->a[i].name, con->a[i].age, con->a[i].telnum, con->a[i].gender);
		}
		printf("----------------------------------------------------------------------------------\n");
	}
}


void ContactFind(Contact* con)
{
	assert(con);
	char find[MAX_NAME] = { 0 };
	printf("请输入要查询的联系人的姓名:\n");
	scanf("%s", find);
	int ret = FindIndex(con, find);
	if (ret < 0)
	{
		printf("您要查询的联系人不存在!\n");
		return;
	}
	else
	{
		printf("查询结果如下:\n");
		printf("%-11s %-11s %-11s %-11s\n", "姓名", "年龄", "电话", "性别");
		printf("%-11s %-11zd %-11s %-11s\n", con->a[ret].name, con->a[ret].age, con->a[ret].telnum, con->a[ret].gender);
	}
}


void ContactDestory(Contact* con)
{
	assert(con);
	con->size = con->capacity = 0;
	free(con->a);
	con->a = NULL;
}

主函数

主函数里也是包含一些函数定义的,包括菜单、加载文件、写入文件。

为了持久化保留数据,我们需要调用我们之前学习过的文件知识,将每次更新的数据写入文件中,每次启动程序前载入历史数据,每次程序终止前写入文件,这样就完成了通讯录。
关于文件知识,小裤儿之前发布过一篇文件管理的博客,介绍了文件管理函数等知识。

//interface.c

# define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"

void menu()
{
	printf("******************通讯录*******************\n");
	printf("*******1.添加联系人     2.删除联系人*******\n");
	printf("*******3.修改联系人     4.查询联系人*******\n");
	printf("*******5.展示通讯录     0.退出通讯录*******\n");
	printf("*******************************************\n");
}

void SaveContact(Contact* con)
{
	FILE* pf = fopen("contact.txt", "wb");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	for (int i = 0; i < con->size; i++)
	{
		fwrite(con->a + i, sizeof(peoinfo), 1, pf);
	}
	fclose(pf);
	pf = NULL;
	printf("通讯录数据保存成功!\n");
}

void LoadContact(Contact* con)
{
	FILE* pf = fopen("contact.txt", "rb");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	peoinfo buff;
	while (fread(&buff, sizeof(peoinfo), 1, pf))
	{
		if (con->size == con->capacity)
		{
			int newcapacity = con->capacity == 0 ? 4 : con->capacity * 2;
			peoinfo* tmp = (peoinfo*)realloc(con->a, sizeof(peoinfo) * newcapacity);
			if (NULL == tmp)
			{
				printf("add error!REASON: realloc function failed!\n");
				exit(-1);
			}
			con->a = tmp;
			con->capacity = newcapacity;
		}
		con->a[con->size] = buff;
		con->size++;
	}
	fclose(pf);
	pf = NULL;
	printf("历史数据读取成功!\n");
}

int main()
{
	Contact con;
	ContactInit(&con);
	LoadContact(&con);
	int input = 0;
	do
	{
		menu();
		printf("请输入你想执行的操作:\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:ContactAdd(&con);
			break;
		case 2:ContactDel(&con);
			break;
		case 3:ContactModify(&con);
			break;
		case 4:ContactFind(&con);
			break;
		case 5:ContactShow(&con);
			break;
		case 0:printf("退出通讯录\n");
			break;
		default:
			printf("输入非法,请重新输入!\n");
			break;
		}
	} while (input);
	SaveContact(&con);
	ContactDestory(&con);
	return 0;
}

学好了顺序表后,通讯录的实现较为简单,代码很容易看懂,如果代码实现有难度,可能是顺序表并没有完全理解或者是知识点不够熟练,如果有问题,我很荣幸能在评论区和你一起讨论。


效果如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果觉得界面稍乱,可以通过增加换行、分隔线或清理屏幕解决。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值