前面的文章介绍了C语言中的 指针、自定义类型等模块,这篇文章将通过编写实现通讯录的代码对这些模块进行应用和进一步加深理解:
目录
1. 通讯录主要功能设计:
2. 通讯录的实现——主页面:
3. 通讯录的实现——保存个人信息:
4. 通讯录功能实现:
4.1 添加个人信息:
4.2 查看个人信息:
4.3 删除个人信息:
4.4 查找指定联系人:
4.5 修改联系人的个人信息:
4.6 按照名字排序信息:
1. 通讯录主要功能设计:
首先,设置想让通讯录达成的功能,例如:
2. 通讯录的实现——主页面:
在实现通讯录各项具体的功能之前,首先应给出一个页面,便于使用者选择自己需要的功能,代码如下:
void menu()
{
printf("*************************\n");
printf("***** 0.exit *****\n");//退出
printf("***** 1.add *****\n");//添加联系人信息
printf("***** 2.del *****\n");//删除联系人信息
printf("***** 3.search *****\n");//查找联系人信息
printf("***** 4.modify *****\n");//改变联系人信息
printf("***** 5.show *****\n");//展示联系人信息
printf("***** 6.sort *****\n");//对联系人进行排序
}
void test()
{
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 0:
break;
default:
break;
}
} while (input);
}
但是,在switch选择语句中,使用不同的数字来划分不同的情况,未免有些太不直观,所以,为了让功能更加直观,可以按照菜单上不同功能对应的数字,用枚举解决这一问题:
enum OPTION
{
exit,
add,
del,
search,
modify,
show,
sort
};
此时,主页面的代码可以根据枚举进行修改,来变得更直观:
void test()
{
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:
break;
default:
break;
}
} while (input);
}
运行效果如下:
3. 通讯录的实现——保存个人信息:
对于上面所列出的信息中,它们的数据类型各不相同,对于不同类型的信息的整合,可以采用结构体的方式进行实现:
typedef struct PeoInfo
{
char name[20];
int age;
char sex[5];
char tele[15];
char add[20];
}PeoInfo;
上面给出的结构体中,包含了功能设计时,所设计的保存联系人姓名,年龄,性别,电话,住址这几个信息。
对于上面用于存储个人信息的数组的大小,也可以采取类似上面相同的方法,用#define进行定义。即:
#define NAME_NUM 20
#define SEX_NUM 5
#define TELE_NUM 15
#define ADD_NUM 20
typedef struct PeoInfo//用于保存个人信息的结构体
{
char name[NAME_NUM];
int age;
char sex[SEX_NUM];
char tele[TELE_NUM];
char add[ADD_NUM];
}PeoInfo;
上面的结构体只能存放一个人的信息,为了可以存放多人信息,可以通过创建一个结构体数组的方法来实现。并且,为了随时更改存储人数的数量,可以采用define将数量改为一个可以随时进行更改的常变量:
#define MAX_NUM 100;
PeoInfo arr[MAX_NUM];
在设置了存储最大人数后,需要将装有个人信息的结构体与编号联系起来,所以,可以再创建一个结构体,用于保存存储个人信息的结构体数组和一个用于计数的变量:
typedef struct contact
{
PeoInfo arr[MAX_NUM];
int sz = 0;
}contact;
再解决了上面的问题后,需要对通讯录进行初始化的工作,可以通过memset函数对通讯录进行初始化,并将这一过程封装在一个初始化函数中:
4. 通讯录功能实现:
4.1 添加个人信息:
在通讯录中添加个人信息时,需要注意,如果通讯录中用于计数的变量sz达到了所设置存储数量的最大值,应给出存储已满的信息,当sz没有到达存储数据的最大值时,可以继续存储数据:
这里,封装一个添加个人信息的函数,并将函数设置在主页面switch语句中添加的部分:
void ADDcontact(contact* pc)
{
if (pc->sz == 100)
{
printf("通讯录已满");
return;
}
printf("请输入名字:");
scanf("%s", (pc->arr[pc->sz]));
printf("请输入年龄:");
scanf("%d", &(pc->arr[pc->sz]));
printf("请输入性别:");
scanf("%s", (pc->arr[pc->sz]));
printf("请输入电话号码:");
scanf("%s", (pc->arr[pc->sz]));
printf("请输入地址:");
scanf("%s", &(pc->arr[pc->sz]));
pc->sz++;
printf("添加联系人成功");
}
4.2 查看个人信息:
上面输入了个人信息后,这些信息就被保存在结构体中,想要查看个人信息,就需要将这些信息打印出来:
void ShowContact(contact* pc)
{
int i = 0;
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-20s\t\n",
"姓名",
"年龄",
"性别",
"电话号码",
"家庭住址");
for (i = 0; i < pc->sz; i++)
{
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-20s\t",
pc->arr[i].name,
pc->arr[i].age,
pc->arr[i].sex,
pc->arr[i].tele,
pc->arr[i].add);
printf("\n");
}
}
4.3 删除个人信息:
想要删除某个人的个人信息,第一步就是要先找到这个人的个人信息,所以,可以先创建一个字符数组,用于输入某个想要删除的人的名字,下面再与结构体中已经有的信息中的姓名,用strcmp函数进行比对,如果strcmp函数的返回值是0,则记录下此时信息在结构体中的编号:
void DelContact(contact* pc)
{
if (pc->sz == 0)
{
printf("通讯录为空,无法删除");
}
//先找到想要删除的人所在通讯录的编号:
char name1[NAME_NUM] = { 0 };
printf("请输入想要删除的人的名字:");
scanf("%s", name1);
int i = 0;
int del = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(name1, pc->arr[i].name) == 0)
{
del = i;
break;
}
}
在找到了想要删除的信息所在的位置后,第二步就是删除相关的信息,总体代码如下:
void DelContact(contact* pc)
{
if (pc->sz == 0)
{
printf("通讯录为空,无法删除");
}
//先找到想要删除的人所在通讯录的编号:
char name1[NAME_NUM] = { 0 };
printf("请输入想要删除的人的名字:");
scanf("%s", name1);
int i = 0;
int del = 0;
int flag = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(name1, pc->arr[i].name) == 0)
{
del = i;
flag = 1;
break;
}
if (flag == 0)
{
printf("不存在用户,删除失败");
return;
}
}
//删除联系人的信息
for (i = del; i < pc->sz - 1; i++)
{
pc->arr[i] = pc->arr[i + 1];
}
pc->sz--;
printf("成功删除联系人\n");
}
在寻找信息时,记录了想要删除的人的信息所在结构体中的位置。
对于整个删除过程,应该是首先添加个人信息,如果其中信息添加错了才会进行删除,假设添加信息阶段一共添加了20人的信息,想要删除的人的信息在结构体数组中的编号为8。
此时,在删除信息的代码中,应该从编号为8进行遍历,并且用编号为9的信息覆盖编号为8的信息,然后,循环继续进行,让编号为10的信息覆盖编号为9的信息,所以,按照这个步骤,最后应该是编号为19的信息覆盖编号为18的信息,也就是循环11次。所以i的范围应该满足:i <= sz-1(19)并且 i >=del。
当覆盖完毕后,此时可以理解为,从编号为del开始的范围所对应的内容都集体向前移动一位,所以,末尾即sz对应的内容不能被查询,所以sz--
在删除某个个人信息时,分了两步,第一步时先通过输入想要删除的人的姓名,找到他在结构体中所对应的编号,但是,不光对于删除信息,在下面的查找信息,改变信息都需要找到这个编号,所以,为了简化代码,应该将寻找个人信息对应的编号这一步骤封装成一个函数。
int del = Findbyname(pc, name1);
if (del == -1)
{
printf("用户不存在");
}
经过函数封装后,代码为:
void DelContact(contact* pc)
{
if (pc->sz == 0)
{
printf("通讯录为空,无法删除");
}
//先找到想要删除的人所在通讯录的编号:
char name1[NAME_NUM] = { 0 };
printf("请输入想要删除的人的名字:");
scanf("%s", name1);
int i = 0;
int del = Findbyname(pc, name1);
if (del == -1)
{
printf("用户不存在\n");
return;
}
//删除联系人的信息
for (i = del; i < pc->sz - 1; i++)
{
pc->arr[i] = pc->arr[i + 1];
}
pc->sz--;
printf("成功删除联系人\n");
}
封装的函数:
int Findbyname(contact* pc, char *name1)
{
int i = 0;
int del = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(name1, pc->arr[i].name) == 0)
{
return i;
}
}
return -1;
}
4.4 查找指定联系人:
步骤与删除某人的个人信息,类似,先找到,再打印出来即可:
void SearchContact(const contact* pc)
{
char name2[20];
scanf("%s", &name2);
int pos = Findbyname(pc, name2);
if (pos == 0)
{
printf("找不到相关信息\n");
}
else
{
int i = 0;
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-20s\t\n",
"姓名",
"年龄",
"性别",
"电话号码",
"家庭住址");
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-20s\t",
pc->arr[pos].name,
pc->arr[pos].age,
pc->arr[pos].sex,
pc->arr[pos].tele,
pc->arr[pos].add);
}
}
4.5 修改联系人的个人信息:
与删除相同,首先要找到需要修改的人在结构体中的编号,再进行重新输入即可:
void ModifyContact(contact* pc)
{
char name3[20];
printf("输入想要修改的信息的人名:");
scanf("%s", name3);
int ret = Findbyname(pc, name3);
if (ret == 0)
{
printf("不存在此人,修改失败");
return;
}
else
{
printf("请输入姓名:");
scanf("%s", pc->arr[ret].name);
printf("请输入年龄:");
scanf("%s", &(pc->arr[ret].age));
printf("请输入性别:");
scanf("%s", pc->arr[ret].sex);
printf("请输入电话:");
scanf("%s", pc->arr[ret].tele);
printf("请输入住址:");
scanf("%s", pc->arr[ret].add);
printf("修改成功\n");
}
}
4.6 按照名字排序信息:
对于不同种类的信息的排序,就需要用到之前介绍过的函数qsort,具体如何使用qsort可以在(qsort对不同数据类型的排序、及模拟qsort函数实现_爱写代码的粉毛护理的博客-CSDN博客)进行理解。
int compare_stu_name(const void* str1, const void* str2)
{
return(strcmp(((PeoInfo*)str1)->name, ((PeoInfo*)str2)->name));
}
//根据名字排序:
void SortContact(contact* pc)
{
int sz1 = sizeof(pc->arr) / sizeof(pc->arr[0]);
qsort(pc->arr, sz1, sizeof(pc->arr[0]), compare_stu_name);
int i = 0;
for (i = 0; i < pc->sz;)
{
if (pc->arr[i].age == 0)
{
i++;
}
else
{
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-20s\t\n",
"姓名",
"年龄",
"性别",
"电话号码",
"家庭住址");
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-20s\t",
pc->arr[i].name,
pc->arr[i].age,
pc->arr[i].sex,
pc->arr[i].tele,
pc->arr[i].add);
printf("\n");
i++;
}
}
}