通讯录-C/C++

问题描述

设计一个通讯录管理程序,要求程序采用模块化设计方法,程序应采用由主控程序调用各模块实现各个功能的方式。程序应具有如下功能:输入记录显示记录查找记录插入记录记录排序删除记录 等。数据存储采用外存存储形式,存放于外存的数据应进行加密处理。

设计分析

通讯录中的数据可以看作是由多条记录组成的一个二维表格,一行对应一条记录,每条记录都有同样的字段序列。在管理程序中对数据进行组织时,可以使用结构体(struct)来描述记录,结构体中的成员即就是记录中的各个字段。通过结构体数组即可以存放通讯录中的多条记录。数据在外存进行存取操作时,可以使用按记录存取的方式进行。

例如,可以采用如下形式定义通讯录对应的结构体:

cpp 复制代码
struct record {// 记录
	char name[20];
	char phone[12];
	char adress[50];
	char postcode[8];
	char e_mail[20];
}student[SIZE];

解决方案

通过定义以下各函数实现程序功能模块的功能,在主函数中调用各函数:

(1)通讯录管理菜单

cpp 复制代码
int menu_select() {// 菜单选择
	char s[80];
	int a;
	system("cls");// 清屏
	printf("\t\t***********欢迎进入通讯管理界面********\n\n");
	printf("\t\t\t0. 输入记录\n");
	printf("\t\t\t1. 显示记录\n");
	printf("\t\t\t2. 按姓名查找\n");
	printf("\t\t\t3. 按电话号码查找\n");
	printf("\t\t\t4. 插入记录 \n");
	printf("\t\t\t5. 按姓名排序\n");
	printf("\t\t\t6. 删除记录\n");
	printf("\t\t\t7. Quit\n");
	printf("\t\t***********************************************\n\n");
	do {
		printf("Enter you choice(0~7):");
		scanf("%s", s);
		a = atoi(s);// 将字符串转化成整型值
	} while (a < 0 || a>7);// 当输入小于0或大于7,将循环输入
	return a;
}

(2)输入记录

cpp 复制代码
int adduser() {// 添加记录
	printf("\t\t\t**************** 请输入用户信息 ****************\n");
	printf("\t\t\t输入姓名:\n");
	scanf("%s", student[num].name);
	printf("\t\t\t输入电话号码:\n");
	scanf("%s", student[num].phone);
	printf("\t\t\t输入地址:\n");
	scanf("%s", student[num].adress);
	printf("\t\t\t输入邮编:\n");
	scanf("%s", student[num].postcode);
	printf("\t\t\t输入e-mail:\n");
	scanf("%s", student[num].e_mail);
	num++;
	printf("\t\t\t是否继续添加?(Y/N):\n");
	if (getch() == 'y' || getch() == 'Y')// 输入大写和小写字母y都行
		adduser();// 再次调用添加记录
	return(0);
}

(3)显示记录

cpp 复制代码
void list() {// 显示记录
	int i;
	system("cls");// 清屏
	if (num != 0) {// 如果记录的数字不为0,逐个打印记录
		printf("\t\t\t*************** 以下为通讯录所有信息************\n");
		for (i = 0; i < num; i++) {
			printf("\t\t\t姓名:%s\n", student[i].name);
			printf("\t\t\t电话:%s\n", student[i].phone);
			printf("\t\t\t地址:%s\n", student[i].adress);
			printf("\t\t\t邮编:%s\n", student[i].postcode);
			printf("\t\t\te-mail:%s\n", student[i].e_mail);
			if (i + 1 < num) {
				system("pause");// 程序暂停
			}
		}
		printf("\t\t\t************************************************\n");
	}
	else// 如果记录数字为0,则程序中无记录
		printf("\t\t\t通讯录中无任何纪录\n");
	printf("\t\t\t按任意键返回主菜单:\n");
	getch();// 获取按下的任意键
	return;
}

(4)按姓名查找记录

