㊙️小明博客主页:➡️ 敲键盘的小明 ㊙️
✅关注小明了解更多知识☝️
文章目录
前言
提示:本篇文章为C语言【通讯录】实现的详细笔记和完整的源码,内容如若有误,请联系小明及时更正。
- 转载请注明原创,谢谢。
一、通讯录效果
剧情抢先看:
功能如此齐全的通讯录是如何实现的呢?让我们来看今天的博客内容:
提示:以下是本篇文章正文内容:
二、整体思路分析
我们在制作通讯录之前,很重要的一件事情,就是我们需要理清楚思路,以及我们需要做些什么。
通讯录 ,顾名思义是存储一个联系人的各种信息,我们今天就比较简单地实现一下存放个人信息的通讯录。
当我们进行制作通讯录的时候,尤其是在进行分文件操作的时候,一定会碰到很多难点,而且我们进行制作的时候,必须要用到以前的知识,就像以前实现三子棋那种小项目一样,但是同时也要加入新的元素进去,所以我们要先对整体工程的逻辑尽可能详细的梳理。
需要实现的功能:
- 添加联系人
- 删除指定联系人
- 查找指定联系人
- 修改指定联系人的信息
- 显示所有联系人
- 联系人的排序
需要存储的个人信息:
- 姓名 年龄 性别 电话 地址
三、逻辑实现
3.1 创建菜单
首先,我们的代码堆在一起显得很冗余,所以还是像之前的三子棋一样,分成三个文件实现:
其次呢,我们需要在test.c项目里,进行总体函数的框架制作,所以我们需要在contact.h 头文件里面包含所有的头文件以及函数声明,因为这样很清晰,很简洁;
我们在其他两个项目文件里面加上 #include “contact.h” 即可,我们就可以直接用头文件里面的头文件和声明了:
接下来我们就可以先来实现一下通讯录的菜单了,看过三子棋的朋友们应该都知道,我们执行代码框架的代码应该在 contact.c 文件中写,所以还是老样子,让我们在 contact.c 文件中先将通讯录的菜单写出来:
#include"contact.h"
void menu()
{
printf("**********************************\n");
printf("**** 1. add 2. del ****\n");
printf("**** 3. search 4. modify ****\n");
printf("**** 5. show 6. sort ****\n");
printf("**** 0. exit 【退出程序】 ****\n");
printf("**********************************\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请输入你的选择:");
} while(input);
return 0;
}
代码运行结果:
这样,我们通讯录的菜单就成功的打印出来了,但这时的通讯录菜单是没什么效果的!因为我们还没有开始写输入选择的操作,接下来我们在 do while 中再加一段 scanf 的菜单功能选择操作的代码:
#define _CRT_SECURE_NO_WARNINGS 1
//代码的测试
#include"contact.h"
void menu()
{
printf("**********************************\n");
printf("**** 1. add 2. del ****\n");
printf("**** 3. search 4. modify ****\n");
printf("**** 5. show 6. sort ****\n");
printf("**** 0. exit 【退出程序】 ****\n");
printf("**********************************\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请输入你的选择:");
scanf("%d", &input);
switch (input)
{
case 1:
//add 添加
break;
case 2:
//del 删除
break;
case 3:
//search 查找
break;
case 4:
//modify 修改
break;
case 5:
//show 显示
break;
case 6:
//sort 排序
break;
case 0:
printf("退出成功!\n");
break;
default:
printf("输入的选择错误!\n");
break;
}
} while(input);
return 0;
}
代码运行结果:
截至到这里,我们就可以成功的打印出通讯录的菜单了,但这时的菜单暂时还没有写我们选择 1 ~ 6 时的功能,由于我们 do while 是由 input 来判断的,所以我们在输入 0 的时候,程序就退出了!
当然,由于我们在 switch 中只有 1 ~ 6 和 0 的选项,所以当我们输入除了这七个数字以外的数字时,就会显示输入的选择错误!
至于 1 ~ 6 的功能实现会在下面的文章中实现。
我们这里的选择是由 1~6 来选择的,我们可以看到 switch 的选项都是数字,在没有注释的情况下很难阅读代码:
这种情况,又该如何优化代码呢?
我们可以使用枚举来将这些功能选项替换掉!创建一个 Option (选项)枚举,具体实现效果如下:
先写一个枚举,然后将 switch 的选项1~6全部替换成 Option 元素:
enum Option
{
EXIT,//0 退出
ADD,//1 添加
DEL,//2 删除
SEARCH,//3 查找
MODIFY,//4 修改
SHOW,//5 显示
SORT,//6 排序
};
总体代码:
#define _CRT_SECURE_NO_WARNINGS 1
//代码的测试
#include"contact.h"
void menu()
{
printf("**********************************\n");
printf("**** 1. add 2. del ****\n");
printf("**** 3. search 4. modify ****\n");
printf("**** 5. show 6. sort ****\n");
printf("**** 0. exit 【退出程序】 ****\n");
printf("**********************************\n");
}
enum Option
{
EXIT,//0 退出
ADD,//1 添加
DEL,//2 删除
SEARCH,//3 查找
MODIFY,//4 修改
SHOW,//5 显示
SORT,//6 排序
};
int main()
{
int input = 0;
do
{
menu();
printf("请输入你的选择:");
scanf("%d", &input);
switch (input)
{
case ADD:
//添加
break;
case DEL:
//删除
break;
case SEARCH:
//查找
break;
case MODIFY:
//修改
break;
case SHOW:
//显示
break;
case SORT:
//排序
break;
case EXIT:
printf("退出成功!\n");
break;
default:
printf("输入的选择错误!\n");
break;
}
} while(input);
return 0;
}
3.2 创建通讯录
上面的代码可以让我们成功的打印出通讯录的菜单,我们接下来开始创建通讯录:
我们在对通讯录进行各种操作前先得有个通讯录吧!
通讯录的本质还是描述一个人的属性,例如:姓名、年龄、性别、电话、住址等。这些都是不同的类型,所以我们可以很容易的想到,用结构体来解决;但这只是描述一个人,我们的通讯录不会只有一个人,而是应该是有很多个!而这些联系人又是同一类型,因此采用结构体数组来创建通讯录!
contact.h 文件中实现:
typedef struct PeoInfo
{
char name[20];
int age;
char sex[5];
char tele[15];
char addr[20];
}PeoInfo;
这就是描述一个人基本属性的结构体!
当我们创建好了这个结构体后,我们就可以创建结构体数组来作为通讯录了:
contact.h 文件中实现:
typedef struct Contact
{
PeoInfo data[100];//存放数据
int sz;//记录当前通讯录中存放了多少个人的信息
}Contact;
OK,这个创建通讯录记好了!
但是,我们会发现两个结构体中都出现了大量的常数,我们万一后期需求有变,这些都得修改,因此为了后期修改方便,我们把这些都改成#define 常量,后期修改起来容易:
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once//确保一个头文件只编译一次
//函数的声明
#include<stdio.h>
#define NAME_MAX 20 //名字
#define SEX_MAX 5 //性别
#define TELE_MAX 12 //电话
#define ADDR_MAX 30 //住址
#define MAX 100 //存放数据
typedef struct PeoInfo
{
//一个人的信息
char name[NAME_MAX]; //名字
int age; //年龄
char sex[SEX_MAX]; //性别
char tele[TELE_MAX]; //电话
char addr[ADDR_MAX]; //地址
}PeoInfo;
typedef struct Contact
{
PeoInfo data[MAX];//存放数据
int sz;//记录当前通讯录中存放了多少个人的信息
}Contact;
然后再在test.c文件中创建即可:
3.3 初始化通讯录
我们创建好了通讯录之后,我们需要先对其进行一个初始化!
把结构体数组的每个元素都初始化为 0,通讯录大小也置为0!
而且,因为我们要改变结构体的内容,所以应该传地址!我们这里采用的是 memset 这个函数直接初始化为0,也可以用个循环来初始化!
contact.h 文件中实现:
//初始化通讯录
void InitContact(Contact* pc);
contact.c 文件中实现:
void InitContact(Contact* pc)
{
assert(pc);//防止pc是无效的
memset(pc->data, 0, sizeof(pc->data));
pc->sz = 0;
}
test.c 文件中实现:
Contact con;//通讯录
//初始化通讯录
InitContact(&con);
代码运行效果:
我们可以看到成功的结构体将内部初始化为了 0 。
此处插播:
memset的使用方法:
3.4 添加联系人
contact.h 文件中实现:
//增加联系人
void AddContact(Contact* pc);
test.c 文件中的case ADD中添加:
case ADD:
//添加
AddContact(&con);
break;
有了上面两段代码,我们就可以在contact.c 文件中写添加联系人的代码了。
contact.c 文件中实现:
3.4.1 判断是否有效
先写一个 assert 断言一下 pc 是否有效:
void AddContact(Contact* pc)
{
assert(pc);//防止pc是无效的
}
3.4.2 判断通讯录是否已满
当我们断言之后,判断一下通讯录中是否还有位置可供我们添加新的联系人信息,在 contact.h 文件中我们的联系人设置的 MAX 是100人。
所以我们用 if 来判断一下,如果此时的 pc 等于了最大人数时,我们就显示:通讯录已满,无法继续添加联系人:
void AddContact(Contact* pc)
{
assert(pc);//防止pc是无效的
if (pc->sz == MAX)
{
printf("通讯录已满,无法继续添加联系人\n");
return;
}
}
3.4.3 添加新的信息
接下来我们就可以写添加新联系人信息的代码了:
void AddContact(Contact* pc)
{
assert(pc);//防止pc是无效的
if (pc->sz == MAX)
{
printf("通讯录已满,无法继续添加联系人\n");
return;
}
//添加信息
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);
//联系人的个数 +1
pc->sz++;
printf("添加成功!\n");
}
3.4.4 添加效果展示
现在是不是就可以成功的添加联系人了。
3.5 显示联系人
添加了联系人之后,我们就应该显示一下,还是老样子,先声明后使用:
contact.h 文件中实现:
//显示联系人
void ShowContact(Contact* pc);
test.c 文件中的case ADD中添加:
case SHOW:
//显示
ShowContact(&con);
break;
有了上面两段代码,我们就可以在contact.c 文件中写显示联系人的代码了。
contact.c 文件中实现:
3.5.1 判断通讯录是否为空
这里和添加联系人时一样,先断言,然后判断一下此时的通讯录是否时空的,如果为 0 ,证明通讯录还没有联系人的信息,没法打印显示,所以提示:通讯录为空,请先添加联系人!:
void ShowContact(Contact* pc)
{
assert(pc);//防止pc是无效的
if (pc->sz == 0)
{
printf("通讯录为空,请先添加联系人!\n");
return;
}
}
3.5.2 显示联系人
那么,如果此时通讯录不为空,说明通讯录里已经存在联系人的信息了,那我们就直接打印显示即可:
void ShowContact(Contact* pc)
{
assert(pc);//防止pc是无效的
if (pc->sz == 0)
{
printf("通讯录为空,请先添加联系人!\n");
return;
}
int i = 0;
printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
for (int i = 0; i < pc->sz; i++)
{
printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].tele,
pc->data[i].addr
);
}
}
3.5.3 显示效果展示
这里,我们先显示一下空通讯录的效果,然后再添加联系人信息,最后显示一下:
添加多个联系人并显示:
效果:
至此,添加联系人和显示联系人的功能我们都成功的实现了!
3.6 删除指定联系人
还是和之前一样,我们上来就先在 contact.h 文件和 test.c 文件添加声明和使用,然后在contact.c 文件中实现:
contact.h 文件中实现:
//删除联系人
void DelContact(Contact* pc);
test.c 文件中的case ADD中添加:
case DEL:
//删除
DelContact(&con);
break;
有了上面两段代码,我们就可以在contact.c 文件中写删除联系人的代码了。
contact.c 文件中实现:
3.6.1 判断通讯录是否为空
同样的,我们还是先断言,然后判断一下此时的通讯录是否时空的,如果为 0 ,证明通讯录还没有联系人的信息,没法删除联系人信息,所以提示:通讯录为空,无需删除!:
void DelContact(Contact* pc)
{
assert(pc);//防止pc是无效的
if (pc->sz == 0)
{
printf("通讯录为空,无需删除!\n");
return;
}
}
3.6.2 查找联系人
然后重点来了 !!!
然后重点来了 !!!
然后重点来了 !!!
不管是我们是查找某个人的信息、删除某个人信息还是修改某个人信息,都需要先输入那个人的姓名,然后进行查找,找到了再删除,找不到就提示查无此人!注意考虑通讯录为空的情况!
所以,我们需要单独封装一个查找函数,然后不管我们之后查找删除还是修改的时候,都可以直接调用这个查找函数去找到通讯录中这个人的信息。
这里的查找返回下标即可。
封装的查找函数:
//查找要删除的人并返回下标
int FindContact(const Contact* pc, const char* name)
{
for (int i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
return i;//找到了
}
}
return -1;//没找到
}
3.6.3 删除该联系人信息
判断通讯录不为空,且能找到这个联系人,那么我们就该删除这个联系人了:
void DelContact(Contact* pc)
{
assert(pc);//防止pc是无效的
if (pc->sz == 0)
{
printf("通讯录为空,无需删除!\n");
return;
}
char name[NAME_MAX];
printf("请输入要删除人的名字:");
scanf("%s",name);
//查找名字为 name 的这个人
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("要删除的这个人不存在!\n");
return;
}
//删除找到的这个联系人
int i = 0;
for (int i = ret; i < pc->sz - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("成功删除联系人%s!\n",name);
}
3.6.4 效果展示
删除前后对比:
OK,这里我们也是成功的删除了通讯录中指定的联系人。
3.7 查找指定联系人
3.7.1 查找并显示
查找指定联系人还是先按指定方式进行查找, 找到了打印,否则显示通讯录为空,查找失败!
老样子,contact.h 文件中实现:
//查找联系人
void SearchContact(Contact* pc);
test.c 文件中实现:
case SEARCH:
//查找
SearchContact(&con);
break;
contact.c 文件中实现:
有了上面的经验,这时我们写查找这个人的代码就轻车熟路了:
void SearchContact(Contact* pc)
{
assert(pc);//防止pc是无效的
if (pc->sz == 0)
{
printf("通讯录为空,查找失败!\n");
return;
}
char name[NAME_MAX];
printf("请输入要查找人的名字:");
scanf("%s", name);
//查找名字为 name 的这个人
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("要查找的这个人不存在!\n");
return;
}
}
然后将我们查到的这个人显示出来:
//显示找到的这个联系人
printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",
pc->data[ret].name,
pc->data[ret].age,
pc->data[ret].sex,
pc->data[ret].tele,
pc->data[ret].addr
);
3.7.2 效果展示
OK,这里我们也是成功的找到了通讯录中指定的联系人。
3.8 修改联系人的信息
3.8.1 查找联系人
老样子:
contact.h 文件中实现:
//修改联系人
void ModifyContact(Contact* pc);
test.c 文件中的case ADD中添加:
case MODIFY:
//修改
ModifyContact(&con);
break;
有了上面两段代码,我们就可以在contact.c 文件中写删除联系人的代码了。
contact.c 文件中实现:
我们先实现一下是否能找到要修改的联系人:
void ModifyContact(Contact* pc)
{
assert(pc);
//判断是否为空
if (pc->sz == 0)
{
printf("通讯录为空,无法进行修改!!\n");
return;
}
char name[NAME_MAX];
printf("请输入要修改的联系人姓名: ");
scanf("%s", name);
//判断是否有该联系人
int ret = FindByName(pc, name);
//有该联系人
if (ret == -1)
{
printf("要修改的联系人不存在!\n");
return;
}
int n = 0;
}
然后重点来了 !!!
然后重点来了 !!!
然后重点来了 !!!
3.8.2 修改的菜单
修改联系人信息这块就有很多种情况了,比如只修改一项,例如只修改名字或性别,也有可能修改多项例如名字、年龄等,也有可能得全部修改这几种情况。
当我们要修改之前,我们能还是期望有一个菜单供我们选择,当修改完一项后我们可能还要继续修改。
基于此我们还是采用和 test.c 文件中得 do…while 循环+菜单来提供选择不同的情况:
//修改联系人信息菜单
void Modifymenu()
{
printf("*****************************************\n");
printf("********* 1. name 2. age **********\n");
printf("********* 3. sex 4. tele **********\n");
printf("********* 5. addr 6. all **********\n");
printf("********* 0. exit **********\n");
printf("*****************************************\n");
}
//修改名字
void ModName(Contact* pc, int ret)
{
assert(pc);
printf("请输入修改后联系人姓名: ");
scanf("%s", pc->data[ret].name);
printf("名字修改成功!\n");
}
//修改年龄
void ModAge(Contact* pc, int ret)
{
assert(pc);
printf("请输入修改后联系人年龄: ");
scanf("%d", &pc->data[ret].age);
printf("年龄修改成功!\n");
}
//修改性别
void ModSex(Contact* pc, int ret)
{
assert(pc);
printf("请输入修改后联系人性别: ");
scanf("%s", &pc->data[ret].sex);
printf("性别修改成功!\n");
}
//修改电话
void ModTele(Contact* pc, int ret)
{
assert(pc);
printf("请输入修改后联系人电话: ");
scanf("%s", &pc->data[ret].tele);
printf("电话修改成功!\n");
}
//修改地址
void ModAddr(Contact* pc, int ret)
{
assert(pc);
printf("请输入修改后联系人地址: ");
scanf("%s", &pc->data[ret].addr);
printf("地址修改成功!\n");
}
void ModAll(Contact* pc, int ret)
{
assert(pc);
printf("请输入联系人姓名: ");
scanf("%s", pc->data[ret].name);
printf("请输入联系人年龄: ");
scanf("%d", &pc->data[ret].age);
printf("请输入联系人性别: ");
scanf("%s", pc->data[ret].sex);
printf("请输入联系人电话: ");
scanf("%s", pc->data[ret].tele);
printf("请输入联系人住址: ");
scanf("%s", pc->data[ret].addr);
printf("信息修改成功!\n");
}
有了这个菜单,我们就能完善剩下的代码了:
enum Option
{
EXIT,//0 退出
NAME,//1 名字
AGE,//2 年龄
SEX,//3 性别
TELE,//4 电话
ADDR,//5 地址
ALL,//6 全部
};
//修改联系人
void ModifyContact(Contact* pc)
{
assert(pc);
//判断是否为空
if (pc->sz == 0)
{
printf("通讯录为空,无法进行修改!!\n");
return;
}
char name[NAME_MAX];
printf("请输入要修改的联系人姓名: ");
scanf("%s", name);
//判断是否有该联系人
int ret = FindByName(pc, name);
//有该联系人
if (ret == -1)
{
printf("要修改的联系人不存在!\n");
return;
}
int n = 0;
do
{
Modifymenu();
printf("请选择修改内容: ");
scanf("%d", &n);
//修改
switch (n)
{
case NAME:
ModName(pc, ret);
break;
case AGE:
ModAge(pc, ret);
break;
case SEX:
ModSex(pc, ret);
break;
case TELE:
ModTele(pc, ret);
break;
case ADDR:
ModAddr(pc, ret);
break;
case ALL:
ModAll(pc, ret);
break;
case EXIT:
printf("修改结束!\n");
break;
default:
printf("选择数非法!\n");
break;
}
} while (n);
}
3.8.3 效果展示
修改前的输入:
修改后的效果:
3.9 联系人的排序
3.9.1 代码
上面,我们已经实现了通讯录的增删查改的基本功能!
现在呢,我们还想让它再有一个排序功能,比如按名字排序,或年龄排序!我们在指针进阶那块介绍过回调函数,这里我们用 qsort 进行对通讯录排序!我们期望还是和上面的修改联系人一样,一开始有个菜单选择,然后可以让我们选择用名字排序还是用年龄排序:
此处我们长话短说,一段代码全部显示:
//排序菜单
void Sortmenu()
{
printf("**********************************\n");
printf("***** 1. name 2. age **********\n");
printf("**********************************\n");
}
//名字比较函数
int cmp_name(const void* str1, const void* str2)
{
return strcmp((((Contact*)str1)->data)->name, (((Contact*)str2)->data)->name);
}
//年龄比较函数
int cmp_age(const void* str1, const void* str2)
{
return (((Contact*)str1)->data)->age - (((Contact*)str2)->data)->age;
}
//名字排序
void SortName(Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name);
}
//年龄排序
void SortAge(Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_age);
}
//排序联系人信息
void SortContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法排序!\n");
return;
}
Sortmenu();
int n = 0;
printf("请选择排序方式: ");
scanf("%d", &n);
//排序
switch (n)
{
case 1:
SortName(pc);
printf("按名字排序成功!\n");
break;
case 2:
SortAge(pc);
printf("按年龄排序成功!\n");
break;
default:
printf("选择的数是非法的!\n");
break;
}
}
3.9.2 效果显示
按名字排序:
按年龄排序:
四、显示优化
截至到此,我们所有的功能就都实现了,但是我们可以发现我们的通讯录显示起来还是有点不舒服,每次选择完的结果都全部堆在了一起,看起来很乱!
解决方法呢,就是将完成功能后的屏幕清理掉!而且清理前再加一个睡眠时间,避免操作后的结果一闪而过 !!!
在每次屏幕打印东西时都加上下面两段代码:
Sleep(1500); //睡眠1.5秒
system(“cls”); //清屏
Sleep(1500); //睡眠1.5秒
system("cls"); //清屏
当然记得包含头文件:#include<windows.h>
效果举例:
到这里就是全部代码的笔记了。
五、全部源码汇总
5.1 contact.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once//确保一个头文件只编译一次
//函数的声明
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<windows.h>
#define NAME_MAX 20 //名字
#define SEX_MAX 5 //性别
#define TELE_MAX 12 //电话
#define ADDR_MAX 30 //住址
#define MAX 100 //存放数据
typedef struct PeoInfo
{
//一个人的信息
char name[NAME_MAX]; //名字
int age; //年龄
char sex[SEX_MAX]; //性别
char tele[TELE_MAX]; //电话
char addr[ADDR_MAX]; //地址
}PeoInfo;
typedef struct Contact
{
PeoInfo data[MAX];//存放数据
int sz;//记录当前通讯录中存放了多少个人的信息
}Contact;
//初始化通讯录
void InitContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//显示联系人
void ShowContact(Contact* pc);
//删除联系人
void DelContact(Contact* pc);
//查找联系人
void SearchContact(Contact* pc);
//修改联系人
void ModifyContact(Contact* pc);
//排序联系人
void SortContact(Contact* pc);
5.2 contact.c
#define _CRT_SECURE_NO_WARNINGS 1
//通讯录的实现
#include"contact.h"
void InitContact(Contact* pc)
{
assert(pc);//防止pc是无效的
memset(pc->data, 0, sizeof(pc->data));
pc->sz = 0;
}
void AddContact(Contact* pc)
{
assert(pc);//防止pc是无效的
if (pc->sz == MAX)
{
printf("通讯录已满,无法继续添加联系人\n");
Sleep(1500);
return;
}
//添加信息
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);
//联系人的个数 +1
pc->sz++;
printf("添加成功!\n");
Sleep(1500);
}
void ShowContact(Contact* pc)
{
assert(pc);//防止pc是无效的
if (pc->sz == 0)
{
printf("通讯录为空,请先添加联系人!\n");
Sleep(1500);
return;
}
int i = 0;
printf("\n%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
for (int i = 0; i < pc->sz; i++)
{
printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].tele,
pc->data[i].addr
);
}
printf("\n");
}
//查找要删除的人并返回下标
int FindByName(const Contact* pc, const char* name)
{
assert(pc);
for (int i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
return i;//找到联系人并返回其下标
}
}
return -1;//找不到
}
void DelContact(Contact* pc)
{
assert(pc);//防止pc是无效的
if (pc->sz == 0)
{
printf("通讯录为空,无需删除!\n");
Sleep(1500);
return;
}
char name[NAME_MAX];
printf("请输入要删除人的名字:");
scanf("%s",name);
//查找名字为 name 的这个人
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("要删除的这个人不存在!\n");
Sleep(1500);
return;
}
//删除找到的这个联系人
int i = 0;
for (int i = ret; i < pc->sz - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("成功删除联系人%s!\n",name);
Sleep(1500);
}
void SearchContact(Contact* pc)
{
assert(pc);//防止pc是无效的
if (pc->sz == 0)
{
printf("通讯录为空,查找失败!\n");
Sleep(1500);
return;
}
char name[NAME_MAX];
printf("请输入要查找人的名字:");
scanf("%s", name);
//查找名字为 name 的这个人
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("要查找的这个人不存在!\n");
Sleep(1500);
return;
}
//显示找到的这个联系人
printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",
pc->data[ret].name,
pc->data[ret].age,
pc->data[ret].sex,
pc->data[ret].tele,
pc->data[ret].addr
);
}
//修改联系人信息菜单
void Modifymenu()
{
printf("*****************************************\n");
printf("********* 1. name 2. age **********\n");
printf("********* 3. sex 4. tele **********\n");
printf("********* 5. addr 6. all **********\n");
printf("********* 0. exit **********\n");
printf("*****************************************\n");
}
//修改名字
void ModName(Contact* pc, int ret)
{
assert(pc);
printf("请输入修改后联系人姓名: ");
scanf("%s", pc->data[ret].name);
printf("名字修改成功!\n");
}
//修改年龄
void ModAge(Contact* pc, int ret)
{
assert(pc);
printf("请输入修改后联系人年龄: ");
scanf("%d", &pc->data[ret].age);
printf("年龄修改成功!\n");
}
//修改性别
void ModSex(Contact* pc, int ret)
{
assert(pc);
printf("请输入修改后联系人性别: ");
scanf("%s", &pc->data[ret].sex);
printf("性别修改成功!\n");
}
//修改电话
void ModTele(Contact* pc, int ret)
{
assert(pc);
printf("请输入修改后联系人电话: ");
scanf("%s", &pc->data[ret].tele);
printf("电话修改成功!\n");
}
//修改地址
void ModAddr(Contact* pc, int ret)
{
assert(pc);
printf("请输入修改后联系人地址: ");
scanf("%s", &pc->data[ret].addr);
printf("地址修改成功!\n");
}
void ModAll(Contact* pc, int ret)
{
assert(pc);
printf("请输入联系人姓名: ");
scanf("%s", pc->data[ret].name);
printf("请输入联系人年龄: ");
scanf("%d", &pc->data[ret].age);
printf("请输入联系人性别: ");
scanf("%s", pc->data[ret].sex);
printf("请输入联系人电话: ");
scanf("%s", pc->data[ret].tele);
printf("请输入联系人住址: ");
scanf("%s", pc->data[ret].addr);
printf("信息修改成功!\n");
Sleep(1000);
}
enum ModifyOption
{
EXIT,//0 退出
NAME,//1 名字
AGE,//2 年龄
SEX,//3 性别
TELE,//4 电话
ADDR,//5 地址
ALL,//6 全部
};
//修改联系人
void ModifyContact(Contact* pc)
{
assert(pc);
//判断是否为空
if (pc->sz == 0)
{
printf("通讯录为空,无法进行修改!!\n");
Sleep(1500);
return;
}
char name[NAME_MAX];
printf("请输入要修改的联系人姓名: ");
scanf("%s", name);
//判断是否有该联系人
int ret = FindByName(pc, name);
//有该联系人
if (ret == -1)
{
printf("要修改的联系人不存在!\n");
Sleep(1500);
return;
}
int n = 0;
do
{
Modifymenu();
printf("请选择修改内容: ");
scanf("%d", &n);
//修改
switch (n)
{
case NAME:
ModName(pc, ret);
break;
case AGE:
ModAge(pc, ret);
break;
case SEX:
ModSex(pc, ret);
break;
case TELE:
ModTele(pc, ret);
break;
case ADDR:
ModAddr(pc, ret);
break;
case ALL:
ModAll(pc, ret);
break;
case EXIT:
printf("修改结束!\n");
Sleep(1000);
break;
default:
printf("选择数非法!\n");
Sleep(1000);
break;
}
} while (n);
}
//排序菜单
void Sortmenu()
{
printf("**********************************\n");
printf("***** 1. name 2. age **********\n");
printf("**********************************\n");
}
//名字比较函数
int cmp_name(const void* str1, const void* str2)
{
return strcmp((((Contact*)str1)->data)->name, (((Contact*)str2)->data)->name);
}
//年龄比较函数
int cmp_age(const void* str1, const void* str2)
{
return (((Contact*)str1)->data)->age - (((Contact*)str2)->data)->age;
}
//名字排序
void SortName(Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name);
}
//年龄排序
void SortAge(Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_age);
}
//排序联系人信息
void SortContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法排序!\n");
Sleep(1500);
return;
}
Sortmenu();
int n = 0;
printf("请选择排序方式: ");
scanf("%d", &n);
//排序
switch (n)
{
case 1:
SortName(pc);
printf("按名字排序成功!\n");
Sleep(1000);
break;
case 2:
SortAge(pc);
printf("按年龄排序成功!\n");
Sleep(1000);
break;
default:
printf("选择的数是非法的!\n");
Sleep(1000);
break;
}
}
5.3 test.c
#define _CRT_SECURE_NO_WARNINGS 1
//代码的测试
#include"contact.h"
void menu()
{
printf("**********************************\n");
printf("**** 1. add 2. del ****\n");
printf("**** 3. search 4. modify ****\n");
printf("**** 5. show 6. sort ****\n");
printf("**** 0. exit 【退出程序】 ****\n");
printf("**********************************\n");
}
enum Option
{
EXIT,//0 退出
ADD,//1 添加
DEL,//2 删除
SEARCH,//3 查找
MODIFY,//4 修改
SHOW,//5 显示
SORT,//6 排序
};
int main()
{
int input = 0;
Contact con;//通讯录
//初始化通讯录
InitContact(&con);
do
{
menu();
printf("请输入你的选择:");
scanf("%d", &input);
switch (input)
{
case ADD:
//添加
AddContact(&con);
Sleep(1500);
system("cls");
break;
case DEL:
//删除
DelContact(&con);
Sleep(1500);
system("cls");
break;
case SEARCH:
//查找
SearchContact(&con);
Sleep(1500);
system("cls");
break;
case MODIFY:
//修改
ModifyContact(&con);
Sleep(1500);
system("cls");
break;
case SHOW:
//显示
ShowContact(&con);
Sleep(1500);
system("cls");
ShowContact(&con);
break;
case SORT:
//排序
SortContact(&con);
Sleep(1500);
system("cls");
break;
case EXIT:
printf("退出成功!\n");
Sleep(1500);
system("cls");
break;
default:
printf("输入的选择错误!\n");
Sleep(1500);
system("cls");
break;
}
} while(input);
return 0;
}
完结
好啦,阅读到这里就已经看完了本期博客的全部内容了