前言:这篇文章博主带着大家一步一步实现通讯录,让你不在是“文”盲。
一、通讯录的实现(静态版)
1.1文件的创建
test.c 测试通讯录
contcat.h 函数和类型的声明
contcat.c 函数的实现
在实现通讯录的程序中,我们使用多文件编程,真是为什么呢?
多文件编程的好处:
1.方便代码复用:模块化的代码可以很方便的迁移到其他项目中。
2.方便分工合作:各个功能模块分成多个文件同时编辑,可以有效地提高团队分工合作的效率
3.便于后续维护:当程序出现错误时,可以分模块进行排查,可以提高效率,使程序更加容易管理
头文件的作用
我们可以将函数、数据的声明,宏的定义,库函数所用到的头文件放在一起,在源文件中只要引用
#include “contact.h”就可以实现,这样可以减少代码的重复编写,提高效率。
1.2通讯录要存放的信息
我们要是一个可以存放100个人信息的通讯录
创建一个结构体,结构体中放我们要存的信息,姓名、年龄、性别、电话号、住址。
typedef struct PeoInfo { char name[10]; int age; char sex[5]; char tele[12]; char addr[15]; }PeoInfo;
1.3通讯录的功能
1.增加联系人 2.删除联系人
3.查找联系人 4.修改联系人
5.显示所有联系人 6.对联系人排序
1.4通讯录的创建
PeoInfo date[100];
int sz = 0;
我们创建好可以存放100个人的通讯录后,还要创建一个变量sz来记录通讯录中存放的人数,所以这两个变量要绑定在一起。我们在创建一个结构体,这样在传参时会更方便。
typedef struct Contact { PeoInfo date[100]; int sz; }Contact;
1.5菜单打印以及基本逻辑的实现
#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; //通讯录 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: printf("退出通讯录\n"); break; default: printf("输入错误,请重新输入\n"); break; } } while (input); } int main() { test(); return 0; }
在case语句里,别人使用我们的代码并不知道1,2,3……代表的是什么功能,所以我们可以使用枚举,让使用者了解我们的功能,提高代码可读性
优化代码:
enum OPTION { Exit, Add, Del, Serach, Modify, Show, Sort };
case Add: break; case Del: break; case Serach: break; case Modify: break; case Show: break; case Sort: break; case Exit: printf("退出通讯录\n"); break; default: printf("输入错误,请重新输入\n"); break;
1.6初始化通讯录
初始化通讯录,我们要改变里面的内容,所以我们要传指针过去。注意要在头文件中对函数声明。
void InitContact(Contact* pc) { memset(pc->date, 0, sizeof(pc->date)); pc->sz = 0; }
1.7增加联系人
我们要考虑通讯录有没有满,如果没有满添加的联系人放到下标sz的地方。我们要使用pc指针,所以用assert断言指针是否有效。
void AddContact(Contact* pc) { assert(pc); if (pc->sz == MAX) { printf("通讯录已满,无法添加\n"); return; } printf("请输入名字:>"); scanf("%s", pc->date[pc->sz].name); printf("请输入年龄:>"); scanf("%d", &(pc->date[pc->sz].name)); printf("请输入性别:>"); scanf("%s", pc->date[pc->sz].sex); printf("请输入电话:>"); scanf("%s", pc->date[pc->sz].tele); printf("请输入地址:>"); scanf("%s", pc->date[pc->sz].addr); pc->sz++; printf("添加成功\n"); }
1.8显示联系人
我们只是显示联系人的数据,不会修改通讯录中的内容,所以在声明时用const修饰:
void ShowContact(const Contact* pc);
void ShowContact(const Contact* pc) { assert(pc); //打印标题 printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址"); int i = 0; for (i = 0; i < pc->sz; i++) { printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[i].name, pc->date[i].age, pc->date[i].sex, pc->date[i].tele, pc->date[i].addr); } }
注意:有 ‘ - ’ 是左对齐,没有 ‘ - ’ 是右对齐。
1.9删除联系人
我们要考虑通信录中是否存在要删除的联系人,所以我们定义一个flag标签。
void DelContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); } char name[20] = { 0 }; int del = 0; int flag = 0; printf("要删除的联系人:>"); scanf("%s", name); int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->date[i].name, name) == 0) { del = i; flag = 1; break; } } if (flag == 0) { printf("要删除的联系人不存在\n"); return; } for (i = del; i < pc->sz - 1; i++) { pc->date[i] = pc->date[i + 1]; } pc->sz--; printf("成功删除联系人\n"); }
在删除,查找,修改的功能中都有查找的程序,所以我们可以把查找的功能封装成一个函数,更加方便 。
优化代码:
int FindByname(Contact* pc, char name[]) { int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->date[i].name, name) == 0) { return i; } } return -1; } void DelContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); } char name[20] = { 0 }; int flag = 0; printf("要删除的联系人:>"); scanf("%s", name); int del = FindByname(pc, name); if (del == -1) { printf("要删除的联系人不存在\n"); return; } int i = 0; for (i = del; i < pc->sz - 1; i++) { pc->date[i] = pc->date[i + 1]; } pc->sz--; printf("成功删除联系人\n"); }
1.10查找联系人
使用上面封装好的查找的函数,如果我们要查找的人存在,就把信息打印在屏幕上。
void SearchContact(const Contact* pc) { assert(pc); char name[20] = { 0 }; printf("请输入要查找人的名字:>"); scanf("%s", name); int pos = FindByname(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); } else { printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[pos].name, pc->date[pos].age, pc->date[pos].sex, pc->date[pos].tele, pc->date[pos].addr); } }
1.11修改联系人
使用上面封装好的查找的函数,要修改的人存在就重新录入它的信息。
void ModifyContact(Contact* pc) { assert(pc); char name[20] = { 0 }; printf("请输入要修改的人的名字:>"); scanf("%s", name); int pos = FindByname(pc, name); if (pos == -1) { printf("要修改的人不存在\n"); } else { printf("请输入名字:>"); scanf("%s", pc->date[pos].name); printf("请输入年龄:>"); scanf("%d", &(pc->date[pos].age)); printf("请输入性别:>"); scanf("%s", pc->date[pos].sex); printf("请输入电话:>"); scanf("%s", pc->date[pos].tele); printf("请输入地址:>"); scanf("%s", pc->date[pos].addr); } printf("修改成功\n"); }
1.12按名字排序
case Sort: //按名字排序 qsort(con.date, con.sz, sizeof(PeoInfo), cmp_by_name); break; int cmp_by_name(const void* p1, const void* p2) { return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name); }
1.13完整代码
contact.h
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <assert.h> #define MAX 100 typedef struct PeoInfo { char name[20]; int age; char sex[5]; char tele[12]; char addr[15]; }PeoInfo; typedef struct Contact { PeoInfo date[MAX]; int sz; }Contact; enum OPTION { Exit, Add, Del, Serach, Modify, Show, Sort }; //函数声明 //初始化 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); //排序 int cmp_by_name(const void* p1, const void* p2);
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 Serach: SearchContact(&con); break; case Modify: ModifyContact(&con); break; case Show: ShowContact(&con); break; case Sort: //按名字排序 qsort(con.date, con.sz, sizeof(PeoInfo), cmp_by_name); break; case Exit: printf("退出通讯录\n"); break; default: printf("输入错误,请重新输入\n"); break; } } while (input); } int main() { test(); return 0; }
contact.c
#include "contact.h" void InitContact(Contact* pc) { memset(pc->date, 0, sizeof(pc->date)); pc->sz = 0; } void AddContact(Contact* pc) { assert(pc); if (pc->sz == MAX) { printf("通讯录已满,无法添加\n"); return; } printf("请输入名字:>"); scanf("%s", pc->date[pc->sz].name); printf("请输入年龄:>"); scanf("%d", &(pc->date[pc->sz].age)); printf("请输入性别:>"); scanf("%s", pc->date[pc->sz].sex); printf("请输入电话:>"); scanf("%s", pc->date[pc->sz].tele); printf("请输入地址:>"); scanf("%s", pc->date[pc->sz].addr); pc->sz++; printf("添加成功\n"); } void ShowContact(const Contact* pc) { assert(pc); //打印标题 printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址"); int i = 0; for (i = 0; i < pc->sz; i++) { printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[i].name, pc->date[i].age, pc->date[i].sex, pc->date[i].tele, pc->date[i].addr); } } int FindByname(Contact* pc, char name[]) { int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->date[i].name, name) == 0) { return i; } } return -1; } void DelContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); } char name[20] = { 0 }; int flag = 0; printf("要删除的联系人:>"); scanf("%s", name); /*int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->date[i].name, name) == 0) { del = i; flag = 1; break; } } if (flag == 0) { printf("要删除的联系人不存在\n"); return; }*/ int del = FindByname(pc, name); if (del == -1) { printf("要删除的联系人不存在\n"); return; } int i = 0; for (i = del; i < pc->sz - 1; i++) { pc->date[i] = pc->date[i + 1]; } pc->sz--; printf("成功删除联系人\n"); } void SearchContact(const Contact* pc) { assert(pc); char name[20] = { 0 }; printf("请输入要查找人的名字:>"); scanf("%s", name); int pos = FindByname(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); } else { printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[pos].name, pc->date[pos].age, pc->date[pos].sex, pc->date[pos].tele, pc->date[pos].addr); } } void ModifyContact(Contact* pc) { assert(pc); char name[20] = { 0 }; printf("请输入要修改的人的名字:>"); scanf("%s", name); int pos = FindByname(pc, name); if (pos == -1) { printf("要修改的人不存在\n"); } else { printf("请输入名字:>"); scanf("%s", pc->date[pos].name); printf("请输入年龄:>"); scanf("%d", &(pc->date[pos].age)); printf("请输入性别:>"); scanf("%s", pc->date[pos].sex); printf("请输入电话:>"); scanf("%s", pc->date[pos].tele); printf("请输入地址:>"); scanf("%s", pc->date[pos].addr); } printf("修改成功\n"); } int cmp_by_name(const void* p1, const void* p2) { return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name); }
二、通讯录的实现(动态版)
改造的目标:
1.通讯录的大小不是固定的,大小是可以调整的。
2.默认初始能放三个人的信息,如果不够,每次增加两个人的信息。
2.1通讯录的创建
动态版本就不用数组来创建,使用malloc函数创建空间。还需要一个变量来存储我们通讯录的最大容量,当存储的信息到达最大容量,我们可以增容。
typedef struct Contact { PeoInfo* date; //指向存放数据的空间 int sz; //当前通讯录存储的信息的个数 int cap; //通讯录当前最大容量 }Contact;
2.2初始化通讯录
使用动态内存函数要引用头文件
#include <stdlib.h>
我们初始为开始可以存放三个人的信息。
void InitContact(Contact* pc) { assert(pc); pc->date = (PeoInfo*)malloc(3 * sizeof(PeoInfo)); if (pc->date == NULL) { perror("InitContact"); return; } pc->sz = 0; pc->cap = DEFAULT_SZ; }
2.3增加联系人
在动态版本中不存在填满的情况,我们要判断增容。在填满的情况下,每次增加两个。我们使用的初始容量和要增加的量可以使用define定义。
1. #define DEFAULT_SZ 3 2. #define INC_SZ 2
如果增容成功或不需要增容,返回1,增加联系人;如果增容失败,返回0。
int CheckCapacity(Contact* pc) { if (pc->sz == pc->cap) { PeoInfo* ptr=(PeoInfo*)realloc(pc->date, (pc->cap + INC_SZ) * sizeof(PeoInfo)); if (ptr == NULL) { perror("CheckCapacity"); return 0; } else { pc->date = ptr; pc->cap += INC_SZ; printf("增容成功\n"); return 1; } } return 1; } void AddContact(Contact* pc) { assert(pc); if (0 == CheckCapacity(pc)) { return; } printf("请输入名字:>"); scanf("%s", pc->date[pc->sz].name); printf("请输入年龄:>"); scanf("%d", &(pc->date[pc->sz].age)); printf("请输入性别:>"); scanf("%s", pc->date[pc->sz].sex); printf("请输入电话:>"); scanf("%s", pc->date[pc->sz].tele); printf("请输入地址:>"); scanf("%s", pc->date[pc->sz].addr); pc->sz++; printf("添加成功\n"); }
2.4完整代码
contact,h
#include <stdio.h> #include <string.h> #include <assert.h> #include <stdlib.h> #define MAX 100 #define DEFAULT_SZ 3 #define INC_SZ 2 typedef struct PeoInfo { char name[20]; int age; char sex[5]; char tele[12]; char addr[15]; }PeoInfo; typedef struct Contact { PeoInfo* date; //指向存放数据的空间 int sz; //当前通讯录存储的信息的个数 int cap; //通讯录当前最大容量 }Contact; enum OPTION { Exit, Add, Del, Serach, Modify, Show, Sort }; //函数声明 //初始化 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); //排序 int cmp_by_name(const void* p1, const void* p2); //释放 void DestoryContact(Contact* pc);
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 Serach: SearchContact(&con); break; case Modify: ModifyContact(&con); break; case Show: ShowContact(&con); break; case Sort: //按名字排序 qsort(con.date, con.sz, sizeof(PeoInfo), cmp_by_name); break; case Exit: DestoryContact(&con); printf("退出通讯录\n"); break; default: printf("输入错误,请重新输入\n"); break; } } while (input); } int main() { test(); return 0; }
contact.c
#include "contact.h" void InitContact(Contact* pc) { assert(pc); pc->date = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo)); if (pc->date == NULL) { perror("InitContact"); return; } pc->sz = 0; pc->cap = DEFAULT_SZ; } int CheckCapacity(Contact* pc) { if (pc->sz == pc->cap) { PeoInfo* ptr=(PeoInfo*)realloc(pc->date, (pc->cap + INC_SZ) * sizeof(PeoInfo)); if (ptr == NULL) { perror("CheckCapacity"); return 0; } else { pc->date = ptr; pc->cap += INC_SZ; printf("增容成功\n"); return 1; } } return 1; } void AddContact(Contact* pc) { assert(pc); if (0 == CheckCapacity(pc)) { return; } printf("请输入名字:>"); scanf("%s", pc->date[pc->sz].name); printf("请输入年龄:>"); scanf("%d", &(pc->date[pc->sz].age)); printf("请输入性别:>"); scanf("%s", pc->date[pc->sz].sex); printf("请输入电话:>"); scanf("%s", pc->date[pc->sz].tele); printf("请输入地址:>"); scanf("%s", pc->date[pc->sz].addr); pc->sz++; printf("添加成功\n"); } void ShowContact(const Contact* pc) { assert(pc); //打印标题 printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址"); int i = 0; for (i = 0; i < pc->sz; i++) { printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[i].name, pc->date[i].age, pc->date[i].sex, pc->date[i].tele, pc->date[i].addr); } } int FindByname(Contact* pc, char name[]) { int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->date[i].name, name) == 0) { return i; } } return -1; } void DelContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); } char name[20] = { 0 }; int flag = 0; printf("要删除的联系人:>"); scanf("%s", name); /*int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->date[i].name, name) == 0) { del = i; flag = 1; break; } } if (flag == 0) { printf("要删除的联系人不存在\n"); return; }*/ int del = FindByname(pc, name); if (del == -1) { printf("要删除的联系人不存在\n"); return; } int i = 0; for (i = del; i < pc->sz - 1; i++) { pc->date[i] = pc->date[i + 1]; } pc->sz--; printf("成功删除联系人\n"); } void SearchContact(const Contact* pc) { assert(pc); char name[20] = { 0 }; printf("请输入要查找人的名字:>"); scanf("%s", name); int pos = FindByname(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); } else { printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[pos].name, pc->date[pos].age, pc->date[pos].sex, pc->date[pos].tele, pc->date[pos].addr); } } void ModifyContact(Contact* pc) { assert(pc); char name[20] = { 0 }; printf("请输入要修改的人的名字:>"); scanf("%s", name); int pos = FindByname(pc, name); if (pos == -1) { printf("要修改的人不存在\n"); } else { printf("请输入名字:>"); scanf("%s", pc->date[pos].name); printf("请输入年龄:>"); scanf("%d", &(pc->date[pos].age)); printf("请输入性别:>"); scanf("%s", pc->date[pos].sex); printf("请输入电话:>"); scanf("%s", pc->date[pos].tele); printf("请输入地址:>"); scanf("%s", pc->date[pos].addr); } printf("修改成功\n"); } int cmp_by_name(const void* p1, const void* p2) { return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name); } void DestoryContact(Contact* pc) { free(pc->date); pc->date = NULL; pc->cap = 0; pc->sz = 0; }
本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位读者三连支持。文章有问题可以在评论区留言,博主一定认真认真修改,以后写出更好的文章。