cpp 复制代码
int searchbyname() {// 按姓名查找
	int mark = 0;// 定义一个变量作为标记
	int i;// 定义一个循环辅助变量
	printf("\t\t\t***************** 按姓名查找 *******************\n");
	char name[20];
	printf("\t\t\t请输入姓名:\n");
	scanf("%s", name);
	for (i = 0; i < num; i++) {
		if (strcmp(student[i].name, name) == 0) {// 将输入的姓名与存入的比较,相同为0进行打印
			printf("\t\t\t************* 以下是您查找的用户信息 ***********\n");
			printf("\t\t\t姓名: %s", student[i].name);
			printf("\t\t\t电话: %s", student[i].phone);
			printf("\t\t\t地址: %s", student[i].adress);
			printf("\t\t\te-mail:%s", student[i].e_mail);
			printf("\t\t\t************************************************\n");
			mark++;// 标记加1
			if ((i + 1) < num) {// 如果遍历到某一位置加1还是比所有记录的数小,选择继续查找或终止查找
				printf("\t\t\t是否继续查找相同名字的用户信息:(y/n)\n");
				if (getch() == 'y' || getch() == 'Y') {// 输入y则继续查找
					continue;
				}
				else
					return(0);
			}
			else {
				printf("\t\t\t按任意键返回主菜单");
				getch();// 获取按下的任意键
				return(0);
			}
		}
	}
	if (mark == 0) {// 如果mark的值为0,表示没有此名字的用户记录
		printf("\t\t\t没有相同姓名的用户纪录\n");
		printf("\t\t\t按任意键返回主菜单\n");
		getch();// 获取按下的任意键
		return(0);
	}
	return 0;
}

(5)按电话号码查找记录

cpp 复制代码
int searchbyphone() {// 按电话号码查找
	int mark = 0;// 定义一个变量用于标记
	int i;// 定义一个循环辅助变量
	printf("\t\t\t****************** 按电话查找 ******************\n");
	char phone[10];
	printf("\t\t\t请输入电话号码:\n");
	scanf("%s", phone);
	for (i = 0; i < num; i++) {
		if (strcmp(student[i].phone, phone) == 0) {// 将输入的电话号码与存入的比较,相同为0进行打印 
			printf("\t\t\t************** 以下是您查找的用户信息 **********\n");
			printf("\t\t\t姓名: %s", student[i].name);
			printf("\t\t\t电话: %s", student[i].phone);
			printf("\t\t\t地址: %s", student[i].adress);
			printf("\t\t\te-mail:%s", student[i].e_mail);
			printf("\t\t\t************************************************\n");
			printf("\t\t\t按任意键返回主菜单\n");
			mark++;// 标记加1
			getch();// 获取按下的任意键
			return(0);
		}
	}
	if (mark == 0) {// 如果mark的值为0,表示没有此电话号码的记录
		printf("\t\t\t没有改用户的信息\n");
		printf("\t\t\t按任意键返回主菜单\n");
		getch();// 获取按下的任意键
		return(0);
	}
	return(0);
}

(6)按电话号码删除记录

cpp 复制代码
void deletebyphone() {// 按电话号码删除记录
	int i, j;// 定义循环辅助变量
	int deletemark = 0;// 定义变量用于标记
	char phone[20];
	printf("\t\t\t请输入要删除用户电话号码:\n");
	scanf("%s", phone);
	if (num == 0) {// 记录变量为0,则无输入记录
		printf("\t\t\t对不起,文件中无任何纪录\n");
		printf("\t\t\t按任意键返回主菜单\n");
		getch();// 获取按下的任意键
		return;
	}
	for (i = 0; i < num; i++) {
		if (strcmp(student[i].phone, phone) == 0) {// 比较输入的电话号码与存入的电话号码比较,相同为0
			printf("\t\t\t以下是您要删除的用户纪录:\n");
			printf("\t\t\t姓名: %s", student[i].name);
			printf("\t\t\t电话: %s", student[i].phone);
			printf("\t\t\t地址: %s", student[i].adress);
			printf("\t\t\te-mail:%s", student[i].e_mail);
			printf("\t\t\t是否删除?(y/n)");
			if (getch() == 'y' || getch() == 'Y') {// 判断是否确认删除
				for (j = i; j < num - 1; j++)// 循环将后一条记录前移1个
					student[j] = student[j + 1];
				num--;
				deletemark++;// 删除标记加1
				printf("\t\t\t删除成功");
				printf("\t\t\t是否继续删除?(y/n)");
				if (getch() == 'y' || getch() == 'Y')// 判断是否继续删除
					deletebyphone();// 调用按电话号码删除记录
				return;
			}
			else
				return;
		}
		continue;
	}
	if (deletemark == 0) {// 判断是否有此电话号码的用户信息
		printf("\t\t\t没有该用户的纪录");
		printf("\t\t\t是否继续删除?(y/n)");
		if (getch() == 'y' || getch() == 'Y')// 判断是否继续删除
			deletebyphone();// 调用按电话号码删除记录
		return;
	}
	return;
}

