通讯录(黑框)

标题我的第一个小项目——通讯录(黑框的)

附上源码(有错误欢迎大家留言)

#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>

// 链表的创建
typedef struct NODE
{
	int id;					  //联系人编号
	char *tel;				 //联系人电话号码
	char *name;				//联系人姓名
	struct NODE * pNext;	//存储下个联系人
}List;

// 分页链表
typedef struct Page {
	int TotalPage;			//总共的页数
	int CurrentPage;		//当前在第几页
	int TotalInfo;			//总共多少条消息
	int OnePageInfo;		//一页显示多少条消息
}Page;

int g_Menu;					//菜单编号,根据不同的编号调用不同的菜单

char g_Key;

/*================================================================================================*/
// 主菜单
void MainMenu();


/*================================================================================================*/
// 1、查看通讯录(分页功能、上一页、下一页,返回主菜单)

//分页的信息(对总条数进行处理,把处理后的数据放到分页的结构体中)
Page* GetPage(List *pHead, int num);  //num为一页显示多少条信息

//显示分页的信息(把每一页上的联系人给显示出来)
void ShowPage(List *pHead, Page *pPage);

//按键功能(吸取用户输入的字符,根据字符进行翻页)
char GetKey();

//小菜单(显示上一页、下一页等信息)
void ShowMenu(Page *pPage);

//翻页功能+把每页上的信息给显示出来,所以里面还会调用 ShowPage(List *pHead,Page *pPage)
void TurnPage(List *pHead, Page *pPage);

//查看功能(把链表的头传入,显示全部的信息)
void Browse(List *pHead);


/*================================================================================================*/
//2、 添加通讯录的功能

//自动获得id
int GetId();

//自动获得手机号
char* GetTel();

//自动获得姓名
char* GetName();

//获得联系人->获得节点
List* GetNode();

//将节点(联系人)添加到链表中
void AddNode(List **ppHead, List **ppEnd, List *pTemp);

//初始化数据,添加多少个联系人
void InitInfo(List **ppHead, List **ppEnd, int num);

//获得输入的字符串:姓名、手机号等
char* GetString();

//手动添加一个联系人,自己输入名字、电话号码
List* GetNodeIn();


/*================================================================================================*/
// 3 查询功能(输入关键字支持前缀模糊搜索,查询结果分页显示、附加菜单、重新查询)
void Query(List *pHead);


/*================================================================================================*/
//4 删除功能(查询、增加按钮删除信息、支持继续删除y)

//删除节点
void DeleteNode(List **ppHead, List **ppEnd, int id);

//删除操作
void DeleteInfo(List **ppHead, List **ppEnd);



/*================================================================================================*/
//5 修改功能(查询、增加按钮u修改信息)
void UpdateInfo(List *pHead);

int main() {
	srand((unsigned int)time(NULL));		//随机数种子
	List *pHead = NULL;    // 链表的头
	List *pEnd = NULL;     //链表的尾
	char c;

	InitInfo(&pHead, &pEnd, 101);     //添加101个联系人

	while (1) {
		MainMenu();
		c = GetKey();
		switch (c)
		{
		case '1':			//查看通讯录
			g_Menu = 1;
			Browse(pHead);
			break;
		case '2':			//添加信息
			AddNode(&pHead, &pEnd, GetNodeIn());
			break;
		case '3':
			g_Menu = 3;
			Query(pHead);
			break;
		case '4':
			g_Menu = 4;
			DeleteInfo(&pHead, &pEnd);
			break;
		case '5':
			g_Menu = 5;
			UpdateInfo(pHead);
			break;
		case 'q':
			exit(0);
			break;
		default:
			break;
		}

	}

	return 0;
}

// 主菜单
void MainMenu() {
	printf("1.查看通讯录\n");
	printf("2.添加信息\n");
	printf("3.查询信息\n");
	printf("4.删除信息\n");
	printf("5.修改信息\n");
	printf("q.退出\n");
}


