目录
🤑通讯录功能介绍
通讯录作为结构体的练习,所有只针对结构体的使用而创建,并没有使用到文件存储和数据库存储,后面会有用文件和数据库存储的练习---------------------🤑尽情期待哦!
🥵通讯录相关功能介绍
我们先说一下我们想要实现的几个功能!
功能有以下几点:
先看一下实现后的效果:
🥵菜单打印
🥵添加个人信息
🥵显示个人信息内容
🥵查找个人信息内容
🥵修改个人信息内容
🥵排序个人信息内容
🥵删除个人信息内容
🤑分析每一个函数的功能实现
🥵数据结构创建的数据类型
定义结构类型:
第一层是人的基本信息,第二层是将全局的指针和人的基本信息结构封装到一起,方便使用。
🥵主菜单/与Main函数调用架构
🥵主菜单函数的实现
🥵打印进度条函数实现
此代码在我的另一篇博客里已经明确讲解,这里我就不进行解析了。
🥵通讯录数组区增加函数实现
1:对数据使用assert是为了保护指针不是NULL指针,已保证程序运行的安全性。
2:在录入信息前,我们先进行判断全局的指针是否为100,如果是100说明数据存储区已经满了,这样就不能进行数据存储啦,所以直接返回。
3:存储数据没有满,我们分别对姓名、年龄、性别、电话、家庭地址进行数据获取,并且获取完成后进行数据条打印,以达到美观效果。
🥵通讯录数组区显示函数实现
这个其实没有什么好说的,将进度条打印的时机放到合适的位置,先打印出格式姓名、年龄、性别、电话、家庭地址的目录,printf上的打印格式是标准的格式,不明白的小伙伴可以区百度查一下哦---🥵
然后格式确定后,我们就直接遍历结构体中的数组进行分行显示就好啦--🥵
🥵通讯录数组区删除函数实现
删除的函数我们同样对指针进行断言一下
1:同样的我们首先判断一下存储器中是否有数据,要是没有数据提示一下return
2:如果存储区中有数据,我们还需要判断一下想要删除的那个个人信息的姓名在不在存储中存储,我们封装了一个函数,以方便其他的函数也可以共享这个函数进行使用,如果没有也提示一下,并且return
3:上面两个条件都成立的情况下我们就可以进行删除数据啦,删除的逻辑其实也很简单,其实就是找到那组数据到存储器中总人头数,低位替换成高位就可以啦,我相信有一点点C语言的小伙伴肯定明白。
🥵通讯录数组区查找函数实现
查找数据并且显示的函数其实和显示函数一样
1:前面的逻辑一样,调用查找姓名的函数来进行查找是否有相同名字的人。
2:如果找到了,直接按照显示的代码进行打印,就是打印一个人的信息,所以FOR循环就可以去掉啦。
🥵通讯录数组区修改函数实现
修改函数的代码也是和前面一样的逻辑,当找到了要修改人的指针下表,我们可以让用户在重新输入要修改的内容。
🥵通讯录数组区排序函数实现
排序函数我们可以调用现成的qsort()库函数来进行实现,当然需要练习的小伙伴也可以按照我上一篇博客自己写一个qsort()模拟实现。
以下本人为了自己练习所有两种方式都进行了实现。
这里我也推荐小伙伴们自己写一下,作为练习嘛 -------🥰之前的博客有关于MyQsort的模拟实现解析。
🤑代码整体展示
🥵主程序代码
#include"Communicate.h"
int main()
{
// 结构体实例化。
Communicate communicateData;
// 调用初始化通讯录数组区函数。
CommunicateInfo(&communicateData);
int input = 0;
do
{
// 调用打印菜单函数。
Menu();
scanf(" %d", &input);
switch (input)
{
case 1:
system("cls");
// 调用通讯录数组区增加函数。
CommunicateAdd(&communicateData);
break;
case 2:
system("cls");
// 调用通讯录数组区删除函数。
CommunicateDelete(&communicateData);
break;
case 3:
system("cls");
CommunicateSearch(&communicateData);
break;
case 4:
system("cls");
CommunicateModfiy(&communicateData);
break;
case 5:
system("cls");
CommunicateShow(&communicateData);
break;
case 6:
system("cls");
CommunicateSort(&communicateData);
break;
case 0:
printf("小程序已退出-->\n");
break;
default:
system("cls");
printf("小程序暂时未开放次功能-->\n");
break;
}
system("pause");
} while (input);
return 0;
}
🥵Communicate.c功能代码
#include"Communicate.h"
// 打印菜单函数 - 实现
void Menu()
{
printf("########################################################\n");
printf("##----------------------功能目录----------------------##\n");
printf("##----------------------------------------------------##\n");
printf("## 1- Add 2- Delete ##\n");
printf("##----------------------------------------------------##\n");
printf("## 3- Search 4- Modfiy ##\n");
printf("##----------------------------------------------------##\n");
printf("## 5- Show 6- Sort ##\n");
printf("##----------------------------------------------------##\n");
printf("## 0- Exit ##\n");
printf("########################################################\n");
printf("请以数字的形式选择功能-->\n");
}
// 打印进度条函数 - 实现
void ProgressBar()
{
char bar[BAR_NUM];
char symbol[] = { '|','/','-','\\' };
memset(bar, '\0', sizeof(bar));
// 初始化完成后,开始进行打印。
int i = 0;
for (i = 0; i < BAR_NUM; i++)
{
printf("[%-100s][%-3d%%][%c]\r", bar, i, symbol[i % 4]);
bar[i] = '#';
Sleep(10);
}
printf("\n");
}
// 录数组区初始化函数 - 实现
void CommunicateInfo(Communicate* pCommunicate)
{
assert(pCommunicate);
pCommunicate->pointer = 0;
memset(pCommunicate->peoMessData, '\0', sizeof(pCommunicate->peoMessData));
}
// 通讯录数组区增加函数 - 实现
void CommunicateAdd(Communicate* pCommunicate)
{
assert(pCommunicate);
if (pCommunicate->pointer >= DATA_MAX) // 判断通讯录个数是否已经满了。
{
printf("通讯录已经达限制-->\n");
return;
}
// 程序走到这里说明通讯录的个数没有满,可以继续存放个人信息。
printf("请输入存储人 - 姓名:> ");
scanf("%s", &pCommunicate->peoMessData[pCommunicate->pointer].name);
printf("请输入存储人 - 年龄:> ");
scanf("%d", &pCommunicate->peoMessData[pCommunicate->pointer].age);
printf("请输入存储人 - 性别:> ");
scanf("%s", &pCommunicate->peoMessData[pCommunicate->pointer].gender);
printf("请输入存储人 - 电话:> ");
scanf("%s", &pCommunicate->peoMessData[pCommunicate->pointer].phone);
printf("请输入存储人 - 家庭住址:> ");
scanf("%s", &pCommunicate->peoMessData[pCommunicate->pointer].address);
// 读进度条 , 提示保存成功字样 - 将全局指针加1。
ProgressBar();
printf("保存成功-->\n");
pCommunicate->pointer++;
//
}
// 通讯录数组区显示函数 - 实现。
void CommunicateShow(Communicate* pCommunicate)
{
assert(pCommunicate);
// 读进度条
ProgressBar();
printf("%-10s\t%-3s\t%-4s\t%-11s\t%-50s\n","姓名","年龄","性别","电话","地址");
// 打印通讯录数组区的内容。
int i = 0;
for (i = 0; i < pCommunicate->pointer; i++)
{
printf("%-10s\t%-3d\t%-4s\t%-11s\t%-50s\n",pCommunicate->peoMessData[i].name,
pCommunicate->peoMessData[i].age,
pCommunicate->peoMessData[i].gender,
pCommunicate->peoMessData[i].phone,
pCommunicate->peoMessData[i].address);
}
}
// 以名字为查找内容的进行查找。
static int FindByName(Communicate* pCommunicate, char name[])
{
assert(pCommunicate);
// FOR循环遍历内容进行对比。
int i = 0;
for (i = 0; i < pCommunicate->pointer; i++)
{
if (strcmp(pCommunicate->peoMessData[i].name, name) == 0)
return i;
}
return -1;
}
// 通讯录数组区删除函数 - 实现。
void CommunicateDelete(Communicate* pCommunicate)
{
assert(pCommunicate);
char name[NAME_MAX] = { 0 };
int i = 0;
// 第一步判断通讯录数组区中是否有个人数据。
if (pCommunicate->pointer == 0)
{
printf("没有个人信息数据--->\n");
return;
}
// 程序走到这里说明通讯录中有相关的个人信息。
printf("请输入要删除个人信息的姓名---> ");
scanf(" %s", &name);
// 删除分为两个阶段:1、查找要删除人的名字 2、删除个人信息。
int pointPos = FindByName(pCommunicate, name);
if (pointPos == -1)
{
printf("没有该个人信息数据,请输入正确的姓名--->\n");
return;
}
// 程序走到这里说明通讯录数组中有要删除人的名字。
for (i = pointPos; i < pCommunicate->pointer-1; i++)
{
pCommunicate->peoMessData[i] = pCommunicate->peoMessData[i + 1];
}
// 读进度条 , 提示删除成功字样 - 将全局指针减1。
ProgressBar();
printf("删除成功-->\n");
pCommunicate->pointer--;
}
// 通讯录数组区查找函数 - 实现。
void CommunicateSearch(Communicate* pCommunicate)
{
assert(pCommunicate);
char name[NAME_MAX] = { 0 };
// 程序走到这里说明通讯录中有相关的个人信息。
printf("请输入要查找个人信息的姓名---> ");
scanf(" %s", &name);
// 删除分为两个阶段:1、查找要查找人的名字 2、查找个人信息。
int pointPos = FindByName(pCommunicate, name);
if (pointPos == -1)
{
printf("没有该个人信息数据,请输入正确的姓名--->\n");
return ;
}
// 程序走到这里说明通讯录数组中有要查找人的名字。
// 读进度条 , 提示删除成功字样 - 将全局指针减1。
ProgressBar();
printf("查询成功-->\n");
// 直接对指针指向的数据组进行打印。
printf("%-10s\t%-3s\t%-4s\t%-11s\t%-50s\n", "姓名", "年龄", "性别", "电话", "地址");
// 打印通讯录数组区的内容。
printf("%-10s\t%-3d\t%-4s\t%-11s\t%-50s\n", pCommunicate->peoMessData[pointPos].name,
pCommunicate->peoMessData[pointPos].age,
pCommunicate->peoMessData[pointPos].gender,
pCommunicate->peoMessData[pointPos].phone,
pCommunicate->peoMessData[pointPos].address);
}
// 通讯录数组区修改函数 - 声明
void CommunicateModfiy(Communicate* pCommunicate)
{
assert(pCommunicate);
char name[NAME_MAX] = { 0 };
// 程序走到这里说明通讯录中有相关的个人信息。
printf("请输入要修改个人信息的姓名---> ");
scanf(" %s", &name);
// 删除分为两个阶段:1、查找要查找人的名字 2、查找个人信息。
int pointPos = FindByName(pCommunicate, name);
if (pointPos == -1)
{
printf("没有该个人信息数据,请输入正确的姓名--->\n");
return;
}
// 程序走到这里说明通讯录数组中有要修改人的名字。
// 删除分为两个阶段:1、查找要查找人的名字 2、查找个人信息。
printf("要修改人的信息已经找到,接下来进行修改数据--->\n");
// 程序走到这里说明通讯录的个数没有满,可以继续存放个人信息。
printf("请输入存储人 - 姓名:> ");
scanf("%s", &pCommunicate->peoMessData[pointPos].name);
printf("请输入存储人 - 年龄:> ");
scanf("%d", &pCommunicate->peoMessData[pointPos].age);
printf("请输入存储人 - 性别:> ");
scanf("%s", &pCommunicate->peoMessData[pointPos].gender);
printf("请输入存储人 - 电话:> ");
scanf("%s", &pCommunicate->peoMessData[pointPos].phone);
printf("请输入存储人 - 家庭住址:> ");
scanf("%s", &pCommunicate->peoMessData[pointPos].address);
// 读进度条 , 提示保存成功字样 - 将全局指针加1。
ProgressBar();
printf("修改成功-->\n");
}
int CompareName(const void* num1, const void* num2)
{
assert(num1 && num2);
return strcmp(((PeopleMessage*)num2)->name, ((PeopleMessage*)num1)->name);
}
// 模拟qsort的Swap函数实现。
void Swap(char* num1, char* num2, int wigth)
{
int i = 0;
for (i = 0; i < wigth; i++)
{
char temp = *num1;
*num1 = *num2;
*num2 = temp;
num1++;
num2++;
}
}
// 模拟qsort函数的实现。
void MyQsort(void* base, int size, int wigth, int CompareName(const void* num1, const void* num2))
{
assert(base);
int i = 0;
for (i = 0; i < size-1; i++)
{
int j = 0;
for (j = 0; j < size - 1 - i; j++)
{
if (CompareName((char*)base + j * wigth, (char*)base + (j + 1) * wigth) > 0)
{
// 交换数据
Swap((char*)base + j * wigth, (char*)base + (j + 1) * wigth, wigth);
}
}
}
}
// 通讯录数组区排序函数 - 实现
void CommunicateSort(Communicate* pCommunicate)
{
// 调用qsort函数库实现排序。
//qsort(pCommunicate->peoMessData, pCommunicate->pointer, sizeof(PeopleMessage), CompareName);
// 调用自己编写的qsort函数库实现排序。
MyQsort(pCommunicate->peoMessData, pCommunicate->pointer, sizeof(PeopleMessage), CompareName);
ProgressBar();
printf("排序成功-->\n");
}
🥵Communicate.h头文件代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#define BAR_NUM 101 // 进度条长度
#define DATA_MAX 100 // 通讯录数据区总大小定义
#define NAME_MAX 10 // 通讯录数据区 - 名字 - 字符总大小定义。
#define GENDER_MAX 4 // 通讯录数据区 - 性别 - 字符总大小定义。
#define PHONE_MAX 11 // 通讯录数据区 - 电话 - 字符总大小定义。
#define ADDRESS_MAX 50 // 通讯录数据区 - 地址 - 字符总大小定义。
// 创建第一层结构体:人的基本信息。
typedef struct PeopleMessage
{
char name[NAME_MAX];
char gender[GENDER_MAX];
char phone[PHONE_MAX];
char address[ADDRESS_MAX];
int age;
}PeopleMessage;
// 创建第二层结构体:通讯录的全局内容。
typedef struct Communicate
{
PeopleMessage peoMessData[DATA_MAX];
int pointer;
}Communicate;
// 打印菜单函数 - 声明。
void Menu();
// 打印进度条函数 - 声明。
void ProgressBar();
// 录数组区初始化函数 - 声明。
void CommunicateInfo(Communicate* pCommunicate);
// 通讯录数组区增加函数 - 声明。
void CommunicateAdd(Communicate* pCommunicate);
// 通讯录数组区显示函数 - 声明。
void CommunicateShow(Communicate* pCommunicate);
// 通讯录数组区删除函数 - 声明。
void CommunicateDelete(Communicate* pCommunicate);
// 通讯录数组区查找函数 - 声明。
void CommunicateSearch(Communicate* pCommunicate);
// 通讯录数组区查找函数 - 声明
void CommunicateModfiy(Communicate* pCommunicate);
// 通讯录数组区排序函数 - 声明
void CommunicateSort(Communicate* pCommunicate);