(7)按姓名删除记录

cpp 复制代码
void deletebyname() {// 按姓名删除记录
	int a = 0;// 循环辅助变量
	int findmark = 0;// 查找标记
	int j;// 循环辅助变量
	int deletemark = 0;// 删除标记
	int i;// 循环辅助变量
	char name[20];
	printf("\t\t\t请输入要删除用户姓名:\n");
	scanf("%s", name);
	for (i = a; i < num; i++) {
		if (strcmp(student[i].name, name) == 0) {// 比较输入的姓名与存入的姓名比较,相同为0
			printf("\t\t\t以下是您要删除的用户纪录:");
			findmark++;// 查找标记加1
			printf("\t\t\t________________________________");
			printf("\t\t\t姓名: %s", student[i].name);
			printf("\t\t\t电话: %s", student[i].phone);
			printf("\t\t\t地址: %s", student[i].adress);
			printf("\t\t\te-mail:%s", student[i].e_mail);
			printf("\t\t\t________________________________");
			printf("\t\t\t是否删除?(y/n)");
			if (getch() == 'y' || getch() == 'Y') {
				for (j = i; j < num - 1; j++)// 遍历记录个数-1,将后一个数据逐个替代前一个数据
					student[j] = student[j + 1];
				num--;// 总记录数减1
				deletemark++;// 删除标记加1
				printf("\t\t\t删除成功");
				if ((i + 1) < num) {
					printf("\t\t\t是否继续删除相同姓名的用户信息?(y/n)");
					if (getch() == 'y') {
						a = i;// 将当前i值赋给a用于后续继续删除相同姓名的用户信息
						continue;
					}
				}
				printf("\t\t\t是否继续删除?(y/n)");
				if (getch() == 'y')// 判断是否继续删除
					deletebyname();// 调用按姓名删除记录
				return;
			}
			if ((i + 1) < num) {// 判断是否将所有用户信息遍历完
				printf("\t\t\t是否继续删除相同姓名的用户信息?(y/n)");
				if (getch() == 'y' || getch() == 'Y') {// 判断是否继续删除相同姓名的用户信息
					a = i;// 将当前i值赋给a用于后续继续删除相同姓名的用户信息
					continue;
				}
			}
		}
		else
			continue;
	}
	if ((deletemark == 0) && (findmark == 0)) {// 判断删除标记和查找标记是否同时为0,为0则没有该用户信息
		printf("\t\t\t没有该用户的纪录");
		printf("\t\t\t是否继续删除?(y/n)");
		if (getch() == 'y' || getch() == 'Y')// 判断是否继续删除
			deletebyname();// 调用按姓名删除记录
		return;
	}
	else if (findmark != 0) {// 判断查找标记不为0,则没有重名
		printf("\t\t\t没有重名信息");
		printf("\t\t\t没有该用户的纪录");
		printf("\t\t\t是否继续删除?(y/n)");
		if (getch() == 'y' || getch() == 'Y')// 判断是否继续删除
			deletebyname();// 调用按姓名删除记录
		return;
	}
}

(8)删除记录

cpp 复制代码
int dele() {// 删除记录
	char choic;
	printf("\t\t\t1-按电话号码删除 2-按姓名删除");
	printf("\t\t\t请选择:");
	choic = getch();// 从键盘获取字符
	switch (choic) {
	case '1':deletebyphone(); break;// 按电话号码删除
	case '2':deletebyname(); break;// 按姓名删除
	}
	return(0);
}

(9)按姓名排序

