我们知道在一个工程中,不可能将所有代码都写到一个文件下,而是根据不同的功能模块,分配到多个文件下,这样便于以后的维护升级。
所以通讯录中我分配了3个文件: test.c用来实现逻辑代码、测试程序, contacts.c用来实现代码逻辑中功能函数的编写,contacts.h用来声明函数和头文件和定义全局变量并且把test.c和contacts.c文件联系起来。
那么我们要在通讯录中实现哪些功能呢?大致如下:
一开始我们需要在test.c测试文件下编写整体的逻辑代码,我希望进到通讯录可以有个菜单显示可执行的功能供我多次选择,代码如下:
#include "contacts.h"void meau()
{printf("*******************************************\n");printf("*********** 1.add 2.del ***********\n");printf("*********** 3.find 4.rev ***********\n");printf("*********** 5.show 6.sort***********\n");printf("*********** 0.exit 7.pur ***********\n");printf("*******************************************\n");
}int main()
{int input = 0;do{meau();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;case 7:break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}
为了保存联系人的信息包括其姓名、年龄、性别、住址、电话,显然我们需要使用结构体来保存多个不同的数据,我们在contacts.h文件下定义便于在其他文件下使用:
使用define定义的变量便于我们以后修改通讯录参数信息
#define MAX_PEO 1000
#define MAX_name 20
#define MAX_sex 6
#define MAX_addrO 15
#define MAX_tele 13typedef struct peoinf//存放个人的信息
{char name[MAX_name];int age;char sex[MAX_sex];char addr[MAX_addrO];char tele[MAX_tele];
}peo;
在通讯录中除了联系人的个人信息我还希望能知道联系人的个数,所以我在创建一个包括联系信息和联系人个数的结构体作为通讯录结构体:
typedef struct Contacts//通讯录包括联系人信息和联系人个数
{peo data[MAX_PEO ];int sz;
}contacts;
在让通讯录执行功能之前,我们应先初始化通讯录让其初值在我们的控制下,首先我们在测试文件下定义结构体变量,用于函数传参
在测试文件下向函数传参,接着我们在.h文件下声明函数在.c文件下编写函数,不光是初始化函数,下文所有函数都是如此操作.
contacts con;ini_con(&con);//初始化通讯录
功能函数的实现:
//初始化通讯录
void ini_con(contacts* p)
{assert(p);p->sz = 0;memset(p->data, 0, sizeof(p->data));
}
我们在向通讯录添加信息前应当先判断通讯录是否已满,如果还有空间则向结构体中写入信息:
//添加通讯录信息
void addcon(contacts* p)
{assert(p);if (MAX_PEO == p->sz){printf("通讯录已满");}else{printf("请输入姓名:>");scanf("%s", p->data[p->sz].name);printf("请输入年龄:>");scanf("%d", &(p->data[p->sz].age));printf("请输入性别:>");scanf("%s", p->data[p->sz].sex);printf("请输入住址:>");scanf("%s", p->data[p->sz].addr);printf("请输入电话:>");scanf("%s", p->data[p->sz].tele);p->sz++;}return;//void类型函数不需要返回什么
}
上图中除年龄之外的结构体成员都是数组,所以不需要用取地址。
我们希望通讯录可以将现有的信息显示出来,实现显示功能:
需要注意的是:因为各组数据长度不一,我们应该预先设置字符长度并且左对齐,让显示界面比较整齐,在打印数据之前 先打印了表头,便于清晰的显示通讯录中的联系人信息。
//显示通讯录信息
void Showcon(const contacts* p)
{assert(p);printf("%-20s\t%-4s\t%-10s\t%-15s\t%-13s\n", "姓名","年龄","性别","住址","电话");for (int i = 0; i < p->sz;i++){printf("%-20s\t%-4d\t%-10s\t%-15s\t%-13s\n", p->data[i].name, p->data[i].age, p->data[i].sex, p->data[i].addr, p->data[i].tele);}
}
我们简单的演示下已有的功能:
要删除指定联系人我们就需要在通讯录中找到他,我们可以使用strcmp比较结构体中存放的姓名与输入要删除名字的大小,当strcmp返回0时即找到了要删除的联系人。
因为在之后的修改查找等功能,都需要使用到strcmp查找联系人的功能,我们可以直接将strcmp比较姓名封装为一个函数find返回联系人所在的下标位置:
//封装查找函数
int find(const contacts* p, char name[20])
{int i = 0;for (i = 0; i < p->sz; i++){if (0 == strcmp(p->data[i].name, name))return i;}return -1;
}
//删除通讯录信息
void delcon(contacts* p)
{assert(p);char name[20] = { 0 };printf("请输入要删除的联系人姓名:>");scanf("%s", name);//int flag = 0;int pos = 0;if (0 == p->sz){printf("通讯录为空,无法删除\n");}else{pos = find(p, name);}if (pos == -1){printf("要删除的联系人不存在\n");return; }//int j = 0;//for (j = pos; j < p->sz - 1; j++)//{// p->data[j] = p->data[j + 1];//}memmove(&(p->data[pos]), &(p->data[pos + 1]), (sizeof(peo) * (p->sz - pos + 2)));p->sz--;printf("已删除\n");
}
删除联系人的方法有三种: 1. 遍历将后面的联系人向前覆盖,缺点有性能的下降。2. memmove向前覆盖. 3. 将最后一个联系人的信息覆盖到要删除的联系人的位置,缺点通讯录顺序会发生改变。
想要查找指定联系人,可以通过名字搜索使用封装好的find函数,查找到了直接显示。
//查找
void findcon(const contacts* p)
{assert(p);char name[20] = { 0 };printf("请输入要查找的联系人姓名:>");scanf("%s", name);int pos=find(p, name);if (-1 == pos)printf("无此联系人\n");else{printf("%-20s\t%-4s\t%-10s\t%-15s\t%-13s\n", "姓名", "年龄", "性别", "住址", "电话");printf("%-20s\t%-4d\t%-10s\t%-15s\t%-13s\n", p->data[pos].name, p->data[pos].age, p->data[pos].sex, p->data[pos].addr, p->data[pos].tele);}
}
为了修改到指定联系人的信息,我们需要通过姓名查找到联系人,再重新录入此人信息:
//修改
void revcon(contacts* p)
{assert(p);char name[20] = { 0 };printf("请输入要修改的联系人姓名:>");scanf("%s", name);int pos = find(p, name);if (-1 == pos)printf("无此联系人\n");else{printf("请输入姓名:>");scanf("%s", p->data[pos].name);printf("请输入年龄:>");scanf("%d", &(p->data[pos].age));printf("请输入性别:>");scanf("%s", p->data[pos].sex);printf("请输入住址:>");scanf("%s", p->data[pos].addr);printf("请输入电话:>");scanf("%s", p->data[pos].tele);}
}
想要排序通讯录可以通过两种方式:通过姓名的字典序或者年龄的大小,这只要使用之前学过得qsort即可完成:
int cmp_int(const void* p1, const void* p2)
{assert(p1 && p2);return *(int*)p1 - *(int*)p2;
}
int cmp_char(const void* p1, const void* p2)
{assert(p1 && p2);return strcmp((*(peo*)p1).name, (*(peo*)p2).name);
}
//排序
void sortcon(contacts* p)
{printf("*******************************\n");printf("******** 1.年龄 2.姓名 ********\n");printf("*******************************\n");int input = 0;scanf("%d", &input);if (1 == input){qsort(&p->data->age, p->sz, sizeof(peo), cmp_int);Showcon(p);}else{qsort(&p->data->name, p->sz, sizeof(peo), cmp_char);Showcon(p);}return;
}
我们分别演示一下:结果如下:
当我们不想再使用目前的通讯录时,可以使用清除的功能,将通讯录所有信息归零;
:::
//清除
void purcon(contacts* p)
{assert(p);p->sz = 0;memset(p->data, 0, sizeof(p->data));
}
#define _CRT_SECURE_NO_WARNINGS 1#include "contacts.h"void meau()
{printf("*******************************************\n");printf("*********** 1.add 2.del ***********\n");printf("*********** 3.find 4.rev ***********\n");printf("*********** 5.show 6.sort***********\n");printf("*********** 0.exit 7.pur ***********\n");printf("*******************************************\n");
}int main()
{contacts con;ini_con(&con);//初始化通讯录int input = 0;do{meau();printf("请选择:>");scanf("%d", &input);switch (input){case 1:addcon(&con);break;case 2:delcon(&con);break;case 3:findcon(&con);break;case 4:revcon(&con);break;case 5:Showcon(&con);break;case 6:sortcon(&con);break;case 0:printf("退出通讯录\n");break;case 7:purcon(&con);break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1#include "contacts.h"//初始化通讯录
void ini_con(contacts* p)
{assert(p);p->sz = 0;memset(p->data, 0, sizeof(p->data));
}
//封装查找函数
int find(const contacts* p, char name[20])
{int i = 0;for (i = 0; i < p->sz; i++){if (0 == strcmp(p->data[i].name, name))return i;}return -1;
}
//添加通讯录信息
void addcon(contacts* p)
{assert(p);if (MAX_PEO == p->sz){printf("通讯录已满");}else{printf("请输入姓名:>");scanf("%s", p->data[p->sz].name);printf("请输入年龄:>");scanf("%d", &(p->data[p->sz].age));printf("请输入性别:>");scanf("%s", p->data[p->sz].sex);printf("请输入住址:>");scanf("%s", p->data[p->sz].addr);printf("请输入电话:>");scanf("%s", p->data[p->sz].tele);p->sz++;}return;//void类型函数不需要返回什么}//显示通讯录信息
void Showcon(const contacts* p)
{assert(p);printf("%-20s\t%-4s\t%-10s\t%-15s\t%-13s\n", "姓名","年龄","性别","住址","电话");for (int i = 0; i < p->sz;i++){printf("%-20s\t%-4d\t%-10s\t%-15s\t%-13s\n", p->data[i].name, p->data[i].age, p->data[i].sex, p->data[i].addr, p->data[i].tele);}
}//删除通讯录信息
void delcon(contacts* p)
{assert(p);char name[20] = { 0 };printf("请输入要删除的联系人姓名:>");scanf("%s", name);//int flag = 0;int pos = 0;if (0 == p->sz){printf("通讯录为空,无法删除\n");}else{pos = find(p, name);}if (pos == -1){printf("要删除的联系人不存在\n");return; }//int j = 0;//for (j = pos; j < p->sz - 1; j++)//{// p->data[j] = p->data[j + 1];//}memmove(&(p->data[pos]), &(p->data[pos + 1]), (sizeof(peo) * (p->sz - pos + 2)));p->sz--;printf("已删除\n");
}//查找
void findcon(const contacts* p)
{assert(p);char name[20] = { 0 };printf("请输入要查找的联系人姓名:>");scanf("%s", name);int pos=find(p, name);if (-1 == pos)printf("无此联系人\n");else{printf("%-20s\t%-4s\t%-10s\t%-15s\t%-13s\n", "姓名", "年龄", "性别", "住址", "电话");printf("%-20s\t%-4d\t%-10s\t%-15s\t%-13s\n", p->data[pos].name, p->data[pos].age, p->data[pos].sex, p->data[pos].addr, p->data[pos].tele);}
}
//修改
void revcon(contacts* p)
{assert(p);char name[20] = { 0 };printf("请输入要修改的联系人姓名:>");scanf("%s", name);int pos = find(p, name);if (-1 == pos)printf("无此联系人\n");else{printf("请输入姓名:>");scanf("%s", p->data[pos].name);printf("请输入年龄:>");scanf("%d", &(p->data[pos].age));printf("请输入性别:>");scanf("%s", p->data[pos].sex);printf("请输入住址:>");scanf("%s", p->data[pos].addr);printf("请输入电话:>");scanf("%s", p->data[pos].tele);}
}int cmp_int(const void* p1, const void* p2)
{assert(p1 && p2);return *(int*)p1 - *(int*)p2;
}
int cmp_char(const void* p1, const void* p2)
{assert(p1 && p2);return strcmp((*(peo*)p1).name, (*(peo*)p2).name);
}
//排序
void sortcon(contacts* p)
{printf("*******************************\n");printf("******** 1.年龄 2.姓名 ********\n");printf("*******************************\n");int input = 0;scanf("%d", &input);if (1 == input){qsort(&p->data->age, p->sz, sizeof(peo), cmp_int);Showcon(p);}else{qsort(&p->data->name, p->sz, sizeof(peo), cmp_char);Showcon(p);}return;
}
//清除
void purcon(contacts* p)
{assert(p);p->sz = 0;memset(p->data, 0, sizeof(p->data));
}
#define _CRT_SECURE_NO_WARNINGS 1#include
#include
#include
#include #define MAX_PEO 1000
#define MAX_name 20
#define MAX_sex 6
#define MAX_addrO 15
#define MAX_tele 13typedef struct peoinf//存放个人的信息
{char name[MAX_name];int age;char sex[MAX_sex];char addr[MAX_addrO];char tele[MAX_tele];
}peo;typedef struct Contacts//通讯录包括联系人信息和联系人个数
{peo data[MAX_PEO];int sz;
}contacts;//初始化通讯录
void ini_con(contacts* p);
//添加联系人信息
void addcon(contacts* p);
//显示通讯录
void Showcon(const contacts* p);
//删除通讯录信息
void delcon(contacts* p);
//查找信息
void findcon(const contacts* p);
//修改联系人信息
void revcon(contacts* p);
//排序通讯录
void sortcon(contacts* p);
//清除通讯录
void purcon(contacts* p);