/*================================================================================================*/
// 查看通讯录(分页功能、上一页、下一页,返回主菜单)

//分页的信息(对总条数进行处理,把处理后的数据放到分页的结构体中)num为一页显示多少条信息
Page* GetPage(List *pHead, int num) {
	Page *page = (Page *)malloc(sizeof(Page));
	page->OnePageInfo = num;
	page->CurrentPage = 0;
	page->TotalInfo = 0;
	page->TotalPage = 0;
	while (pHead != NULL)
	{
		(page->TotalInfo)++;
		pHead = pHead->pNext;
	}
	if (page->TotalInfo % page->OnePageInfo == 0) {
		page->TotalPage = page->TotalInfo / page->OnePageInfo;
	}
	else {
		page->TotalPage = page->TotalInfo / page->OnePageInfo + 1;
	}
	return page;
}

//显示分页的信息(把每一页上的联系人给显示出来)
void ShowPage(List *pHead, Page *pPage) {
	int begin = (pPage->CurrentPage - 1) * 10 + 1;
	int end = (pPage->CurrentPage) * 10;
	int count = 0;
	while (pHead != NULL) {
		count++;
		if (count >= begin && count <= end) {
			printf("%d	%s	%s\n", pHead->id, pHead->name, pHead->tel);

		}
		pHead = pHead->pNext;
	}
}

//按键功能(吸取用户输入的字符,根据字符进行翻页)
char GetKey() {
	char c, y;
	int flag = 1;
	while ((c = getchar()) != '\n' || flag) {   //防止在输入之前有个空格 用flag标记一下 确保循环执行一次
		y = c;								  //c = '\n'时就会返回'\n',用y记录下c的值,返回y
		flag = 0;
	}
	return y;
}

//小菜单(显示上一页、下一页等信息)
void ShowMenu(Page *pPage) {
	switch (g_Menu)
	{
	case 1:
		printf("当前第%d页  总共%d页  总共%d条  k上一页  m下一页  b返回主菜单\n", pPage->CurrentPage, pPage->TotalPage, pPage->TotalInfo);
		break;
	case 3:
		printf("当前第%d页  总共%d页  总共%d条  k上一页  m下一页  c重新查询  b返回主菜单\n", pPage->CurrentPage, pPage->TotalPage, pPage->TotalInfo);
		break;
	case 4:
		printf("当前第%d页  总共%d页  总共%d条  k上一页  m下一页  d删除信息  b返回主菜单\n", pPage->CurrentPage, pPage->TotalPage, pPage->TotalInfo);
		break;
	case 5:
		printf("当前第%d页  总共%d页  总共%d条  k上一页  m下一页  u修改信息  b返回主菜单\n", pPage->CurrentPage, pPage->TotalPage, pPage->TotalInfo);
		break;
	default:
		break;
	}

}

//翻页功能+把每页上的信息给显示出来,所以里面还会调用 ShowPage(List *pHead,Page *pPage)
void TurnPage(List *pHead, Page *pPage) {

	//因为初始化时默认当前页为0,查看时要把第一页给显示出来,所以给c赋值‘k’,确保开始显示出来第一页
	char c = 'm';

	while (1)
	{
		switch (c)
		{
		case 'm':			//下一页
			if (pPage->CurrentPage < pPage->TotalPage) {   //判断是否为最后一页
				pPage->CurrentPage++;
				ShowPage(pHead, pPage);        //把信息显示出来
				ShowMenu(pPage);               //在信息的下面显示出来小菜单
			}
			else {
				printf("已经是最后一页了\n");
			}
			break;
		case 'k':         //上一页
			if (pPage->CurrentPage > 1) {          //判断是否为第一页
				pPage->CurrentPage--;
				ShowPage(pHead, pPage);
				ShowMenu(pPage);
			}
			else {
				printf("当前已经是第一页了\n");
			}
			break;
		case 'b':             //返回主菜单
			return;
			break;
		case 'c':
			return;
			break;
		case 'd':
			return;
			break;
		case 'u':
			return;
			break;
		default:
			break;
		}
		c = GetKey();      //输入一个字母进行上一页下一页
		g_Key = c;
	}

}

