#include"Contact.h"
int main()
{
int input;
//菜单
mune1();
//若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
//若输入为0,则判断为FALSE,跳出循环,退出通讯录
//创建通讯录:
Contact con;
//初始化函数:传入指针减少内存占用
InitContact(&con);
do {
//选项的输入
printf("请输入选项>:");
scanf("%d", &input);
//若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
//若输入为0,则判断为FALSE,跳出循环,退出通讯录
switch (input)
{
case ADD:
AddContact(&con);
break;
case DEL:
DelContact(&con);
break;
case SEARCH:
SearchContact(&con);
break;
case MODIFY:
ModifyContact(&con);
break;
case SHOW:
PrintContact(&con);
break;
case SORT:
SortContact(&con);
break;
case EXIT:
//保存到文件中
SaveContact(&con);
//销毁通讯录空间
DestroyContact(&con);
printf("退出通讯录\n");
break;
case Hide_Room:
//将当前写入文件保存到文件中
SaveContact(&con);
//销毁当前空间
DestroyContact(&con);
if (EncryptionContact())
{
//初始化原本空间,进入加密空间
Hide_InitContact(&con);
ShowHide();
//加密程序空间功能
func(&con);
goto judge;
}
else
{
goto judge;
}
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
judge:
return 0;
}
这里的基本思路就是:
这就是整体基本思路,在Test.c中一目了然。
1.我们描述一个人是复杂的,不是一个类型元素可以描述,比如姓名是字符串,年龄是整形,所以这里要采用自定义类型(结构体)来定义联系人信息:
//人的信息
typedef struct PeoInfo
{
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char address[ADDR_MAX];
char phone[PHONE_MAX];
char class[CLASS_MAX];
}PeoInfo;
这里我们定义了联系人的姓名、年龄、性别、地址、电话、以及分组;
2.个人通讯录相当于一个数组,元素是PeoInfo类型(联系人),这里我们可以采用静态数组,但实际上静态数组在后续的添加人数的时候,扩容比较呆板,所以这里我们选择的是顺序表的数据结构,这更方便于增添人数(当然链表也可以实现,后续补充)
//以顺序表实现
typedef struct Contact
{
//创建通讯录
PeoInfo* data;
int sz;//记录当前通讯录中的人数
int capacity;//记录当前通讯录的空间大小
}Contact;
通过这个代码我们就可以定义一个通讯录喽!当然接下来就要初始化通讯录,创建空间:
void InitContact(Contact* pc)
{
assert(pc);
pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX);
//在堆上申请空间
if (pc->data == NULL)
{
//检验是否申请成功,方便调试检验;
perror("malloc error");
}
pc->sz = 0;//最初空间人数
pc->capacity = INIT_MAX;//空间大小
}
这里的代码表示我们在堆上申请空间,申请了INIT_MAX个人数空间,OK这里通讯录的建立就完成咯!
通讯录具体有什么功能需要实现呢?这里只需要看一眼Test.h就一目了然了:
#pragma once
//类型的定义和声明放入头文件
#include
#include
#include
#include
#include
#include
//宏定义:
#define INIT_MAX 4
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 20
#define PHONE_MAX 12
#define CLASS_MAX 20
//选择菜单
void mune1();
void mune();
//枚举优化选项
enum input
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT,
Hide_Room = 110,
};
enum way
{
S_ByName = 1,
S_ByAge,
S_BySex,
S_ByAddr,
S_ByPhone,
S_ByClass,
};
//人的信息
typedef struct PeoInfo
{
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char address[ADDR_MAX];
char phone[PHONE_MAX];
char class[CLASS_MAX];
}PeoInfo;
//以顺序表实现
typedef struct Contact
{
//创建通讯录
PeoInfo* data;
int sz;
int capacity;
}Contact;
//初始化结构体
void InitContact(Contact* pc);
//扩容函数
void CapacityContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//删除联系人
void DelContact(Contact* pc);
//查找联系人
int SearchContact(const Contact* pc);
//查找方法:
// 按名字查找:
int SearchByName(const Contact* ps);
// 按年龄查找:
void SearchByAge(const Contact* ps);
// 按性别查找:
void SearchBySex(const Contact* ps);
// 按地址查找:
void SearchByAddr(const Contact* ps);
//按分组查找:
void SearchByClass(const Contact* ps);
// 按电话查找:
int SearchByPhone(const Contact* ps);
//修改联系人
void ModifyContact(Contact* pc);
//打印通讯录
void PrintContact(const Contact* pc);
//对通讯录成员进行排序
void SortContact(const Contact* pc);
//销毁通讯录内存空间
void DestroyContact(Contact* pc);
//保存通讯录到磁盘
void SaveContact(const Contact* pc);
//加载通讯录信息
void LondContact(Contact* pc);
//通讯录按照名字排序
void SortContact(const Contact* pc);
//通讯录成员信息交换
void Swap(PeoInfo* left, PeoInfo* right);
//双指针快排
void DP_QuickSort(PeoInfo* a, int left, int right);
//选择排序
void InsertSort(PeoInfo* a, int n);
//隐蔽空间定义
void Hide_InitContact(Contact* pc);
//隐蔽空间文件调用
void Hide_LondContact(Contact* pc);
//隐蔽空间密码登录
bool EncryptionContact();
//进入展示
void ShowHide();
//隐蔽空间文件保存
void Hide_SaveContact(const Contact* pc);
void func(Contact* pc);
可以看到.h文件里包含了很多内容:头文件定义,宏定义,自定义类型声明,函数声明等等;
接下来我们就具体实现一下上述功能函数:
这里就是最重要的地方咯,注意咯!!!
增添联系人代码实现:
void AddContact(Contact* pc)
{
assert(pc);
//自动扩容
CapacityContact(pc);
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].address);
printf("请输入联系人电话:");
scanf("%s", pc->data[pc->sz].phone);
printf("请设置联系人组别:");
scanf("%s", pc->data[pc->sz].class);
//这里sz记录当前通讯录人数
pc->sz++;
return;
}
运行效果:
增添联系人代码比较简单,但要注意一个问题,我们不断添加人数,会达到通讯录初始化的最大空间容量,所以我们需要考虑通讯录的扩容问题,如果我们按照最开始的想法用数组来存储联系人,则不能灵活的更改通讯录容量,需要手动更改代码空间比较麻烦,而用顺序表就可以很好解决这个问题;
void CapacityContact(Contact* pc)
{
if (pc->sz == pc->capacity)
{
pc->data = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * INIT_MAX * 2);
if (pc->data == NULL)
{
perror("realloc error");
}
pc->capacity = pc->capacity * 2;
printf("扩容成功\n");
}
}
当sz(当前通讯录人数)等于capacity(通讯录空间大小),则可以通过动态内存管理realloc,对原来的空间扩容,可以自动实现就十分方便;
1.删除联系人需要考虑,通讯录中是否储存了联系人,判断通讯录是否为空;
2.实际情况中,我们删除是根据人的姓名等信息,所以这里就要具体得到要删除对象的位置,这里就要用查找功能;
3.删除的思想:覆盖+下标索引减小,实现部分空间无法访问,间接的删除;
void DelContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录中无对象可操作!请先增加!");
mune1();
return;
}
int ret = SearchByName(pc);
if (ret == -1)
{
printf("删除失败请重新操作!");
mune1();
return;
}
int i = ret;
for (i = ret; i < pc->sz - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
printf("删除成功!\n");
//这里并不是完全删除,把\0发给int时默认为零,我们sz减减,就相当于访问不到那片空间
pc->sz--;
mune1();
}
运行效果:
1.这里就用最简单的方法:遍历通讯录对比实现
2.当然这里我提供了六种查找方式,当然最也可以算是五种,因为最后一种分类查找我把它定为分组;
总查找函数:
int SearchContact(const Contact* pc)
{
assert(pc);
//多种方式查找:
mune();
int input;
int ret = -1;
do {
//选项的输入
printf("请输入选项>:");
scanf("%d", &input);
//若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
//若输入为0,则判断为FALSE,跳出循环,
switch (input)
{
case S_ByName:
ret = SearchByName(pc);
break;
case S_ByAge:
SearchByAge(pc);
break;
case S_BySex:
SearchBySex(pc);
break;
case S_ByAddr:
SearchByAddr(pc);
break;
case S_ByPhone:
ret = SearchByPhone(pc);
break;
case S_ByClass:
SearchByClass(pc);
break;
case EXIT:
printf("查找完成,已经返回上一级\n");
mune1();
break;
default:
printf("该查找方式还待开发哦,请重新输入\n");
break;
}
} while (input);
return ret;
}
这里和test.c中相似,各类查找也差不多相同,这里我就列出一个比较常用的咯!
int SearchByName(const Contact* ps)
{
int i = 0;
char name[NAME_MAX];
int k = 1;
printf("请输入需要的联系人名字:");
scanf("%s", name);
for (i = 0; i < ps->sz; i++)
{
if (strcmp(name, ps->data[i].name) == 0)
{
//暂时不考虑重名
if (k == 1)
{
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
k--;
}
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].address,
ps->data[i].phone,
ps->data[i].class);
return i;
}
}
printf("无法找到该联系人信息\n");
return -1;
}
运行效果:
(这里存在缺陷:就是重名,因为这里函数要返回int,所以只能用于不重名查找,当然如果重名,我们多掉用两次就可以了,还有就是通讯录里重名应该有其他备注吧哈哈!)
这个代码也比较简单思路是:找到,并且输入新信息覆盖即可;
void ModifyContact(Contact* pc)
{
int ret = -1;
int i;
i = SearchByName(pc);
if (i != ret)
{
printf("请输入修改的内容(部分):\n");
printf("请输入联系人名字:");
scanf("%s", pc->data[i].name);
printf("请输入联系人年龄:");
scanf("%d", &(pc->data[i].age));
printf("请输入联系人性别:");
scanf("%s", pc->data[i].sex);
printf("请输入联系人地址:");
scanf("%s", pc->data[i].address);
printf("请输入联系人电话:");
scanf("%s", pc->data[i].phone);
}
}
运行效果:
这个功能应该最先完成,因为有了它方便调试每个功能的代码;
思路很简单:遍历打印(但要注意格式美化,不然可太挫了)
void PrintContact(const Contact* pc)
{
assert(pc);
int i = 0;
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
for (i = 0; i < pc->sz; i++)
{
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].address,
pc->data[i].phone,
pc->data[i].class);
}
}
这个功能实现就相对于前面的功能来说就有意思多了,来听我细细道来:
void Swap( int* left,int* right)
{
int t = *left;
*left = *right;
*right = t;
}
void Hoare_QuickSort(int* a, int left, int right)
{
//当二分到key值的一边只有一个数,或者没有时,便递归结束
if (left >= right)
return;
int end = right, begin = left;
int keyi = left;//这里表示的是key的下标索引
while (left < right)
{
//左边做key,右边先走,可以保证相遇位置比key更小
//right找小找到和找不到:
//找到:left没有找到大,直到相遇
//没找到:直接和left相遇,直接找到keyi值
while (left<right&&a[right] >= a[keyi])//right找小停下
right--;
while (left<right&&a[left] <= a[keyi])//left找大(保证相遇小于key)
left++;
Swap( &a[left],&a [right]);//交换两者,分配
}
//最后相遇位置便是key的位置:
Swap(&a[left], &a[keyi]);
keyi = left;
//key左边数组的处末索引:begin,keyi-1
Hoare_QuickSort(a, begin, keyi - 1);
//key右边数组的初末索引:keyi+1,end
Hoare_QuickSort(a, keyi + 1, end);
}
当然Hoare大佬提出的版本肯定是存在一定缺陷的,需要优化,但是这种思想真的厉害!
这里直接给出时间复杂度:O(NlgN)~O(N*N)
- 缺陷: 1.当所需要排的数列是顺序或者逆序时,快排时间复杂度是最大N的平方,严重影响快排的速度。2.快排在对数据少,并且部分具有一定顺序的排序并不是很完美。3.Hoare大佬的快排思路难以理解,思路理解困难。
对于上述缺陷我这里就不过度介绍了,但的确有优化方式(我会在后续的八大排序中介绍)在通讯录排序中用较优秀的方式来实现(这里就是和库里排序函数实现相近了):
void Swap(PeoInfo* left, PeoInfo* right)
{
PeoInfo t = *left;
*left = *right;
*right = t;
}
int GerMidNumi(PeoInfo* a, int left, int right)
{
int mid = (right + left) / 2;
if (strcmp(a[left].name, a[mid].name) > 0)
{
if (strcmp(a[mid].name, a[right].name) > 0)
{
return mid;
}
else if (strcmp(a[left].name, a[right].name) < 0)
{
return left;
}
else
{
return right;
}
}
else
{
if (strcmp(a[left].name, a[right].name) > 0)
{
return left;
}
else if (strcmp(a[mid].name, a[right].name) < 0)
{
return mid;
}
else
{
return right;
}
}
}
void DP_QuickSort(PeoInfo* a, int left, int right)
{
int end = right, begin = left;
if (left >= right)
return;
//小区间优化:
if ((right - left + 1) > 10)
{
//方案二:优化:三数取中:不是最小,最大的哪一个(优化更加明显)
int midi = GerMidNumi(a, left, right);
if (midi != left)
Swap(&a[left], &a[midi]);
int prev = left;
int cur = prev + 1;
int keyi = left;
while (cur <= right)
{
if (strcmp(a[cur].name, a[keyi].name) < 0 && ++prev != cur)
Swap(&a[cur], &a[prev]);
cur++;
}
Swap(&a[prev], &a[keyi]);
keyi = prev;
DP_QuickSort(a, begin, keyi - 1);
DP_QuickSort(a, keyi + 1, end);
}
else
{
InsertSort(a, right - left + 1);
}
}
void InsertSort(PeoInfo* a, int n)
{
for (int i = 1; i < n; i++)
{
int end = i - 1;
PeoInfo tmp = a[i];
// 将tmp插入到[0,end]区间中,保持有序
while (end >= 0)
{
if (strcmp(tmp.name, a[end].name) < 0)
{
a[end + 1] = a[end];
--end;
}
else
{
break;
}
}
a[end + 1] = tmp;
}
}
运行效果:
这里很有趣,但在这个部分就不过度介绍了,在后续博客会有详细介绍哈!
我们当前所写的代码都是在内存里写的,一旦关闭数据便会清除,所以需要把数据导入到本地磁盘中进行保存,这里就需要文件相关知识了。知识掌握了,就十分简单了!
void LondContact(Contact* pc)
{
FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "rb");
if (NULL == pf)
{
perror("LondContact error");
}
else
{
int i = 0;
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, pf))
{
CapacityContact(pc);
pc->data[i] = tmp;
pc->sz++;
i++;
}
fclose(pf);
pf = NULL;
}
}
void SaveContact(const Contact* pc)
{
FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "wb");
if (NULL == pf)
{
perror("SaveContact error");
}
else
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
}
fclose(pf);
pf = NULL;
printf("保存成功\n");
}
}
这就实现了通讯录的基本功能喽
这里我的通讯录是把分组定义为联系人的属性了的,所以只需要按照分组查找打印即可:
void SearchByClass(const Contact* ps)
{
{
int i = 0;
char class[CLASS_MAX];
int flag = 0;
int k = 1;
printf("请输入需要查找联系人的组别:");
scanf("%s", class);
for (i = 0; i < ps->sz; i++)
{
if (strcmp(class, ps->data[i].class) == 0)
{
flag = 1;
if (k == 1)
{
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
k--;
}
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].address,
ps->data[i].phone,
ps->data[i].class);
}
}
if (flag)
{
return;
}
else
{
printf("无法找到该联系人信息\n");
}
}
}
void ShowHide()
{
char arr1[] = "Welcome to Hide Room !!!";
char arr2[] = "########################";
int left = 0;
int right = strlen(arr1) - 1;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
Sleep(1000);
//清屏
system("cls");
left++;
right--;
}
printf("%s\n", arr1);
}
void Administrators(char* password)
{
char newpassword[20];
printf("请输入修改密码》:");
scanf("%s", newpassword);
strcpy(password, newpassword);
printf("修改成功\n");
}
bool EncryptionContact()
{
int i = 0;
char password[20] = { 0 };
char insure[20] = { "123456" };
//打开一个文件夹用来记录空间密码:
FILE* pf1 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "rb");
if (NULL == pf1)
{
perror("password1 error");
}
else
{
char tmp[20] = { 0 };
fread(&tmp, 20, 1, pf1);
strcpy(insure, tmp);
fclose(pf1);
pf1 = NULL;
}
//判断的主要函数:
printf("请输入进入密码》:");
for (i = 0; i < 3; i++)
{
scanf("%s", password);
if (0 == strcmp(password, insure))
{
return true;
}
else if (0==strcmp(password,"管理员入口"))
{
//进入管理员系统进行密码修改
Administrators(insure);
//存入密码文件中
FILE* pf2 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "wb");
if (NULL == pf2)
{
perror("password2 error");
}
else
{
fwrite(insure, 20, 1, pf2);
fclose(pf2);
pf2 = NULL;
printf("保存成功\n");
}
printf("请输入进入密码》:");
}
else
{
printf("第%d次密码输入错误\n", i + 1);
if (i < 2)
printf("请重新输入》:");
}
}
//linux操作系统实现
printf("密码输入三次错误!请在24小时后重试\n");
return false;
}
运行效果:
这里可以形成一个对比,就是代码没有封装可读性就很差,这里可以把写入和写出封装成函数。这里关于隐蔽空间其他功能大致相同就不过多介绍了。
Contact.c完整代码:
#include"Contact.h"
void mune()
{
printf("*******************************************************\n");
printf("********1.SearchByName 2.SearchByAge ***************\n");
printf("********3.SearchBySex 4.SearchByAddr ************\n");
printf("********5.SearchByPhone 6.SearchByclass ************\n");
printf("******************* 0.exit **************************\n");
printf("*******************************************************\n");
}
void mune1()
{
printf("**************************************\n");
printf("********1.ADD 2.DEL ***************\n");
printf("********3.SEARCH 4.MODIFY ************\n");
printf("********5.SHOW 6.SORT ************\n");
printf("********0.EXIT ************\n");
}
void func(Contact* pc)
{
int input;
mune1();
do {
printf("请输入选项>:");
scanf("%d", &input);
//若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
//若输入为0,则判断为FALSE,跳出循环,退出通讯录
switch (input)
{
case ADD:
AddContact(pc);
break;
case DEL:
DelContact(pc);
break;
case SEARCH:
SearchContact(pc);
break;
case MODIFY:
ModifyContact(pc);
break;
case SHOW:
PrintContact(pc);
break;
case SORT:
SortContact(pc);
break;
case EXIT:
//保存到文件中
Hide_SaveContact(pc);
//销毁通讯录空间
DestroyContact(pc);
printf("退出通讯录\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return;
}
void LondContact(Contact* pc)
{
FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "rb");
if (NULL == pf)
{
perror("LondContact error");
}
else
{
int i = 0;
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, pf))
{
CapacityContact(pc);
pc->data[i] = tmp;
pc->sz++;
i++;
}
fclose(pf);
pf = NULL;
}
}
//主要用于函数的实现操作,功能实现处
//动态内存处理
void InitContact(Contact* pc)
{
assert(pc);
pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX);
if (pc->data == NULL)
{
perror("malloc error");
}
pc->sz = 0;
pc->capacity = INIT_MAX;
//读取文件
LondContact(pc);
}
void CapacityContact(Contact* pc)
{
if (pc->sz == pc->capacity)
{
pc->data = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * INIT_MAX * 2);
if (pc->data == NULL)
{
perror("realloc error");
}
pc->capacity = pc->capacity * 2;
printf("扩容成功\n");
}
}
void AddContact(Contact* pc)
{
assert(pc);
//自动扩容
CapacityContact(pc);
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].address);
printf("请输入联系人电话:");
scanf("%s", pc->data[pc->sz].phone);
printf("请设置联系人组别:");
scanf("%s", pc->data[pc->sz].class);
pc->sz++;
return;
}
void DelContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录中无对象可操作!请先增加!");
mune1();
return;
}
int ret = SearchByName(pc);
if (ret == -1)
{
printf("删除失败请重新操作!");
mune1();
return;
}
int i = ret;
for (i = ret; i < pc->sz - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
printf("删除成功!\n");
//这里并不是完全删除,把\0发给int时默认为零,我们sz减减,就相当于访问不到那片空间
pc->sz--;
mune1();
}
int SearchContact(const Contact* pc)
{
assert(pc);
//多种方式查找:
mune();
int input;
int ret = -1;
do {
//选项的输入
printf("请输入选项>:");
scanf("%d", &input);
//若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
//若输入为0,则判断为FALSE,跳出循环,
switch (input)
{
case S_ByName:
ret = SearchByName(pc);
break;
case S_ByAge:
SearchByAge(pc);
break;
case S_BySex:
SearchBySex(pc);
break;
case S_ByAddr:
SearchByAddr(pc);
break;
case S_ByPhone:
ret = SearchByPhone(pc);
break;
case S_ByClass:
SearchByClass(pc);
break;
case EXIT:
printf("查找完成,已经返回上一级\n");
mune1();
break;
default:
printf("该查找方式还待开发哦,请重新输入\n");
break;
}
} while (input);
return ret;
}
int SearchByName(const Contact* ps)
{
int i = 0;
char name[NAME_MAX];
int k = 1;
printf("请输入需要的联系人名字:");
scanf("%s", name);
for (i = 0; i < ps->sz; i++)
{
if (strcmp(name, ps->data[i].name) == 0)
{
//暂时不考虑重名
if (k == 1)
{
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
k--;
}
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].address,
ps->data[i].phone,
ps->data[i].class);
return i;
}
}
printf("无法找到该联系人信息\n");
return -1;
}
void SearchByAge(const Contact* ps)
{
int i = 0;
int age;
int flag = 0;
int k = 1;
printf("请输入需要查找联系人的年龄:");
scanf("%d", &age);
for (i = 0; i < ps->sz; i++)
{
if (age == ps->data[i].age)
{
flag = 1;
if (k == 1)
{
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
k--;
}
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].address,
ps->data[i].phone,
ps->data[i].class);
}
}
if (flag)
{
return;
}
else
{
printf("无法找到该联系人信息\n");
}
}
void SearchBySex(const Contact* ps)
{
int i = 0;
char sex[SEX_MAX];
int flag = 0;
int k = 1;
printf("请输入需要查找联系人的性别:");
scanf("%s", sex);
for (i = 0; i < ps->sz; i++)
{
if (strcmp(sex, ps->data[i].sex) == 0)
{
flag = 1;
if (k == 1)
{
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
k--;
}
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].address,
ps->data[i].phone,
ps->data[i].class);
}
}
if (flag)
{
return;
}
else
{
printf("无法找到该联系人信息\n");
}
}
void SearchByAddr(const Contact* ps)
{
{
int i = 0;
char addr[ADDR_MAX];
int flag = 0;
int k = 1;
printf("请输入需要查找联系人的地址:");
scanf("%s", addr);
for (i = 0; i < ps->sz; i++)
{
if (strcmp(addr, ps->data[i].address) == 0)
{
flag = 1;
if (k == 1)
{
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
k--;
}
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].address,
ps->data[i].phone,
ps->data[i].class);
}
}
if (flag)
{
return;
}
else
{
printf("无法找到该联系人信息\n");
}
}
}
void SearchByClass(const Contact* ps)
{
{
int i = 0;
char class[CLASS_MAX];
int flag = 0;
int k = 1;
printf("请输入需要查找联系人的组别:");
scanf("%s", class);
for (i = 0; i < ps->sz; i++)
{
if (strcmp(class, ps->data[i].class) == 0)
{
flag = 1;
if (k == 1)
{
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
k--;
}
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].address,
ps->data[i].phone,
ps->data[i].class);
}
}
if (flag)
{
return;
}
else
{
printf("无法找到该联系人信息\n");
}
}
}
int SearchByPhone(const Contact* ps)
{
int i = 0;
char phone[PHONE_MAX];
int k = 1;
printf("请输入需要查找联系人电话号码:");
scanf("%s", phone);
for (i = 0; i < ps->sz; i++)
{
if (strcmp(phone, ps->data[i].phone) == 0)
{
if (k == 1)
{
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
k--;
}
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].address,
ps->data[i].phone,
ps->data[i].class);
return i;
}
}
printf("无法找到该联系人信息\n");
return -1;
}
void ModifyContact(Contact* pc)
{
int ret = -1;
int i;
i = SearchByName(pc);
if (i != ret)
{
printf("请输入修改的内容(部分):\n");
printf("请输入联系人名字:");
scanf("%s", pc->data[i].name);
printf("请输入联系人年龄:");
scanf("%d", &(pc->data[i].age));
printf("请输入联系人性别:");
scanf("%s", pc->data[i].sex);
printf("请输入联系人地址:");
scanf("%s", pc->data[i].address);
printf("请输入联系人电话:");
scanf("%s", pc->data[i].phone);
}
}
void PrintContact(const Contact* pc)
{
assert(pc);
int i = 0;
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
for (i = 0; i < pc->sz; i++)
{
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].address,
pc->data[i].phone,
pc->data[i].class);
}
}
void DestroyContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
pc = NULL;
}
void SaveContact(const Contact* pc)
{
FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "wb");
if (NULL == pf)
{
perror("SaveContact error");
}
else
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
}
fclose(pf);
pf = NULL;
printf("保存成功\n");
}
}
void SortContact(const Contact* pc)
{
assert(pc);
DP_QuickSort(pc->data, 0, pc->sz - 1);
printf("排序完成\n");
}
void Swap(PeoInfo* left, PeoInfo* right)
{
PeoInfo t = *left;
*left = *right;
*right = t;
}
int GerMidNumi(PeoInfo* a, int left, int right)
{
int mid = (right + left) / 2;
if (strcmp(a[left].name, a[mid].name) > 0)
{
if (strcmp(a[mid].name, a[right].name) > 0)
{
return mid;
}
else if (strcmp(a[left].name, a[right].name) < 0)
{
return left;
}
else
{
return right;
}
}
else
{
if (strcmp(a[left].name, a[right].name) > 0)
{
return left;
}
else if (strcmp(a[mid].name, a[right].name) < 0)
{
return mid;
}
else
{
return right;
}
}
}
void DP_QuickSort(PeoInfo* a, int left, int right)
{
int end = right, begin = left;
if (left >= right)
return;
//小区间优化:
if ((right - left + 1) > 10)
{
//方案二:优化:三数取中:不是最小,最大的哪一个(优化更加明显)
int midi = GerMidNumi(a, left, right);
if (midi != left)
Swap(&a[left], &a[midi]);
int prev = left;
int cur = prev + 1;
int keyi = left;
while (cur <= right)
{
if (strcmp(a[cur].name, a[keyi].name) < 0 && ++prev != cur)
Swap(&a[cur], &a[prev]);
cur++;
}
Swap(&a[prev], &a[keyi]);
keyi = prev;
DP_QuickSort(a, begin, keyi - 1);
DP_QuickSort(a, keyi + 1, end);
}
else
{
InsertSort(a, right - left + 1);
}
}
void InsertSort(PeoInfo* a, int n)
{
for (int i = 1; i < n; i++)
{
int end = i - 1;
PeoInfo tmp = a[i];
// 将tmp插入到[0,end]区间中,保持有序
while (end >= 0)
{
if (strcmp(tmp.name, a[end].name) < 0)
{
a[end + 1] = a[end];
--end;
}
else
{
break;
}
}
a[end + 1] = tmp;
}
}
void Hide_InitContact(Contact* pc)
{
assert(pc);
pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX);
if (pc->data == NULL)
{
perror("Hide_malloc error");
}
pc->sz = 0;
pc->capacity = INIT_MAX;
//读取文件
Hide_LondContact(pc);
}
void Hide_LondContact(Contact* pc)
{
FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\hide_contact.txt", "rb");
if (NULL == pf)
{
perror("Hide_LondContact error");
}
else
{
int i = 0;
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, pf))
{
CapacityContact(pc);
pc->data[i] = tmp;
pc->sz++;
i++;
}
fclose(pf);
pf = NULL;
}
}
void ShowHide()
{
char arr1[] = "Welcome to Hide Room !!!";
char arr2[] = "########################";
int left = 0;
int right = strlen(arr1) - 1;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
Sleep(1000);
system("cls");
left++;
right--;
}
printf("%s\n", arr1);
}
void Administrators(char* password)
{
char newpassword[20];
printf("请输入修改密码》:");
scanf("%s", newpassword);
strcpy(password, newpassword);
printf("修改成功\n");
}
bool EncryptionContact()
{
int i = 0;
char password[20] = { 0 };
char insure[20] = { "123456" };
FILE* pf1 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "rb");
if (NULL == pf1)
{
perror("password1 error");
}
else
{
char tmp[20] = { 0 };
fread(&tmp, 20, 1, pf1);
strcpy(insure, tmp);
fclose(pf1);
pf1 = NULL;
}
printf("请输入进入密码》:");
for (i = 0; i < 3; i++)
{
scanf("%s", password);
if (0 == strcmp(password, insure))
{
return true;
}
else if (0==strcmp(password,"管理员入口"))
{
Administrators(insure);
FILE* pf2 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "wb");
if (NULL == pf2)
{
perror("password2 error");
}
else
{
fwrite(insure, 20, 1, pf2);
fclose(pf2);
pf2 = NULL;
printf("保存成功\n");
}
printf("请输入进入密码》:");
}
else
{
printf("第%d次密码输入错误\n", i + 1);
if (i < 2)
printf("请重新输入》:");
}
}
//linux操作系统实现
printf("密码输入三次错误!请在24小时后重试\n");
return false;
}
void Hide_SaveContact(const Contact* pc)
{
FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\hide_contact.txt", "wb");
if (NULL == pf)
{
perror("Hide_SaveContact error");
}
else
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
}
fclose(pf);
pf = NULL;
printf("保存成功\n");
}
}
内存泄漏是必须注意的,这里开始malloc了空间,如果没有释放则会影响项目的速度,举个例子:
void DestroyContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
pc = NULL;
}
代码简单不累,相当实惠哈哈,所以这是要养成的习惯,在申请空间后一定记住手动free多余空间;
是不是还是有些区别的呢?
我们往往可以发现我们在写类似“项目”的时候,发现代码一长,是真的难调,一调就是一天,所以我们就要用一些技巧:
PS:好久没写博客咯,后续会抓紧的哈哈!美图献上(夹带私货),一起加油!