通讯录目录
用C语言模拟出来一个通讯录,首先要分头文件和源文件的,我这里分了一个头文件和两个源文件:
test.c这里用于存放主函数和调用其他函数,contacts.c用于存放通讯录的各种功能函数,contacts.h用于存放引用头文件的代码和自定义函数的声明和预处理指令。
首先,我们写的通讯录鸭油7个功能:
添加联系人,删除联系人,修改联系人的信息,查找联系人,展示通讯录联系人,排序通讯录中的联系人,退出通讯录。
test.c
#include "contacts.h" enum list { exit,//默认值为0 add, del, modify, find, show, sort }; void catalogue() { printf("*********************************\n"); printf("*** 1.add 2.del ***\n"); printf("*** 3.modify 4.find ***\n"); printf("*** 5.show 6.sort ***\n"); printf("*** 0.exit ***\n"); printf("*********************************\n"); } int main() { int n = 0; do { catalogue();//通讯录菜单 printf("请选择>"); scanf("%d", &n);//选择要做什么 switch (n) { case exit://退出程序 printf("退出通讯录"); break; case add://添加联系人 break; case del://删除联系人 break; case find://查找联系人 break; case modify://修改联系人信息 break; case show://展示联系人 break; case sort://排序通讯录 break; default: printf("输入错误请重新输入\n"); } } while (n); return 0; }
Contacts.c
#include "contacts.h"
Contacts.h
#include <stdio.h>
运行起来看一下效果:
下面我们就着手安排剩下的功能。
初始化通讯录
首先我们要想一下,通讯录里面的联系人个人信息都有什么,我自己定义的有,名字,年龄,性别,电话,住址。
因为通讯录里面要储存一些联系人,联系人又分这些信息,那么我们用构造体来定义一个联系人再合适不过。
Contacts.h
//定义的结构体 typedef struct person { char name[20];//名字 int age;//年龄 char sex[20];//性别 char phone[20];//电话 char location[20];//住址 }person;
这是联系人的类型,那么一个通讯录我们假设能储存一百个人,那么还需要有一个变量来计算一下通讯录当前有多少人才行。
Contacts.h
typedef struct contacts { person data[100];//存放人信息的位置 int count;//记录通讯录的人数 }contacts;
这里因为data和count是维护整个通讯录的关键变量,count是根据date里面的元素数量变化而变化,放在一个结构体里面更方便用。
然后整个程序就是这样子的:
Contacts.h
#include <stdio.h> #include <string.h> //定义的结构体 typedef struct person { char name[20];//名字 int age;//年龄 char sex[20];//性别 char phone[20];//电话 char location[20];//住址 }person; typedef struct contacts { person data[100];//存放人信息的位置 int count;//记录通讯录的人数 }contacts; //函数声明区 void initialize(contacts* pc);//初始化通讯录
Contacts.c
#include "contacts.h" void initialize(contacts* pc) { pc->count = 0;//将计数的变量初始化为0 memset(pc->data, 0, sizeof(pc->data));//将数组里面的内容都初始化为0 }
test.c
#include "contacts.h" enum list { exit,//默认值为0 add, del, modify, find, show, sort }; void catalogue() { printf("*********************************\n"); printf("*** 1.add 2.del ***\n"); printf("*** 3.modify 4.find ***\n"); printf("*** 5.show 6.sort ***\n"); printf("*** 0.exit ***\n"); printf("*********************************\n"); } int main() { int n = 0; contacts con;//通讯录 initialize(&con);//初始换通讯录 do { catalogue();//通讯录菜单 printf("请选择>"); scanf("%d", &n);//选择要做什么 switch (n) { case exit://退出程序 printf("退出通讯录"); break; case add://添加联系人 break; case del://删除联系人 break; case find://查找联系人 break; case modify://修改联系人信息 break; case show://展示联系人 break; case sort://排序通讯录 break; default: printf("输入错误请重新输入\n"); } } while (n); return 0; }
这里我们初始化完成了。
这里要说一下,我们传结构体就要传结构体的地址,因为能节省内存。
(这里忘记添加assert函数来断言了,下面补上了)。
添加联系人和展示通讯录的联系人
添加联系人首先要先判断通讯录是不是人数已经满了,然后在contacts结构体中的person data[100]存放联系人的信息,从data[0]开始,那么count就是计算有多少个联系人,一开始也是0,多一个就++,那么count也对应了data数组的下标存放位置。
存放进去之后我们顺便也写一下打印函数,打印就很简单了,定义一个变量来当数组下标,小于count就可以了。
contacts.h
//函数声明区 void initialize(contacts* pc);//初始化通讯录 void addcontact(contacts* pc);//输入联系人信息 void showcontact(const contacts* pc);//打印通讯录,因为打印不需要修改里面的数值,所以用const修饰一下更安全
contacts.c
void addcontact(contacts* pc) { assert(pc != NULL);//断言pc指向的位置不是空指针 if (pc->count == MAX) { printf("通讯录已满\n"); return 0; } printf("姓名:"); scanf("%s", pc->data[pc->count].name);//这里注意一下,数组名是首元素地址,所以不用取地址了 printf("年龄:"); scanf("%d", &(pc->data[pc->count].age)); printf("性别:"); scanf("%s", pc->data[pc->count].sex); printf("电话号:"); scanf("%s", pc->data[pc->count].phone); printf("家庭住址:"); scanf("%s", pc->data[pc->count].location); pc->count++; printf("增加成功\n"); } void showcontact(const contacts* pc) { assert(pc != NULL); int i = 0; printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20\t\n", "姓名", "年龄","性别","电话号","家庭住址"); for (i = 0; i < pc->count; i++) { printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20\t\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].phone, pc->data[i].location); } }
test.c
int main() { int n = 0; contacts con;//通讯录 initialize(&con);//初始换通讯录 do { catalogue();//通讯录菜单 printf("请选择>"); scanf("%d", &n);//选择要做什么 switch (n) { case exit://退出程序 printf("退出通讯录"); break; case add://添加联系人 addcontact(&con); break; case del://删除联系人 break; case find://查找联系人 break; case modify://修改联系人信息 break; case show://展示联系人 showcontact(&con); break; case sort://排序通讯录 break; default: printf("输入错误请重新输入\n"); } } while (n); return 0; }
来看一下效果:
删除联系人,修改联系人,查找联系人
这三个放在一起写比较方便,因为修改和删除需要先查找有没有这个联系人才可以操作,查找功能更不用说。
首先要写一个查找联系人的函数,用strcmp函数来查找你输入的名字在通讯录里有无。
删除联系人的函数:
contacts.c
int find_out(char* p1 , contacts* p2) { assert(p1 != NULL); assert(p2 != NULL); int i = 0; for (i = 0; i < p2->count; i++) { if (!strcmp(p1, p2->data[i].name))//如果相等就返回0,前面加了!操作符,所以非零条件不成立 return i; } return -1; } int delcontact(contacts* pc) { assert(pc != NULL); char name[20] = { 0 }; printf("输入此人姓名\n"); scanf("%s", name); int i = find_out(name, pc); if (i == -1) { printf("无此人信息\n"); return 1; } pc->count = pc->count - 1; while (i < pc->count) { pc->data[i] = pc->data[i + 1];//删除的过程 i++; } printf("删除成功"); }
其实删除人的过程很简单,你选定的元素是data[i],然后被data[i+1]覆盖,data[i+1]被data[i+2]覆盖以此循环。
因为通过一个查找的逻辑找到了此人,所以通讯录的人就会少一人,那么count就会减一,这样让i<count就不会有问题了,如果count不减少,i=99,count=100,就会造成数组的越界访问,这样不好处理,所以我们直接让count- -,这样i最多也就是98,i+1=99;至于data[99]这个位置的元素怎么办,不用理会,上面的添加联系人和展示通讯录都是count进行很重要的操作,新添加的联系人会覆盖掉原来末尾中没有被位移的联系人信息;如果没有添加展示联系人的话根本不会打印出来末尾的那个联系人。
修改联系人就更容易了,直接将原来联系人的信息覆盖掉就可以了,等于无循环版本添加联系人函数。
修改联系人的函数:
contacts.c
int find_out(char* p1 , contacts* p2) { assert(p1 != NULL); assert(p2 != NULL); int i = 0; for (i = 0; i < p2->count; i++) { if (!strcmp(p1, p2->data[i].name))//如果相等就返回0,前面加了!操作符,所以非零条件不成立 return i; } return -1; } int modifycontact(contacts* pc) { assert(pc != NULL); printf("输入此人姓名\n"); char name[20] = { 0 }; scanf("%s", name); int i = find_out(name, pc); if (i == -1) { printf("无此人信息\n"); return 1; } printf("请输入要修改的信息\n"); printf("姓名:"); scanf("%s", pc->data[i].name); printf("年龄:"); scanf("%d", &(pc->data[i].age)); printf("性别:"); scanf("%s", pc->data[i].sex); printf("电话号:"); scanf("%s", pc->data[i].phone); printf("家庭住址:"); scanf("%s", pc->data[i].location); printf("修改成功\n"); }
查找联系人的函数就是展示通讯录函数的无循环版本。
这是查找联系人的函数:
contacts.c
int find_out(char* p1 , contacts* p2) { assert(p1 != NULL); assert(p2 != NULL); int i = 0; for (i = 0; i < p2->count; i++) { if (!strcmp(p1, p2->data[i].name))//如果相等就返回0,前面加了!操作符,所以非零条件不成立 return i; } return -1; } int findcontact(contacts* pc) { assert(pc != NULL); printf("输入此人姓名\n"); char name[20] = { 0 }; scanf("%s", name); int i = find_out(name, pc); if (i == -1) { printf("无此人信息\n"); return 1; } printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20\t\n", "姓名", "年龄", "性别", "电话号", "家庭住址"); printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20\t\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].phone, pc->data[i].location); }
这是代码运行的效果(写一点调试一点,这样就会让代码的bug容易修复):