今天实现的通讯录功能主要有:
0.退出通讯录
1.添加联系人
2.删除指定联系人
3.查找指定联系人
4.修改指定联系人
5.显示当前通讯录
6.联系人排序(名字和年龄)
7.清空通讯录
我们把通讯录分为三个文件来实现,第一个test.c文件来写通讯录主要框架,第二个contact.c文件来实现函数功能,第三个contact.h文件来引用头文件和函数的声明。首先我们需要把通讯录的框架给实现出来,之后逐步实现每个函数的功能。
#include"contact.h"
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT,
EMPTY
};
void menu();
int main()
{
int input = 0;
Contact con ;
InitContact(&con);
do
{
menu();
printf("请输入你想选择的操作:");
scanf("%d", &input);
switch (input)
{
case EXIT:
printf("退出通讯录成功");
break;
case ADD:
ADDContact(&con);
break;
case DEL:
DELContact(&con);
break;
case SEARCH:
SearchContact(&con);;
break;
case MODIFY:
ModifyContact(&con);
break;
case SHOW:
SHOWContact(&con);
break;
case SORT:
SortContact(&con);
break;
case EMPTY:
InitContact(&con);
printf("清空通讯录成功\n");
break;
default:
printf("输入错误\n");
break;
}
} while (input);
return 0;
}
我们用do while循环来实现通讯录的主体框架,我们使用枚举给每个操作选项赋值,可读性更高。
我们先来把该声明的函数声明一下,并且引用需要的头文件,设置一些需要重复使用的值,以及对结构体的声明。
#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include
#include
#include
#include
#define NAME_MAX 20
#define SEX_MAX 10
#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 menu();
void InitContact(Contact* pc);
void ADDContact(Contact* pc);
void SHOWContact(const Contact* pc);
void DELContact(Contact* pc);
void SearchContact(Contact* pc);
void ModifyContact(Contact* pc);
void SortContact(Contact* pc);
这样我们就把整个通讯录引用函数的头文件全部包含在了contact.h中,并且定义了一个PeoInfo的结构体,里面存放了一个联系人的名字、年龄、性别、电话、住址。并将该结构体命名为PeoInfo。之后我们再定义一个结构体Contact,里面用PeoInfo定义一个数组,这样就能存放许多联系人的数据,并且为了记录存放了多少个联系人,定义一个整形sz来记录,并且把该结构体命名为Contact。
接下来我们一个一个来实现通讯录的函数功能,但在此之前,我们需要在主函数中使用Contact来定义一个通讯录出来,因为定义出来的通讯录里面的值是随机的,所以我们需要初始化通讯录,把里面的值统统赋为0。
int input = 0;
Contact con ;
InitContact(&con);
也就是这写代码,首先input是我们进行选择操作所定义的整形值,con是定义出来的通讯录,
而InitContact函数则是用来初始化con的,所以我们把con的地址传过去。
接下来我们来看一下初始化函数功能的实现。
void InitContact(Contact* pc)
{
assert(pc);//断言传过来指针非空
pc->sz = 0;//给sz赋值为0
memset(pc->data, 0, sizeof(pc->data));
}
首先,我们防止传过来指针是空指针所以使用assert函数,之后给sz记录当前联系人数为0(因为还没有添加联系人,当然就为0),之后我们在之前了解过memset函数,是一个填充函数,我们能通过该函数把data成员里面的元素全部赋值为0。
顺便来介绍一下memset函数的使用:
memset 是 C/C++ 语言中的一个库函数,用于将一段内存区域的内容设置为指定的值。
memset 函数的声明如下:
void* memset(void* ptr, int value, size_t num);
参数解释如下:
ptr:指向要被设置的内存区域的起始地址的指针。
value:要设置的值,以 int 类型表示。
num:要设置的字节数,即要设置的内存区域的大小。
memset 函数的工作原理是将指定的值 value 复制到由 ptr 所指向的内存区域的前 num 个字节中。
之后我们来调试一下,看一下是否初始化成功。
这是代码走到这里的监视窗口,可以看到里面存放的值都是随机的。
代码执行过初始化函数后,我们来查看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].tele);
printf("请输入住址:");
scanf("%s", pc->data[pc->sz].addr);
//
pc->sz++;
printf("添加联系人成功!\n");
}
首先我们先来断言防止传入指针为空,之后如果通讯录已满,我们直接退出该函数。之后我们来提示输入联系人的各项数据,通过scanf函数,将数据存放到data中的各项定义变量。因为通过sz来记录联系人人数,所以是data[sz],但又因为只能通过传入指针pc来找到sz,所以是data[pa->sz]。这样我们就实现了添加一个联系人的各项数据,之后将通过pc找到sz来实现sz++,记录联系人人数,最后提示一下添加联系人成功。
刚刚我们只是添加成功,可以通过调试来查看是否存放成功,但无法在程序运行台中显示出来,所以我们先来实现显示函数,来将添加成功的联系人显示出来。
void SHOWContact(const Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无需打印\n");
return;
}
int i = 0;
//名字 年龄 性别 电话 地址
//xxx xxx xxx xxx xxx
printf("%-20s%-10s%-10s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
for (i = 0; i < pc->sz; i++)
{
//打印每个人的信息
printf("%-20s%-10d%-10s%-12s%-30s\n",
pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
}
}
首先,我们只是显示联系人,不希望其发生改变,所以可以在传入指针中用const来修饰指针pc,之后仍然是断然防止传入指针为空,如果sz也就是记录联系人人数等于0,那么就无需打印通讯录,之后我们为了让打印出来的联系人更加直观所以用printf函数来显示出来data成员的各项数据。之后通过for循环,以及使用pc指针找到sz来遍历data成员,并且全部打印出来就可以了。
我们在实现删除联系人函数功能之前,必须先来找到该成员,包括后面的修改联系人,查找并显示联系人,都需要先找到该联系人,所以我们把找到该联系人的功能,单独封装为一个函数来实现。
int FindByName(Contact* pc, char* name)
{
assert(pc);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name,name)==0)
{
return i;
}
}
return -1;
}
首先,既然要查找该联系人,那么就需要两个参数,一个是con的地址,通过pc来找到,另一个是要找的联系人的名字,定义一个char型的指针变量来接受,首先我们依然先来断言一下防止传入指针pc为空,之后通过for循环,用pc找到sz来遍历data成员来查找到该联系人,如果找到我们怎么判断名字是否相等,就通过strcmp函数,等于0就说明查找到了,这时候返回i,就能记录当前联系人的下标,如果遍历完了没有找到,我们就返回-1。
有了查找函数,接下来我们来实现删除函数功能。
void DELContact(Contact* pc)
{
char name[NAME_MAX];
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,不可删除\n");
return;
}
printf("请输入你想删除的联系人:");
scanf("%s", name);
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("该联系人不存在,无法删除!\n");
return;
}
int i = 0;
for (i = ret; i < pc->sz-1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除该联系人成功!\n");
}
首先依然是接受con用Contact指针变量pc来接受,定义一个char型的name数组,之后依然是断然防止pc为空,如果通过pc找到的sz为0,那么就无法删除联系人。之后提示打印想要删除的联系人,然后通过scanf函数来输入,之后定义一个ret来接受通过FindByName查找到的下标,如果ret等于-1,说明该联系人不存在,不为0,说明存在,之后我们通过for循环让i等于ret,之后遍历到通过pc找到的sz-1,我们把ret之后的每个data成员往前移动一位,这样就实现了删除。最后通过pc找到的sz–,来记录联系人人数。
我们来实现查找并单独打印的函数功能,这个函数实现起来也是十分简单,接下来我们来看一下
void SearchContact(Contact* pc)
{
assert(pc);
char name[NAME_MAX];
printf("请输入想查找的联系人");
scanf("%s", &name);
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("该联系人不存在!\n");
return;
}
printf("%-20s%-10s%-10s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
printf("%-20s%-10d%-10s%-12s%-30s\n",
pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}
依然是和前面函数一样的指针pc,断言,之后定义一个char型的name数组,提示想要查找的联系人,传参给FindByName来查找并赋值给ret,如果ret等于-1,那么该联系人不存在,否则打印即可。
这个函数实现起来也是十分简单,我们来一起看一下吧。
void ModifyContact(Contact* pc)
{
assert(pc);
char name[NAME_MAX];
printf("请输入想修改的联系人");
scanf("%s", &name);
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("该联系人不存在!\n");
return;
}
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");
}
首先依然是同样的pc指针,断言,定义char型的name数组,输入修改联系人名字,通过FindByName函数查找到的下标传给ret,如果等于-1,则说明该联系人不存在,否则直接输入data成员的各项数据,存放到data[ret]中去。
我们来实现算是最后一个功能,排序功能。
int compare_name(const void* base,const void* src)
{
return strcmp(((PeoInfo*)base)->name , ((PeoInfo*)src)->name);
}
int compare_age(const void* base, const void* src)
{
return (((PeoInfo*)base)->age-((PeoInfo*)src)->age);
}
void SortContact(Contact* pc)
{
int ret = 0;
printf("1按名字排序,2按年龄排序\n");
scanf("%d", &ret);
if (ret == 1)
{
qsort(pc->data, pc->sz, sizeof(PeoInfo), compare_name);
SHOWContact(pc);
printf("名字排序成功\n");
}
else if (ret == 2)
{
qsort(pc->data, pc->sz, sizeof(PeoInfo), compare_age);
SHOWContact(pc);
printf("年龄排序成功\n");
}
else
{
printf("选择错误,返回操作");
}
}
排序功能,需要我们自定义比较函数,我们先通过ret来选择按名字排序还是年龄排序,之后再不同的情况中同qsort函数来排序后通过SHOWContact函数来显示排序过后的通讯录,即可。两个自定义比较函数,分别强转为PeoInfo类型指针后指向年龄相减,或者指向名字用strcmp函数比较即可。就实现了两个不同的排序情况。
最后如果我们想要清空通讯录,直接调用初始化函数即可,这样就把所有的数据清空了
可以通过调试监视窗口,确实是清空了。
最后给大家分享鄙人代码
#include"contact.h"
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT,
EMPTY
};
void menu();
int main()
{
int input = 0;
Contact con ;
InitContact(&con);
do
{
menu();
printf("请输入你想选择的操作:");
scanf("%d", &input);
switch (input)
{
case EXIT:
printf("退出通讯录成功");
break;
case ADD:
ADDContact(&con);
break;
case DEL:
DELContact(&con);
break;
case SEARCH:
SearchContact(&con);;
break;
case MODIFY:
ModifyContact(&con);
break;
case SHOW:
SHOWContact(&con);
break;
case SORT:
SortContact(&con);
break;
case EMPTY:
InitContact(&con);
printf("清空通讯录成功\n");
break;
default:
printf("输入错误\n");
break;
}
} while (input);
return 0;
}
#include "contact.h"
void menu()
{
printf("*****************************\n");
printf("*****0.EXIT****1.ADD*********\n");
printf("*****2.DEL*****3.SEARCH******\n");
printf("*****4.MODIFY**5.SHOW********\n");
printf("*****6.SORT****7.EMPTY*******\n");
}
void InitContact(Contact* pc)
{
assert(pc);
pc->sz = 0;
memset(pc->data, 0, sizeof(pc->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].tele);
printf("请输入住址:");
scanf("%s", pc->data[pc->sz].addr);
//
pc->sz++;
printf("添加联系人成功!\n");
}
void SHOWContact(const Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无需打印\n");
return;
}
int i = 0;
//名字 年龄 性别 电话 地址
//xxx xxx xxx xxx xxx
printf("%-20s%-10s%-10s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
for (i = 0; i < pc->sz; i++)
{
//打印每个人的信息
printf("%-20s%-10d%-10s%-12s%-30s\n",
pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
}
}
int FindByName(Contact* pc, char* name)
{
assert(pc);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name,name)==0)
{
return i;
}
}
return -1;
}
void DELContact(Contact* pc)
{
char name[NAME_MAX];
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,不可删除\n");
return;
}
printf("请输入你想删除的联系人:");
scanf("%s", name);
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("该联系人不存在,无法删除!\n");
return;
}
int i = 0;
for (i = ret; i < pc->sz-1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除该联系人成功!\n");
}
void SearchContact(Contact* pc)
{
assert(pc);
char name[NAME_MAX];
printf("请输入想查找的联系人");
scanf("%s", &name);
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("该联系人不存在!\n");
return;
}
printf("%-20s%-10s%-10s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
printf("%-20s%-10d%-10s%-12s%-30s\n",
pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}
void ModifyContact(Contact* pc)
{
assert(pc);
char name[NAME_MAX];
printf("请输入想修改的联系人");
scanf("%s", &name);
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("该联系人不存在!\n");
return;
}
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");
}
int compare_name(const void* base,const void* src)
{
return strcmp(((PeoInfo*)base)->name , ((PeoInfo*)src)->name);
}
int compare_age(const void* base, const void* src)
{
return (((PeoInfo*)base)->age-((PeoInfo*)src)->age);
}
void SortContact(Contact* pc)
{
int ret = 0;
printf("1按名字排序,2按年龄排序\n");
scanf("%d", &ret);
if (ret == 1)
{
qsort(pc->data, pc->sz, sizeof(PeoInfo), compare_name);
SHOWContact(pc);
printf("名字排序成功\n");
}
else if (ret == 2)
{
qsort(pc->data, pc->sz, sizeof(PeoInfo), compare_age);
SHOWContact(pc);
printf("年龄排序成功\n");
}
else
{
printf("选择错误,返回操作");
}
}
#pragma once
#include
#include
#include
#include
#define NAME_MAX 20
#define SEX_MAX 10
#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 menu();
void InitContact(Contact* pc);
void ADDContact(Contact* pc);
void SHOWContact(const Contact* pc);
void DELContact(Contact* pc);
void SearchContact(Contact* pc);
void ModifyContact(Contact* pc);
void SortContact(Contact* pc);