目录
1.项目功能需求分析
实现一个通讯录:
通讯录保存个人信息名字,年龄 性别 电话 住址 用保存人的信息的结构体实现
1.通讯录至少能存放100个人的信息
2.添加联系人
3.删除指定联系人
4.查找指定联系人
5.显示所有人的信息
6.排序功能7.可以修改指定联系人的信息
2.文件框架说明
test.c 主菜单文件,用于功能测试
contact.c 函数具体实现文件
contact.h 存放函数和类型的声明和必要头文件
3.程序主框架实现
我们希望在程序中实现不同的操作,比如上述的增删查改联系人的信息,而不是执行一次程序就结束,用户可以选择退出。接下来我们就实现一下主体框架,包含主页面菜单显示。
void menu() { printf("----------------------------------\n"); printf("|***0.Exit 1.ADD***********|\n"); printf("|***2.DEL 3.SEARCH*********|\n"); printf("|***4.MODIFY 5.SHOW***********|\n"); printf("|***6.SORT ****************|\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: printf("退出程序成功\n"); break; default: printf("选择错误,请根据菜单选项进行功能选择,谢谢配合\n"); break; } } while (input); } int main() { test(); return 0; }
case后面的选项是1,2,3,4,5,那么我们想可不可以利用枚举,让case后面的选项既能表示我们的功能含义又能表示功能选择数字,这样的代码可读性就会更高一些,我们就可以修改如下 :
首先定义选择枚举类型:
enum OPtion { EXIT,//0 ADD,//1 DEL,//2 SEARCH, MODIFY, SHOW, SORT };
这个依然是放在我们的头文件中去定义,这样代码的整体美观些,接下来的结构修改为:
void menu() { printf("----------------------------------\n"); printf("|***0.Exit 1.ADD***********|\n"); printf("|***2.DEL 3.SEARCH*********|\n"); printf("|***4.MODIFY 5.SHOW***********|\n"); printf("|***6.SORT ****************|\n"); printf("----------------------------------\n"); } void test() { int input = 0; Contact con; InitContact(&con); do { menu(); printf("请选择:》"); scanf("%d", &input); switch (input) { case ADD: break; case DEL: break; case SEARCH: break; case MODIFY: break; case SHOW: break; case SORT: break; case EXIT: printf("退出程序成功\n"); break; default: printf("选择错误,请根据菜单选项进行功能选择,谢谢配合\n"); break; } } while (input); } int main() { test(); return 0; }
4.创建联系人结构体类型和通讯录结构体类型
由于通讯录存储的是每一个联系人的基本信息,名字、电话、性别、住址等,所以我们可以封装一个联系人结构体类型用于描述每一个联系人。
typedef struct PeoInfo { char name[20]; int age; char sex[5]; char telepnumber[12]; char addr[30]; } PeoInfo;
为了后续书写的方便将struct PeoInfo类型重定义为PeoInfo
同样的,我们的通讯录要能存放一百个人的信息的话,这里的100个信息都是联系人结构体类型,我们可以用一个结构体数组来存储。
PeoInfo data[100];
由于,我们后续会对通讯录进行增删操作,就会改变数组的大小,为了方便查看或者显示或者为了方便操作我们可以定义一个SZ来记录数组的大小,增加一个联系人,sz+1.......
为了方便后期传参使用,我们可以封装一个通讯录结构体,里面包含联系人的信息和通讯录的大小,后期我们传参操作就方便多了:
typedef struct Contact { PeoInfo data[100]; int sz; }Contact;
这里为了后续书写简洁,采用了类型重定义,为了应用方便两个类型的声明都可以放在头文件中。
5.程序功能实现--封装功能函数实现不同功能
5.1通讯录初始化
当我们有了上述准备,接下来我们就利用通讯录结构体类型创建一个通讯录,然后首先对通讯录进行初始化。
Contact con; InitContact(&con);
初始化函数具体实现,我们将通讯录联系人这个数组初始化为0(这里使用前面讲到的memset函数,大家不懂怎么使用可以进我主页看一下相关文章),将sz也初始化为0.我们传参使用了结构体地址传参,接收参数使用了结构体指针,内存占用少。
void Initcontact(Contact* pc) { memset(pc->data, 0, sizeof(pc->data)); pc->sz = 0; }
5.2增加联系人
我们每增加一个联系人,我们的sz++;然后录入一个联系人的信息到数组中
修改的还是通讯录结构体的数组,我们还是传地址参数。
首先考虑添加问题①:添加联系人,由于我们限制了数组的大小是100,就是说我们只能录入100个人的信息,当程序启动进行录入的时候,我们就需要考虑一下100个满没满,如果没满就正常添加,如果满了应该告诉我们的用户通讯录满了没有办法添加了。判断满没满可以利用我们的sz这个记录数组大小的参数与100进行大小判断。
void AddContact(Contact* pc) { //首先判断通讯录满每满 if (pc->sz == 100) { printf("通讯录已经满了,请联系开发者扩容或者删除部分联系人\n"); return;//通讯录满了就直接返回后面不执行 } }
这里可以思考一些对数组大小的指定也影响着这里的判断,如果以后通讯录满了,客户要求扩容,那我们是不是要修改至少两个地方,为了方便我们可以利用宏#defing来定义数组的大小,到时候需要扩容我们就只用修改这个宏就可以了。(当然其他的数组大小指定也可以这样修改)
#define DATAMAX 100 typedef struct Contact { PeoInfo data[DATAMAX]; int sz; }Contact;
增加函数修改为:
void AddContact(Contact* pc) { //首先判断通讯录满每满 if (pc->sz == DATAMAX) { printf("通讯录已经满了,请联系开发者扩容或者删除部分联系人\n"); return;//通讯录满了就直接返回后面不执行 } }
②当通讯录没有满,我们就要考虑进行数据信息录入了
void AddContact(Contact* pc) { assert(pc);//断言防止传入空指针 //首先判断通讯录满每满 if (pc->sz == DATAMAX) { printf("通讯录已经满了,请联系开发者扩容或者删除部分联系人\n"); return;//通讯录满了就直接返回后面不执行 } printf("请输入联系人的名字>\n"); scanf("%s", pc->data[pc->sz].name);//由于name是数组名这里就不要&符号了 printf("请输入联系人的年龄>\n"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入联系人的性别>\n"); scanf("%s", pc->data[pc->sz].sex); printf("请输入联系人的电话>\n"); scanf("%s", pc->data[pc->sz].telepnumber); printf("请输入联系人的地址>\n"); scanf("%s", pc->data[pc->sz].addr); \ //添加联系人成功,我们sz++ pc->sz++; printf("添加联系人成功\n"); }
5.3显示所有联系人的信息
为了看一下我们添加联系人或者删除联系人的效果,我们这里就先写显示函数
用于我们只是显示通讯录信息,并不将参数内容进行修改所以参数最好使用const进行修饰,防止出错,这一步不理解的伙伴可以点击我的主页看一下我讲解const的博文。
这个函数我们只用循环打印我们data数组内容就行
void ShowContact(const Contact* pc) { assert(pc);//断言一下防止传入空指针 int i = 0; printf("————————————————————————————————————————————————————————————————————————————————————————\n"); 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].telepnumber, pc->data[i].addr); printf("————————————————————————————————————————————————————————————————————————————————————————\n"); } printf("————————————————————————————————————————————————————————————————————————————————————————\n");
我们来看一下前两个函数执行的效果:
5.4删除指定联系人的信息
首先,如果通讯录为空,我们就没有删除的东西
第二,要删除对应联系人的信息,实现思想是先找到对应联系人的名字匹配相同将后面的内容前移覆盖完成删除。
void DelCotact(Contact* pc) { if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); return; } char name[DATAMAX] = { 0 }; assert(pc);//断言,防止传入空指针 printf("请输入要删除的人的名字:》\n"); scanf("%s", name); //遍历找到要删除的人 int i = 0; int del = 0; int flag = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { del = i; flag = 1; break; } } if (flag == 0) { printf("找不到要删除的人,请检查名字是否输入正确\n"); return; } //找到了,删除联系人 for (i = del; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("成功删除联系人\n"); }
由于我们后面修改呀等等都会用到查找这个函数,所以我们将其封装为一个查找函数,那我们就可以改造代码如下:
int Findbyname(Contact* pc, char name[]) { assert(pc); int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i;//找到了 } } return -1;//找不到 } void DelCotact(Contact* pc) { if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); return; } char name[DATAMAX] = { 0 }; assert(pc);//断言,防止传入空指针 printf("请输入要删除的人的名字:》\n"); scanf("%s", name); //遍历找到要删除的人 int i = 0; int del = 0; del = Findbyname(pc, name); if (del == -1) { printf("找不到要删除的人,请检查名字是否输入正确\n"); return; } //找到了,删除联系人 for (i = del; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("成功删除联系人\n"); }
我们来看一下效果:
5.5查找指定联系人
这里我们就实现一下通过名字查找,之所以单独写一个查找函数是因为在功能中,查找到过后还要显示出来。
看实现:
void SearchContact(Contact* pc) { assert(pc); char name[DATAMAX] = { 0 }; printf("请输入要查找的人的名字:》\n"); scanf("%s", name); int pos = Findbyname(pc, name); if (pos == -1) { printf("要查找的人不存在,请检查名字是否输入正确\n"); } else { printf("————————————————————————————————————————————————————————————————————————————————————————\n"); printf("|%-20s\t|%-4s\t|%-5s\t|%-12s\t|%-30s|\n", "名字", "年龄", "性别", "电话", "地址"); printf("————————————————————————————————————————————————————————————————————————————————————————\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].telepnumber, pc->data[pos].addr); printf("————————————————————————————————————————————————————————————————————————————————————————\n"); } }
这里查找也可以根据其他的比如号码等,可以利用Switch来实现。看一下效果:
5.6修改联系人的信息
通过名字来找到要修改信息的联系人,然后重新录入信息
void ModifyContact(Contact* pc) { assert(pc); char name[DATAMAX] = { 0 }; printf("请输入要修改人的名字:>\n"); scanf("%s", name); int pos = Findbyname(pc, name); if (pos == -1) { printf("要修改的人不存在,请检查名字是否输入正确\n"); } else { printf("请输入要修改人的名字>\n"); scanf("%s", pc->data[pos].name);//由于name是数组名这里就不要&符号了 printf("请输入要修改人的年龄>\n"); scanf("%d", &(pc->data[pos].age)); printf("请输入要修改人的性别>\n"); scanf("%s", pc->data[pos].sex); printf("请输入要修改人的电话>\n"); scanf("%s", pc->data[pos].telepnumber); printf("请输入要修改人的地址>\n"); scanf("%s", pc->data[pos].addr); \ printf("修改成功\n"); } }
我们看一下效果:
6.结语及源码
以上就是本期的所有内容,大家可以配合解释和原码运行理解。创作不易,大家如果觉得还可以的话,欢迎大家三连,有问题的地方欢迎大家指正,一起交流学习,一起成长,我是Nicn,正在c++方向前行的奋斗者,感谢大家的关注与喜欢。下面附上整个项目源码。后续会陆续更新升级版,大家敬请期待。
test.c
// // 实现一个通讯录 // 通讯录保存个人信息 // 名字,年龄 性别 电话 住址 用保存人的信息的结构体 // // 1.通讯录存放100个人的信息 // 1.添加联系人 // 2.删除指定联系人 // 3.查找指定联系人 // 6。显示所有人的信息 // 7.排序功能 // test 测试通讯录 // contact.h 函数和类型的声明 // contact.c 函数的实现 // // // void menu() { printf("----------------------------------\n"); printf("|***0.Exit 1.ADD***********|\n"); printf("|***2.DEL 3.SEARCH*********|\n"); printf("|***4.MODIFY 5.SHOW***********|\n"); printf("|***6.SORT ****************|\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: DelCotact(&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; }
contact.h
#pragma once #include<stdio.h> #include<string.h> #include<assert.h> #define DATAMAX 100 enum OPtion { EXIT,//0 ADD,//1 DEL,//2 SEARCH, MODIFY, SHOW, SORT }; //类型的声明 typedef struct PeoInfo { char name[20]; int age; char sex[5]; char telepnumber[12]; char addr[30]; } PeoInfo; typedef struct Contact { PeoInfo data[DATAMAX]; int sz; }Contact; //初始化函数 void Initcontact(Contact* pc);//函数声明 void AddContact(Contact* pc);//增加联系人函数 void ShowContact(const Contact* pc);//显示通讯录信息 void DelCotact(Contact* pc);//删除联系人信息 void SearchContact(Contact* pc);//查找联系人的信息 void ModifyContact(Contact* pc);//修改联系人的信息
contact.c
#include"contact.h" int Findbyname(Contact* pc, char name[]) { assert(pc); int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i;//找到了 } } return -1;//找不到 } void Initcontact(Contact* pc) { memset(pc->data, 0, sizeof(pc->data)); pc->sz = 0; } void AddContact(Contact* pc) { assert(pc);//断言防止传入空指针 //首先判断通讯录满每满 if (pc->sz == DATAMAX) { printf("通讯录已经满了,请联系开发者扩容或者删除部分联系人\n"); return;//通讯录满了就直接返回后面不执行 } printf("请输入联系人的名字>\n"); scanf("%s", pc->data[pc->sz].name);//由于name是数组名这里就不要&符号了 printf("请输入联系人的年龄>\n"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入联系人的性别>\n"); scanf("%s", pc->data[pc->sz].sex); printf("请输入联系人的电话>\n"); scanf("%s", pc->data[pc->sz].telepnumber); printf("请输入联系人的地址>\n"); scanf("%s", pc->data[pc->sz].addr); \ //添加联系人成功,我们sz++ pc->sz++; printf("添加联系人成功\n"); } void ShowContact(const Contact* pc) { assert(pc);//断言一下防止传入空指针 int i = 0; printf("————————————————————————————————————————————————————————————————————————————————————————\n"); printf("|%-20s\t|%-4s\t|%-5s\t|%-12s\t|%-30s|\n", "名字", "年龄", "性别", "电话", "地址"); printf("————————————————————————————————————————————————————————————————————————————————————————\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].telepnumber, pc->data[i].addr); printf("————————————————————————————————————————————————————————————————————————————————————————\n"); } printf("————————————————————————————————————————————————————————————————————————————————————————\n"); } void DelCotact(Contact* pc) { if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); return; } char name[DATAMAX] = { 0 }; assert(pc);//断言,防止传入空指针 printf("请输入要删除的人的名字:》\n"); scanf("%s", name); //遍历找到要删除的人 int i = 0; int del = 0; del = Findbyname(pc, name); if (del == -1) { printf("找不到要删除的人,请检查名字是否输入正确\n"); return; } //找到了,删除联系人 for (i = del; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("成功删除联系人\n"); } void SearchContact(Contact* pc) { assert(pc); char name[DATAMAX] = { 0 }; printf("请输入要查找的人的名字:》\n"); scanf("%s", name); int pos = Findbyname(pc, name); if (pos == -1) { printf("要查找的人不存在,请检查名字是否输入正确\n"); } else { printf("————————————————————————————————————————————————————————————————————————————————————————\n"); printf("|%-20s\t|%-4s\t|%-5s\t|%-12s\t|%-30s|\n", "名字", "年龄", "性别", "电话", "地址"); printf("————————————————————————————————————————————————————————————————————————————————————————\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].telepnumber, pc->data[pos].addr); printf("————————————————————————————————————————————————————————————————————————————————————————\n"); } } void ModifyContact(Contact* pc) { assert(pc); char name[DATAMAX] = { 0 }; printf("请输入要修改人的名字:>\n"); scanf("%s", name); int pos = Findbyname(pc, name); if (pos == -1) { printf("要修改的人不存在,请检查名字是否输入正确\n"); } else { printf("请输入要修改人的名字>\n"); scanf("%s", pc->data[pos].name);//由于name是数组名这里就不要&符号了 printf("请输入要修改人的年龄>\n"); scanf("%d", &(pc->data[pos].age)); printf("请输入要修改人的性别>\n"); scanf("%s", pc->data[pos].sex); printf("请输入要修改人的电话>\n"); scanf("%s", pc->data[pos].telepnumber); printf("请输入要修改人的地址>\n"); scanf("%s", pc->data[pos].addr); \ printf("修改成功\n"); } }