Bootstrap

C语言实现通讯录(初级版)

前言

在深度学习了一段时间C语言后,我们可以实现写一段通讯录功能来巩固已学的知识
此篇文章旨在详解通讯路的基本实现,功能框架等等
注:此通讯录存在一定的缺陷,下篇文章将会对其进行一定的优化

一、通讯录的基本功能

在上手写通讯录之前,我们要先构思好我们需要想好通讯录需要哪些功能,以及怎样实现:
首先通讯录的目的当然是
存储联系人的一些基本信息,比如姓名,性别,年龄,电话,地址
而能操作的功能可能有
1.联系人的增加
2.联系人的删除
3.联系人的查找
4.修改联系人信息
5.打印当前已存储信息
6.将联系人按一定顺序排序
7.清空当前所有联系人
8.退出程序

2.基本运行框架

在写对应的功能之前,我们需要写一些基本的逻辑框架,将程序运行起来
首先我们创建一个text.c的源文件,此源文件旨在将需要实现的功能集合起来调动功能函数
我们需要写一个menu函数,将函数的操作菜单实现出来,以供用户的使用
如图:
·在这里插入图片描述

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

而我们站在用户的角度,我们在没退出程序之前,每进行一次操作,可能会想要继续下一次操作
所以我们应该在每次操作结束之后都打印一次选择菜单,并且都能选择功能进行接下来的功能
这里我们用do…while语句实现具体操作,而功能的选择是选择开关,我们选择用switch语句实现,同时我们可以定义一个枚举常量,将需要的功能列举出来,便于我们后面功能的编写以及调用

void menu()
{
	printf("***************************\n");
	printf("***** 1.add    2.del    ***\n");
	printf("***** 3.search 4.modify ***\n");
	printf("***** 5.show   6.empty  ***\n");
	printf("***** 7.sort   0.exit   ***\n");
	printf("***************************\n");
}
enum op
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	EMPTY,
	SORT
};

