⭐博客主页:️CS semi主页
⭐欢迎关注:点赞收藏+留言
⭐系列专栏:C语言进阶
⭐代码仓库:C Advanced
家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们的支持是我创作最大的动力,欢迎友友们私信提问,家人们不要忘记点赞收藏+关注哦!!!
通讯录是利用C语言进行制作的一个比较复杂的模型,当我们进行制作通讯录的时候,难免会碰到很多难点,尤其是在进行分文件操作的时候,当我们进行制作的时候,必须要用到以前的知识,但是同时也要加入新的元素进去,这个才是我们学习的意义,闲话不多说,一句话就是“加油干!!!”
我们在制作通讯录之前,很重要的一件事情就是需要理清楚我们的思路以及我们需要做些什么,通讯录顾名思义是要有联系人的各种各样的信息,我们今天就比较简单地实现一下存放1000个人的信息,然后利用各种各样的功能进行实现,如下图,我们需要进行实现的各类信息:
首先,这三板斧添加三个新建项是必须的,这样我们的代码就不会堆在一起显得很冗杂。
其次,我们需要在test.c项目里面进行总体函数的框架制作,我们需要慢慢地进行制作,一起跟着来吧!
首先你需要在contgact.h头文件里面包含所有的头文件以及函数声明,因为这样很清晰,很简洁,我们在其他项目里面加上#include"contact.h"即可,我们就可以直接用头文件里面的头文件和声明了,虽然很神奇,但很常规。
其次就是利用初阶学习的知识进行制作一个swtich–case语句来进行封装这些功能(是在test.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("******* 7.empty 0.exit *******\n");
printf("************************************\n");
}
int main()
{
int input = 0;
do {
menu();
printf("请选择:>");
scanf("%d", &input);
switch(input)
{
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 0:
break;
default:
break;
}
} while (input);
return 0;
}
那我们接下来简单声明一下人的信息(在contact.h头文件中):
//人的信息
typedef struct PeoInfo {
char name[20];
int age;
char sex[5];
char addr[30];
char tele[12];
}PeoInfo;
另外,我们创建出人的信息以后是不是需要开辟一个空间来将这些放进去,所以,我们在test.c中进行创建通讯录的操作,是创建空间把人放进去:
我们创建完之后,很疑惑的一件事情是我们不知道我们此时放了多少个人的信息,我们不知道我们新加上去的应该放在哪里,所以我们需要加一个sz变量进行显示当前已经放了多少了。所以我们把sz和PeoInfo两个变量都重新建立一个结构体并放在里面(在contact.h头文件中以及在test.c中声明)。
此时我们进行总体的框架就搭建好了,我们这时候只用到了test.c和contact.h这两个文件,那就附上原码:
test.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("******* 7.empty 0.exit *******\n");
printf("************************************\n");
}
int main()
{
int input = 0;
//创建通讯录
Contact con;
do {
menu();
printf("请选择:>");
scanf("%d", &input);
switch(input)
{
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
contact.h
#include
//人的信息
typedef struct PeoInfo {
char name[20];
int age;
char sex[5];
char addr[30];
char tele[12];
}PeoInfo;
typedef struct Contact {
//创建通讯录
PeoInfo data[1000];//存放人的信息
int sz;//当前已经放的信息的个数
}Contact;
我们加上一个宏定义吧!这样子更加方便清晰:
test.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("******* 7.empty 0.exit *******\n");
printf("************************************\n");
}
int main()
{
int input = 0;
//创建通讯录
Contact con;
do {
menu();
printf("请选择:>");
scanf("%d", &input);
switch(input)
{
case 1:
AddContact(&con);
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
contact.h
#define MAX 1000
#define NAMEMAX 20
#define SEWXMAX 5
#define ADDRMAX 30
#define TELEMAX 12
#include
//人的信息
typedef struct PeoInfo {
char name[NAMEMAX];
int age;
char sex[SEWXMAX];
char addr[ADDRMAX];
char tele[TELEMAX];
}PeoInfo;
typedef struct Contact {
//创建通讯录
PeoInfo data[MAX];//存放人的信息
int sz;//当前已经放的信息的个数
}Contact;
这个为什么我要直接拿出来一整个模块来讲解,而不是直接来个大括号{0},是因为,我们如果将它们放到模块里更加灵活,所以直接来初始化:
contact.h中放声明:
contact.c中放定义:
test.c中放动作:
那我们进行完初始化那就可以进行相关的操作了,直接往下看~~~
联系人的增加应该算是瓶颈,是需要利用我们新学习的知识进行操作,是有略微难度的,这其中比较难的是进行scanf操作用到的结构体指针,接下来我细细讲解,关于如何写增加联系人的代码:
首先我们进入程序以后需要在test.c中的case 1:子语句下加我们需要操作的函数,这个与初始化相同(在test.c中):
其次,我们在contact.h中进行声明函数:
最后,是我们的重头戏,我们需要在contact.c中进行函数的定义,也就是函数的操作:
我们先写这么个函数头头,我们在进行增加联系人的前提条件就是联系人已经满了,我们吭哧吭哧添加了1000个了已经,再添加一个人早就满了,可是如果你不让计算机判断一下通讯录里面有没有满,满了以后你不让计算机判断一下,还给它加工作那它肯定要生脾气,到维护不了的地方,你也不知道输出的是啥,所以要加个判断:
这个MAX就是我们的宏定义1000,这个return;是因为我们是无参数返回的函数,所以加一个return;是退出程序的意思。
接下来就是重头戏的增加联系人的操作了,先看代码再解释:
这似乎很复杂,但大家想一想这个pc就是我们前面定义的结构体指针它指向的是Contact结构体,而这个结构体又包含了PeoInfo这个结构体,是不是很绕,那画个图解释一下吧!
简单而言就是一个往下指向的作用,所以就是先pc->data,而data又是结构体指针PeoInfo类型的,所以再指向结构体指针里的name/age/sex/addr/tele,而其中只有age不是数组,所以需要加&符号。
我们有点猴急,我们就想看一看输入以后了想给它显示一下,那我们找对应的5来进行显示一下:
根据上面增加的用处,我们在test.c中的5中加入显示的元素:
接下来我们在contact.h中写入函数的声明(因为显示操作不能改变通讯录里面的值):
最后我们在contact.c中写入函数的定义,这里有了前面的基础就比较简单了,那我们就直接上手写吧!
刚开始的表头printf是用来固定打印信息名称的,底下的打印是打印输入的值的,如下图所示:
删除联系人的操作有些许复杂,跟紧节奏出发吧!
老规矩,还是需要在test.c中找到case2的位置进行呼出函数的操作:
其次需要在contact.h中声明函数:
最后我们就需要在contact.c中进行函数的定义,同时也是最难的一部分,我们先上代码再解析:
这串代码很长,但很好理解,首先我们需要判断已经没有联系人了的这种情况,所以我们就需要加一个if判断语句,如果是已经没有联系人了,那就单纯的返回空,
如果有,那我们进行操作,先是需要查找通讯录里面的这个人的位置,就需要用到strcmp函数进行名字的对比,
另外就是需要删除这个人的所有信息,这里就直接将后面的信息全部往前覆盖即可,直接删除成功。
那很多人也想了,这串代码有点长,能不能重新建立一个函数进行直接调用,是不是更加方便一点,那我们就直接创建一个FindByName函数进行将这些数据进去然后调用即可。
改进以后:
只在contact.c中进行改进,就将代码拷贝到函数里面去,原本的pc就是地址:
查找这个动作不就是在删除里面我们调出来的一个函数吗?那我们直接用好了,再进行打印一下就好了:
test.c
contact.h
contact.c:
删除无非就是先找到这个联系人再进行覆盖。
test.c:
contact.h:
contact.c:
这里排序我们用到的是qsort函数,大家如果不太了解的话,直接一个链接供大家参考:qsort函数详解
test.c:
contact.h:
contact.c:
清空操作与初始化是一样的:
test.c:
contact.h:
contact.c:
细节1:加入assert断言
细节2:运用Sleep函数进行控制时长
直接上代码:
test.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("******* 7.empty 0.exit *******\n");
printf("************************************\n");
}
int main()
{
int input = 0;
//创建通讯录
Contact con;
//初始化通讯录
InitContact(&con);
do {
menu();
printf("请选择:>");
scanf("%d", &input);
switch(input)
{
case 1:
AddContact(&con);
break;
case 2:
DelContact(&con);
Sleep(1000);
break;
case 3:
SearchContact(&con);
break;
case 4:
ModifyContact(&con);
Sleep(500);
break;
case 5:
ShowContact(&con);
break;
case 6:
qsort(&con, con.sz, sizeof(con.data[0]), ContactSortName);
printf("排序成功\n");
Sleep(1000);
break;
case 7:
EmptyContact(&con);
printf("已全部清空\n");
Sleep(1000);
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
contact.h:
#define MAX 1000
#define NAMEMAX 20
#define SEWXMAX 5
#define ADDRMAX 30
#define TELEMAX 12
#include
#include
#include
#include
#include
//人的信息
typedef struct PeoInfo {
char name[NAMEMAX];
int age;
char sex[SEWXMAX];
char addr[ADDRMAX];
char tele[TELEMAX];
}PeoInfo;
typedef struct Contact {
//创建通讯录
PeoInfo data[MAX];//存放人的信息
int sz;//当前已经放的信息的个数
}Contact;
//初始化通讯录
void InitContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//显示通讯录里的联系人
void ShowContact(const Contact* pc);
//删除联系人
void DelContact(Contact* pc);
//查找联系人
void SearchContact(const Contact* pc);
//修改指定联系人信息
void ModifyContact(Contact* pc);
//排序
int ContactSortName(void* e1, void* e2);
//清空
void EmptyContact(Contact* pc);
contact.c:
//负责实现声明
#include"contact.h"
//实现初始化通讯录
void InitContact(Contact* pc) {
assert(pc);
pc->sz = 0;
memset(pc->data, 0, sizeof(pc->data));//传过来的是地址,根据地址找到了data数组,算的是data数组的总大小
}
//增加联系人
void AddContact(Contact* pc) {
assert(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].addr);
printf("请输入电话>");
scanf("%s", pc->data[pc->sz].tele);
pc->sz++;
}
//显示通讯录里的信息
void ShowContact(const Contact* pc) {
assert(pc);
int i = 0;
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "name", "age", "sex", "address", "telephone");
for (i = 0; i < pc->sz; i++) {
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].addr,
pc->data[i].tele);
}
}
int FindByName(const Contact* pc,char name[]) {
assert(pc);
int i = 0;
int pos = 0;
for (i = 0; i < pc->sz; i++) {
if (strcmp(pc->data[i].name, name) == 0) {
pos = i;
return i;
}
}
return -1;
}
//删除联系人
void DelContact(Contact* pc) {
assert(pc);
char name[NAMEMAX] = { 0 };
//没有联系人不删除
if (pc->sz == 0) {
printf("通讯录为空,无法删除\n");
return;
}
//删除联系人
//找到要删除的人
printf("请输入要删除的人的名字:>");
scanf("%s", name);
//查找
int ret = FindByName(pc, name);
if (-1 == ret) {
printf("查无此人\n");
return;
}
else {
//删除
int i = 0;
for (i = ret; i < pc->sz - 1; i++) {
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除成功\n");
}
}
//查找联系人
void SearchContact(const Contact* pc) {
assert(pc);
char name[NAMEMAX] = { 0 };
printf("请输入要查找人的名字>");
scanf("%s", name);
int ret = FindByName(pc, name);
if (-1 == ret) {
printf("查无此人\n");
return;
}
else {
//打印信息
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "name", "age", "sex", "address", "telephone");
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[ret].name,
pc->data[ret].age,
pc->data[ret].sex,
pc->data[ret].addr,
pc->data[ret].tele);
}
}
//修改指定联系人
void ModifyContact(Contact* pc) {
assert(pc);
//先找这个联系人
char name[NAMEMAX] = { 0 };
printf("请输入要修改人的名字>");
scanf("%s", name);
int ret = FindByName(pc, name);
if (-1 == ret) {
printf("查无此人\n");
return;
}
else {
//信息重新录入
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].addr);
printf("请输入电话>");
scanf("%s", pc->data[ret].tele);
printf("修改完成\n");
}
}
//排序
int ContactSortName(void* e1, void* e2) {
assert(e1 && e2);
return strcmp((Contact*)e1, (Contact*)e2);
}
//清空
void EmptyContact(Contact* pc) {
assert(pc);
pc->sz = 0;
memset(pc->data, 0, sizeof(pc->data));
}
这个通讯录到这里简单的操作肯定是结束了,但这个通讯录并不是最终版本哦,肯定还是需要完善的,变的更加高级,更加好用!!!
支持和三连是必不可少的家人们~~~