cpp 复制代码
int sortbyname() {// 按姓名排序
	int i, j;// 循环辅助变量
	struct record tmp;
	for (i = 1; i < num; i++) {
		if (strcmp(student[i].name, student[i - 1].name) < 0) {// 比较相邻两个姓名小于0时,则i位置的姓名要排在前面
			tmp = student[i];
			j = i - 1;
			do {
				student[j + 1] = student[j];
				j--;
			} while ((strcmp(tmp.name, student[j].name) < 0 && j >= 0));
			student[j + 1] = tmp;
		}
	}
	printf("\t\t\t排序成功,是否显示?(y/n)");
	if (getch() == 'y')// 是否显示
		list();// 调用显示记录
	return(0);
}

(10)读取外存文件数据

cpp 复制代码
void readfile() {
	/*从文件student_address_book.dat首部开始,按记录长度sizeof(struct record)*/
	/*循环读出每条记录,直至文件尾部;每读出一条记录,则调用encrypt()函数*/
	/*对相应字段进行解密处理,并使记录计数器num加1,统计出记录总数。 */
	FILE* ptr = fopen("student_address_book.dat", "r");//打开文件
	if (ptr == NULL) {//判断文件是否成功打开
		printf("open file student_address_book.dat打开失败");
		return;
	}
	num = 0;
	while (fread(&student[num], sizeof(struct record), 1, ptr) == 1) {//循环读取每条记录并进行解密
		encrypt(student[num].name);
		encrypt(student[num].phone);
		encrypt(student[num].adress);
		encrypt(student[num].postcode);
		encrypt(student[num].e_mail);
		num++;
	}
	fclose(ptr);//关闭文件
	ptr = NULL;//将文件设置为空
}

(11)向外存文件写入数据

cpp 复制代码
void writefile() {
	/*根据记录总数num,从首条记录即结构体数组首元素student[0]开始, */
	/*调用encrypt()函数对相应字段进行加密处理,并将当前记录整体写入*/
	/*文件student_address_book.dat中,直至最后一条记录。 */
	/*也可以先对所有记录进行加密处理,然后整体一次性写入文件。 */
	FILE* ptw = fopen("student_address_book.dat", "w");//打开文件
	if (ptw == NULL) {//判断文件是否成功打开
		printf("open file student_address_book.dat打开失败");
		return;
	}
	int i = 0;//循环辅助变量
	for (i = 0; i < num; i++) {//把联系人信息循环写入文件中并进行加密处理
		encrypt(student[i].name);
		encrypt(student[i].phone);
		encrypt(student[i].adress);
		encrypt(student[i].postcode);
		encrypt(student[i].e_mail);
		fwrite(&student[i], sizeof(struct record), 1, ptw);//将数据整体写入文件
	}
	fclose(ptw);//关闭文件
	ptw = NULL;//将文件设置为空
}

(12)用户信息加密处理

cpp 复制代码
void encrypt(char* pwd) {//对数据进行加密操作
	/*与15(二进制码是00001111)异或,实现低四位取反,高四位保持不变*/
	while (*pwd != '\0') {//循环遍历数组
		*pwd = *pwd ^ 15;//将每条数据与15进行异或 
		pwd++;
	}
}

(13)主函数

cpp 复制代码
int main() {
	printf("\t\t************************************************\n");
	printf("\t\t***************欢迎进入通讯录*******************\n");
	printf("\t\t*************************************************\n");
	printf("按任意键进入主菜单\n");
	readfile();//读取文件里的内容
	getch();
	int selectnum;
	while (1) {
		selectnum = menu_select();
		switch (selectnum) {
			case 0:
			{
				adduser();// 调用添加记录
				break;
			}
			case 1:
			{
				list();// 调用显示记录
				break;
			}
			case 2:
			{
				searchbyname();// 调用按姓名查找
				break;
			}
			case 3:
			{
				searchbyphone();// 调用按电话号码查找
				break;
			}
			case 4:
			{
				adduser();// 调用添加记录
				break;
			}
			case 5:
			{
				sortbyname();// 调用按姓名排序
				break;
			}
			case 6:
			{
				dele();// 调用删除记录
				break;
			}
			case 7:
			{
				printf("BYE BYE!\n");
				system("pause");// 程序暂停
				writefile();//将程序中的数据写入文件
				getchar();// 从缓冲区读取一个字符
				exit(0);// 退出程序
			}
		}
	}
	getchar();// 从缓冲区读取一个字符
	return 0;
}

