1.通讯录实现要求
通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址
提供方法:
- 添加联系人信息
- 删除指定联系人信息
- 查找指定联系人信息
- 修改指定联系人信息
- 显示所有联系人信息
- 清空所有联系人
- 以名字排序所有联系人
2.静态版通讯录实现
整个程序的实现需要建立三个文件
contact.h 通讯录的结构体定义及函数的声明
contact.c 函数的实现
main.c 主函数调用
2.1 contact.h文件实现
头文件引用和宏定义
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<assert.h> #include<stdlib.h> #include<string.h> #define NAME_MAX 10 //名字的长度(单位:字节) #define SEX_MAX 6 //性别长度 #define ADDR_MAX 20 //住址长度 #define TELE_MAX 12 //电话长度 #define N 100 //通讯录的长度(单位为个人结构体大小)
结构体定义
typedef struct people //个人结构体定义 { char name[NAME_MAX]; //姓名 char sex[SEX_MAX]; //性别 int age; //年龄 char tele[TELE_MAX]; //电话 char addr[ADDR_MAX]; //住址 }peo; typedef struct Contact //通讯录结构体定义 { peo data[N]; //个人结构体数组 int sz; //结构体长度 }Con;
枚举定义,方便主函数switch语句调用,易分辨。
enum { EXIT,//退出 ADD,//增加 DEL,//删除 MOD,//修改 SEARCH,//查找 SHOW,//打印 DISTORY,//删除全部 QSORT//以名称排序 };
函数声明
void InitCon(Con* cont);//初始化函数 void add(Con* cont);//增加联系人 void show(const Con* cont);//打印联系人 int FindName(const Con* cont, const char* name);//查找联系人(内含) void del(Con* cont);//删除联系人 void mod(Con* cont);//修改联系人 void sel(const Con* cont);//查找联系人打印 void Distory(Con* cont);//删除所有联系人 int cmp_stu_by_name(const void* p1, const void* p2);//排序调用的回调函数
下面我们来看最关键的部分,即为函数定义
2.2 contact.c文件实现
首先我们要包含头文件#include "contact.h"
初始化函数InitCon
void InitCon(Con* cont) { assert(cont); cont->sz = 0; memset(cont->data, 0, sizeof(cont->data)); }
开头我们先断言,防止传NULL指针,第二步初始化长度为0,最后将结构体数组中的元素均初始化为0即可。
添加联系人函数add
void add(Con* cont) { assert(cont); if (cont->sz == N) { printf("添加失败,通讯录已满"); return; } printf("请输入要添加联系人的信息:\n"); printf("请输入姓名:"); scanf("%s", cont->data[cont->sz].name); printf("请输入性别:"); scanf("%s", cont->data[cont->sz].sex); printf("请输入年龄:"); scanf("%d", &cont->data[cont->sz].age); printf("请输入电话:"); scanf("%s", cont->data[cont->sz].tele); printf("请输入地址:"); scanf("%s", cont->data[cont->sz].addr); cont->sz++; printf("添加成功\n"); }
开始一样,我们先断言防止传NULL指针,第二就是判断空间有没有满,如果满了,直接返回退出并提示,如果没满,则继续添加联系人信息,添加完之后提示添加成功,再将sz++。
显示联系人函数show
void show(const Con* cont) { assert(cont); int i = 0; printf(" 通讯录\n"); printf(" +---------------------------------------------------------------+\n"); printf(" |姓名 性别 年龄 电话 地址 |\n"); for (i = 0; i < cont->sz; i++) { printf(" |%-10s %-5s %-5d %-11s %-15s |\n", cont->data[i].name, cont->data[i].sex, cont->data[i].age, cont->data[i].tele, cont->data[i].addr); } printf(" +---------------------------------------------------------------+\n"); }
首先一样,我们先断言防止传NULL指针,第二就是打印题头,然后对结构体数组进行遍历打印,注意对齐,根据不同情况可自行调整。
查找联系人函数(内含)FindName
int FindName(const Con* cont, const char* name)//查找人函数 { assert(cont && name);//防止传入空指针 int i = 0; for (i = 0; i < cont->sz; i++) { if (!strcmp(cont->data[i].name, name))//查找通讯录是否有这个名字 { return i;//有就返回下标 } } return -1;//没有返回一个负数. }
实现这个函数主要是为了后面的删除、修改和查找并打印函数,方便复用,减少代码冗余。
首先同样,我们先断言防止传NULL指针,然后遍历使用strcmp函数进行字符匹配,查看是否有这个名字,有就返回下标,没有就返回负数。
删除联系人函数del
void del(Con* cont)//删除联系人函数 { assert(cont); int i = 0; char name[NAME_MAX]; printf("请输入需要删除的联系人的姓名:\n"); scanf("%s", name); i = FindName(cont, name); if (i == -1) { printf("通讯录中没有该联系人,删除失败\n"); return; } for (; i < cont->sz - 1; i++) { cont->data[i] = cont->data[i + 1]; } cont->sz--; printf("删除成功,姓名为%s的联系人已删除\n", name); }
首先同样,我们先断言防止传NULL指针,然后创建一个字符数组,方便输入姓名,再复用上面的查找函数,如果返回-1,则说明没有这个联系人,提示后返回退出,如果有,则按照其返回的下标向后遍历依次向前覆盖。最后sz–。
修改联系人函数mod
void mod(Con* cont)//修改联系人函数 { assert(cont); int ret = 0; char name[NAME_MAX]; printf("请输入要修改的联系人的姓名:\n"); scanf("%s", name); ret = FindName(cont, name); if (ret == -1) { printf("通讯录中没有该联系人,修改失败\n"); return; } printf("请输入修改后联系人的信息:\n"); printf("请输入姓名:"); scanf("%s", cont->data[ret].name); printf("请输入性别:"); scanf("%s", cont->data[ret].sex); printf("请输入年龄:"); scanf("%d", &cont->data[ret].age); printf("请输入电话:"); scanf("%s", cont->data[ret].tele); printf("请输入地址:"); scanf("%s", cont->data[ret].addr); printf("修改成功\n"); }
首先同样,我们先断言防止传NULL指针,然后创建一个字符数组,方便输入姓名,再复用上面的查找函数,如果返回-1,则说明没有这个联系人,提示后返回退出,如果有,则同增加联系人依次修改,当然你也可以再进行优化,修改某一项。
查找联系人函数sel
void sel(const Con* cont)//查询联系人函数 { char name[NAME_MAX]; printf("请输入要查询的联系人的名字:\n"); scanf("%s", name); int ret = FindName(cont, name); if (ret == -1) { printf("通讯录中没有该联系人,查询失败.\n"); return; } printf("查询成功,该联系信息如下:\n"); printf(" +---------------------------------------------------------------+\n"); printf(" |姓名 性别 年龄 电话 地址 |\n"); printf(" |%-10s %-5s %-5d %-11s %-15s |\n", cont->data[ret].name, cont->data[ret].sex, cont->data[ret].age, cont->data[ret].tele, cont->data[ret].addr); printf(" +---------------------------------------------------------------+\n"); }
首先我们创建一个字符数组,方便输入姓名,再复用上面的查找函数,如果返回-1,则说明没有这个联系人,提示后返回退出,如果有,则同show函数打印,只不过这里只打印一个。
删除所有联系人函数Distory
void Distory(Con* cont) { assert(cont); cont->sz = 0; printf("全部联系人删除成功!\n"); }
删除全部联系人,只需要将sz归0即可,下一次添加就会直接覆盖,而且也不能再访问之前的联系人数据了。
排序联系人函数的回调函数cmp_stu_by_name
int cmp_stu_by_name(const void* p1, const void* p2) { return strcmp(((peo*)p1)->name, ((peo*)p2)->name); }
这是调用库函数qsort给通讯录以姓名排序的一个回调函数,不理解的可以看我之前指针进阶那篇文章,其中就包含了qsort函数的使用及其回调函数的定义。
2.3 main.c文件实现
#include"contact.h" void menu() { printf("\n 欢迎使用通讯录:\n"); printf(" +-------------------------------------------------------------+\n"); printf(" | 1.添加联系人 2.删除联系人 |\n"); printf(" | 3.修改联系人 4.查询联系人 |\n"); printf(" | 5.展示通讯录 6.删除全部联系人 |\n"); printf(" | 7.排序联系人 0.退出通讯录 |\n"); printf(" +-------------------------------------------------------------+\n"); printf("请选择:"); } int main() { int input = 0; Con cont; InitCon(&cont); while (1) { do { menu(); scanf("%d", &input); switch (input) { case EXIT: printf("退出通讯录"); break; case ADD: add(&cont); break; case DEL: del(&cont); break; case MOD: mod(&cont); break; case SEARCH: sel(&cont); break; case SHOW: show(&cont); break; case DISTORY: Distory(&cont); break; case QSORT: qsort(cont.data, cont.sz, sizeof(peo), cmp_stu_by_name); printf("排序成功\n"); break; default: printf("输入错误"); break; } } while (input); break; } return 0; }
这里首先就是一个菜单排版,然后就是switch语句对各函数调用,这里的每个case选项用的是前面枚举定义的各个名称方便辨别。
2.4 静态版通讯录全部文件代码
//contact.h
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<assert.h> #include<stdlib.h> #include<string.h> #define NAME_MAX 10 #define SEX_MAX 6 #define ADDR_MAX 20 #define TELE_MAX 12 #define N 100 typedef struct people { char name[NAME_MAX]; char sex[SEX_MAX]; int age; char tele[TELE_MAX]; char addr[ADDR_MAX]; }peo; typedef struct Contact { peo data[N]; int sz; }Con; enum { EXIT, ADD, DEL, MOD, SEARCH, SHOW, DISTORY, QSORT }; InitCon(Con* cont); void add(Con* cont); void show(const Con* cont); int FindName(const Con* cont, const char* name); void del(Con* cont); void mod(Con* cont); void sel(const Con* cont); void Distory(Con* cont); int cmp_stu_by_name(const void* p1, const void* p2);
//contact.c
#include "contact.h" InitCon(Con* cont) { assert(cont); cont->sz = 0; memset(cont->data, 0, sizeof(cont->data)); } void add(Con* cont) { assert(cont); if (cont->sz == N) { printf("添加失败,通讯录已满"); return; } printf("请输入要添加联系人的信息:\n"); printf("请输入姓名:"); scanf("%s", cont->data[cont->sz].name); printf("请输入性别:"); scanf("%s", cont->data[cont->sz].sex); printf("请输入年龄:"); scanf("%d", &cont->data[cont->sz].age); printf("请输入电话:"); scanf("%s", cont->data[cont->sz].tele); printf("请输入地址:"); scanf("%s", cont->data[cont->sz].addr); cont->sz++; printf("添加成功\n"); } void show(const Con* cont) { assert(cont); int i = 0; printf(" 通讯录\n"); printf(" +---------------------------------------------------------------+\n"); printf(" |姓名 性别 年龄 电话 地址 |\n"); for (i = 0; i < cont->sz; i++) { printf(" |%-10s %-5s %-5d %-11s %-15s |\n", cont->data[i].name, cont->data[i].sex, cont->data[i].age, cont->data[i].tele, cont->data[i].addr); } printf(" +---------------------------------------------------------------+\n"); } int FindName(const Con* cont, const char* name)//查找人函数 { assert(cont && name);//防止传入空指针 int i = 0; for (i = 0; i < cont->sz; i++) { if (!strcmp(cont->data[i].name, name))//查找通讯录是否有这个名字 { return i;//有就返回下标 } } return -1;//没有返回一个负数. } void del(Con* cont)//删除联系人函数 { assert(cont);//防止传入空指针 int i = 0; char name[NAME_MAX]; printf("请输入需要删除的联系人的姓名:\n"); scanf("%s", name); i = FindName(cont, name); if (i == -1) { printf("通讯录中没有该联系人,删除失败\n"); return; } for (; i < cont->sz - 1; i++)//注意这里sz要-1,因为下面用到了i+1下标 { cont->data[i] = cont->data[i + 1]; } cont->sz--; printf("删除成功,姓名为%s的联系人已删除\n", name); } void mod(Con* cont)//修改联系人函数 { assert(cont);//防止传入空指针 int ret = 0; char name[NAME_MAX]; printf("请输入要修改的联系人的姓名:\n"); scanf("%s", name); ret = FindName(cont, name); if (ret == -1) { printf("通讯录中没有该联系人,修改失败\n"); return; } printf("请输入修改后联系人的信息:\n"); printf("请输入姓名:"); scanf("%s", cont->data[ret].name); printf("请输入性别:"); scanf("%s", cont->data[ret].sex); printf("请输入年龄:"); scanf("%d", &cont->data[ret].age); printf("请输入电话:"); scanf("%s", cont->data[ret].tele); printf("请输入地址:"); scanf("%s", cont->data[ret].addr); printf("修改成功.\n"); } void sel(const Con* cont)//查询联系人函数 { char name[NAME_MAX]; printf("请输入要查询的联系人的名字:\n"); scanf("%s", name); int ret = FindName(cont, name); if (ret == -1) { printf("通讯录中没有该联系人,查询失败.\n"); return; } printf("查询成功,该联系信息如下:\n"); printf(" +---------------------------------------------------------------+\n"); printf(" |姓名 性别 年龄 电话 地址 |\n"); printf(" |%-10s %-5s %-5d %-11s %-15s |\n", cont->data[ret].name, cont->data[ret].sex, cont->data[ret].age, cont->data[ret].tele, cont->data[ret].addr); printf(" +---------------------------------------------------------------+\n"); } void Distory(Con* cont) { assert(cont); cont->sz = 0; printf("全部联系人删除成功!\n"); } int cmp_stu_by_name(const void* p1, const void* p2) { return strcmp(((peo*)p1)->name, ((peo*)p2)->name); }
//main.c
#include"contact.h" void menu() { printf("\n 欢迎使用通讯录:\n"); printf(" +-------------------------------------------------------------+\n"); printf(" | 1.添加联系人 2.删除联系人 |\n"); printf(" | 3.修改联系人 4.查询联系人 |\n"); printf(" | 5.展示通讯录 6.删除全部联系人 |\n"); printf(" | 7.排序联系人 0.退出通讯录 |\n"); printf(" +-------------------------------------------------------------+\n"); printf("请选择:"); } int main() { int input = 0; Con cont; InitCon(&cont); while (1) { do { menu(); scanf("%d", &input); switch (input) { case EXIT: printf("退出通讯录"); break; case ADD: add(&cont); break; case DEL: del(&cont); break; case MOD: mod(&cont); break; case SEARCH: sel(&cont); break; case SHOW: show(&cont); break; case DISTORY: Distory(&cont); break; case QSORT: qsort(cont.data, cont.sz, sizeof(peo), cmp_stu_by_name); printf("排序成功\n"); break; default: printf("输入错误"); break; } } while (input); break; } return 0; }