我们在对于通讯录的实现会以下出现4个版本:静态版本,动态版本,文件版本,数据库版本,在此篇博客中我们实现的是静态版本,也是最容易理解的版本,其他的版本会在接下来的博客中陆续实现。
目录
对于通讯录这个程序来说,实现通讯录的代码长度偏长,我们最好将代码分为三个文件,其次在一个工程中,养成分文件写代码的习惯必不可少,在此处我们将通讯录的实现分为三个文件来写:

一般来说,我们会在头文件中写函数的声明,即需要的其他头文件。
对于一个通讯录我们在写之前需要预想一下需要实现的功能:
首先通讯录中的每个学生是一个复杂对象,他有姓名,性别,电话,年龄,地址等特性,所以我们想到构造一个结构体类型来描述这一复杂对象:
注意:在这里我们想要使代码具有扩展性,所以在这里的个数在前面使用#define定义。
- #define MAX 100
- #define MAX_NAME 20
- #define MAX_SEX 6
- #define MAX_TELE 12
- #define MAX_ADDR 30
- struct PeoInfo
- {
- char name[MAX_NAME];
- char sex[MAX_SEX];
- char tele[MAX_TELE];
- int age;
- char addr[MAX_ADDR];
- };
其次,我们要描述一个通讯录,要有每个学生的信息以及学生的数量,也是一个复杂对象,构造结构体来实现:
- struct Contact
- {
- struct PeoInfo data[MAX];
- int sz;
- };
我们在实现各个功能时,首先要有一个大致的思路,即要实现哪些函数,函数的名字,以及在什么情况下调用函数。
- int main()
- {
- int input = 0;
- struct Contact con; //创建通讯录
- InitContact(&con); //对通讯录初始化
- do
- {
- menu();
- printf("请选择:\n");
- scanf("%d", &input);
- switch (input)
- {
- case 1:
- AddContact(&con); //在通讯录中增加信息
- break;
- case 2:
- DelContact(&con); //在通讯录中删除指定联系人
- break;
- case 3:
- SearchContact(&con); //查找指定联系人
- break;
- case 4:
- ModifyContact(&con); //修改指定联系人
- break;
- case 5:
- ShowContact(&con); //展示通讯录的内容
- break;
- case 6:
- SortContact(&con); //对通讯录里的学生按照姓名进行排序
- break;
- case 0:
- printf("退出通讯录\n");
- break;
- default:
- printf("输入错误,请重新选择\n");
- break;
- }
- } while (input);
- return 0;
- }
我们发现在上面我没写代码时每次写case语句,例如写case 1时我们要去菜单函数看要实现什么功能,发现对应的是增加功能时再去写增加函数,相对来说比较麻烦,所以在这里我们可以使用枚举常量来实现,增加代码的可读性和可维护性。
-
- enum Option
- {
- EXIT, //默认为0
- ADD, //1
- DEL, //2
- SEARCH, //3
- MODIFY, //4
- SHOW, //5
- SORT //6
- };
对于枚举常量来说如果不赋初值默认第一个常量是0,然后依次相加,正好与case ADD与case 1等价,同理替换其他的。
- int main()
- {
- int input = 0;
- struct Contact con; //创建通讯录
- InitContact(&con); //对通讯录初始化
- do
- {
- menu();
- printf("请选择:\n");
- scanf("%d", &input);
- switch (input)
- {
- case ADD:
- AddContact(&con); //在通讯录中增加信息
- break;
- case DEL:
- DelContact(&con); //在通讯录中删除指定联系人
- break;
- case SEARCH:
- SearchContact(&con); //查找指定联系人
- break;
- case MODIFY:
- ModifyContact(&con); //修改指定联系人
- break;
- case SHOW:
- ShowContact(&con); //展示通讯录的内容
- break;
- case SORT:
- SortContact(&con); //对通讯录里的学生按照姓名进行排序
- break;
- case EXIT:
- printf("退出通讯录\n");
- break;
- default:
- printf("输入错误,请重新选择\n");
- break;
- }
- } while (input);
- return 0;
- }
我们在设计程序的时候,需要给用户提示这个通讯录能够实现什么功能,可以对通讯录进行什么操作,这个时候菜单就显得格外重要。
- void menu()
- {
- printf("*******************************************************\n");
- printf("************ 1.add 2.del ***************\n");
- printf("************ 3.search 4.modify ***************\n");
- printf("************ 5.show 6.sort ***************\n");
- printf("************ 0.exit ***************\n");
- printf("*******************************************************\n");
- }
我们创建了通讯录,此时通讯录中没有任何数据,我们要对它进行初始化。
- void InitContact(struct Contact* pc)
- {
- pc->sz = 0;
- memset(pc->data, 0, 100 * sizeof(struct PeoInfo));
- }
在这里,我们使用了memset函数,将通讯录的数据置为0,其次,我们需要更改通讯录里面的内容,所以我们在这里传参传的是通讯录的地址。
我们在通讯录中添加学生信息的前提是通讯录没有满,所以在函数中我们需要判断通讯录中的学生数量,其次在传参的时候,我们可能不小心传成空指针,所以在这里我们可以使用assert函数进行判断。
- void AddContact(struct Contact* pc)
- {
- assert(pc);
- //增加信息的前提是通讯录没有满
- if (pc->sz == MAX)
- {
- printf("通讯录已满\n");
- return;
- }
-
- printf("请输入姓名:\n");
- scanf("%s", pc->data[pc->sz].name);
-
- printf("请输入性别:\n");
- scanf("%s", pc->data[pc->sz].sex);
-
- printf("请输入年龄:\n");
- scanf("%d", &pc->data[pc->sz].age);
-
- printf("请输入电话:\n");
- scanf("%s", &pc->data[pc->sz].tele);
-
- printf("请输入地址:\n");
- scanf("%s", pc->data[pc->sz].addr);
-
- pc->sz++;
- printf("成功添加联系人\n");
- }
- void ShowContact(struct Contact* pc)
- {
- int i = 0;
- printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
- for (i = 0; i < pc->sz; i++)
- {
- printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
- }
- }
在下面的删除指定联系人函数和查找指定联系人函数都需要查找函数,所以我们先实现查找函数,我们在这里通过姓名寻找,查找到了返回下标。
- static int FindByName(struct 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;
- }