最终整合代码

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<conio.h>

#define SIZE 100

struct record {// 记录
	char name[20];
	char phone[12];
	char adress[50];
	char postcode[8];
	char e_mail[20];
}student[SIZE];

int num;

int menu_select() {// 菜单选择
	char s[80];
	int a;
	system("cls");// 清屏
	printf("\t\t***********欢迎进入通讯管理界面********\n\n");
	printf("\t\t\t0. 输入记录\n");
	printf("\t\t\t1. 显示记录\n");
	printf("\t\t\t2. 按姓名查找\n");
	printf("\t\t\t3. 按电话号码查找\n");
	printf("\t\t\t4. 插入记录 \n");
	printf("\t\t\t5. 按姓名排序\n");
	printf("\t\t\t6. 删除记录\n");
	printf("\t\t\t7. Quit\n");
	printf("\t\t***********************************************\n\n");
	do {
		printf("Enter you choice(0~7):");
		scanf("%s", s);
		a = atoi(s);// 将字符串转化成整型值
	} while (a < 0 || a>7);// 当输入小于0或大于7,将循环输入
	return a;
}

int adduser() {// 添加记录
	printf("\t\t\t**************** 请输入用户信息 ****************\n");
	printf("\t\t\t输入姓名:\n");
	scanf("%s", student[num].name);
	printf("\t\t\t输入电话号码:\n");
	scanf("%s", student[num].phone);
	printf("\t\t\t输入地址:\n");
	scanf("%s", student[num].adress);
	printf("\t\t\t输入邮编:\n");
	scanf("%s", student[num].postcode);
	printf("\t\t\t输入e-mail:\n");
	scanf("%s", student[num].e_mail);
	num++;
	printf("\t\t\t是否继续添加?(Y/N):\n");
	if (getch() == 'y' || getch() == 'Y')// 输入大写和小写字母y都行
		adduser();// 再次调用添加记录
	return(0);
}

void list() {// 显示记录
	int i;
	system("cls");// 清屏
	if (num != 0) {// 如果记录的数字不为0,逐个打印记录
		printf("\t\t\t*************** 以下为通讯录所有信息************\n");
		for (i = 0; i < num; i++) {
			printf("\t\t\t姓名:%s\n", student[i].name);
			printf("\t\t\t电话:%s\n", student[i].phone);
			printf("\t\t\t地址:%s\n", student[i].adress);
			printf("\t\t\t邮编:%s\n", student[i].postcode);
			printf("\t\t\te-mail:%s\n", student[i].e_mail);
			if (i + 1 < num) {
				system("pause");// 程序暂停
			}
		}
		printf("\t\t\t************************************************\n");
	}
	else// 如果记录数字为0,则程序中无记录
		printf("\t\t\t通讯录中无任何纪录\n");
	printf("\t\t\t按任意键返回主菜单:\n");
	getch();// 获取按下的任意键
	return;
}

int searchbyname() {// 按姓名查找
	int mark = 0;// 定义一个变量作为标记
	int i;// 定义一个循环辅助变量
	printf("\t\t\t***************** 按姓名查找 *******************\n");
	char name[20];
	printf("\t\t\t请输入姓名:\n");
	scanf("%s", name);
	for (i = 0; i < num; i++) {
		if (strcmp(student[i].name, name) == 0) {// 将输入的姓名与存入的比较,相同为0进行打印
			printf("\t\t\t************* 以下是您查找的用户信息 ***********\n");
			printf("\t\t\t姓名: %s", student[i].name);
			printf("\t\t\t电话: %s", student[i].phone);
			printf("\t\t\t地址: %s", student[i].adress);
			printf("\t\t\te-mail:%s", student[i].e_mail);
			printf("\t\t\t************************************************\n");
			mark++;// 标记加1
			if ((i + 1) < num) {// 如果遍历到某一位置加1还是比所有记录的数小,选择继续查找或终止查找
				printf("\t\t\t是否继续查找相同名字的用户信息:(y/n)\n");
				if (getch() == 'y' || getch() == 'Y') {// 输入y则继续查找
					continue;
				}
				else
					return(0);
			}
			else {
				printf("\t\t\t按任意键返回主菜单");
				getch();// 获取按下的任意键
				return(0);
			}
		}
	}
	if (mark == 0) {// 如果mark的值为0,表示没有此名字的用户记录
		printf("\t\t\t没有相同姓名的用户纪录\n");
		printf("\t\t\t按任意键返回主菜单\n");
		getch();// 获取按下的任意键
		return(0);
	}
	return 0;
}