int main()
{
	int n = 0;
	do
	{
		menu();
		printf("请选择>:");
		scanf("%d", &n);
		switch (n)
		{
		case(ADD):
			break;
		case(DEL):
			break;
		case(SEARCH):
			break;
		case(MODIFY):
			break;
		case(SHOW):
			break;
		case(EMPTY):
			break;
		case(SORT):
			break;
		case(EXIT)://在定义枚举常量时,我们将EXIT放在第一个,这样EXIT的值就为0
			break;//可以巧妙运用"零为假非零为真"的定义退出程序
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (n);
	return 0;
}

到这里基本框架就已经写出,此时我们需要考虑想想如何存储通讯录,而定义结构体变量就能很好的帮助我们解决这个问题,这里我们创建一个 contact.h的头文件便于我们编写此程序的代码

我们先依据上文中通讯录能够存储联系人的一些基本信息,比如姓名,性别,年龄,电话,地址给出一个结构体 perinform用来给出每个人能存储的信息

#define SIZE_NAME 20
#define SIZE_SEX 10
#define SIZE_TELEPHONE 20
#define SIZE_ADDRESS 30
#define MAX 100
//此处我们用宏定义来定义每个变量的大小,便于之后的使用与修改
typedef struct perinform
{
	char name[SIZE_NAME];
	int age;
	char sex[SIZE_SEX];
	char telephone[SIZE_TELEPHONE];
	char address[SIZE_ADDRESS];
}perinform;

而细心的小伙伴可能会问,这个结构体只能存储一个人的信息,而我们要实现的结构体可能会有多个人
这里需要声明的是 此处我们给出的结构体 perinform更像是一个模板,是每个人都能存储的基本参数,实际情况下我们会使用该结构体类型的数组来存储每一个人的信息
我们在后面新定义一个结构体 contact

typedef struct contact
{
	int sz;//sz用来记录一共存储了多少个人的信息
	perinform inform[MAX];//此处我们给定一个perinform类型的数组,默认给的大小是100
}contact;

到此处通讯录的框架基本完成,接下来需要做的就是通讯录功能的实现
这里我们创建一个 contact.c的源文件用来写通讯录的功能函数

在写各项功能之前我们需要做的是在 之前创建的text.c文件中给定一个我们刚刚声明的contact类型结构体变量con用来存储我们的通讯录
注:而不管做任何功能的实现,都需要修改con中的数据,由此我们在写函数的时候将con的地址传给对应的功能函数

为了方便起见我们将需要实现的对应功能函数的引用进行补充,得到以下代码(这里还没写功能函数,但提前把函数名和函数的参数给定好了)

#include "contact.h"

void menu()
{
	printf("***************************\n");
	printf("***** 1.add    2.del    ***\n");
	printf("***** 3.search 4.modify ***\n");
	printf("***** 5.show   6.empty  ***\n");
	printf("***** 7.sort   0.exit   ***\n");
	printf("***************************\n");
}
enum op
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	EMPTY,
	SORT
};

int main()
{
	int n = 0;
	contact con;
	initialization(&con);
	do
	{
		menu();
		printf("请选择>:");
		scanf("%d", &n);
		switch (n)
		{
		case(ADD):
			Add(&con);
			break;
		case(DEL):
			Del(&con);
			break;
		case(SEARCH):
			Search(&con);
			break;
		case(MODIFY):
			Modify(&con);
			break;
		case(SHOW):
			Show(&con);
			break;
		case(EMPTY):
			initialization(&con);
			printf("清空完成!\n");
			break;
		case(SORT):
			Sort(&con);
			break;
		case(EXIT):
			printf("退出成功!\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (n);
	return 0;
}

三、功能函数的实现

我们创建一个contact.c文件专门用来储存实现功能函数的代码

1.初始化函数

我们在上文中创建了一个contact类型的结构体变量con但我们并没有对其初始化,我们在使用他存储联系人信息之前,需要对其初始化

这里我们将sz初始化为0,并且运用memset函数将con中的perinform类型的结构体数组inform初始化

void initialization(contact* pc)
{
	pc->sz = 0;
	memset(pc->inform, 0, sizeof(pc->inform));
}

2.增加功能

void Add(contact* pc)
{
	printf("请输入姓名>:");
	scanf("%s", pc->inform[pc->sz].name);
	printf("请输入年龄>:");
	scanf("%d", &(pc->inform[pc->sz].age));
	printf("请输入性别>:");
	scanf("%s", pc->inform[pc->sz].sex);
	printf("请输入电话号码>:");
	scanf("%s", pc->inform[pc->sz].telephone);
	printf("请输入住址>:");
	scanf("%s", pc->inform[pc->sz].address);

	pc->sz++;//每次增加了之后将sz自增1用于记录存储了多少联系人

	printf("添加成功\n");
}

3.打印功能

void Show(contact* pc)
{
	printf("%-10s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");//先打印一排信息栏便于观察
	for (int i = 0; i < pc->sz; i++)//逐个打印出每个联系人的信息
	{
		printf("%-10s %-5d %-5s %-12s %-30s\n", pc->inform[i].name, pc->inform[i].age, pc->inform[i].sex, pc->inform[i].telephone, pc->inform[i].address);
	}
}

4.查找,删除,修改功能

将这三个功能放在一起讲是因为他们都需要判断是否能在已储存的联系人中找到需要操作的联系人,如果找不到那么也就执行不了对应的删除、修改操作,所以这三个功能函数都需要在进入函数的时候就判断是否能找到需要找的联系人,这里我们以联系人的姓名作为查找方式

//由于该函数是只在contact.c文件中被引用 所以我们用static修饰这个函数
//形参中char* arr的指针指向的是用户输入的需要查找的联系人姓名
static int Find_name(char* arr, contact* pc)
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(arr, pc->inform[i]->name) == 0)
		{
			return i;
		}
	}
	return -1;
}

查找联系人:

void Search(contact* pc)
{
	char arr[SIZE_NAME];
	printf("请输入查找人姓名>;");
	scanf("%s", arr);
	int ret = Find_name(arr, pc);
	if (ret == -1)
	{
		printf("未找到该联系人\n");
	}
	else//这里如果我们找到了就将该联系人的信息打印出来
	{
		printf("%-10s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-10s %-5d %-5s %-12s %-30s\n", pc->inform[ret].name, pc->inform[ret].age, pc->inform[ret].sex, pc->inform[ret].telephone, pc->inform[ret].address);
	}
}

修改联系人:

void Modify(contact* pc)
{
	char arr[SIZE_NAME];
	printf("请输入查找人姓名>;");
	scanf("%s", arr);
	int ret = Find_name(arr, pc);
	if (ret == -1)
	{
		printf("未找到该联系人\n");
	}
	else
	{
		printf("请输入姓名>:");
		scanf("%s", pc->inform[ret].name);
		printf("请输入年龄>:");
		scanf("%d", &(pc->inform[ret].age));
		printf("请输入性别>:");
		scanf("%s", pc->inform[ret].sex);
		printf("请输入电话号码>:");
		scanf("%s", pc->inform[ret].telephone);
		printf("请输入住址>:");
		scanf("%s", pc->inform[ret].address);

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

删除联系人:

void Del(contact* pc)
{
	char arr[SIZE_NAME];
	printf("请输入删除人姓名>;");
	scanf("%s", arr);
	int ret = Find_name(arr,pc);
	if (ret == -1)
	{
		printf("未找到该联系人\n");
	}
	else//删除之后我们需要将后面的联系人往前移一位
	{
		for (int i = ret; i < pc->sz - 1; i++)
		{
			pc->inform[i] = pc->inform[i + 1];
		}
		pc->sz--;
		printf("删除成功!\n");
	}
}

5.排序功能

谈到排序有些小伙伴可能有些不知所措,但别担心其实很简单,我们可以用qsort函数来实现将结构体数组排序
注:这里如果有不知道如何使用qsort函数的小伙伴可以看看我之前的文章
qsort函数的使用方法
其次我们要想到用什么进行排序,这里我们用姓名进行排序,当然你也可以用其他的比如年龄

//此处与上文相同,我们只会在contact.c文件中调用cmp_name函数,所以我们在前面加上static修饰
static int cmp_name(const void* p1, const void* p2)
{
	return strcmp(((perinform*)p1)->name, ((perinform*)p2)->name);
}


void Sort(contact* pc)
{
	qsort(pc->inform, pc->sz, sizeof(perinform), cmp_name);
	printf("排序成功!\n");
}

到这里功能函数就基本上完成了,我们需要再将功能函数在contact.h的头文件中声明一下

四、实现代码

text.c

#include "contact.h"

void menu()
{
	printf("***************************\n");
	printf("***** 1.add    2.del    ***\n");
	printf("***** 3.search 4.modify ***\n");
	printf("***** 5.show   6.empty  ***\n");
	printf("***** 7.sort   0.exit   ***\n");
	printf("***************************\n");
}
enum op
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	EMPTY,
	SORT
};

int main()
{
	int n = 0;
	contact con;
	initialization(&con);
	do
	{
		menu();
		printf("请选择>:");
		scanf("%d", &n);
		switch (n)
		{
		case(ADD):
			Add(&con);
			break;
		case(DEL):
			Del(&con);
			break;
		case(SEARCH):
			Search(&con);
			break;
		case(MODIFY):
			Modify(&con);
			break;
		case(SHOW):
			Show(&con);
			break;
		case(EMPTY):
			initialization(&con);
			printf("清空完成!\n");
			break;
		case(SORT):
			Sort(&con);
			break;
		case(EXIT):
			printf("退出成功!\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (n);
	return 0;
}

contact.h

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define SIZE_NAME 20
#define SIZE_SEX 10
#define SIZE_TELEPHONE 20
#define SIZE_ADDRESS 30
#define MAX 100

typedef struct perinform
{
	char name[SIZE_NAME];
	int age;
	char sex[SIZE_SEX];
	char telephone[SIZE_TELEPHONE];
	char address[SIZE_ADDRESS];
}perinform;


typedef struct contact
{
	int sz;
	perinform inform[MAX];
}contact;

void initialization(contact* pc);

void Add(contact* pc);

void Show(contact* pc);

void Del(contact* pc);

void Search(contact* pc);

void Modify(contact* pc);

void Sort(contact* pc);

void Savecontact(contact* pc);

void Destorycontact(contact* pc);

void Loadcontact(contact* pc);

contact.c

#include "contact.h"

void initialization(contact* pc)
{
	pc->sz = 0;
	memset(pc->inform, 0, sizeof(pc->inform));
}

void Add(contact* pc)
{
	printf("请输入姓名>:");
	scanf("%s", pc->inform[pc->sz].name);
	printf("请输入年龄>:");
	scanf("%d", &(pc->inform[pc->sz].age));
	printf("请输入性别>:");
	scanf("%s", pc->inform[pc->sz].sex);
	printf("请输入电话号码>:");
	scanf("%s", pc->inform[pc->sz].telephone);
	printf("请输入住址>:");
	scanf("%s", pc->inform[pc->sz].address);

	pc->sz++;

	printf("添加成功\n");
}


void Show(contact* pc)
{
	printf("%-10s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-10s %-5d %-5s %-12s %-30s\n", pc->inform[i].name, pc->inform[i].age, pc->inform[i].sex, pc->inform[i].telephone, pc->inform[i].address);
	}
}

static int Find_name(char* arr, contact* pc)
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(arr, pc->inform->name) == 0)
		{
			return i;
		}
	}
	return -1;
}


void Search(contact* pc)
{
	char arr[SIZE_NAME];
	printf("请输入查找人姓名>;");
	scanf("%s", arr);
	int ret = Find_name(arr, pc);
	if (ret == -1)
	{
		printf("未找到该联系人\n");
	}
	else//这里如果我们找到了就将该联系人的信息打印出来
	{
		printf("%-10s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-10s %-5d %-5s %-12s %-30s\n", pc->inform[ret].name, pc->inform[ret].age, pc->inform[ret].sex, pc->inform[ret].telephone, pc->inform[ret].address);
	}
}

void Modify(contact* pc)
{
	char arr[SIZE_NAME];
	printf("请输入查找人姓名>;");
	scanf("%s", arr);
	int ret = Find_name(arr, pc);
	if (ret == -1)
	{
		printf("未找到该联系人\n");
	}
	else
	{
		printf("请输入姓名>:");
		scanf("%s", pc->inform[ret].name);
		printf("请输入年龄>:");
		scanf("%d", &(pc->inform[ret].age));
		printf("请输入性别>:");
		scanf("%s", pc->inform[ret].sex);
		printf("请输入电话号码>:");
		scanf("%s", pc->inform[ret].telephone);
		printf("请输入住址>:");
		scanf("%s", pc->inform[ret].address);

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

void Del(contact* pc)
{
	char arr[SIZE_NAME];
	printf("请输入删除人姓名>;");
	scanf("%s", arr);
	int ret = Find_name(arr,pc);
	if (ret == -1)
	{
		printf("未找到该联系人\n");
	}
	else//删除之后我们需要将后面的联系人往前移一位
	{
		for (int i = ret; i < pc->sz - 1; i++)
		{
			pc->inform[i] = pc->inform[i + 1];
		}
		pc->sz--;
		printf("删除成功!\n");
	}
}

static int cmp_name(const void* p1, const void* p2)
{
	return strcmp(((perinform*)p1)->name, ((perinform*)p2)->name);
}


void Sort(contact* pc)
{
	qsort(pc->inform, pc->sz, sizeof(perinform), cmp_name);
	printf("排序成功!\n");
}

以上就是通讯录初级版的基本实现,下篇文章中将会对其进行优化

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;