今天我们的目标是,写出我们自己满意的通讯录。实现通讯录的五个功能:增,删,查,改,示,也就是增加联系人,删除联系人,查找联系人,修改联系人信息,展示联系人。那就让我们进入主题吧。
我们分别建立3个文件:一个头文件和两个源文件。
该文件是用于包含其它头文件,并且存放功能实现函数的函数声明。好处就是可以整合整个程序中所用到的全部头文件和函数声明,一目了然。并在引用时只需引用Contact.h头文件。
这个文件主要是用于书写所有的程序功能实现的函数定义。一、将所有定义书写在一起方便我们进行阅读,修改;二来大大提升了程序的可移植性,当他人想要使用我们定义的函数时,只需将整个Contact.c文件发送给对方即可;最后也可以将其设置为静态库从而实现我们函数代码的隐藏。
这文件里所书写的是我们程序主体部分,并对程序进行执行逻辑的编辑和检查。结合前面两个文件的使用,可以使得我们的程序逻辑变得清晰,既有利于我们进行程序的运行逻辑检查。
首先我们定义两个函数,menu为菜单函数,负责向玩家打印游戏菜单,Contact为通讯录功能函数,负责实现整个通讯录功能的实现。当程序开始编译运行后,首先执行菜单函数供玩家选择功能,接着执行Contact函数实现玩家选择的功能。
//菜单
void menu()
{
printf("*************************************\n");
printf("*************************************\n");
printf("*************************************\n");
printf("*************************************\n");
printf("*************************************\n");
printf("*************************************\n");
printf("*************************************\n");
printf("*************************************\n");
}
//实现通讯录功能函数
void Contact()
{
}
int main()
{
menu();
Contact();
return 0;
}
同时,我们在使用通讯录时,往往会出现一次性添加、删除或修改多个联系人信息的场景,于是我们就需要让我们的程序多次循环执行:
void Contact()
{
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 0:
printf("正在退出程序\n")
break;
default:
printf("您的选择有误,请重新选择\n");
}
} while (input);
}
我们通过使用do...while循环语句,保证了我们程序多次执行。并且我们通过输入值input作为循环判断条件,减少了变量创建从而节省了空间,也避免了因为输入错误导致直接跳出执行。同时,通过借助switch分支语句,我们也实现了对通讯录不同功能的调用和对输入选择的合法性检测。(这里也可以用if语句实现,看个人喜好)
现在通过编译让我们来看看效果:
在上面我们已经确定好了函数的主题主题实现逻辑,接下来就是实现各个功能模块。当然在实现功能模块之前我们先来实现向用户反馈通讯录功能的函数menu。
void menu()
{
printf("*************************************\n");
printf("************通讯录功能如下***********\n");
printf("************* 1.Add *************\n");
printf("************* 2.Del *************\n");
printf("************* 3.Search *************\n");
printf("************* 4.Modify *************\n");
printf("************* 0.Exit *************\n");
printf("*************************************\n");
}
我们来看看执行效果:
菜单打印好后,成勋的主题实现逻辑也就确定好了,接下来便是对我们通讯录的功能实现方式进行设计与编写了。
首先我们要能清楚我们的操作对象究竟是谁,我们可以想一想,我们平时在使用通讯录时,我们的操作对象应当是一个个联系人,已经每一个联系人的相关信息,于是我们可以想到,我们需要一种类似数组一样可以存储相同类别的东西,于是在这里,我们就使用结构体来进行实现:
typedef struct PeoInfo
{
char name[max_name];
char sex[10];
int age;
char tele[20];
char addr[max_addr];
}PeonInfo;
我们在头文件Contact.h中定义一个名PeoInfo(people information)的结构体类型struct PeoInfo,并使用typedef关键字将该类型命名为PeoInfo,接着我们在结构体内部创建了姓名,性别,年龄,联系方式和住址五个结构体成员,以用于存储结构体变量的信息。
于是在我们想要执行功能之前,应当首先创建出一个用于储存联系人信息的结构体数组,并创建变量sz记录已经存入的联系人数量:
void Contact()
{
int input = 0;
//创建能够容纳1000个联系人相关信息的结构体数组:
PeoInfo data[1000];
int sz = 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 0:
printf("正在退出程序");
break;
default:
printf("您的选择有误,请重新选择\n");
}
但是这样的方式在进行传参时,既要传递数组又要传递变量的地址,还是有些繁琐,所以我们就用一个结构体把他包装起来:
typedef struct contact
{
//创建能够容纳1000个联系人相关信息的结构体数组:
PeoInfo data[Max];
int sz;
}contact;
并且为了便于之后对通讯录的修改我这边使用宏定义了几个值得最大值:
#define max_name 20
#define max_addr 30
#define Max 1000
#define max_tele 20
并且我们还知道,枚举类型中各成员得为0开始依次递增,所以我们在使用一个枚举类型来是我们得选项对应用户得选择:
enum Option
{
Exit,
Add,
Del,
Search,
Modify,
print
};
有了这个枚举我们就可以把刚刚得代码改为:
do
{
menu();
printf("请您进行选择:");
scanf("%d", &input);
switch (input)
{
case Add:
break;
case Del:
break;
case Search:
break;
case Modify:
break;
case Print:
break;
case Exit:
printf("正在退出程序");
break;
default:
printf("您的选择有误,请重新选择\n");
}
} while (input);
这样通讯录得大致逻辑我们就搞定了,接下来就是各大功能的实现了。
我们在创建好通讯录之后,需要对创建好的通讯录进行初始化,否则内部得数据将为随机值而无法预测,导致程序得不合法:
在头文件声明初始化函数:
//初始化函数
void InitContact(contact* p);
创建通讯录和初始化:
//创建通讯录
contact con;
//初始化通讯录
InitContact(&con);
我们对通讯录得初始化是通过函数调用实现的,所以在对通讯录结构体成员进行修改时是需要通过结构体指针进行访问的。
首先我们将统计数量的变量sz初始化为0;即表示最初的通讯录中的联系人信息为0还有既然没有联系人信息,为了避免随机值对程序造成影响,我们就通过使用之前讲过的menset函数将联系人信息data的数据全部初始化为0:
打印单个联系人信息很好处理,直接打印即可,因这里我们不需要对传入地址内的数据进行修改,所以在数组传参时,我们可以使用const对其进行修饰,并实现打印:
void PrintContact(const contact * p, int x)
{
assert(p);
printf(" 联系人 :%4d\n", x + 1);
printf(" 姓 名 :&s\n", p->data[x].name);
printf(" 性 别 :%s\n",p->data[x].sex);
printf(" 年 龄 :%d\n", p->data[x].name);
printf("联系方式:%s\n", p->data[x].tele);
printf("当前住址:%s\n", p->data[x].addr);
}
首先这个函数可以作为单个功能,用于方便我们查看当前通讯录内的联系人存储信息,再者我们在删除联系认识,需要了解联系人的储存情况,进而准确的删除我们想要删除的特定联系人信息。
void PrintAllContact(const contact* p)
{
assert(p);
printf("联系人 姓名 性别 年龄 联系方式 住址\n");
int i = 0;
for (i = 0; i < p->sz; i++)
{
printf(" %04d %-20s %-5s %-4d %-12s %-30s\n", i + 1,
p->data[i].name, p->data[i].sex, p->data[i].age,
p->data[i].tele, p->data[i].addr);
}
}
首先我们在函数调用时,因为我们要对内存中的数据进行实际的修改,所以使用传址调用,应当向函数传入存放结构体数组的地址(数组名为首元素地址)与计数变量数组的contact类型结构体变量con的地址:
AddContact(&Con);
接着我们便对Addcontact函数功能实现进行设计。函数功能部分实现也很简单,每次询问一项联系人信息,然后有用户输入该项信息,并向该联系人保存地址处存入信息。但是宰割汽检仍有很多细节需要我们注意。要注意的第一个点就是信息存入的地址,我们对于通讯录的访问是通过指针进行的,所以信息的存入地址一定是对应的存入地址,数组应当使用指针进行访问,变量则应该使用指针进行访问,:
void AddContact(contact* p)
{
printf("请输入联系人姓名:");
scanf("%s", p->data[p->sz].name);
printf("请输入联系人性别:");
scanf("%s", p->data[p->sz].sex);
printf("请输入联系人年龄:");
scanf("%d", &(p->data[p->sz].age));
printf("请输入联系人联系方式:");
scanf("%s", p->data[p->sz].tele);
printf("请输入联系人的地址:");
scanf("%s", p->data[p->sz].addr);
PrintContact(p, p->sz);
printf("联系人添加成功\n");
p->sz++;
}
并且我们还注意到这里有一个很巧妙的设计,那就是我们在进行访问时,数组的下标恰好与我们初始化时统计的变量sz相同,并且每一次添加完联系人我们都让sz++;这时候他又变成我们下一次需要访问的结构体数组的下标了。
而且我们进行存储前还应当进行一次判断,即判断容量是否满了,如果已经满了,则应当提示用户没有足够的容量存储联系人,若没有则将用户存入的信息存入到对应位置并且反馈存入联系人的信息:
void AddContact(contact* p)
{
if (p->sz == Max)
{
printf("容量不足,无法存储");
}
else
{
printf("请输入联系人姓名:");
scanf("%s", p->data[p->sz].name);
printf("请输入联系人性别:");
scanf("%s", p->data[p->sz].sex);
printf("请输入联系人年龄:");
scanf("%d", &(p->data[p->sz].age));
printf("请输入联系人联系方式:");
scanf("%s", p->data[p->sz].tele);
printf("请输入联系人的地址:");
scanf("%s", p->data[p->sz].addr);
PrintContact(p, p->sz);
printf("联系人添加成功\n");
p->sz++;
}
}
在想要删除联系人信息时候,我们首先应当对通讯录内容进行判断,如此时的通讯录中没有存储任何联系人的信息,则应当提示用户没有联系人信息,当通讯录保存有联系人信息时,则首先应将当前通讯录中所有联系人信息进行打印供用户确认,当用户确认删除某一联系人信息时,允许用户通过输入联系人的编号来删除该联系人。
删除时,我们的实现方式是让选中联系人的后一个联系人直接将其覆盖并以此类推,最后sz减一就可以了:
void DelContact(contact* p)
{
assert(p);
int num = 0;
if (p->sz == 0)
{
printf("当前通讯录没有联系人");
}
else
{
PrintAllContact(p);
printf("请输入您想删除的联系人编号:");
scanf("%d", &num);
int x = num - 1;
if (0 <= x && x < p->sz)
{
for (int j = x; j < p->sz; j++)
{
p->data[j] = p->data[j + 1];
}
p->sz--;
PrintAllContact(p);
}
}
}
查找联系人的逻辑很简单,我们只需要定义一个字符串,然后让用户输入想要查找的联系人的姓名,接着我们就可以将通讯录中的联系人姓名与用户输入姓名,进行比较,若相同就将下标传递给打印函数,若没有找到就提示不存在联系人:
void SearchContact(const contact* p)
{
assert(p);
char name[20] = { 0 };
printf("请输入您想要查询的联系人姓名:");
scanf("%s", name);
int i = 0;
int ret = 1;
for (i = 0; i < p->sz; i++)
{
int count = strcmp(p->data[i].name, name);
if (count==0)
{
PrintContact(p, i);
ret = 0;
break;
}
}
if (ret)
{
printf("未找到联系人\n");
}
}
修改也很简单,首先我们同样对通讯录中的内容进行判断,内容为空则提示通讯录中没有联系人信息,否则提示进行修改。
在修改时,首先打印当前通讯录全部信息供用户进行选择,用户可以通过联系人人编号选择修改目标(获取下标),并选择想要修改的内容,在通过switch语句或者if语句实现对目标内容修改,最后将修改后的信息反馈给用户:
void ModifyContact(contact* p)
{
assert(p);
int x = 0;
int input = 0;
if (p->sz == 0)
{
printf("对不起,当前通讯录中没有联系人信息!\n");
}
else
{
PrintAllContact(p);
printf("请输入您想要修改的联系人编号:>");
scanf("%d", &x);
PrintContact(p, x - 1);
printf("当前支持修改的信息:\n");
printf("1.Name\n");
printf("2.Sex\n");
printf("3.Age\n");
printf("4.Tele\n");
printf("5.Addr\n");
printf("请选择您想要修改的信息:>");
scanf("%d", &input);
while (input)
{
switch (input)
{
case 1:
printf("请输入联系人姓名:");
scanf("%s", p->data[x - 1].name);
printf("修改成功!\n");
PrintContact(p, x - 1);
input = 0;
break;
case 2:
printf("请输入联系人性别:");
scanf("%s", p->data[x - 1].sex);
printf("修改成功!\n");
PrintContact(p, x - 1);
input = 0;
break;
case 3:
printf("请输入联系人年龄:");
scanf("%d", &(p->data[x - 1].age));
printf("修改成功!\n");
PrintContact(p, x - 1);
input = 0;
break;
case 4:
printf("请输入联系人联系方式:");
scanf("%s", p->data[x - 1].tele);
printf("修改成功!\n");
PrintContact(p, x - 1);
input = 0;
break;
case 5:
printf("请输入联系人住址:");
scanf("%s", p->data[x - 1].addr);
printf("修改成功!\n");
PrintContact(p, x - 1);
input = 0;
break;
default:
printf("您的选择有误,请重新选择!\n");
break;
}
}
}
}
到这里,我们基础版通讯就算完成了,这基础版存在很多瑕疵,但随着我们深入学习就可以将这些瑕疵去除。本文仍有很多不足之处,欢迎各位随时批评指正。
全部代码:
//Contact.h
#pragma once
#include
#include
#include
#define max_name 20
#define max_addr 30
#define Max 1000
#define max_tele 20
enum Option
{
Exit,
Add,
Del,
Search,
Modify,
Print
};
typedef struct PeoInfo
{
char name[max_name];
char sex[10];
int age;
char tele[max_tele];
char addr[max_addr];
}PeoInfo;
typedef struct contact
{
//创建能够容纳1000个联系人相关信息的结构体数组:
PeoInfo data[Max];
int sz;
}contact;
//初始化函数
void InitContact(contact* p);
//打印单个联系人函数:
void PrintContact(const contact* p, int x);
打印所有联系人函数
void PrintAllContact(const contact* p);
//增加联系人信息
void AddContact(contact* p);
//删除联系人
void DelContact(contact* p);
//修改联系人信息
void ModifyContact(contact* p);
//查找联系人:
void SearchContact(const contact* p);
//Contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
void InitContact(contact* p)
{
p->sz = 0;
memset(p->data, 0, sizeof(p->data));
}
void PrintContact(const contact * p, int x)
{
assert(p);
printf(" 联系人 :%4d\n", x + 1);
printf(" 姓 名 :%s\n", p->data[x].name);
printf(" 性 别 :%s\n",p->data[x].sex);
printf(" 年 龄 :%d\n", p->data[x].age);
printf("联系方式:%s\n", p->data[x].tele);
printf("当前住址:%s\n", p->data[x].addr);
}
void PrintAllContact(const contact* p)
{
assert(p);
printf("联系人 姓名 性别 年龄 联系方式 住址\n");
int i = 0;
for (i = 0; i < p->sz; i++)
{
printf(" %04d %-20s %-5s %-4d %-12s %-30s\n", i + 1, p->data[i].name, p->data[i].sex, p->data[i].age, p->data[i].tele, p->data[i].addr);
}
}
void AddContact(contact* p)
{
if (p->sz == Max)
{
printf("容量不足,无法存储");
}
else
{
printf("请输入联系人姓名:");
scanf("%s", p->data[p->sz].name);
printf("请输入联系人性别:");
scanf("%s", p->data[p->sz].sex);
printf("请输入联系人年龄:");
scanf("%d", &(p->data[p->sz].age));
printf("请输入联系人联系方式:");
scanf("%s", p->data[p->sz].tele);
printf("请输入联系人的地址:");
scanf("%s", p->data[p->sz].addr);
PrintContact(p, p->sz);
printf("联系人添加成功\n");
p->sz++;
}
}
void DelContact(contact* p)
{
assert(p);
int num = 0;
if (p->sz == 0)
{
printf("当前通讯录没有联系人");
}
else
{
PrintAllContact(p);
printf("请输入您想删除的联系人编号:");
scanf("%d", &num);
int x = num - 1;
if (0 <= x && x < p->sz)
{
for (int j = x; j < p->sz; j++)
{
p->data[j] = p->data[j + 1];
}
p->sz--;
PrintAllContact(p);
}
}
}
void SearchContact(const contact* p)
{
assert(p);
char name[20] = { 0 };
printf("请输入您想要查询的联系人姓名:");
scanf("%s", name);
int i = 0;
int ret = 1;
for (i = 0; i < p->sz; i++)
{
int count = strcmp(p->data[i].name, name);
if (count==0)
{
PrintContact(p, i);
ret = 0;
break;
}
}
if (ret)
{
printf("未找到联系人\n");
}
}
void ModifyContact(contact* p)
{
assert(p);
int x = 0;
int input = 0;
if (p->sz == 0)
{
printf("对不起,当前通讯录中没有联系人信息!\n");
}
else
{
PrintAllContact(p);
printf("请输入您想要修改的联系人编号:>");
scanf("%d", &x);
PrintContact(p, x - 1);
printf("当前支持修改的信息:\n");
printf("1.Name\n");
printf("2.Sex\n");
printf("3.Age\n");
printf("4.Tele\n");
printf("5.Addr\n");
printf("请选择您想要修改的信息:>");
scanf("%d", &input);
while (input)
{
switch (input)
{
case 1:
printf("请输入联系人姓名:");
scanf("%s", p->data[x - 1].name);
printf("修改成功!\n");
PrintContact(p, x - 1);
input = 0;
break;
case 2:
printf("请输入联系人性别:");
scanf("%s", p->data[x - 1].sex);
printf("修改成功!\n");
PrintContact(p, x - 1);
input = 0;
break;
case 3:
printf("请输入联系人年龄:");
scanf("%d", &(p->data[x - 1].age));
printf("修改成功!\n");
PrintContact(p, x - 1);
input = 0;
break;
case 4:
printf("请输入联系人联系方式:");
scanf("%s", p->data[x - 1].tele);
printf("修改成功!\n");
PrintContact(p, x - 1);
input = 0;
break;
case 5:
printf("请输入联系人住址:");
scanf("%s", p->data[x - 1].addr);
printf("修改成功!\n");
PrintContact(p, x - 1);
input = 0;
break;
default:
printf("您的选择有误,请重新选择!\n");
break;
}
}
}
}
//text.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
//菜单
void menu()
{
printf("*************************************\n");
printf("************通讯录功能如下***********\n");
printf("************* 1.Add *************\n");
printf("************* 2.Del *************\n");
printf("************* 3.Search *************\n");
printf("************* 4.Modify *************\n");
printf("************* 0.Exit *************\n");
printf("*************************************\n");
}
//实现通讯录功能函数
void Contact()
{
int input = 0;
//创建通讯录
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 Print:
PrintAllContact(&con);
break;
case Exit:
printf("正在退出程序");
break;
default:
printf("您的选择有误,请重新选择\n");
}
} while (input);
}
int main()
{
Contact();
return 0;
}