小程序|通讯录小程序(C语言)


通讯录小程序(C语言)

  • 程序介绍
  • 实现思路和内容概括
  • 代码实现
    • 打印菜单
    • 定义通讯录
    • 初始化通讯录函数
    • 添加联系人函数
    • 显示通讯录函数
    • 查找通讯录函数
    • 删除联系人
    • 查找指定联系人
    • 修改指定联系人信息
    • 排序(按姓名)
  • 完整代码
    • contact.h
    • contact.c
    • test.c
  • 运行展示
  • 总结

程序介绍 【小程序|通讯录小程序(C语言)】通过前面学习我们可以实现通讯录小程序的代码,首先,我们需要创建一个通讯录,通讯录中存放1000个人的信息,信息包括:名字,性别,年龄,电话,住址。通讯录主要由5个功能:增加联系人、删除联系人、修改联系人、查找联系人、按名称子排序。下面我们来看实现过程。
实现思路和内容概括 首先我们将完整的代码分为3个部分——contact.h(头文件)、contact.c(函数部分)、test.c(主函数实现部分)。我们会创建一个大的框架,将菜单放入其中,菜单有7个选项:1.add 2.del 3.search 4.modify 5.show 6.sort 0.exit
输入“1”,添加联系人信息,输入“2”,删除指定联系人信息,输入“3”,查找指定联系人信息(按姓名查找并打印),输入“4”,修改指定联系人信息(按姓名查找),输入“5”,打印当前的通讯录所有联系人,输入“6”,将通讯录所有联系人按姓名排序。输入“0”,退出通讯录。
代码实现 打印菜单
void menu() { printf("****************************\n"); printf("**** 1.add2.del****\n"); printf("**** 3.search4.modify ****\n"); printf("**** 5.show6.sort****\n"); printf("**** 0.exit****\n"); printf("****************************\n"); printf("****************************\n"); } enum Option { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; int main() { int input=0; //创建一个通讯录 struct 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: SortContactByName(&con); break; case EXIT: printf("退出通讯录。\n"); break; default: printf("选择错误!\n"); break; } } while (input); return 0; }

我们利用枚举类型将EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SORT放入其中,因为枚举类型中的成员属于常量所以具有常量的属性,我们可以利用此属性运用到switch上,这样就提高了代码的可读性。利用do while循环,我们先打印menu()函数,再利用input变量,只要输入非0,都会打印菜单,只是效果不同。
定义通讯录
//描述人的信息 #define NAME_MAX 20 #define SEX_MAX 5 #define TELE_MAX 12 #define ADDR_MAX 30 #define MAX 1000 struct PeoInfo { char name[NAME_MAX]; int age; char sex[SEX_MAX]; char tele[TELE_MAX]; char addr[ADDR_MAX]; }; //通讯录 struct Contact { struct PeoInfo data[MAX]; //1000个人的信息存放进data数组中 int sz ; //记录当前存放进通讯录中的有效信息的个数 };

定义一个通讯录需要两个结构体,struct PeoInfo结构体是描述一个人的信息,struct Contact结构体是通讯录本身,我们将struct PeoInfo中的个人信息存放在struct Contact结构体中以实现联系,也就是struct Contact的成员data[1000]是struct PeoInfo结构体类型,data[1000]是一个结构体类型的数组,里面有name[20],age,sex[5],tele[12],addr[30]。
初始化通讯录函数
void InitContact(struct Contact* pc) { pc->sz = 0; //默认没有信息 //memset(pc->data, 0, MAX * sizeof(struct PeoInfo)); memset(pc->data, 0, sizeof(pc->data)); }

当我们定义一个通讯录结构体时,数值都是随机值,因此我们需要初始化,将通讯录所有的信息数据都变成“0”,这里使用了memset()函数,我们在内存函数博客中介绍了这个函数,不在细说。具体实现原理可以看前面的博客内存函数(C语言)
添加联系人函数
void AddContact(struct Contact* pc) { if (pc->sz == MAX) {printf("通讯录已满!\n"); } else {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 ); //提示添加成功 printf("添加成功\n"); pc->sz++; } }

AddContact()函数,首先先进行判断,sz(记录当前存放进通讯录中的有效信息的个数)是否等于MAX(1000),如果有,则打印通讯录已满,如果没有则按要求输入信息,并提示添加成功,sz++。
显示通讯录函数
void ShowContact(struct Contact* pc) { int i = 0; printf("%15s\t%5s\t%8s\t%15s\t%30s\n\n", "name", "age", "sex", "tele", "addr"); for (i = 0; i < pc->sz; i++) {//打印每一个数据 printf("%15s\t%5d\t%8s\t%15s\t%30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } }

在ShowContact()函数中,我们先打印标题"name", “age”, “sex”, “tele”, “addr”,然后利用for循环将信息一一对应标题都打印下来。
查找通讯录函数
int FindContactByName(const struct Contact* pc, const char *name) { int i = 0; for (i = 0; i < pc->sz; i++) {if (strcmp(pc->data[i].name, name) == 0) {return i; } } //找不到 return -1; }

FindContactByName()函数的基本实现是通过strcmp()函数实现的,利用for循环,找到查找的名字于通讯录名字相等的此时i的值,并返回i的值,此时i的值正是data数组的下标,方便后续操作,关于strcmp()函数实现原理可以看以前博客字符与字符串函数(C语言)。
删除联系人
void DelContact(struct Contact* pc) { if (pc->sz == 0) {printf("通讯录为空,无法删除\n"); return; } char name[NAME_MAX] = { 0 }; printf("请输入要删除人的名字:>"); scanf("%s", name); //查找 int pos = FindContactByName(pc, name); if (pos == -1) {printf("指定的联系人不存在\n"); } else {//删除 int j = 0; for (j = pos; j < pc->sz-1; j++) {pc->data[j] = pc->data[j + 1]; } pc->sz--; //提示 printf("删除成功\n"); } }

DelContact()函数和AddContact()函数类似,但是比添加联系人要复杂,删除联系人先再找到指定的联系人,在进行操作,因此,DelContact()函数中运用了查找通讯录函数,利用名字进行比较找出指定的联系人,在进行删除时,并不是直接删除,而是利用后一个信息将前一个信息的覆盖,如此达到删除联系人的信息。
查找指定联系人
void SearchContact(const struct Contact* pc) { char name[NAME_MAX] = { 0 }; printf("输入要查找人的名字:>"); scanf("%s", name); int pos = FindContactByName(pc, name); if (-1 == pos) {printf("查无此人\n"); } else {printf("%15s\t%5s\t%8s\t%15s\t%30s\n\n", "name", "age", "sex", "tele", "addr"); printf("%15s\t%5d\t%8s\t%15s\t%30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } }

SearchContact()函数是在FindContactByName()函数的基础之上增加了打印的功能,如果没有查找到指定的联系人打印“查无此人”,否则打印出该联系人的所有信息。
修改指定联系人信息
void ModifyContact(struct Contact* pc) { char name[NAME_MAX] = { 0 }; printf("输入要修改人的名字:>"); scanf("%s", name); int pos = FindContactByName(pc, name); if (-1 == pos) {printf("要修改的人不存在\n"); } else {printf("请输入新的名字:>"); scanf("%s", pc->data[pos].name); printf("请输入新的年龄:>"); scanf("%d", &(pc->data[pos].age)); printf("请输入新的性别:>"); scanf("%s", pc->data[pos].sex); printf("请输入新的电话:>"); scanf("%s", pc->data[pos].tele); printf("请输入新的地址:>"); scanf("%s", pc->data[pos].addr); } }

ModifyContact()函数是利用FindContactByName()函数先将想要修改的联系人找到,然后输入新的所有信息来覆盖原来的信息。
排序(按姓名)
int cmp_name(const void* e1, const void* e2) { return strcmp(((struct Contact*)e1)->data->name , ((struct Contact*)e2)->data->name); } void SortContactByName(struct Contact* pc) { qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name); printf("排序成功\n"); }

排序运用到了qsort()函数,这个函数可以排序任意类型的数据,因此结构体也可以。但是需要引用到头文件#include
qsort()函数:
形式:void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) )
解释:qsort函数实现了一种快速排序算法,用于对num元素数组进行排序,每个元素的宽度为字节。参数base是指向要排序的数组的基的指针。qsort用已排序的元素覆盖此数组。参数compare是指向用户提供的例程的指针,该例程比较两个数组元素并返回指定其关系的值。
也就是说,*base是一个指针,num是要排序的个数,width是排序元素的大小,int (__cdecl *compare )(const void *elem1, const void *elem2 ) 是一个函数,这个函数就是用来判断怎样比较的。以写的代码为例,pc是指针指向的是struct Contact con结构体,pc->sz是记录当前存放进通讯录中的有效信息的个数,也就对应了打印的个数,sizeof(pc->data[0])是个人信息的结构体的大小,cmp_name()函数是按名字来进行排序。
完整代码 contact.h
#include #include #include #define NAME_MAX 20 #define SEX_MAX 5 #define TELE_MAX 12 #define ADDR_MAX 30 #define MAX 1000//描述人的信息 struct PeoInfo { char name[NAME_MAX]; int age; char sex[SEX_MAX]; char tele[TELE_MAX]; char addr[ADDR_MAX]; }; //通讯录 struct Contact { struct PeoInfo data[MAX]; //1000个人的信息存放进data数组中 int sz ; //记录当前存放进通讯录中的有效信息的个数 }; //初始化通讯录 void InitContact(struct Contact* pc); //增加联系人 void AddContact(struct Contact* pc); //显示通讯录 void ShowContact(struct Contact* pc); //删除联系人 void DelContact(struct Contact* pc); //查找指定联系人 void SearchContact(const struct Contact* pc); //修改指定联系人 void ModifyContact(struct Contact* pc); //按姓名排序通讯录 void SortContactByName(struct Contact* pc);

用#define定义的常量能够方便代码的修改,增加了代码的维护性。
contact.c
#include"contact.h" void InitContact(struct Contact* pc) { pc->sz = 0; //默认没有信息 //memset(pc->data, 0, MAX * sizeof(struct PeoInfo)); memset(pc->data, 0, sizeof(pc->data)); }void AddContact(struct Contact* pc) { if (pc->sz == MAX) {printf("通讯录已满!\n"); } else {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 ); //提示添加成功 printf("添加成功\n"); pc->sz++; } }void ShowContact(struct Contact* pc) { int i = 0; printf("%15s\t%5s\t%8s\t%15s\t%30s\n\n", "name", "age", "sex", "tele", "addr"); for (i = 0; i < pc->sz; i++) {//打印每一个数据 printf("%15s\t%5d\t%8s\t%15s\t%30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } }int FindContactByName(const struct Contact* pc, const char *name) { int i = 0; for (i = 0; i < pc->sz; i++) {if (strcmp(pc->data[i].name, name) == 0) {return i; } } //找不到 return -1; }void DelContact(struct Contact* pc) { if (pc->sz == 0) {printf("通讯录为空,无法删除\n"); return; } char name[NAME_MAX] = { 0 }; printf("请输入要删除人的名字:>"); scanf("%s", name); //查找 int pos = FindContactByName(pc, name); if (pos == -1) {printf("指定的联系人不存在\n"); } else {//删除 int j = 0; for (j = pos; j < pc->sz-1; j++) {pc->data[j] = pc->data[j + 1]; } pc->sz--; //提示 printf("删除成功\n"); } }void SearchContact(const struct Contact* pc) { char name[NAME_MAX] = { 0 }; printf("输入要查找人的名字:>"); scanf("%s", name); int pos = FindContactByName(pc, name); if (-1 == pos) {printf("查无此人\n"); } else {printf("%15s\t%5s\t%8s\t%15s\t%30s\n\n", "name", "age", "sex", "tele", "addr"); printf("%15s\t%5d\t%8s\t%15s\t%30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } }void ModifyContact(struct Contact* pc) { char name[NAME_MAX] = { 0 }; printf("输入要修改人的名字:>"); scanf("%s", name); int pos = FindContactByName(pc, name); if (-1 == pos) {printf("要修改的人不存在\n"); } else {printf("请输入新的名字:>"); scanf("%s", pc->data[pos].name); printf("请输入新的年龄:>"); scanf("%d", &(pc->data[pos].age)); printf("请输入新的性别:>"); scanf("%s", pc->data[pos].sex); printf("请输入新的电话:>"); scanf("%s", pc->data[pos].tele); printf("请输入新的地址:>"); scanf("%s", pc->data[pos].addr); } } int cmp_name(const void* e1, const void* e2) { return strcmp(((struct Contact*)e1)->data->name , ((struct Contact*)e2)->data->name); } void SortContactByName(struct Contact* pc) { qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name); printf("排序成功\n"); }

存放用到的所有函数,需要引用头文件#include"contact.h"。
test.c
#include "contact.h" void menu() { printf("****************************\n"); printf("**** 1.add2.del****\n"); printf("**** 3.search4.modify ****\n"); printf("**** 5.show6.sort****\n"); printf("**** 0.exit****\n"); printf("****************************\n"); printf("****************************\n"); } enum Option { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; int main() { int input=0; //创建一个通讯录 struct 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: SortContactByName(&con); break; case EXIT: printf("退出通讯录。\n"); break; default: printf("选择错误!\n"); break; } } while (input); return 0; }

主函数部分,这个部分也是实现部分,进入函数,先创建一个通讯录struct Contact con,然后初始化,再根据所选的input,进行个系列的操作,以此达到通讯录的增删改查等功能。
运行展示 小程序|通讯录小程序(C语言)
文章图片

总结 关于通讯录其实还有很多改进的地方,这只是最简易的版本,还可以加入文件导入,动态版本等等,相对于改进的版本,这是最简易也是最好理解的。有难度的在于qsort()函数的理解,当然我们也可以采用自己实现的排序冒泡或者快排都可以。好了通讯录小程序也可以说的上将C语言中语法的大部分内容都用了一边,对于编程能力的提升和语法的理解是有着很大的帮助的,希望大家能够抽出时间将代码敲上一敲。如果有什么错误或者建议,希望各位能够提出建议,谢谢各位!

    推荐阅读