//查看功能(把链表的头传入,显示全部的信息)
void Browse(List *pHead) {
	Page *pPage = GetPage(pHead, 10);
	TurnPage(pHead, pPage);
	free(pPage);           //用完之后清掉空间
	pPage = NULL;
}




/*================================================================================================*/
// 添加通讯录的功能

//自动获得id
int GetId() {
	static int id = 1;
	return id++;
}

//自动获得手机号
char* GetTel() {
	int i;
	char *tel = (char *)malloc(12);
	for (i = 0; i < 11; i++) {
		if (i == 0) {
			tel[i] = '1';
			continue;
		}
		if (i == 1) {
			if (rand() % 3 == 0) {
				tel[i] = '3';
				continue;
			}
			else if (rand() % 3 == 1) {
				tel[i] = '5';
				continue;
			}
			else {
				tel[i] = '8';
				continue;
			}
		}
		tel[i] = rand() % 10 + '0';
	}
	tel[i] = '\0';
	return tel;
}

//自动获得姓名
char* GetName() {
	int i;
	char *name = (char *)malloc(6);
	for (i = 0; i < 5; i++) {
		name[i] = rand() % 26 + 'a';
	}
	name[i] = '\0';
	return name;
}

//获得联系人->获得节点
List* GetNode() {
	List *pTemp = (List *)malloc(sizeof(List));
	pTemp->id = GetId();				//方便测试,应设置自动获取id,并且有序
	pTemp->name = GetName();			//自动获得名字
	pTemp->tel = GetTel();			//自动获得电话号码
	pTemp->pNext = NULL;
	return pTemp;
}

//将节点(联系人)添加到链表中
void AddNode(List **ppHead, List **ppEnd, List *pTemp) {
	//如果链表中没有节点
	if (*ppHead == NULL) {
		*ppHead = pTemp;
		*ppEnd = pTemp;
		return;
	}
	//如果有节点直接插入到尾
	(*ppEnd)->pNext = pTemp;
	*ppEnd = pTemp;
	return;
}

//初始化数据,添加多少个联系人
void InitInfo(List **ppHead, List **ppEnd, int num) {
	int i;
	for (i = 0; i < num; i++) {
		AddNode(ppHead, ppEnd, GetNode());
	}
}

//获得输入的字符串:姓名、手机号等
char* GetString() {
	char c;
	int count = 0;
	int size = 5;
	char *str = (char *)malloc(5);
	char *newstr = NULL;			//备用空间
	while ((c = getchar()) != '\n')
	{
		str[count] = c;
		count++;
		if (count + 1 == size) {
			str[count] = '\0';
			size += 5;
			newstr = (char*)malloc(size);
			strcpy(newstr, str);
			free(str);
			str = newstr;
		}
	}
	str[count] = '\0';
	return str;
}

//手动添加一个联系人,自己输入名字、电话号码
List* GetNodeIn() {
	List *pTemp = (List *)malloc(sizeof(List));
	pTemp->id = GetId();
	printf("请输入您要添加的联系人的姓名:\n");
	pTemp->name = GetString();
	printf("请输入您要添加的联系人的手机号:\n");
	pTemp->tel = GetString();
	pTemp->pNext = NULL;
	return pTemp;
}



