相信各位对于通讯录都不是很陌生吧。通讯录我们在学校的大作业,课程设计经常会去使用它。那么今天我们将使用C语言来实现一个简单的通讯录。
目录
前言
一、通讯录的需求
二、工程文件的创建
三、通讯录的声明和定义
四、通讯录各函数的声明和定义
五、通讯录的目录和逻辑
六、通讯录功能实现之初始化通讯录
七、通讯录功能实现之增加联系人
八、通讯录功能实现之删除联系人
九、通讯录功能实现之查找联系人
十、通讯录功能实现之修改联系人
十一、通讯录功能实现之排序
十二、通讯录功能实现之打印通讯录
十三、通讯录完整代码(分文件)
test.c文件
Contact.h文件
Contact.c文件
十四、通讯录完整代码(一个文件)
总结
首先我们要明白一个通讯录要有什么信息呢?
1.要能够存放人的信息:姓名,年龄,性别,地址,电话
2.通讯录能存放多少个人的信息:我们暂时先定为100个人的信息
3.通讯录的功能:
1>增加联系人
2>删除指定联系人
3>查找指定联系人
4>修改联系人的信息
5>显示所有联系人的信息
6>排序(按照年龄、姓名等排序)
上面这些都是通讯录最最最基本的功能。当然,我们可以增加其他的功能,比如说:通讯录要可以保存、查找某个联系人时可以通过多个信息进行筛选、通讯录可以动态自动增容等等
这些设想我们都可以去实现,但是首先,我们要完成最基本的通讯录。就是以上六个功能,之后,我们在这些功能上进行修改,使得我们的通讯录变得更加强大。
我们采用分文件的形式来完成这个通讯录,当然我们文末会给出一个文件版本的通讯录
test.c文件用来测试通讯录
Contact.c用来完成通讯录的实现
Contact.h用来实现函数的声明
我们想要创建一个通讯录也就是说,要将很多个人的信息给集合起来。那么这就是一个数组。
而每一个人的信息,他又有了很多个类型,我们需要将这些信息给集合起来,这就是一个结构体。
#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 10
#define ADDRESS_MAX 30
#define TELEPHONE_MAX 12//定义一个结构体类型,这里存放人的信息
typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char address[ADDRESS_MAX];char telephone[TELEPHONE_MAX];
}PeoInfo;
//所有人的都放到这里
typedef struct Contact
{PeoInfo data[MAX];int size;
}Contact;
如上代码所示,我们利用两个结构体,来实现我们的通讯录的声明
PeoInfo这个结构体存放的是每一个人信息,为了方便我们后续的修改,我们使用了宏
每个人的信息都是一个结构体,我们要存储个人,这些人的类型都是相同的。所以我们要使用一个数组,也就是结构体数组。但是呢,我们肯定还需要知道现在存放了几个人的信息了。所以我们还需要一个变量来确定现在的结构体数组里面存放了几个人的信息了。不妨我们就直接把这个结构体数组和这个变量给集合起来。在创建一个结构体。这样方便我们后续的实现。
我们想,通讯录要实现六个功能。
1>增加联系人
2>删除指定联系人
3>查找指定联系人
4>修改联系人的信息
5>显示所有联系人的信息
6>排序(按照年龄、姓名等排序)
这六个功能,我们不妨先给他们声明一些函数。先不去实现。
//初始化通讯录
void InitContact(Contact* pc);
//添加联系人
void AddContact(Contact* pc);
//删除指定联系人
void DelContact(Contact* pc);
//查找指定联系人
void SearchContact(const Contact* pc);
//修改指定联系人
void ModifyContact(Contact* pc);
//排序通讯录
void SortContact(Contact* pc);
//打印通讯录
void ShowContact(const Contact* pc);
需要注意的是,查找和打印并不需要修改通讯录的值,所以我们使用const来保护我们的通讯录
有了这些声明我们假设我们已经实现了,我们可以就来完成一下我们的目录了
void menu()
{printf("*************************\n");printf("**** 1.Add ****\n");printf("**** 2.Del ****\n");printf("**** 3.Search ****\n");printf("**** 4.Modify ****\n");printf("**** 5.Show ****\n");printf("**** 6.Sort ****\n");printf("**** 0.exit ****\n");printf("*************************\n");}
int main()
{int input = 0;Contact con;InitContact(&con);do{menu();printf("请输入你的需求>:");scanf("%d", &input);switch (input){case 1:printf("添加联系人\n");AddContact(&con);break;case 2:printf("删除指定联系人\n");DelContact(&con);break;case 3:printf("查找指定联系人\n");SearchContact(&con);break;case 4:printf("修改指定联系人\n");ModifyContact(&con);break;case 5:printf("打印所有联系人\n");ShowContact(&con);break;case 6:printf("排序联系人\n");SortContact(&con);break;case 0:printf("退出通讯录\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}
如上代码所示,我们利用do while语句,就可以来实现我们的通讯录的基本逻辑了。同时也写出了我们的代码
当我们创建好一个通讯录的时候,我们需要将他初始化。
我们可以简单粗暴的直接使用con={0},但是这种方法太粗暴了。
我们完全可以将其封装成一个函数。来实现他
我们这里先断言pc,防止空指针。然后使用memset函数来置空通讯录
//初始化通讯录
void InitContact(Contact* pc)
{assert(pc);memset(pc->data, 0, sizeof(pc->data));pc->size = 0;
}
现在我们来实现通讯的添加联系人。
我们同样先断言,然后我们还需要做的就是判断通讯是否满了。如果满了那么直接返回即可
如果没满,那么就正常使用scanf来添加即可。这里我们的参数必须是指针变量。我们要传地址过去才能修改通讯录的值。
//添加联系人
void AddContact(Contact* pc)
{assert(pc);if (pc->size == MAX){printf("通讯录已满,添加失败\n");return;}printf("请输入联系人的姓名:");scanf("%s", ((pc->data)[pc->size]).name);printf("请输入联系人的年龄:");scanf("%d", &((pc->data)[pc->size].age));printf("请输入联系人的性别:");scanf("%s", (pc->data)[pc->size].sex);printf("请输入联系人的地址:");scanf("%s", (pc->data)[pc->size].address);printf("请输入联系人的电话:");scanf("%s", (pc->data)[pc->size].telephone);pc->size++;printf("恭喜你,添加成功\n");
}
添加了联系人,那么与之对应的就是删除操作了
我们删除的基本思路就是,先断言指针,防止空指针
然后如果通讯录空了,那么就不需要删除
我们这里利用姓名来删除联系人。
我们创建一个数组,将输入的联系人姓名放入其中
然后我们创建一个根据名字查找的函数,这个函数的基本思想就是strcmp函数来比较名字,如果名字存在,则返回下标。否则返回-1
我们根据下标来进行删除
删除的时候,我们只需要就后面的元素统一往前挪动一个单位即可,最后不要忘记pc->size--
//在通讯录中通过名字查找一个人,并返回他的下标
int FindByName(const Contact* pc, char* arr)
{assert(pc && arr);int i = 0;for (i = 0; i < pc->size; i++){if (strcmp(pc->data[i].name, arr) == 0){return i;}}return -1;
}
//删除指定联系人
void DelContact(Contact* pc)
{assert(pc);if (pc->size == 0){printf("通讯录为空,无法删除\n");return;}printf("请输入你要删除的联系人姓名>:");char arr[NAME_MAX] = { 0 };scanf("%s", arr);int pos = FindByName(pc, arr);if (pos == -1){printf("没有这个人\n");return;}int i = pos;for (i = pos; i < pc->size - 1; i++){pc->data[i] = pc->data[i + 1];}pc->size--;printf("删除成功\n");
}
在查找联系人中,我们同样使用名字来查找,这个就又需要使用我们之前的根据名字返回下标函数了。可以将这个封装成一个函数是很有必要的。
我们直接根据这个下标进行格式化打印即可
//查找指定联系人
void SearchContact(const Contact* pc)
{assert(pc);if (pc->size == 0){printf("通讯录为空,无法查找\n");return;}char arr[NAME_MAX] = { 0 };printf("请输入你要查找的名字>:");scanf("%s", arr);int pos = FindByName(pc, arr);if (pos == -1){printf("通讯录中不存在这个人\n");return;}printf("%-20s %-4s %-5s %-30s %-12s\n", "姓名", "年龄", "性别", "地址", "电话");printf("%-20s %-4d %-5s %-30s %-12s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].address,pc->data[pos].telephone);
}
我们现在实现的是修改联系人的信息
对于这个函数,我们同样还是根据名字来查找到这个联系人的下标,有了下标,那么修改这个就很简单了。
//修改指定联系人
void ModifyContact(Contact* pc)
{assert(pc);if (pc->size == 0){printf("通讯录为空,无法修改\n");return;}char arr[NAME_MAX] = { 0 };printf("请输入你要修改的人的名字\n");scanf("%s", arr);int pos = FindByName(pc, arr);if (pos == -1){printf("该联系人不存在\n");return;}printf("请输入联系人的姓名:");scanf("%s", pc->data[pos].name);printf("请输入联系人的年龄:");scanf("%d", &(pc->data[pos].age));printf("请输入联系人的性别:");scanf("%s", pc->data[pos].sex);printf("请输入联系人的地址:");scanf("%s", pc->data[pos].address);printf("请输入联系人的电话:");scanf("%s", pc->data[pos].telephone);printf("修改成功\n");
}
对于排序我们其实比较熟悉的,我们直接使用快速排序即可。因为我们之前已经介绍过快排的基本使用了。我们这里采用了两种方式来排序,可以供使用者进行选择
值得思考的是,我们也可以利用选择的方式,我们在写一个根据年龄查找下标的函数。然后我们就可以选择通过年龄来找到我们需要修改的联系人,并且返回他的下标了。这样我们查找的功能就更加强大了
void cmp_by_name(void* e1, void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void cmp_by_age(void* e1, void* e2)
{return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age;
}
//排序通讯录
void SortContact(Contact* pc)
{assert(pc);int input = 0;printf("请选择你需要按姓名排序还是按照年龄排序\n");printf("按照姓名排序请输入1,按照年龄排序请输入2 :\n");scanf("%d", &input);if (input == 1)qsort(pc, pc->size, sizeof(PeoInfo), cmp_by_name);if (input == 2)qsort(pc, pc->size, sizeof(PeoInfo), cmp_by_age);printf("排序成功\n");
}
我们对通讯录有了那么多的实现,那么我们也得看到我们的实现后的样子吧,所以我们就很有必要完成一个打印函数。这个函数的实现也很简单,就是利用遍历的思想即可
//打印通讯录
void ShowContact(const Contact* pc)
{assert(pc);int i = 0;printf("%-20s %-4s %-5s %-30s %-12s\n","姓名","年龄","性别","地址","电话");for (i = 0; i < pc->size; i++){printf("%-20s %-4d %-5s %-30s %-12s\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex, pc->data[i].address,pc->data[i].telephone);}}
test.c文件
#define _CRT_SECURE_NO_WARNINGS 1 #include"Contact.h" void menu() {printf("*************************\n");printf("**** 1.Add ****\n");printf("**** 2.Del ****\n");printf("**** 3.Search ****\n");printf("**** 4.Modify ****\n");printf("**** 5.Show ****\n");printf("**** 6.Sort ****\n");printf("**** 0.exit ****\n");printf("*************************\n");} int main() {int input = 0;Contact con;InitContact(&con);do{menu();printf("请输入你的需求>:");scanf("%d", &input);switch (input){case 1:printf("添加联系人\n");AddContact(&con);break;case 2:printf("删除指定联系人\n");DelContact(&con);break;case 3:printf("查找指定联系人\n");SearchContact(&con);break;case 4:printf("修改指定联系人\n");ModifyContact(&con);break;case 5:printf("打印所有联系人\n");ShowContact(&con);break;case 6:printf("排序联系人\n");SortContact(&con);break;case 0:printf("退出通讯录\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0; }
Contact.h文件
#pragma once #include
#include #include #include #define MAX 100 #define NAME_MAX 20 #define SEX_MAX 10 #define ADDRESS_MAX 30 #define TELEPHONE_MAX 12//定义一个结构体类型,这里存放人的信息 typedef struct PeoInfo {char name[NAME_MAX];int age;char sex[SEX_MAX];char address[ADDRESS_MAX];char telephone[TELEPHONE_MAX]; }PeoInfo; //所有人的都放到这里 typedef struct Contact {PeoInfo data[MAX];int size; }Contact; //初始化通讯录 void InitContact(Contact* pc); //添加联系人 void AddContact(Contact* pc); //删除指定联系人 void DelContact(Contact* pc); //查找指定联系人 void SearchContact(const Contact* pc); //修改指定联系人 void ModifyContact(Contact* pc); //排序通讯录 void SortContact(Contact* pc); //打印通讯录 void ShowContact(const Contact* pc);
Contact.c文件
#define _CRT_SECURE_NO_WARNINGS 1 #include"Contact.h" //初始化通讯录 void InitContact(Contact* pc) {assert(pc);memset(pc->data, 0, sizeof(pc->data));pc->size = 0; } //添加联系人 void AddContact(Contact* pc) {assert(pc);if (pc->size == MAX){printf("通讯录已满,添加失败\n");return;}printf("请输入联系人的姓名:");scanf("%s", ((pc->data)[pc->size]).name);printf("请输入联系人的年龄:");scanf("%d", &((pc->data)[pc->size].age));printf("请输入联系人的性别:");scanf("%s", (pc->data)[pc->size].sex);printf("请输入联系人的地址:");scanf("%s", (pc->data)[pc->size].address);printf("请输入联系人的电话:");scanf("%s", (pc->data)[pc->size].telephone);pc->size++;printf("恭喜你,添加成功\n"); } //在通讯录中通过名字查找一个人,并返回他的下标 int FindByName(const Contact* pc, char* arr) {assert(pc && arr);int i = 0;for (i = 0; i < pc->size; i++){if (strcmp(pc->data[i].name, arr) == 0){return i;}}return -1; } //删除指定联系人 void DelContact(Contact* pc) {assert(pc);if (pc->size == 0){printf("通讯录为空,无法删除\n");return;}printf("请输入你要删除的联系人姓名>:");char arr[NAME_MAX] = { 0 };scanf("%s", arr);int pos = FindByName(pc, arr);if (pos == -1){printf("没有这个人\n");return;}int i = pos;for (i = pos; i < pc->size - 1; i++){pc->data[i] = pc->data[i + 1];}pc->size--;printf("删除成功\n"); } //查找指定联系人 void SearchContact(const Contact* pc) {assert(pc);if (pc->size == 0){printf("通讯录为空,无法查找\n");return;}char arr[NAME_MAX] = { 0 };printf("请输入你要查找的名字>:");scanf("%s", arr);int pos = FindByName(pc, arr);if (pos == -1){printf("通讯录中不存在这个人\n");return;}printf("%-20s %-4s %-5s %-30s %-12s\n", "姓名", "年龄", "性别", "地址", "电话");printf("%-20s %-4d %-5s %-30s %-12s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].address,pc->data[pos].telephone); } //修改指定联系人 void ModifyContact(Contact* pc) {assert(pc);if (pc->size == 0){printf("通讯录为空,无法修改\n");return;}char arr[NAME_MAX] = { 0 };printf("请输入你要修改的人的名字\n");scanf("%s", arr);int pos = FindByName(pc, arr);if (pos == -1){printf("该联系人不存在\n");return;}printf("请输入联系人的姓名:");scanf("%s", pc->data[pos].name);printf("请输入联系人的年龄:");scanf("%d", &(pc->data[pos].age));printf("请输入联系人的性别:");scanf("%s", pc->data[pos].sex);printf("请输入联系人的地址:");scanf("%s", pc->data[pos].address);printf("请输入联系人的电话:");scanf("%s", pc->data[pos].telephone);printf("修改成功\n"); } void cmp_by_name(void* e1, void* e2) {return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name); } void cmp_by_age(void* e1, void* e2) {return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age; } //排序通讯录 void SortContact(Contact* pc) {assert(pc);int input = 0;printf("请选择你需要按姓名排序还是按照年龄排序\n");printf("按照姓名排序请输入1,按照年龄排序请输入2 :\n");scanf("%d", &input);if (input == 1)qsort(pc, pc->size, sizeof(PeoInfo), cmp_by_name);if (input == 2)qsort(pc, pc->size, sizeof(PeoInfo), cmp_by_age);printf("排序成功\n"); } //打印通讯录 void ShowContact(const Contact* pc) {assert(pc);int i = 0;printf("%-20s %-4s %-5s %-30s %-12s\n","姓名","年龄","性别","地址","电话");for (i = 0; i < pc->size; i++){printf("%-20s %-4d %-5s %-30s %-12s\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex, pc->data[i].address,pc->data[i].telephone);}}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#include
#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 10
#define ADDRESS_MAX 30
#define TELEPHONE_MAX 12//定义一个结构体类型,这里存放人的信息
typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char address[ADDRESS_MAX];char telephone[TELEPHONE_MAX];
}PeoInfo;
//所有人的都放到这里
typedef struct Contact
{PeoInfo data[MAX];int size;
}Contact;
//初始化通讯录
void InitContact(Contact* pc);
//添加联系人
void AddContact(Contact* pc);
//删除指定联系人
void DelContact(Contact* pc);
//查找指定联系人
void SearchContact(const Contact* pc);
//修改指定联系人
void ModifyContact(Contact* pc);
//排序通讯录
void SortContact(Contact* pc);
//打印通讯录
void ShowContact(const Contact* pc);void menu()
{printf("*************************\n");printf("**** 1.Add ****\n");printf("**** 2.Del ****\n");printf("**** 3.Search ****\n");printf("**** 4.Modify ****\n");printf("**** 5.Show ****\n");printf("**** 6.Sort ****\n");printf("**** 0.exit ****\n");printf("*************************\n");}
int main()
{int input = 0;Contact con;InitContact(&con);do{menu();printf("请输入你的需求>:");scanf("%d", &input);switch (input){case 1:printf("添加联系人\n");AddContact(&con);break;case 2:printf("删除指定联系人\n");DelContact(&con);break;case 3:printf("查找指定联系人\n");SearchContact(&con);break;case 4:printf("修改指定联系人\n");ModifyContact(&con);break;case 5:printf("打印所有联系人\n");ShowContact(&con);break;case 6:printf("排序联系人\n");SortContact(&con);break;case 0:printf("退出通讯录\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}//初始化通讯录
void InitContact(Contact* pc)
{assert(pc);memset(pc->data, 0, sizeof(pc->data));pc->size = 0;
}
//添加联系人
void AddContact(Contact* pc)
{assert(pc);if (pc->size == MAX){printf("通讯录已满,添加失败\n");return;}printf("请输入联系人的姓名:");scanf("%s", ((pc->data)[pc->size]).name);printf("请输入联系人的年龄:");scanf("%d", &((pc->data)[pc->size].age));printf("请输入联系人的性别:");scanf("%s", (pc->data)[pc->size].sex);printf("请输入联系人的地址:");scanf("%s", (pc->data)[pc->size].address);printf("请输入联系人的电话:");scanf("%s", (pc->data)[pc->size].telephone);pc->size++;printf("恭喜你,添加成功\n");
}
//在通讯录中通过名字查找一个人,并返回他的下标
int FindByName(const Contact* pc, char* arr)
{assert(pc && arr);int i = 0;for (i = 0; i < pc->size; i++){if (strcmp(pc->data[i].name, arr) == 0){return i;}}return -1;
}
//删除指定联系人
void DelContact(Contact* pc)
{assert(pc);if (pc->size == 0){printf("通讯录为空,无法删除\n");return;}printf("请输入你要删除的联系人姓名>:");char arr[NAME_MAX] = { 0 };scanf("%s", arr);int pos = FindByName(pc, arr);if (pos == -1){printf("没有这个人\n");return;}int i = pos;for (i = pos; i < pc->size - 1; i++){pc->data[i] = pc->data[i + 1];}pc->size--;printf("删除成功\n");
}
//查找指定联系人
void SearchContact(const Contact* pc)
{assert(pc);if (pc->size == 0){printf("通讯录为空,无法查找\n");return;}char arr[NAME_MAX] = { 0 };printf("请输入你要查找的名字>:");scanf("%s", arr);int pos = FindByName(pc, arr);if (pos == -1){printf("通讯录中不存在这个人\n");return;}printf("%-20s %-4s %-5s %-30s %-12s\n", "姓名", "年龄", "性别", "地址", "电话");printf("%-20s %-4d %-5s %-30s %-12s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].address,pc->data[pos].telephone);
}
//修改指定联系人
void ModifyContact(Contact* pc)
{assert(pc);if (pc->size == 0){printf("通讯录为空,无法修改\n");return;}char arr[NAME_MAX] = { 0 };printf("请输入你要修改的人的名字\n");scanf("%s", arr);int pos = FindByName(pc, arr);if (pos == -1){printf("该联系人不存在\n");return;}printf("请输入联系人的姓名:");scanf("%s", pc->data[pos].name);printf("请输入联系人的年龄:");scanf("%d", &(pc->data[pos].age));printf("请输入联系人的性别:");scanf("%s", pc->data[pos].sex);printf("请输入联系人的地址:");scanf("%s", pc->data[pos].address);printf("请输入联系人的电话:");scanf("%s", pc->data[pos].telephone);printf("修改成功\n");
}
void cmp_by_name(void* e1, void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void cmp_by_age(void* e1, void* e2)
{return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age;
}
//排序通讯录
void SortContact(Contact* pc)
{assert(pc);int input = 0;printf("请选择你需要按姓名排序还是按照年龄排序\n");printf("按照姓名排序请输入1,按照年龄排序请输入2 :\n");scanf("%d", &input);if (input == 1)qsort(pc, pc->size, sizeof(PeoInfo), cmp_by_name);if (input == 2)qsort(pc, pc->size, sizeof(PeoInfo), cmp_by_age);printf("排序成功\n");
}
//打印通讯录
void ShowContact(const Contact* pc)
{assert(pc);int i = 0;printf("%-20s %-4s %-5s %-30s %-12s\n", "姓名", "年龄", "性别", "地址", "电话");for (i = 0; i < pc->size; i++){printf("%-20s %-4d %-5s %-30s %-12s\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].address,pc->data[i].telephone);}}
我们本节实现了一个简单的通讯录,但是要注意的是,这个通讯录其实并不完善。因为他的容量是死的。我们希望可以实现一个可以动态扩容的通讯录。其次他的一个缺陷就是关闭了这个文件之后,在打开就会发现,之前的信息不见了。我们希望可以实现一个不会消失数据的通讯录。这些我们都将在后面的文章中实现