1.实现怎样一个通讯录
实现一个通讯录 | 联系人信息: |
1.可以保存100个人的信息 | 名字 |
2.添加联系人 | 年龄 |
3.删除指定联系人 | 性别 |
4.查找指定联系人 | 电话 |
5.修改指定联系人 | 住址 |
6.排序联系人 | |
7.显示所有联系人信息 |
2.通讯录的实现
2.1创建两个源文件和一个头文件
首先我们创建contact.c和test.c,contact.h,在头文件中包含了程序所需的各种头文件并且实现对各种函数的声明,而源文件test.c用于引用函数,contact.c实现函数。这样做的目的是为了各个文件可以处理各自模块的功能,增强逻辑性和代码的清晰度,使得可读性更高。
2.2搭建构架
1.菜单打印
首先在test.c这个源文件里面把菜单打印出来,直接使用printf函数打印出通讯录的功能即可。
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"); }
2.使用do while
这里相比较之前写的游戏代码进行了改进,因为数字的具体含义不知道,所以使用了枚举常量代替,而枚举常量会进行默认赋值,所以从0开始一一对应就行了,增加了代码的可读性。
enum Option { EXIT,//0 ADD, DEL, SEARCH, MODIFY, SHOW, SORT };
int main() { 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: ShowContact(&con); break; case SORT: break; case EXIT: printf("退出通讯录\n"); break; default: printf("选择错误,重新选择\n"); break; } } while (input); return 0; }
3.使用结构体保存联系人的信息
接下来在contact.h里面创建结构体来包含人的信息,如果觉得在使用结构体时每次都要写成struct PeoInfom比较复杂,可以在struct前面加上typedef,这样的话使用这个结构体写PeoInfom就行。如果我们在数组里面写上数字的话,就是常量,以后如果发生变化,修改起来不够方便,可以使用#define定义常量。
#define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<stdio.h> #include<assert.h> #include<string.h> #define MAME_MAX 40 #define SEX_MAX 10 #define TELE_MAX 12 #define ADDR_MAX 30 #define MAX 100 //类型的声明 typedef struct PeoInfom { char name[MAME_MAX]; int age; char sex[SEX_MAX]; char tele[TELE_MAX]; char addr[ADDR_MAX]; }PeoInfom;
4.将通讯录初始化
在contact.h里面创建一个结构体,sz记录的是当前通讯录中存放的人的信息个数,PeoInfom data是用来存放数据。
typedef struct Contact { PeoInfom data[MAX];//存放数据 int sz;//记录的是当前通讯录中存放的人的信息个数 }Contact;
在test.c的主函数里面创建通讯录contact con,这个通讯录里面有一个存放数据的数组,还有个联系人数量,现在这个通讯录没有数据。
Contact con;
结果调试以后发现data和sz都是随机数,所以先对通讯录初始化。结构体传参的时候尽量传址,传值的话如果结构体过大会导致性能下降,在test.c中进行传址。
InitContact(&con);//初始化通讯录
在contact.h中声明函数:
void InitContact(Contact* pc);//初始化通讯录
在contact.c中进行函数的实现,sz直接访问赋0即可。data是一块连续的空间,所以使用memset函数将数据全部变为0,data单独放在sizeof内部表示这个数组,第三个参数直接使用sizeof求出data的大小就行了,单位都是字节。当然使用循环也许,但是memset更加方便快捷。
void InitContact(Contact* pc) { assert(pc); pc->sz = 0; memset(pc->data, 0, sizeof(pc->data)); }
5.添加联系人
首先在case语句中写上添加联系人函数AddContact,然后进行传址。
1. case ADD: 2. AddContact(&con); 3. break;
在contact.h中声明:
void AddContact(Contact* pc);//增加联系人
在contact.c中实现:
首先判断一下通讯录空间是否满了,使用if判断sz是不是等于MAX。如果没有满,则开始输入信息,先打印提醒信息,在输入,名字放在通讯录里面data数组的下标为pc->sz的位置上,所以是pc->data[pc->sz].name,name是数组名,数组名本身是地址,所以不需要使用&。然后模仿名字这样把各项信息输入进去,最后sz++,再打印提示信息。
void AddContact(Contact* pc) { assert(pc); if (pc->sz == MAX) { 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"); }
那么我们输入成功之后是看不见这些信息的,所以需要完成show函数,展示出来。
6.展示通讯录信息
首先在case语句中写上添加联系人函数ShowContact,然后进行传址。
1. case SHOW: 2. ShowContact(&con); 3. break;
在contact.c中实现:
由于不需要修改数据,使用const限制一下参数。
先使用if判断一下通讯录是否为空,如果不是再打印信息。
首先我们把各项信息的标题打印出来,确定好间隔。然后开始打印信息,通过找到data数组的下标找出相应的结构体,然后使用下标访问操作符找出相对应的信息,打印出来。
void ShowContact(const Contact *pc) { if(ps->sz == 0) { printf("通讯录为空\n"); } else { int i = 0; //标题 printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //数据 for(i = 0; i < pc->sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } } }
7.删除指定联系人
首先在contact.h声明:
void DelContact(Contact* pc);//删除指定联系人
在test.c中使用:
1. case DEL: 2. DelContact(&con); 3. break;
在contact.c中实现:
删除联系人先判断一下通讯录是否为空,名字单独创建一个数组,然后输入名字,然后开始在通讯录查找名字。
写一个Findbyname的名字查找函数,参数分别是pc这个通讯录和name,在通讯录里面查找sz次,使用strcmp函数比较,如果等于0,就是找到了这个联系人,则返回下标,否则返回-1.
回到删除函数,如果返回的是-1,则联系人不存在。找到了则将返回的下标作为for函数的i,将i+1这个结构体代替i这个结构体,然后不断的循环。如果判断条件设置为i<pc->sz的话,访问到最后一个结构体就会越界,所以是sz-1,并且for循环走完之后sz--,如果要删除最后一个结构体的时候。则不会访问到最后一个结构体,已经被删除了。
int Findbyname(Contact* pc,char name[]) { assert(pc); for (int i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i; } } return -1; } void DelContact(Contact* pc) { char name[NAME_MAX]; assert(pc); if (pc->sz == 0) { printf("通讯录为空\n"); } printf("请输入要删除的联系人:"); scanf("%s", name); int ret = Findbyname(pc, name); if (ret == -1) { printf("要删除的人不存在\n"); return; } else { for (int i = ret; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("删除成功\n"); } }
8.查找联系人
在test.c中使用:
1. case SEARCH: 2. SearchContact(&con); 3. break;
在contact.h中声明:
void SearchContact(const Contact* pc);//查找联系人
在contact.c中实现:
这里其实是使用到了Findbyname这个函数和展示函数,需要注意的是要把下标换成ret。
void SearchContact(const Contact* pc) { char name[NAME_MAX]; assert(pc); printf("请输入联系人:"); scanf("%s", name); int ret = Findbyname(pc, name); if (ret == -1) { printf("要查找的人不存在\n"); return; } else { //标题 printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //数据 printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n", pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr); } }
9.修改联系人
在contact.h里面声明:
void ModifyContact(Contact* pc);//修改联系人信息
在test.c中使用:
1. case MODIFY: 2. ModifyContact(&con); 3. break;
在contact.c中实现:
修改函数使用Findbyname函数后直接用添加联系人的方法就可以了,需要注意的是把下标改成ret。
void ModifyContact(Contact* pc) { char name[NAME_MAX]; assert(pc); printf("请输入联系人:"); scanf("%s", name); int ret = Findbyname(pc, name); if (ret == -1) { printf("要修改的人不存在\n"); return; } printf("请输入名字:"); scanf("%s", pc->data[ret].name); printf("请输入年龄:"); scanf("%d", &(pc->data[ret].age)); printf("请输入性别:"); scanf("%s", pc->data[ret].sex); printf("请输入电话:"); scanf("%s", pc->data[ret].tele); printf("请输入地址:"); scanf("%s", pc->data[ret].addr); printf("修改联系人成功\n"); }
10.排序联系人
在test.c中使用:
1. case SORT: 2. SortContact(&con); 3. break;
在contact.h里面声明:
void SortContact(Contact* pc);//排序联系人
在contact.c中实现:
这里使用一个qsort进行排序即可,比较函数使用strcmp。
int cmp_name(const void* e1, const void* e2) { return (strcmp(((Contact*)e1)->data->name, ((Contact*)e2)->data->name)); } //联系人排序 void SortContact(Contact* pc) { assert(pc); qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name); //打印 printf("排序完成\n"); ShowContact(pc); }
完整代码:
contact.h:
#define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<stdio.h> #include<assert.h> #include<string.h> #define NAME_MAX 40 #define SEX_MAX 10 #define TELE_MAX 12 #define ADDR_MAX 30 #define MAX 100 //类型的声明 typedef struct PeoInfom { char name[NAME_MAX]; int age; char sex[SEX_MAX]; char tele[TELE_MAX]; char addr[ADDR_MAX]; }PeoInfom; typedef struct Contact { PeoInfom 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); pc->sz = 0; memset(pc->data, 0, sizeof(pc->data)); } void AddContact(Contact* pc) { assert(pc); if (pc->sz == MAX) { 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); if (pc->sz == 0) { printf("通讯录为空\n"); } else { int i = 0; //标题 printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //数据 for (i = 0; i < pc->sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } } } int Findbyname(Contact* pc,char name[]) { assert(pc); for (int i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i; } } return -1; } void DelContact(Contact* pc) { char name[NAME_MAX]; assert(pc); if (pc->sz == 0) { printf("通讯录为空\n"); } printf("请输入要删除的联系人:"); scanf("%s", name); int ret = Findbyname(pc, name); if (ret == -1) { printf("要删除的人不存在\n"); return; } else { for (int i = ret; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("删除成功\n"); } } void SearchContact(const Contact* pc) { char name[NAME_MAX]; assert(pc); printf("请输入联系人:"); scanf("%s", name); int ret = Findbyname(pc, name); if (ret == -1) { printf("要查找的人不存在\n"); return; } else { //标题 printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //数据 printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n", pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr); } } void ModifyContact(Contact* pc) { char name[NAME_MAX]; assert(pc); printf("请输入联系人:"); scanf("%s", name); int ret = Findbyname(pc, name); if (ret == -1) { printf("要修改的人不存在\n"); return; } printf("请输入名字:"); scanf("%s", pc->data[ret].name); printf("请输入年龄:"); scanf("%d", &(pc->data[ret].age)); printf("请输入性别:"); scanf("%s", pc->data[ret].sex); printf("请输入电话:"); scanf("%s", pc->data[ret].tele); printf("请输入地址:"); scanf("%s", pc->data[ret].addr); printf("修改联系人成功\n"); } int cmp_name(const void* e1, const void* e2) { return (strcmp(((Contact*)e1)->data->name, ((Contact*)e2)->data->name)); } //联系人排序 void SortContact(Contact* pc) { assert(pc); qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name); //打印 printf("排序完成\n"); ShowContact(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"); } enum Option { EXIT,//0 ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; int main() { 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); return 0; }