目录
十. 成员信息排序 (Cont_Sort 和 qsort()函数)
一. 前言
通讯录是一种常见的应用程序,用于存储和管理联系人的信息。通过通讯录,我们可以方便地查找和联系朋友、家人或者同事。为了更好地理解和掌握C语言的应用,本博客将带您一步步实现一个简单的C语言通讯录。
希望本博客能够给您带来一些启发和帮助,让您更好地理解和运用C语言。让我们一起开始吧!
二. 框架
首先,对于通讯录,我设想的是完成以下6个功能:
- 增加人员信息
- 删除人员信息
- 修改人员信息
- 查找人员信息
- 显示人员信息
- 排序人员信息
所以需要先在main函数中写一个菜单:
enum choice { EXIT, ADD, DEL, MODIFY, SEARCH, SORT, SHOW }; void menu() { printf(" * 欢迎进入通讯录系统 *\n"); printf(" ***************************\n"); printf(" *** 1.ADD 2.DEL ***\n"); printf(" *** 3.MODIFY 4.SEARCH ***\n"); printf(" *** 5.SORT 6.SHOW ***\n"); printf(" *** 0.EXIT ***\n"); printf(" ***************************\n"); } int main() { int input = 0; Contact con; InitContact(&con); do { menu(); printf("请输入要进行的操作:"); scanf("%d", &input); switch (input) { case ADD: Cont_ADD(&con); break; case DEL: Cont_DEL(&con); break; case MODIFY: Cont_MODIFY(&con); break; case SEARCH: Cont_SESRCH(&con); break; case SORT: Cont_SORT(&con); break; case EXIT: break; case SHOW: Cont_SHOW(&con); break; default: printf("输入不合法,请按照要求输入\n"); break; } } while (input); return 0; }
输出如下:
在这个通讯录中,我将使用结构体来表示每个联系人的信息,包括姓名、电话号码和地址等。通过使用结构体数组,我们可以方便地存储和管理多个联系人的信息。
OVER
三. 人员信息结构体和通讯录结构体的创建
3.1 人员信息结构体
对于人员信息,我希望存储的是每个人的姓名,年龄,电话号码以及住址,因此我们需要用结构体来存储信息,直接上代码:
#define NAME_MAX 20 #define SEX_MAX 5 #define TELE_MAX 15 #define ADDR_MAX 30 typedef struct PeoInfo { char name[NAME_MAX]; int age; char sex[SEX_MAX]; char tele[TELE_MAX]; char address[ADDR_MAX]; }PeoInfo;
3.2 通讯录结构体
对于通讯录,我们希望存储的是每个人的信息,因此需要嵌套一个人员信息结构体。
What's more,还需要一个整形变量来记录这个结构体存了多少人。
#define MAX 100 typedef struct Contact { PeoInfo data[MAX]; int sz; }Contact;
OVER
四. 初始化通讯录
通讯录已经建立完成,接下来我们需要定义一个通讯录的变量然后将其初始化,代码如下:
void InitContact(Contact* con) { assert(con); con->sz = 0; memset(con->data, 0, sizeof(con->data)); }
我们运用了memset() 函数将通讯录初始化,具体用法可以参考博主的另一篇文章:C语言字符函数和内存函数https://mp.csdn.net/mp_blog/creation/editor/134046041
五. 增加人员信息(Cont_Add)
增加人员信息, 需要运用到通讯录结构体类型的指针来访问通讯录结构体以及人员信息结构体来增加信息,代码如下:
void Cont_ADD(Contact* con) { assert(con); printf("请输入要增加的人数:"); int num = 0; scanf("%d", &num); if ((con->sz)+num >= MAX) { printf("增加的人数太多,无法加入!\n"); return; } else { int i = 0; for (i = 0; i < num; i++) { printf("请输入姓名:"); scanf("%s", (con->data[con->sz]).name); printf("请输入年龄:"); scanf("%d", &((con->data[con->sz]).age)); printf("请输入性别:"); scanf("%s", (con->data[con->sz]).sex); printf("请输入手机号:"); scanf("%s", (con->data[con->sz]).tele); printf("请输入住址:"); scanf("%s", (con->data[con->sz]).address); con->sz++; Sleep(100); printf("增加成功\n"); printf("---------------------------------------\n"); } } for (int i = 0; i < 5; i++) { printf("\n"); } }
Ps:
(con -> data[con -> sz]).
此行代码的意思是先用通讯录结构体类型的指针访con 访问它的PeopInfo类型的数组的第sz个元素,然后再访问这个元素的name or age or sex or tele or address。
运行结果:
六. 显示人员信息 (Cont_Show)
如果要显示人员信息,首先要判断结构体里面是否有人员,其次要有一个title来表示下面的信息代表什么,最后在输出人员信息。
void Cont_SHOW(Contact* con) { assert(con); if (con->sz == 0) { printf("现无人员,请输入后再进行显示!\n"); return; } printf("%-9s%-20s%-15s%-15s%-15s%-20s\n", "序号","姓名", "年龄", "性别", "手机号", "住址"); int i = 0; for (i = 1; i <= con->sz; i++) { printf("%-9d%-20s%-15d%-15s%-15s%-20s\n", i, (con->data[i - 1]).name, (con->data[i - 1]).age, (con->data[i - 1]).sex, (con->data[i - 1]).tele, (con->data[i - 1]).address ); } for (int i = 0; i < 5; i++) { printf("\n"); } }
运行结果:
七. 修改人员信息 (Cont_Modify)
首先,如果要修改人员信息,首先要判断结构体中是否有人员,如果没有就直接返回;
第二,如果有人员,读取用户输入并判断在PeopInfo数组中是否存在这个人,如果没有就直接返回;
第三,如果有这个人,那么就要显示出来并且在让用户依次让用户修改信息。
最后,显示修改成功。
在第二个步骤中,我们要判断在PeopInfo数组中是否存在这个人,因此我们需要在写一个函数FindByName() 来判断,大概的实现思路就是遍历PeopInfo数组看一下是否能找到。
代码如下:
static int FindbyNAME(Contact* con,char* name) { assert(con); int i = 0; for (i = 0; i < con->sz; i++) { if (strcmp(con->data[i].name, name) == 0) { return i; } } return -1; }
void Cont_MODIFY(Contact* con) { assert(con); char name[NAME_MAX] = { 0 }; if (con->sz == 0) { printf("通讯录为空,无法修改!\n"); return; } else { printf("请输入要修改的人的姓名:"); scanf("%s", name); } int ret = FindbyNAME(con, name); if (-1 == ret) { printf("无此人信息\n"); return; } printf("%-9s%-20s%-15s%-15s%-15s%-20s\n", "序号", "姓名", "年龄", "性别", "手机号", "住址"); printf("%-9d%-20s%-15d%-15s%-15s%-20s\n", ret + 1, (con->data[ret]).name, (con->data[ret]).age, (con->data[ret]).sex, (con->data[ret]).tele, (con->data[ret]).address ); printf("请输入要修改的信息\n"); printf("请输入名字:"); scanf("%s", con->data[ret].name); printf("请输入年龄:"); scanf("%d", &(con->data[ret].age)); printf("请输入性别:"); scanf("%s", con->data[ret].sex); printf("请输入电话:"); scanf("%s", con->data[ret].tele); printf("请输入地址:"); scanf("%s", con->data[ret].address); printf("修改成功\n"); for (int i = 0; i < 5; i++) { printf("\n"); } }
运行结果:
八. 删除人员信息 (Cont_Del)
首先,还是要判断PeopInfo数组里面是否有人员信息,如果有则继续,没有的话则返回。
第二,就是判断用户的输入在数组中是否存在,因此还是需要调用PeopInfo()函数。
第三,就是要将返回的第ret个元素删除,并将后面的所有元素向前移动。
代码如下:
void Cont_DEL(Contact* con) { assert(con); if (con->sz == 0) { printf("通讯录为空,无法删除!\n"); return; } char name[NAME_MAX] = { 0 }; printf("请输入要删除的人的姓名:"); scanf("%s",name); int ret = FindbyNAME(con,name); if (ret == -1) { printf("要删除的人不存在!\n"); return; } else { int i = 0; for (i = ret; i < con->sz - 1; i++) { con->data[i] = con->data[i + 1]; } con->sz--; printf("删除成功!\n"); } for (int i = 0; i < 5; i++) { printf("\n"); } }
这里需要注意的是:
con->data[i] = con->data[i + 1];
这行代码的范围应该是 ret 到 sz - 2,因为如果当i = sz - 1的时候 i + 1 = sz,很明显就越界了。 当然如果要修改最后一个元素,最后sz会直接自减1,也就不需要删除了。
运行结果如下:
九. 查找人员信息 (Cont_Search)
首先,如果要查找人员信息,就要判断数组是否有元素;
其次,就要判断用户的输入是否存在于数组中,如果存在就有打印出来(还是要用到FindByName()函数)
代码如下:
void Cont_SESRCH(Contact* con) { assert(con); if (0 == con->sz) { printf("当前没有人数信息,请增加后再使用此功能!\n"); return; } printf("请输入要查找的人的姓名:"); char name[NAME_MAX] = { 0 }; scanf("%s", name); int ret = FindbyNAME(con, name); if (ret == -1) { printf("查无此人"); } else { printf("%-9s%-20s%-15s%-15s%-15s%-20s\n", "序号", "姓名", "年龄", "性别", "手机号", "住址"); printf("%-9d%-20s%-15d%-15s%-15s%-20s\n", ret + 1, (con->data[ret]).name, (con->data[ret]).age, (con->data[ret]).sex, (con->data[ret]).tele, (con->data[ret]).address ); } int i = 0; for (i = 0; i < 5; i++) { printf("\n"); } }
运行结果如下:
十. 成员信息排序 (Cont_Sort 和 qsort()函数)
10.1 qsort() 函数
首先,要进行排序还是要判断数组是否有元素;
其次,要让用户选择按照什么进行排序(年龄 or 姓名);
因此可以看出来这里最重要的是我们如何进行排序,我们运用qsort() 函数:
此函数具体参数如下:
第一个参数是要排序的元素的起始地址,第二个参数是要排序多少个元素,第三个元素是一个元素多少个字节,第四个参数是要传入一个函数(用于比较两个元素大小的方法),用函数指针接受,具体的方法等博主有空写一篇关于指针的知识再详细解释。
10.2 传参解释
首先第一个元素是要排序的元素的首元素地址,我们要排序的是PeopInfo类型的数组data,因此应该传入 :
(con -> data)//data 是数组名 就是首元素地址
其次是要排序的元素个数:
(con -> sz) //元素个数就是现在有多少个人的信息,就是sz
然后是每个元素的大小:
sizeof((con -> data[0])//每个元素大小都一样,因此传入第一个元素打小就好
最后就是要自己写一个用于比较两元素大小的函数,我把它称为ComByName() 和 ComByAge()
static int ComByName(const void* e1,const void* e2) { const PeoInfo* c1 = (const PeoInfo*)e1; const PeoInfo* c2 = (const PeoInfo*)e2; return strcmp(c1->name, c2->name); } static ComByAge(const void* e1, const void* e2) { const PeoInfo* c1 = (const PeoInfo*)e1; const PeoInfo* c2 = (const PeoInfo*)e2; return (c1->age) - (c2->age); }
10.3 具体实现方法
直接上代码:
void Cont_SORT(Contact* con) { if (0 == con->sz) { printf("通讯录无人员信息,无法排序。\n"); return; } printf("请输入要按照什么排序(1.姓名 2.年龄):"); int input = 0; scanf("%d", &input); if (1 == input) { qsort(con->data, con->sz, sizeof(PeoInfo), ComByName); Cont_SHOW(con); } else if (2 == input) { qsort(con->data, con->sz, sizeof(PeoInfo), ComByAge); Cont_SHOW(con); } else { printf("输入不合法!"); return; } }
运行结果如下:
十一. 所有代码
首先,此代码由3个部分组成:
第一个是test.c 是用来存放main函数的地方
第二个是contact.c 是用来写具体函数实现方法的地方
第三个是contact.h 用来存放函数的具体声明和头文件。
test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "contact.h" void menu() { printf(" * 欢迎进入通讯录系统 *\n"); printf(" ***************************\n"); printf(" *** 1.ADD 2.DEL ***\n"); printf(" *** 3.MODIFY 4.SEARCH ***\n"); printf(" *** 5.SORT 6.SHOW ***\n"); printf(" *** 0.EXIT ***\n"); printf(" ***************************\n"); } int main() { int input = 0; Contact con; InitContact(&con); do { menu(); printf("请输入要进行的操作:"); scanf("%d", &input); switch (input) { case ADD: Cont_ADD(&con); break; case DEL: Cont_DEL(&con); break; case MODIFY: Cont_MODIFY(&con); break; case SEARCH: Cont_SESRCH(&con); break; case SORT: Cont_SORT(&con); break; case EXIT: break; case SHOW: Cont_SHOW(&con); break; default: printf("输入不合法,请按照要求输入\n"); break; } } while (input); return 0; }
contact.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "contact.h" void InitContact(Contact* con) { assert(con); con->sz = 0; memset(con->data, 0, sizeof(con->data)); } void Cont_ADD(Contact* con) { assert(con); printf("请输入要增加的人数:"); int num = 0; scanf("%d", &num); if ((con->sz)+num >= MAX) { printf("增加的人数太多,无法加入!\n"); return; } else { int i = 0; for (i = 0; i < num; i++) { printf("请输入姓名:"); scanf("%s", (con->data[con->sz]).name); printf("请输入年龄:"); scanf("%d", &((con->data[con->sz]).age)); printf("请输入性别:"); scanf("%s", (con->data[con->sz]).sex); printf("请输入手机号:"); scanf("%s", (con->data[con->sz]).tele); printf("请输入住址:"); scanf("%s", (con->data[con->sz]).address); con->sz++; Sleep(100); printf("增加成功\n"); printf("---------------------------------------\n"); } } for (int i = 0; i < 5; i++) { printf("\n"); } } void Cont_SHOW(Contact* con) { assert(con); if (con->sz == 0) { printf("现无人员,请输入后再进行显示!\n"); return; } printf("%-9s%-20s%-15s%-15s%-15s%-20s\n", "序号","姓名", "年龄", "性别", "手机号", "住址"); int i = 0; for (i = 1; i <= con->sz; i++) { printf("%-9d%-20s%-15d%-15s%-15s%-20s\n", i, (con->data[i - 1]).name, (con->data[i - 1]).age, (con->data[i - 1]).sex, (con->data[i - 1]).tele, (con->data[i - 1]).address ); } for (int i = 0; i < 5; i++) { printf("\n"); } } static int FindbyNAME(Contact* con,char* name) { assert(con); int i = 0; for (i = 0; i < con->sz; i++) { if (strcmp(con->data[i].name, name) == 0) { return i; } } return -1; } void Cont_DEL(Contact* con) { assert(con); if (con->sz == 0) { printf("通讯录为空,无法删除!\n"); return; } char name[NAME_MAX] = { 0 }; printf("请输入要删除的人的姓名:"); scanf("%s",name); int ret = FindbyNAME(con,name); if (ret == -1) { printf("要删除的人不存在!\n"); return; } else { int i = 0; for (i = ret; i < con->sz - 1; i++) { con->data[i] = con->data[i + 1]; } con->sz--; printf("删除成功!\n"); } for (int i = 0; i < 5; i++) { printf("\n"); } } void Cont_MODIFY(Contact* con) { assert(con); char name[NAME_MAX] = { 0 }; if (con->sz == 0) { printf("通讯录为空,无法修改!\n"); return; } else { printf("请输入要修改的人的姓名:"); scanf("%s", name); } int ret = FindbyNAME(con, name); if (-1 == ret) { printf("无此人信息\n"); return; } printf("%-9s%-20s%-15s%-15s%-15s%-20s\n", "序号", "姓名", "年龄", "性别", "手机号", "住址"); printf("%-9d%-20s%-15d%-15s%-15s%-20s\n", ret + 1, (con->data[ret]).name, (con->data[ret]).age, (con->data[ret]).sex, (con->data[ret]).tele, (con->data[ret]).address ); printf("请输入要修改的信息\n"); printf("请输入名字:"); scanf("%s", con->data[ret].name); printf("请输入年龄:"); scanf("%d", &(con->data[ret].age)); printf("请输入性别:"); scanf("%s", con->data[ret].sex); printf("请输入电话:"); scanf("%s", con->data[ret].tele); printf("请输入地址:"); scanf("%s", con->data[ret].address); printf("修改成功\n"); for (int i = 0; i < 5; i++) { printf("\n"); } } void Cont_SESRCH(Contact* con) { assert(con); if (0 == con->sz) { printf("当前没有人数信息,请增加后再使用此功能!\n"); return; } printf("请输入要查找的人的姓名:"); char name[NAME_MAX] = { 0 }; scanf("%s", name); int ret = FindbyNAME(con, name); if (ret == -1) { printf("查无此人"); } else { printf("%-9s%-20s%-15s%-15s%-15s%-20s\n", "序号", "姓名", "年龄", "性别", "手机号", "住址"); printf("%-9d%-20s%-15d%-15s%-15s%-20s\n", ret + 1, (con->data[ret]).name, (con->data[ret]).age, (con->data[ret]).sex, (con->data[ret]).tele, (con->data[ret]).address ); } int i = 0; for (i = 0; i < 5; i++) { printf("\n"); } } static int ComByName(const void* e1,const void* e2) { const PeoInfo* c1 = (const PeoInfo*)e1; const PeoInfo* c2 = (const PeoInfo*)e2; return strcmp(c1->name, c2->name); } static ComByAge(const void* e1, const void* e2) { const PeoInfo* c1 = (const PeoInfo*)e1; const PeoInfo* c2 = (const PeoInfo*)e2; return (c1->age) - (c2->age); } void Cont_SORT(Contact* con) { if (0 == con->sz) { printf("通讯录无人员信息,无法排序。\n"); return; } printf("请输入要按照什么排序(1.姓名 2.年龄):"); int input = 0; scanf("%d", &input); if (1 == input) { qsort(con->data, con->sz, sizeof(PeoInfo), ComByName); Cont_SHOW(con); } else if (2 == input) { qsort(con->data, con->sz, sizeof(PeoInfo), ComByAge); Cont_SHOW(con); } else { printf("输入不合法!"); return; } }
contact.h
#pragma once #include <stdio.h> #include <Windows.h> #include <string.h> #include <stdlib.h> #include <assert.h> #define NAME_MAX 20 #define SEX_MAX 5 #define TELE_MAX 15 #define ADDR_MAX 30 #define MAX 100 enum choice { EXIT, ADD, DEL, MODIFY, SEARCH, SORT, SHOW }; typedef struct PeoInfo { char name[NAME_MAX]; int age; char sex[SEX_MAX]; char tele[TELE_MAX]; char address[ADDR_MAX]; }PeoInfo; typedef struct Contact { PeoInfo data[MAX]; int sz; }Contact; void InitContact(Contact *con);//初始化通讯录 void Cont_ADD(Contact *con);//增加人数信息 void Cont_SHOW(Contact* con);//展示人数信息 void Cont_DEL(Contact *con);//删除人数信息 void Cont_MODIFY(Contact *con);//修改信息 void Cont_SESRCH(Contact *con); //查找人数信息 void Cont_SORT(Contact *con); //排序人数信息
十二. 结语
以上就是对通讯录代码的简单实现,我们成功地实现了一个简单的C语言通讯录。在这个过程中,我们学习了C语言的基本语法和数据结构的应用,掌握了结构体的定义和使用,以及数组的操作等。
感谢您的阅读和关注,希望您在学习和实践中取得更大的进步!