int searchbyphone() {// 按电话号码查找
	int mark = 0;// 定义一个变量用于标记
	int i;// 定义一个循环辅助变量
	printf("\t\t\t****************** 按电话查找 ******************\n");
	char phone[10];
	printf("\t\t\t请输入电话号码:\n");
	scanf("%s", phone);
	for (i = 0; i < num; i++) {
		if (strcmp(student[i].phone, phone) == 0) {// 将输入的电话号码与存入的比较,相同为0进行打印 
			printf("\t\t\t************** 以下是您查找的用户信息 **********\n");
			printf("\t\t\t姓名: %s", student[i].name);
			printf("\t\t\t电话: %s", student[i].phone);
			printf("\t\t\t地址: %s", student[i].adress);
			printf("\t\t\te-mail:%s", student[i].e_mail);
			printf("\t\t\t************************************************\n");
			printf("\t\t\t按任意键返回主菜单\n");
			mark++;// 标记加1
			getch();// 获取按下的任意键
			return(0);
		}
	}
	if (mark == 0) {// 如果mark的值为0,表示没有此电话号码的记录
		printf("\t\t\t没有改用户的信息\n");
		printf("\t\t\t按任意键返回主菜单\n");
		getch();// 获取按下的任意键
		return(0);
	}
	return(0);
}

void deletebyphone() {// 按电话号码删除记录
	int i, j;// 定义循环辅助变量
	int deletemark = 0;// 定义变量用于标记
	char phone[20];
	printf("\t\t\t请输入要删除用户电话号码:\n");
	scanf("%s", phone);
	if (num == 0) {// 记录变量为0,则无输入记录
		printf("\t\t\t对不起,文件中无任何纪录\n");
		printf("\t\t\t按任意键返回主菜单\n");
		getch();// 获取按下的任意键
		return;
	}
	for (i = 0; i < num; i++) {
		if (strcmp(student[i].phone, phone) == 0) {// 比较输入的电话号码与存入的电话号码比较,相同为0
			printf("\t\t\t以下是您要删除的用户纪录:\n");
			printf("\t\t\t姓名: %s", student[i].name);
			printf("\t\t\t电话: %s", student[i].phone);
			printf("\t\t\t地址: %s", student[i].adress);
			printf("\t\t\te-mail:%s", student[i].e_mail);
			printf("\t\t\t是否删除?(y/n)");
			if (getch() == 'y' || getch() == 'Y') {// 判断是否确认删除
				for (j = i; j < num - 1; j++)// 循环将后一条记录前移1个
					student[j] = student[j + 1];
				num--;
				deletemark++;// 删除标记加1
				printf("\t\t\t删除成功");
				printf("\t\t\t是否继续删除?(y/n)");
				if (getch() == 'y' || getch() == 'Y')// 判断是否继续删除
					deletebyphone();// 调用按电话号码删除记录
				return;
			}
			else
				return;
		}
		continue;
	}
	if (deletemark == 0) {// 判断是否有此电话号码的用户信息
		printf("\t\t\t没有该用户的纪录");
		printf("\t\t\t是否继续删除?(y/n)");
		if (getch() == 'y' || getch() == 'Y')// 判断是否继续删除
			deletebyphone();// 调用按电话号码删除记录
		return;
	}
	return;
}

