5. 通讯录的实现
实现一个通讯录:
通讯录中保存人的信息:
- 名字
- 年龄
- 性别
- 电话
- 住址
- 通讯录中可以存放100个人的信息
- 增加联系人
- 删除指定联系人
- 修改指定联系人
- 查找指定联系人
- 显示所有联系人的信息
- 排序功能
首先,我们需要三个文件:
- test.c - 测试通讯录
- contact.h - 函数和类型的声明
- contact.c - 函数的实现
设计保存人的信息的这个结构体:
//contact.h //类型的声明 typedef struct PeoInfo { char name[20]; int age; char sex[5]; char tele[12]; char addr[30]; }PeoInfo;
接着,我们实现一下大体逻辑:
//test.c 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 test() { int input = 0; do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: break; case 2: break; case 3: break; case 4: break; case 5: break; case 6: break; case 0: break; default: break; } } while (input); } int main() { test(); return 0; } •
我们要实现通讯录的各项功能,首先要有通讯录:一个 PeoInfo 类型的数组,但是我们再思考一下,如果我们要添加联系人,那么我们是不是需要一个变量来统计通讯录中一共有多少个人,所以还需要一个整型变量。
//contact.h //通讯录 typedef struct Contact { PeoInfo data[100]; int sz; }Contact;
//test.c #include "contact.h" void test() { //首先得有通讯录 Contact con; }
对通讯录进行初始化:
//contact.h #include <string.h> #include <assert.h> //函数声明 //初始化通讯录 void InitContact(Contact* pc);
//contact.c #include "contact.h" void InitContact(Contact* pc) { assert(pc); memset(pc->data, 0, sizeof(pc->data)); pc->sz = 0; }
//test.c void test() { InitContact(&con); }
注:
传参时传的是地址,有以下两点原因:
- 要改变实参的值,就要传地址过去
- 根据之前对结构体的学习,结构体一般传地址,因为传整个结构体要开辟的内存空间太大了
增加联系人:
//contact.h //增加联系人 void AddContact(Contact* pc);
//contact.c void AddContact(Contact* pc) { if (100 == pc->sz) { printf("通讯录已满,无法添加\n"); return; } }
我们发现前面创建data数组时用到了100,这里也用到了100,之后如果要修改值,两处都要改,那么我们应该如何简化它呢?
//contact.h #define MAX 100 #define MAX_NAME 20 #define MAX_SEX 5 #define MAX_TELE 12 #define MAX_ADDR 30 enum OPTION { EXIT,//0 ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; //类型的声明 typedef struct PeoInfo { char name[MAX_NAME]; int age; char sex[MAX_SEX]; char tele[MAX_TELE]; char addr[MAX_ADDR]; }PeoInfo; //通讯录 typedef struct Contact { PeoInfo data[MAX]; int sz; }Contact;
//contact.c void AddContact(Contact* pc) { assert(pc); if (MAX == pc->sz) { printf("通讯录已满,无法添加\n"); return; } printf("请输入名字:>"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:>"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入性别:>"); scanf("%s", pc->data[pc->sz].sex); printf("请输入电话:>"); scanf("%s", pc->data[pc->sz].tele); printf("请输入地址:>"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("成功增加联系人\n"); }
//test.c void test() { int input = 0; //首先得有通讯录 Contact con; InitContact(&con); do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case ADD: AddContact(&con); break; case DEL: break; case SEARCH: break; case MODIFY: break; case SHOW: break; case SORT: break; case EXIT: break; default: break; } } while (input); }
显示联系人:
//contact.h //显示所有联系人的信息 void ShowContact(const Contact* pc);
//contact.c void ShowContact(const Contact* pc) { assert(pc); int i = 0; //打印列标题 printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址"); //打印数据 for (i = 0; i < pc->sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } }
删除指定联系人:
//contact.h //删除指定联系人 void DelContact(Contact* pc);
//contact.c void DelContact(Contact* pc) { assert(pc); if (0 == pc->sz) { printf("通讯录为空,无法删除\n"); return; } char name[MAX_NAME] = { 0 }; //删除 printf("请输入要删除的人的名字:>"); scanf("%s", name); //找到要删除的人 int i = 0; int del = 0; int flag = 0; for (i = 0; i < pc->sz; i++) { if (0 == strcmp(pc->data[i].name, name)) { del = i; flag = 1; break; } } if (0 == flag) { printf("要删除的人不存在\n"); return; } //删除坐标为del的联系人 for (i = del; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("成功删除联系人\n"); }
但是这个代码有一些缺陷:我们可以发现我们要实现的查找联系人和修改联系人这两个功能同样也需要先进行查找,因此我们可以对查找联系人的这一代码块进行分装,让它单独作为一个函数。
//contact.c static int FindByName(const Contact* pc, char name[]) { int i = 0; for (i = 0; i < pc->sz; i++) { if (0 == strcmp(pc->data[i].name, name)) { return i;//找到了 } } return -1;//找不到 } void DelContact(Contact* pc) { assert(pc); if (0 == pc->sz) { printf("通讯录为空,无法删除\n"); return; } char name[MAX_NAME] = { 0 }; //删除 printf("请输入要删除的人的名字:>"); scanf("%s", name); //找到要删除的人 int del = FindByName(pc, name); if (-1 == del) { printf("要删除的人不存在\n"); return; } int i = 0; //删除坐标为del的联系人 for (i = del; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("成功删除联系人\n"); }
查找指定联系人:
//contact.h //查找指定联系人 void SearchContact(const Contact* pc);
//contact.c void SearchContact(const Contact* pc) { assert(pc); char name[MAX_NAME] = { 0 }; printf("请输入要查找人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (-1 == pos) { printf("要查找的人不存在\n"); } else { //打印列标题 printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址"); //打印数据 printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } }
修改指定联系人:
//contact.h //修改指定联系人 void ModifyContact(Contact* pc);
//contact.c void ModifyContact(Contact* pc) { assert(pc); char name[MAX_NAME] = { 0 }; printf("请输入要修改人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (-1 == pos) { printf("要修改的人不存在\n"); } else { 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].tele); printf("请输入地址:>"); scanf("%s", pc->data[pos].addr); printf("修改成功\n"); } }
排序功能:
我们可以按照名字排序,也可以按照年龄排序。
//contact.h enum SELECT { NAME = 1, AGE }; //排序功能 void SortContact(Contact* pc);
//contact.c void select() { printf("********************************\n"); printf("***** 1. name 2. age *****\n"); printf("********************************\n"); } int cmp_by_name(const void* p1, const void* p2) { return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name); } int cmp_by_age(const void* p1, const void* p2) { return ((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age; } void SortContact(Contact* pc) { assert(pc); if (0 == pc->sz) { printf("通讯录为空,无法排序\n"); return; } int input = 0; do { select(); printf("请选择按何种方式进行排序:>"); scanf("%d", &input); switch (input) { case NAME: qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name); printf("排序成功\n"); break; case AGE: qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_age); printf("排序成功\n"); break; default: printf("选择错误,重新选择\n"); break; } } while (input != NAME && input != AGE); }
完整代码:
//contact.h #include <string.h> #include <assert.h> #include <stdio.h> #include <stdlib.h> #define MAX 100 #define MAX_NAME 20 #define MAX_SEX 5 #define MAX_TELE 12 #define MAX_ADDR 30 enum OPTION { EXIT,//0 ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; enum SELECT { NAME = 1, AGE }; //类型的声明 typedef struct PeoInfo { char name[MAX_NAME]; int age; char sex[MAX_SEX]; char tele[MAX_TELE]; char addr[MAX_ADDR]; }PeoInfo; //通讯录 typedef struct Contact { PeoInfo data[MAX]; int sz; }Contact; //函数声明 //初始化通讯录 void InitContact(Contact* pc); //增加联系人 void AddContact(Contact* pc); //显示所有联系人的信息 void ShowContact(const Contact* pc); //删除指定联系人 void DelContact(Contact* pc); //查找指定联系人 void SearchContact(const Contact* pc); //修改指定联系人 void ModifyContact(Contact* pc); //排序功能 void SortContact(Contact* pc);
//contact.c #include "contact.h" void InitContact(Contact* pc) { assert(pc); memset(pc->data, 0, sizeof(pc->data)); pc->sz = 0; } void AddContact(Contact* pc) { assert(pc); if (MAX == pc->sz) { printf("通讯录已满,无法添加\n"); return; } printf("请输入名字:>"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:>"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入性别:>"); scanf("%s", pc->data[pc->sz].sex); printf("请输入电话:>"); scanf("%s", pc->data[pc->sz].tele); printf("请输入地址:>"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("成功增加联系人\n"); } void ShowContact(const Contact* pc) { assert(pc); int i = 0; //打印列标题 printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址"); //打印数据 for (i = 0; i < pc->sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } } static int FindByName(const Contact* pc, char name[]) { int i = 0; for (i = 0; i < pc->sz; i++) { if (0 == strcmp(pc->data[i].name, name)) { return i;//找到了 } } return -1;//找不到 } void DelContact(Contact* pc) { assert(pc); if (0 == pc->sz) { printf("通讯录为空,无法删除\n"); return; } char name[MAX_NAME] = { 0 }; //删除 printf("请输入要删除的人的名字:>"); scanf("%s", name); //找到要删除的人 int del = FindByName(pc, name); if (-1 == del) { printf("要删除的人不存在\n"); return; } int i = 0; //删除坐标为del的联系人 for (i = del; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("成功删除联系人\n"); } void SearchContact(const Contact* pc) { assert(pc); char name[MAX_NAME] = { 0 }; printf("请输入要查找人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (-1 == pos) { printf("要查找的人不存在\n"); } else { //打印列标题 printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址"); //打印数据 printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } } void ModifyContact(Contact* pc) { assert(pc); char name[MAX_NAME] = { 0 }; printf("请输入要修改人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (-1 == pos) { printf("要修改的人不存在\n"); } else { 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].tele); printf("请输入地址:>"); scanf("%s", pc->data[pos].addr); printf("修改成功\n"); } } void select() { printf("********************************\n"); printf("***** 1. name 2. age *****\n"); printf("********************************\n"); } int cmp_by_name(const void* p1, const void* p2) { return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name); } int cmp_by_age(const void* p1, const void* p2) { return ((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age; } void SortContact(Contact* pc) { assert(pc); if (0 == pc->sz) { printf("通讯录为空,无法排序\n"); return; } int input = 0; do { select(); printf("请选择按何种方式进行排序:>"); scanf("%d", &input); switch (input) { case NAME: qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name); printf("排序成功\n"); break; case AGE: qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_age); printf("排序成功\n"); break; default: printf("选择错误,重新选择\n"); break; } } while (input != NAME && input != AGE); }
//test.c #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"); } void test() { int input = 0; //首先得有通讯录 Contact con; InitContact(&con); do { menu(); printf("请选择:>"); 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); } int main() { test(); return 0; }