🛰️博客主页:✈️銮同学的干货分享基地
🛰️欢迎关注:👍点赞🙌收藏✍️留言
🛰️系列专栏:💐【进阶】C语言学习
🛰️代码仓库:🎉VS2022_C语言仓库
**家人们更新不易,你们的👍点赞👍和👉关注👈真的对我真重要,各位路过的友友麻烦多多点赞关注,欢迎你们的私信提问,感谢你们的转发!**
** ***** 关注我,关注我,关注我,***你们将会看到更多的优质内容!!
🏡🏡*** 本文重点 ***🏡🏡:
🚅 优化完善静态通讯录****(源码在结尾) 🚏🚏
🥰前言🥰:
在上篇文章中我们已经使用我们所学过的**结构体**相关知识,写出了一个**基础版本的通讯录工具**,但是我们也知道这个**基础版本的通讯录工具仍然存在着许多的缺陷**。
我们注意到,在我们的基础版通讯录中,我们**对输入的值没有合法性检测**,这将会导致,**无论用户输入什么样的值都将会被我们的通讯录存储**,并且**由于输入与反馈的数据类型及格式差异,很有可能会导致输出错误**。并且我们可以回想一下,我们手机里的通讯录在保存好联系人信息后,在我们进行查看时,会**按照类似字典内的排序方式(即****字典排序****)将所有联系人进行排序后反馈**给用户,而在我们基础版的通讯录中,保存的联系人信息还没有经过排序。最后还有**对输出反馈的优化**,相信各位小伙伴们在使用通讯录的时侯,屏幕上的打印反馈信息也应该都不是凌乱的吧。
而关于上面所说的这些问题,我们今天就将**逐一进行处理**。
一、输入合法性检测🤠:
关于合法性检测,我们的要求是**对需要进行输入合法性检测的信息进行合法性检测**。例如**输入联系方式时若用户输入非数字字符,则提示用户输入非法**;以及在用户**输入年龄时应当对年龄范围进行限制,超出限制范围则应提示用户输入非法**。
①.对“ 联系方式 ”的合法性检测:
对联系方式的合法性检测我们认为应当分为两步,首先我们应当**对输入的联系方式内容进行检测**,这里所采用的方式是,对数组内字符串进行**遍历**,在**前11个位置(联系方式为 11 位)每个位置上的字符均为****数字字符**** 0~9 时,则继续向后遍历,全部遍历完成且没有错误后则判断为合法,否则为不合法,提醒用户输入非法并要求用户重新进行输入**:
scanf("%s", p->data[p->sz].tele);
char check1[MAX_TELE] = { 0 };
strcpy(check1, p->data[p->sz].tele);
int i = 0;
int cmp = 0;
//比较变量cmp用于标记各位置上的判断结果
for (i = 0; i < 11; i++)
{
if ('0' <= check1[i] && check1[i] <= '9')
{
cmp = 0;
}
else
{
cmp = 1;
break;
}
}
if (cmp)
{
printf("您输入的联系方式有误,请重新输入!\n");
}
接下来我们还要进行联系方式长度检测,我们当前所使用的联系方式通常为 11 位,于是我们就将位数暂且定为11位,并且我们**前面的合法位判断中已经确定了每一位上均为合法**,于是在这里我们**只需要对位数加以判断即可**,我们选择的判断方法是**若第十二位为初始化时的 0(即第十二位没有输入值),则合法,否则不合法**:
if (check1[11] == 0)
//下标从零开始,第十二位下标为11
{
;
//若合法则不进行操作,不合法则提示不合法并重新输入
}
else
{
cmp = 1;
}
最后我们再对整个循环条件进行判断即可。我们**使用了 do ... while 循环,保证了合法性判断至少进行一次**,并在**判断循环一开始便让判断条件 input 变为 0(假),若在判断结束时仍没有不合法现象,则判断为假跳出循环,合法性判断结束**;若在过程中**判断存在不合法输入,则将其值重新赋为 1,提示不合法后继续进入下一循环**:
int input = 1;
do
{
input = 0;
//直接让input为0,若出现不合法则改其值为1继续循环
//不符合不合法则跳出循环
printf("请输入联系人联系方式:>");
scanf("%s", p->data[p->sz].tele);
char check1[MAX_TELE] = { 0 };
strcpy(check1, p->data[p->sz].tele);
int i = 0;
int cmp = 0;
//比较变量cmp用于标记各位置上的判断结果
for (i = 0; i < 11; i++)
{
if ('0' <= check1[i] && check1[i] <= '9')
{
cmp = 0;
}
else
{
cmp = 1;
break;
}
}
if (check1[11] == 0)
//下标从零开始,第十二位下标为11
{
;
//若合法则不进行操作,不合法则提示不合法并重新输入
}
else
{
cmp = 1;
}
if (cmp)
{
input = 1;
//不合法继续循环
printf("您输入的联系方式有误,请重新输入!\n");
}
} while (input);
同时我们**对“修改联系人信息”功能中的相关输入也需要采用这样的方式进行合法性判断**:
case 4:
do
{
input_cmp = 0;
//直接让input_cmp为0,若出现不合法则改其值为1继续循环
//不符合不合法则跳出循环
printf("请输入联系人联系方式:>");
scanf("%s", p->data[x - 1].tele);
char check1[MAX_TELE] = { 0 };
strcpy(check1, p->data[x - 1].tele);
int i = 0;
int cmp = 0;
//比较变量cmp用于标记各位置上的判断结果
for (i = 0; i < 11; i++)
{
if ('0' <= check1[i] && check1[i] <= '9')
{
cmp = 0;
}
else
{
cmp = 1;
break;
}
}
if (check1[11] == 0)
//下标从零开始,第十二位下标为11
{
;
//若合法则不进行操作,不合法则提示不合法并重新输入
}
else
{
cmp = 1;
}
if (cmp)
{
input_cmp = 1;
//不合法继续循环
printf("您输入的联系方式有误,请重新输入!\n");
}
else
{
printf("修改成功!\n");
}
} while (input_cmp);
PrintContact(p, x - 1);
input = 0;
break;
** ②.对“年龄”进行合法性检测:**
对年龄的合法性检测最为简单,我们**只需要判断用户输入的年龄位于区间 0~100 之间即可,合法则跳出,否则继续循环**:
int input = 1;
do
{
printf("请输入联系人年龄:>");
scanf("%d", &(p->data[p->sz].age));
if (0 <= p->data[p->sz].age && p->data[p->sz].age <= 100)
{
input = 0;
}
else
{
printf("您输入的年龄信息有误,请重新输入!\n");
}
} while (input);
同样的,**将“修改联系人信息”功能中的输入以同样的方式进行合法性检测**:
case 3:
do
{
printf("请输入联系人年龄:>");
scanf("%d", &(p->data[x - 1].age));
if (0 <= p->data[x - 1].age && p->data[x - 1].age <= 100)
{
input_cmp = 0;
printf("修改成功!\n");
}
else
{
printf("您输入的年龄信息有误,请重新输入!\n");
}
} while (input_cmp);
PrintContact(p, x - 1);
input = 0;
break;
二、字典排序🤑:
字典排序相对简单,简单来说,就是**按照像字典里那样,根据姓名的排序,将通讯录中联系人信息进行排序**。
而我们要想进行实现,其实也很简单,我们只需要**像冒泡排序那样进行遍历**,**将每一个联系人的姓名均与下一个联系人进行比较,如果后一个联系人的姓名更靠前,则将二者的信息进行交换,否则继续向后一个进行比较**:
//字典排序:
void sort(contact* p)
{
int i = 0;
PeoInfo temp;
for (i = 0; i < p->sz; i++)
{
if (strcmp(p->data[i].name, p->data[i + 1].name) > 0)
{
temp = p->data[i + 1];
p->data[i + 1] = p->data[i];
p->data[i] = temp;
}
}
}
在这里,我们只需要**再定义一个中间结构体,并通过中间结构体直接交换两个联系人的信息**即可,而不用逐一交换两个联系人的各项信息。
三、反馈优化🤯:
而关于反馈优化则很简单了。在**优化前**,我们的通讯录小工具运行起来是这个样子的:
优化前的程序运行结果**肉眼可见的繁杂、凌乱,一团乱麻地堆在一起**。于是我们就需要对小工具的打印反馈过程进行优化。
我们使用的方法仍然是,**使用 Sleep 命令与 system 命令**,共同协作完成优化工作。
而关于 Sleep 与 system 命令,我们**前面在对三子棋游戏与扫雷游戏(点击跳转)进行优化时,就已经为大家讲解过了**,这里就不再做过多的赘述,各位小伙伴们可以**通过点击游戏名跳转至我们之前关于这两个命令的讲解部分**进行学习。
四、优化版通讯录全部源码🤩:
** 废话不多说,直接给大家上源码**!
** ①.Contact.h:**
#pragma once
//定义宏常量:
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
//引用头文件:
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<Windows.h>
//选项枚举:
enum Option
{
Exit,//值为0
Add,//值为1
Del,//值为2
Search,//值为3
Modify,//值为4
Print//值为5
};
//联系人信息:
typedef struct PeoInfo
{
char name[MAX_NAME];
char sex[MAX_SEX];
int age;
char tele[MAX_TELE];
char addr[MAX_ADDR];
}PeoInfo;
//通讯录调用封装:
typedef struct contact
{
PeoInfo data[MAX];
int sz;
}contact;
//函数声明:
void InitContact(contact* p);
void sort(contact* p);
void PrintContact(const contact* p, int x);
void PrintAllContact(const contact* p);
void AddContact(contact* p);
void DelContact(contact* p);
void SearchContact(const contact* p);
void ModifyContact(const contact* p);
** ②.Contact.c:**
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
//初始化通讯录:
void InitContact(contact* p)
{
assert(p);
p->sz = 0;
memset(p->data, 0, sizeof(p->data));
//使用memeset函数将p->data所指向的空间中的数据初始化为0
//操作的空间大小为sizeof函数所计算出的p->data所指向空间的大小,即整个无联系人数据的结构体数组data所占的空间的大小
}
//字典排序:
void sort(contact* p)
{
int i = 0;
PeoInfo temp;
for (i = 0; i < p->sz; i++)
{
if (strcmp(p->data[i].name, p->data[i + 1].name) > 0)
{
temp = p->data[i + 1];
p->data[i + 1] = p->data[i];
p->data[i] = temp;
}
}
}
//打印联系人信息:
void PrintContact(const contact* p, int x)
{
assert(p);
printf(" 联系人 :%04d\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)
{
assert(p);
if (p->sz == MAX)
{
system("cls");
printf("通讯录空间不足,无法添加新成员!\n");
Sleep(1500);
system("cls");
}
else
{
printf("请输入联系人姓名:>");
scanf("%s", p->data[p->sz].name);
printf("请输入联系人性别:>");
scanf("%s", p->data[p->sz].sex);
//对年龄进行合法性检测:
int input = 1;
do
{
printf("请输入联系人年龄:>");
scanf("%d", &(p->data[p->sz].age));
if (0 <= p->data[p->sz].age && p->data[p->sz].age <= 100)
{
input = 0;
}
else
{
Sleep(1000);
system("cls");
printf("您输入的年龄信息有误,请重新输入!\n");
Sleep(1500);
system("cls");
printf("请输入联系人姓名:>%s\n", p->data[p->sz].name);
printf("请输入联系人性别:>%s\n", p->data[p->sz].sex);
}
} while (input);
//对联系方式进行合法性检测:
input = 1;
do
{
input = 0;
//直接让input为0,若出现不合法则改其值为1继续循环
//不符合不合法则跳出循环
printf("请输入联系人联系方式:>");
scanf("%s", p->data[p->sz].tele);
char check1[MAX_TELE] = { 0 };
strcpy(check1, p->data[p->sz].tele);
int i = 0;
int cmp = 0;
//比较变量cmp用于标记各位置上的判断结果
for (i = 0; i < 11; i++)
{
if ('0' <= check1[i] && check1[i] <= '9')
{
cmp = 0;
}
else
{
cmp = 1;
break;
}
}
if (check1[11] == 0)
//下标从零开始,第十二位下标为11
{
;
//若合法则不进行操作,不合法则提示不合法并重新输入
}
else
{
cmp = 1;
}
if (cmp)
{
input = 1;
//不合法继续循环
Sleep(1000);
system("cls");
printf("您输入的联系方式有误,请重新输入!\n");
Sleep(1500);
system("cls");
printf("请输入联系人姓名:>%s\n", p->data[p->sz].name);
printf("请输入联系人性别:>%s\n", p->data[p->sz].sex);
printf("请输入联系人年龄:>%d\n", p->data[p->sz].age);
}
} while (input);
printf("请输入联系人住址:>");
scanf("%s", p->data[p->sz].addr);
Sleep(1000);
system("cls");
printf("****************************\n");
printf("****************************\n");
printf("**** 联系人信息添加成功!***\n");
printf("****************************\n");
printf("****************************\n");
PrintContact(p, p->sz);
sort(p);
p->sz++;
}
}
//删除联系人:
void DelContact(contact* p)
{
assert(p);
int num = 0;
if (p->sz == 0)
{
printf("对不起,当前通讯录中没有联系人信息!\n");
Sleep(1500);
}
else
{
PrintAllContact(p);
printf("请输入您想删除的联系人编号:>");
scanf("%d", &num);
int x = num - 1;
if (0 <= x && x <= p->sz)
{
int j = 0;
for (j = x; j < p->sz; j++)
{
p->data[j] = p->data[j + 1];
p->sz--;
}
Sleep(1000);
system("cls");
printf("**************************\n");
printf("**************************\n");
printf("**** 联系人信息已删除!***\n");
printf("**************************\n");
printf("**************************\n");
PrintAllContact(p);
Sleep(3000);
}
}
}
//查询联系人:
void SearchContact(const contact* p)
{
assert(p);
char name[MAX_NAME] = { 0 };
printf("请输入您想要查询的联系人姓名:>");
scanf("%s", &name);
Sleep(1000);
system("cls");
int i = 0;
int ret = 1;
for (i = 0; i < p->data; i++)
{
if (0 == strcmp(name, p->data[i].name))
{
printf("************************\n");
printf("************************\n");
printf("**** 成功找到联系人!***\n");
printf("************************\n");
printf("************************\n");
PrintContact(p, i);
Sleep(3000);
ret = 0;
break;
}
}
if (ret)
{
printf("************************\n");
printf("************************\n");
printf("**** 未找到该联系人!***\n");
printf("************************\n");
printf("************************\n");
Sleep(1500);
}
}
//修改联系人信息:
void ModifyContact(contact* p)
{
assert(p);
int x = 0;
int input = 0;
int input_cmp = 1;
if (p->sz == 0)
{
printf("对不起,当前通讯录中没有联系人信息!\n");
Sleep(1500);
system("cls");
}
else
{
PrintAllContact(p);
printf("请输入您想要修改的联系人编号:>");
scanf("%d", &x);
Sleep(1000);
system("cls");
do
{
printf("***************************\n");
printf("***************************\n");
PrintContact(p, x - 1);
printf("***************************\n");
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);
Sleep(1000);
system("cls");
switch (input)
{
case 1:
printf("***************************\n");
printf("***************************\n");
PrintContact(p, x - 1);
printf("***************************\n");
printf("请更新联系人姓名:");
scanf("%s", p->data[x - 1].name);
Sleep(1000);
system("cls");
printf("**************************\n");
printf("**************************\n");
printf("**** 联系人姓名已修改!***\n");
printf("**************************\n");
printf("**************************\n");
PrintContact(p, x - 1);
Sleep(3000);
system("cls");
input = 0;
break;
case 2:
printf("***************************\n");
printf("***************************\n");
PrintContact(p, x - 1);
printf("***************************\n");
printf("请更新联系人性别:");
scanf("%s", p->data[x - 1].sex);
Sleep(1000);
system("cls");
printf("**************************\n");
printf("**************************\n");
printf("**** 联系人性别已修改!***\n");
printf("**************************\n");
printf("**************************\n");
PrintContact(p, x - 1);
Sleep(3000);
system("cls");
input = 0;
break;
case 3:
do
{
printf("***************************\n");
printf("***************************\n");
PrintContact(p, x - 1);
printf("***************************\n");
printf("请更新联系人年龄:>");
scanf("%d", &(p->data[x - 1].age));
Sleep(1000);
system("cls");
if (0 <= p->data[x - 1].age && p->data[x - 1].age <= 100)
{
input_cmp = 0;
printf("**************************\n");
printf("**************************\n");
printf("**** 联系人年龄已修改!***\n");
printf("**************************\n");
printf("**************************\n");
}
else
{
printf("您输入的年龄信息有误,请重新输入!\n");
Sleep(1500);
system("cls");
}
} while (input_cmp);
PrintContact(p, x - 1);
Sleep(3000);
system("cls");
input = 0;
break;
case 4:
do
{
input_cmp = 0;
//直接让input_cmp为0,若出现不合法则改其值为1继续循环
//不符合不合法则跳出循环
printf("***************************\n");
printf("***************************\n");
PrintContact(p, x - 1);
printf("***************************\n");
printf("请更新联系人联系方式:>");
scanf("%s", p->data[x - 1].tele);
Sleep(1000);
system("cls");
char check1[MAX_TELE] = { 0 };
strcpy(check1, p->data[x - 1].tele);
int i = 0;
int cmp = 0;
//比较变量cmp用于标记各位置上的判断结果
for (i = 0; i < 11; i++)
{
if ('0' <= check1[i] && check1[i] <= '9')
{
cmp = 0;
}
else
{
cmp = 1;
break;
}
}
if (check1[11] == 0)
//下标从零开始,第十二位下标为11
{
;
//若合法则不进行操作,不合法则提示不合法并重新输入
}
else
{
cmp = 1;
}
if (cmp)
{
input_cmp = 1;
//不合法继续循环
printf("您输入的联系方式有误,请重新输入!\n");
Sleep(1500);
system("cls");
}
else
{
printf("******************************\n");
printf("******************************\n");
printf("**** 联系人联系方式已修改!***\n");
printf("******************************\n");
printf("******************************\n");
}
} while (input_cmp);
PrintContact(p, x - 1);
Sleep(3000);
system("cls");
input = 0;
break;
case 5:
printf("***************************\n");
printf("***************************\n");
PrintContact(p, x - 1);
printf("***************************\n");
printf("请更新联系人住址:");
scanf("%s", p->data[x - 1].addr);
Sleep(1000);
system("cls");
printf("**************************\n");
printf("**************************\n");
printf("**** 联系人住址已修改!***\n");
printf("**************************\n");
printf("**************************\n");
PrintContact(p, x - 1);
Sleep(3000);
system("cls");
input = 0;
break;
default:
printf("您的选择有误,请重新选择!\n");
Sleep(1500);
system("cls");
break;
}
}while (input);
}
}
** ③.test.c:**
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
void menu()
{
printf("**********************************\n");
printf("**********************************\n");
printf("******** 欢迎使用本通讯录 ********\n");
printf("**********************************\n");
printf("***** 本通讯录现提供以下功能 *****\n");
printf("************ 1.Add ***************\n");
printf("************ 2.Del ***************\n");
printf("************ 3.Search ************\n");
printf("************ 4.Modify ************\n");
printf("************ 5.Print *************\n");
printf("************ 0.Exit **************\n");
printf("**********************************\n");
printf("**********************************\n");
}
void Contact()
{
int input = 0;
contact con;
InitContact(&con);
do
{
menu();
printf("请您进行选择:> ");
scanf("%d", &input);
switch (input)
{
case Add:
Sleep(1000);
system("cls");
AddContact(&con);
Sleep(3000);
system("cls");
break;
case Del:
Sleep(1000);
system("cls");
DelContact(&con);
system("cls");
break;
case Search:
Sleep(1000);
system("cls");
SearchContact(&con);
system("cls");
break;
case Modify:
Sleep(1000);
system("cls");
ModifyContact(&con);
Sleep(1000);
system("cls");
break;
case Print:
Sleep(1000);
system("cls");
PrintAllContact(&con);
Sleep(1000);
system("cls");
break;
case Exit:
Sleep(1000);
system("cls");
printf("正在退出!\n");
Sleep(1000);
system("cls");
break;
default:
Sleep(1000);
system("cls");
printf("您的选择有误,请重新选择!\n");
Sleep(1500);
system("cls");
break;
}
} while (input);
}
int main()
{
Contact();
return 0;
}
🥳总结🥳:
至此,我们关于**通讯录的优化就全部完成了**。不过我们看到我们目前写出来的通讯录**仍旧功能简单**,各位小伙伴们下去以后可以**自行研究,再给它添加上我们需要的各种功能**!
🔥🔥***坚强并不只是在大是大非中不屈服,而也是在挫折前不改变自己***🔥🔥
更新不易,辛苦各位小伙伴们动动小手,**👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!**最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!
版权归原作者 銮崽的干货分享基地 所有, 如有侵权,请联系我们删除。