void deletebyname() {// 按姓名删除记录
	int a = 0;// 循环辅助变量
	int findmark = 0;// 查找标记
	int j;// 循环辅助变量
	int deletemark = 0;// 删除标记
	int i;// 循环辅助变量
	char name[20];
	printf("\t\t\t请输入要删除用户姓名:\n");
	scanf("%s", name);
	for (i = a; i < num; i++) {
		if (strcmp(student[i].name, name) == 0) {// 比较输入的姓名与存入的姓名比较,相同为0
			printf("\t\t\t以下是您要删除的用户纪录:");
			findmark++;// 查找标记加1
			printf("\t\t\t________________________________");
			printf("\t\t\t姓名: %s", student[i].name);
			printf("\t\t\t电话: %s", student[i].phone);
			printf("\t\t\t地址: %s", student[i].adress);
			printf("\t\t\te-mail:%s", student[i].e_mail);
			printf("\t\t\t________________________________");
			printf("\t\t\t是否删除?(y/n)");
			if (getch() == 'y' || getch() == 'Y') {
				for (j = i; j < num - 1; j++)// 遍历记录个数-1,将后一个数据逐个替代前一个数据
					student[j] = student[j + 1];
				num--;// 总记录数减1
				deletemark++;// 删除标记加1
				printf("\t\t\t删除成功");
				if ((i + 1) < num) {
					printf("\t\t\t是否继续删除相同姓名的用户信息?(y/n)");
					if (getch() == 'y') {
						a = i;// 将当前i值赋给a用于后续继续删除相同姓名的用户信息
						continue;
					}
				}
				printf("\t\t\t是否继续删除?(y/n)");
				if (getch() == 'y')// 判断是否继续删除
					deletebyname();// 调用按姓名删除记录
				return;
			}
			if ((i + 1) < num) {// 判断是否将所有用户信息遍历完
				printf("\t\t\t是否继续删除相同姓名的用户信息?(y/n)");
				if (getch() == 'y' || getch() == 'Y') {// 判断是否继续删除相同姓名的用户信息
					a = i;// 将当前i值赋给a用于后续继续删除相同姓名的用户信息
					continue;
				}
			}
		}
		else
			continue;
	}
	if ((deletemark == 0) && (findmark == 0)) {// 判断删除标记和查找标记是否同时为0,为0则没有该用户信息
		printf("\t\t\t没有该用户的纪录");
		printf("\t\t\t是否继续删除?(y/n)");
		if (getch() == 'y' || getch() == 'Y')// 判断是否继续删除
			deletebyname();// 调用按姓名删除记录
		return;
	}
	else if (findmark != 0) {// 判断查找标记不为0,则没有重名
		printf("\t\t\t没有重名信息");
		printf("\t\t\t没有该用户的纪录");
		printf("\t\t\t是否继续删除?(y/n)");
		if (getch() == 'y' || getch() == 'Y')// 判断是否继续删除
			deletebyname();// 调用按姓名删除记录
		return;
	}
}

int dele() {// 删除记录
	char choic;
	printf("\t\t\t1-按电话号码删除 2-按姓名删除");
	printf("\t\t\t请选择:");
	choic = getch();// 从键盘获取字符
	switch (choic) {
	case '1':deletebyphone(); break;// 按电话号码删除
	case '2':deletebyname(); break;// 按姓名删除
	}
	return(0);
}

int sortbyname() {// 按姓名排序
	int i, j;// 循环辅助变量
	struct record tmp;
	for (i = 1; i < num; i++) {
		if (strcmp(student[i].name, student[i - 1].name) < 0) {// 比较相邻两个姓名小于0时,则i位置的姓名要排在前面
			tmp = student[i];
			j = i - 1;
			do {
				student[j + 1] = student[j];
				j--;
			} while ((strcmp(tmp.name, student[j].name) < 0 && j >= 0));
			student[j + 1] = tmp;
		}
	}
	printf("\t\t\t排序成功,是否显示?(y/n)");
	if (getch() == 'y')// 是否显示
		list();// 调用显示记录
	return(0);
}

void encrypt(char* pwd) {//对数据进行加密操作
	/*与15(二进制码是00001111)异或,实现低四位取反,高四位保持不变*/
	while (*pwd != '\0') {//循环遍历数组
		*pwd = *pwd ^ 15;//将每条数据与15进行异或 
		pwd++;
	}
}