/*================================================================================================*/
// 3 查询功能(输入关键字支持前缀模糊搜索,查询结果分页显示、附加菜单、重新查询)
void Query(List *pHead) {
	//把模糊搜索出来的重新置成一个链表
	List *newpHead = NULL;
	List *newpEnd = NULL;
	List *pMark = pHead;
	List *pDel = NULL;
	char *str = NULL;
	char c;
	//因为要重新查询,所以有个大循环
	while (1)
	{
		//因为可以不确认,重新输入,这里也要用个循环
		while (1)
		{
			printf("请输入关键字:\n");
			str = GetString();
			printf("a确认  其他重新输出:\n");
			c = GetKey();
			if (c == 'a') {
				break;
			}
			else {
				free(str);
				str = NULL;
			}
		}
		pHead = pMark;   //每次遍历前都让头指针重新指回头,因为经过循环后,pHead = NULL
		//遍历链表去寻找有关键字的电话或者姓名
		while (pHead != NULL)
		{
			if (strncmp(pHead->name, str, strlen(str)) == 0 || strncmp(pHead->tel, str, strlen(str)) == 0) {
				List *pTemp = (List *)malloc(sizeof(List));
				pTemp->id = pHead->id;
				pTemp->tel = pHead->tel;
				pTemp->name = pHead->name;
				pTemp->pNext = NULL;
				AddNode(&newpHead, &newpEnd, pTemp);     //将查询到的联系人放入新的链表中
			}
			pHead = pHead->pNext;
		}
		Browse(newpHead);	//将查询到的结果分页显示出来、这里也要有个专门的小菜单、附加重新查询的功能

		// 查看完后可能又会进行一次查询,我们要把已经查询完的链表给清掉
		while (newpHead != NULL) {
			pDel = newpHead;
			newpHead = newpHead->pNext;
			free(pDel);
			pDel = NULL;
		}
		newpEnd = NULL;
		if (g_Key == 'b' || g_Key == 'd' || g_Key == 'u') {
			break;
		}
	}
}



/*================================================================================================*/
//4 删除功能(查询、增加按钮删除信息、支持继续删除y)

//删除节点
void DeleteNode(List **ppHead, List **ppEnd, int id) {
	List *pDel = NULL;
	List *pTemp = *ppHead;
	//判断一下是否头删除
	if (pTemp->id == id) {
		pDel = pTemp;
		pTemp = pTemp->pNext;
		free(pDel);
		pDel = NULL;
		return;
	}
	while (pTemp->pNext != NULL)
	{
		if (pTemp->pNext->id == id) {
			pDel = pTemp->pNext;
			pTemp->pNext = pTemp->pNext->pNext;
			free(pDel);
			pDel = NULL;
			if (pTemp->pNext == NULL) {
				*ppEnd = pTemp;
			}
		}
		pTemp = pTemp->pNext;
	}
	return;
}

//删除操作(可以继续删除)
void DeleteInfo(List **ppHead, List **ppEnd) {
	char *str = NULL;
	int id = 0;
	//首先要查询功能
	while (1)
	{
		Query(*ppHead);		//这里也要有个小菜单
		if (g_Key == 'b') {
			break;
		}
		printf("请输入您要删除的编号:\n");
		str = GetString();
		id = atoi(str);
		free(str);
		str = NULL;
		DeleteNode(ppHead, ppEnd, id);
		printf("按y继续删除  其他键返回主菜单\n");
		if (GetKey() != 'y') {
			break;
		}

	}

}



/*================================================================================================*/
//5 修改功能(查询、增加按钮u修改信息)
void UpdateInfo(List *pHead) {
	char *str = NULL;
	int id = 0;
	Query(pHead);
	printf("请输入您要修改的编号:\n");
	str = GetString();
	id = atoi(str);
	free(str);
	str = NULL;
	//遍历链表
	while (pHead != NULL)
	{
		if (pHead->id == id) {
			printf("请输入您要修改的姓名:\n");
			str = GetString();
			if (strlen(str) > 0) {
				free(pHead->name);
				pHead->name = str;
			}
			printf("请输入你要修改的手机号:\n");
			str = GetString();
			if (strlen(str) > 0) {
				free(pHead->tel);
				pHead->tel = str;
			}
		}


		pHead = pHead->pNext;
	}

	return;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值