在这里有两种方式删除指定联系人,一种是使用memmove函数,关于memmove函数的介绍及实现在之前的字符与字符串函数的博客中已经详细讲过,可以去回看。
方式一:
- void DelContact(struct Contact* pc)
- {
- printf("请输入联系人的姓名:\n");
- char name[20];
- scanf("%s", name);
- int ret = FindByName(pc, name);
- if (ret == -1)
- {
- printf("要查找的联系人不存在\n");
- }
- else
- {
- memmove(&(pc->data[ret]), &(pc->data[ret + 1]), (pc->sz - ret) * sizeof(struct PeoInfo));
- }
- pc->sz--;
- printf("成功删除\n");
- }
方式二:
- void DelContact1(struct Contact* pc)
- {
- printf("请输入联系人的姓名:\n");
- char name[20];
- scanf("%s", name);
- int ret = FindByName(pc, name);
- if (ret == -1)
- {
- printf("要查找的联系人不存在\n");
- }
- else
- {
- int j = 0;
- for (j = ret; j < pc->sz - 1; j++)
- {
- pc->data[j] = pc->data[j + 1];
- }
- }
- pc->sz--;
- printf("成功删除\n");
- }
先判断联系人是否存在,如果不存在,则输出不存在,如果存在输出此联系人的其他信息。
- void SearchContact(struct Contact* pc)
- {
- char name[MAX];
- printf("请输入查找人的名字:\n");
- scanf("%s", &name);
- int ret = FindByName(pc, name);
- if (ret == -1)
- {
- printf("要查找的联系人不存在\n");
- }
- else
- {
- printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
- printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[ret].name, pc->data[ret].sex, pc->data[ret].age, pc->data[ret].tele, pc->data[ret].addr);
- }
- }
- void ModifyContact(struct Contact* pc)
- {
- char name[MAX];
- printf("请输入要修改的人的姓名:\n");
- scanf("%s", &name);
- int ret = FindByName(pc, name);
- if (ret == -1)
- {
- printf("要修改的联系人不存在\n");
- }
- else
- {
- printf("请输入姓名:\n");
- scanf("%s", pc->data[pc->sz].name);
-
- printf("请输入性别:\n");
- scanf("%s", pc->data[pc->sz].sex);
-
- printf("请输入年龄:\n");
- scanf("%d", &pc->data[pc->sz].age);
-
- printf("请输入电话:\n");
- scanf("%s", &pc->data[pc->sz].tele);
-
- printf("请输入地址:\n");
- scanf("%s", pc->data[pc->sz].addr);
-
- printf("修改成功\n");
- }
- }
在这里排序的时候我们使用qsort函数进行排序,关于qsort函数我们在<指针进阶>博客里面详细解释过,不理解的朋友可以回看。
qsort排序时,我们需要给qsort函数传一个比较函数,按照姓名排序时,我们传的比较函数是CmpByName函数。
- int CmpByName(const void* e1, const void* e2)
- {
- return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
- }
- void SortContact(struct Contact* pc)
- {
- qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByName);
- }
- int CmpByAge(const void* e1, const void* e2)
- {
- return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
- }
- void SortContact(struct Contact* pc)
- {
- qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
-
- //qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByName);
- }
- #include "contact.h"
-
- void menu()
- {
- printf("*******************************************************\n");
- printf("************ 1.add 2.del ***************\n");
- printf("************ 3.search 4.modify ***************\n");
- printf("************ 5.show 6.sort ***************\n");
- printf("************ 0.exit ***************\n");
- printf("*******************************************************\n");
- }
-
- int main()
- {
- int input = 0;
- struct Contact con; //创建通讯录
- InitContact(&con); //对通讯录初始化
- do
- {
- menu();
- printf("请选择:\n");
- scanf("%d", &input);
- switch (input)
- {
- case ADD:
- AddContact(&con); //在通讯录中增加信息
- break;
- case DEL:
- DelContact(&con); //在通讯录中删除指定联系人
- break;
- case SEARCH:
- SearchContact(&con); //查找指定联系人
- break;
- case MODIFY:
- ModifyContact(&con); //修改指定联系人
- break;
- case SHOW:
- ShowContact(&con); //展示通讯录的内容
- break;
- case SORT:
- SortContact(&con); //对通讯录里的学生按照姓名进行排序
- break;
- case EXIT:
- printf("退出通讯录\n");
- break;
- default:
- printf("输入错误,请重新选择\n");
- break;
- }
- } while (input);
- return 0;
- }
- #include "contact.h"
-
-
- void InitContact(struct Contact* pc)
- {
- pc->sz = 0;
- memset(pc->data, 0, 100 * sizeof(struct PeoInfo));
- }
-
- void AddContact(struct Contact* pc)
- {
- assert(pc);
- //增加信息的前提是通讯录没有满
- if (pc->sz == MAX)
- {
- printf("通讯录已满\n");
- return;
- }
-
- printf("请输入姓名:\n");
- scanf("%s", pc->data[pc->sz].name);
-
- printf("请输入性别:\n");
- scanf("%s", pc->data[pc->sz].sex);
-
- printf("请输入年龄:\n");
- scanf("%d", &pc->data[pc->sz].age);
-
- printf("请输入电话:\n");
- scanf("%s", &pc->data[pc->sz].tele);
-
- printf("请输入地址:\n");
- scanf("%s", pc->data[pc->sz].addr);
-
- pc->sz++;
- printf("成功添加联系人\n");
- }
-
- static int FindByName(struct 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;
- }
-
- void DelContact(struct Contact* pc)
- {
- printf("请输入联系人的姓名:\n");
- char name[20];
- scanf("%s", name);
- int ret = FindByName(pc, name);
- if (ret == -1)
- {
- printf("要查找的联系人不存在\n");
- }
- else
- {
- memmove(&(pc->data[ret]), &(pc->data[ret + 1]), (pc->sz - ret) * sizeof(struct PeoInfo));
- }
- pc->sz--;
- printf("成功删除\n");
- }
-
- void DelContact1(struct Contact* pc)
- {
- printf("请输入联系人的姓名:\n");
- char name[20];
- scanf("%s", name);
- int ret = FindByName(pc, name);
- if (ret == -1)
- {
- printf("要查找的联系人不存在\n");
- }
- else
- {
- int j = 0;
- for (j = ret; j < pc->sz - 1; j++)
- {
- pc->data[j] = pc->data[j + 1];
- }
- }
- pc->sz--;
- printf("成功删除\n");
- }
-
- void ShowContact(struct Contact* pc)
- {
- int i = 0;
- printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
- for (i = 0; i < pc->sz; i++)
- {
- printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
- }
- }
-
- void SearchContact(struct Contact* pc)
- {
- char name[MAX];
- printf("请输入查找人的名字:\n");
- scanf("%s", &name);
- int ret = FindByName(pc, name);
- if (ret == -1)
- {
- printf("要查找的联系人不存在\n");
- }
- else
- {
- printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
- printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[ret].name, pc->data[ret].sex, pc->data[ret].age, pc->data[ret].tele, pc->data[ret].addr);
- }
- }
-
- void ModifyContact(struct Contact* pc)
- {
- char name[MAX];
- printf("请输入要修改的人的姓名:\n");
- scanf("%s", &name);
- int ret = FindByName(pc, name);
- if (ret == -1)
- {
- printf("要修改的联系人不存在\n");
- }
- else
- {
- printf("请输入姓名:\n");
- scanf("%s", pc->data[pc->sz].name);
-
- printf("请输入性别:\n");
- scanf("%s", pc->data[pc->sz].sex);
-
- printf("请输入年龄:\n");
- scanf("%d", &pc->data[pc->sz].age);
-
- printf("请输入电话:\n");
- scanf("%s", &pc->data[pc->sz].tele);
-
- printf("请输入地址:\n");
- scanf("%s", pc->data[pc->sz].addr);
-
- printf("修改成功\n");
- }
- }
-
- int CmpByName(const void* e1, const void* e2)
- {
- return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
- }
-
- int CmpByAge(const void* e1, const void* e2)
- {
- return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
- }
-
- void SortContact(struct Contact* pc)
- {
- qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
-
- //qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByName);
- }
- #pragma once
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #define MAX 100
- #define MAX_NAME 20
- #define MAX_SEX 6
- #define MAX_TELE 12
- #define MAX_ADDR 30
-
- enum Option
- {
- EXIT, //默认为0
- ADD, //1
- DEL, //2
- SEARCH, //3
- MODIFY, //4
- SHOW, //5
- SORT //6
- };
-
- #include
- #include
- #include
- #include
-
-
- struct PeoInfo
- {
- char name[MAX_NAME];
- char sex[MAX_SEX];
- char tele[MAX_TELE];
- int age;
- char addr[MAX_ADDR];
- };
-
- struct Contact
- {
- struct PeoInfo data[MAX];
- int sz;
- };
-
- //初始化通讯录
- void InitContact(struct Contact * pc);
-
- //在通讯录中增加信息
- void AddContact(struct Contact * pc);
-
- //在通讯录中删除指定联系人
- void DelContact(struct Contact* pc);
-
- //展示通讯录的内容
- void ShowContact(struct Contact* pc);
-
- //查找指定联系人
- void SearchContact(struct Contact* pc);
-
- //修改指定联系人
- void ModifyContact(struct Contact* pc);
-
- //排序
- void SortContact(struct Contact* pc);