void readfile() {
	/*从文件student_address_book.dat首部开始,按记录长度sizeof(struct record)*/
	/*循环读出每条记录,直至文件尾部;每读出一条记录,则调用encrypt()函数*/
	/*对相应字段进行解密处理,并使记录计数器num加1,统计出记录总数。 */
	FILE* ptr = fopen("student_address_book.dat", "r");//打开文件
	if (ptr == NULL) {//判断文件是否成功打开
		printf("open file student_address_book.dat打开失败");
		return;
	}
	num = 0;
	while (fread(&student[num], sizeof(struct record), 1, ptr) == 1) {//循环读取每条记录并进行解密
		encrypt(student[num].name);
		encrypt(student[num].phone);
		encrypt(student[num].adress);
		encrypt(student[num].postcode);
		encrypt(student[num].e_mail);
		num++;
	}
	fclose(ptr);//关闭文件
	ptr = NULL;//将文件设置为空
}

void writefile() {
	/*根据记录总数num,从首条记录即结构体数组首元素student[0]开始, */
	/*调用encrypt()函数对相应字段进行加密处理,并将当前记录整体写入*/
	/*文件student_address_book.dat中,直至最后一条记录。 */
	/*也可以先对所有记录进行加密处理,然后整体一次性写入文件。 */
	FILE* ptw = fopen("student_address_book.dat", "w");//打开文件
	if (ptw == NULL) {//判断文件是否成功打开
		printf("open file student_address_book.dat打开失败");
		return;
	}
	int i = 0;//循环辅助变量
	for (i = 0; i < num; i++) {//把联系人信息循环写入文件中并进行加密处理
		encrypt(student[i].name);
		encrypt(student[i].phone);
		encrypt(student[i].adress);
		encrypt(student[i].postcode);
		encrypt(student[i].e_mail);
		fwrite(&student[i], sizeof(struct record), 1, ptw);//将数据整体写入文件
	}
	fclose(ptw);//关闭文件
	ptw = NULL;//将文件设置为空
}

int main() {
	printf("\t\t************************************************\n");
	printf("\t\t***************欢迎进入通讯录*******************\n");
	printf("\t\t*************************************************\n");
	printf("按任意键进入主菜单\n");
	readfile();//读取文件里的内容
	getch();
	int selectnum;
	while (1) {
		selectnum = menu_select();
		switch (selectnum) {
			case 0:
			{
				adduser();// 调用添加记录
				break;
			}
			case 1:
			{
				list();// 调用显示记录
				break;
			}
			case 2:
			{
				searchbyname();// 调用按姓名查找
				break;
			}
			case 3:
			{
				searchbyphone();// 调用按电话号码查找
				break;
			}
			case 4:
			{
				adduser();// 调用添加记录
				break;
			}
			case 5:
			{
				sortbyname();// 调用按姓名排序
				break;
			}
			case 6:
			{
				dele();// 调用删除记录
				break;
			}
			case 7:
			{
				printf("BYE BYE!\n");
				system("pause");// 程序暂停
				writefile();//将程序中的数据写入文件
				getchar();// 从缓冲区读取一个字符
				exit(0);// 退出程序
			}
		}
	}
	getchar();// 从缓冲区读取一个字符
	return 0;
}
相关推荐
A懿轩A1 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
机器视觉知识推荐、就业指导1 小时前
C++设计模式:享元模式 (附文字处理系统中的字符对象案例)
c++
半盏茶香1 小时前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
Ronin3052 小时前
11.vector的介绍及模拟实现
开发语言·c++
✿ ༺ ོIT技术༻2 小时前
C++11:新特性&右值引用&移动语义
linux·数据结构·c++
字节高级特工2 小时前
【C++】深入剖析默认成员函数3:拷贝构造函数
c语言·c++
计算机学长大白3 小时前
C中设计不允许继承的类的实现方法是什么?
c语言·开发语言
唐诺8 小时前
几种广泛使用的 C++ 编译器
c++·编译器
XH华8 小时前
初识C语言之二维数组(下)
c语言·算法
冷眼看人间恩怨9 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget