C语言实现 通讯录管理系统

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100
#define TRUE 1
#define FALSE 0
#define Status int
#define fname  "txl.txt"
typedef struct            //成员信息
{
	 char ID[12];
	 char name[12];
	 char mphone[12];
	 char addr[40];
	 char tel[16];
}
DataType;
typedef struct node          //数据结点
{
	DataType data;
	struct node *next;
}
Node;
typedef Node *Llist; //结点指针
char *menu_1[] = {
 "**********菜单*********\n",
 "1.添加好友信息\n",
 "2.列表好友信息\n",
 "3.搜索好友信息\n",
 "4.删除好友信息\n"
 "0.退出程序\n",
 "***********************\n" };
/*********************************************************************************************
函数名称:fgets_wrapper
参数:buffer输入缓冲区指针;buflen最大输入字符数,实际最大输入buflen-1; fp输入流
功能:重新封装fgets函数;
      解决fgets输入时最大长度超过buflen-1个字符后输入缓冲区遗留问题及输入包含'\n'问题
区别: scanf("%s",buffer) 输入字符串不能有空格;
      gets(buffer)输入字符串超过buffer长度导致溢出错误;
   fgets(buffer,buflen,fp)最大输入buflen-1个字符,'\n'会被输入;输入被截断后输入缓冲区有遗留
***********************************************************************************************/
char *fgets_wrapper(char *buffer, size_t buflen, FILE *fp)
{
	if (fgets(buffer, buflen, fp) != 0)
	{
		size_t len = strlen(buffer);
		if (len > 0 && buffer[len - 1] == '\n')
		{
			buffer[len - 1] = '\0';
		}
		//清空剩余的数据
		else
		{
			int ch;
			while ((ch = getc(fp)) != EOF && ch != '\n');
		}
		return buffer;
	}
	return 0;
}
char menu(char *str[], int len)     //菜单函数,让用户选择功能
{
	char sel;
	int i;
	for (i = 0; i < len; i++)
	{
		printf("%s", str[i]);
	}
	printf("请输入您的选择:");
	scanf(" %c", &sel);
	getchar();
	return sel;
}
Status InitList(Llist *L)       //初始化链表
{
	*L = (Llist)malloc(sizeof(Node)); //分配头结点的内存空间
	if (NULL == *L)                   //分配失败
	{
		return FALSE;
	}
	else                      //分配成功
	{
		(*L)->next = NULL;
		return TRUE;
	}
}
Status ListLength(Llist L)      //测量链表长度(返回成员个数)
{
	int i = 0;
	Llist p;
	p = L->next;
	while (NULL != p)
	{
		i++;
		p = p->next;
	}
	return i;
}
Status ListEmpty(Llist L)   //判断链表是否为空
{
	if (0 == ListLength(L))
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}
Status ListInsert(Llist *L, int i, DataType e)  //将e插入链表的第i个位置
{
	int j = 1;
	Llist p, q;
	if (i < 1 || i > ListLength(*L) + 1)
	{
		return FALSE;
	}
	p = (*L);
	while (NULL != p && j < i)     //p指向要插入位置的前一个
	{
		p = p->next;
		j++;
	}
	q = (Llist)malloc(sizeof(Node));
	//分配一个节点空间,将数据放入节点,再将节点插入链表
	if (NULL == q)
	{
		printf("内存分配失败,按回车键退出...\n");
		getchar();
		exit(0);
	}
	q->data = e;
	q->next = p->next;
	p->next = q;
	return TRUE;
}
Status GetElem(Llist L, int i, DataType *e)    //取链表中第i个位置的数据
{
	int j = 1;
	Llist p;
	if (i < 1 || i > ListLength(L))
	{
		return FALSE;
	}
	p = L;
	while (NULL != p && j < i)     //p指向要取数据位置的前一个
	{
		p = p->next;
		j++;
	}
	p = p->next;
	*e = p->data;
	return TRUE;
}
Status ListDelete(Llist *L, int i, DataType *e)   //删除链表中第i个位置的数据
{
	int j = 1;
	Llist p, q;
	if (i < 1 || i > ListLength(*L))
	{
		return FALSE;
	}
	p = (*L);
	while (NULL != p && j < i)     //p指向要删除数据位置的前一个
	{
		p = p->next;
		j++;
	}
	q = p->next; //先将要删位置的next赋给前一个位置的next
	p->next = q->next;
	//将删除位置数据用e返回,释放删除的节点
	*e = q->data;
	free(q);
	return TRUE;
}
Status ClearList(Llist *L)    //清空链表
{
	int i = 0;
	Llist p, q;
	if (NULL == (*L)->next)
	{
		return TRUE;
	}
	p = q = (*L)->next;
	do
	{
		p = p->next;
		free(q);
		i++;
		q = p;
	} while (NULL != p);
	//删除一个free一个,将头节点的指针置空
	(*L)->next = NULL;
	printf("cleared item = %d\n", i);

	return TRUE;
}
Status Input(Llist L, DataType *e)   //输入函数 
{
	Llist p;
	int i = 0;

	p = L->next;
	printf("请输入ID:");
	fgets_wrapper(e->ID, 12, stdin);
	for (p; NULL != p; p = p->next)        //判断输入ID是否存在,存在则重新输入
	{
		if (!strcmp(p->data.ID, e->ID))
		{
			printf("此ID已存在,请重新输入ID\n");
			Input(L, e);
			i++;
		}
	}
	if (1 == i)                    //通过i的值判断程序是否往下执行 
	{
		return TRUE;
	}
	else
	{
		printf("请输入姓名:");
		fgets_wrapper(e->name, 12, stdin);
		printf("请输入手机号:");
		fgets_wrapper(e->mphone, 12, stdin);
		printf("请输入住址:");
		fgets_wrapper(e->addr, 40, stdin);
		printf("请输入电话:");
		fgets_wrapper(e->tel, 16, stdin);
	}
	printf("按回车键继续...\n");
	getchar();
	return TRUE;
}
Status Output(DataType e)   //输出函数
{
	printf("好友ID:%s\n", e.ID);
	printf("姓名:%s\n", e.name);
	printf("手机号码:%s\n", e.mphone);
	printf("家庭住址:%s\n", e.addr);
	printf("公司电话:%s\n", e.tel);
	return TRUE;
}
void ListSort(Llist L)      //按姓名冒泡排序
{
	DataType temp;
	Llist p, q;
	for (p = L; NULL != p->next; p = p->next)
	{
		for (q = p->next; NULL != q; q = q->next)
		{
			if (strcmp(p->data.name, q->data.name) > 0)
			{
				temp = p->data;
				p->data = q->data;
				q->data = temp;
			}
		}
	}
}
Status List(Llist L)    //列表信息   先调用排序,再依次输出
{
	ListSort(L);
	int i;
	Llist p;
	if (NULL == L->next)
	{
		printf("当前还没有任何记录\n");
		printf("按回车键继续...\n");
		getchar();
	}
	else
	{
		p = L->next;
		i = 1;
		while (NULL != p)
		{
			printf("第%d条记录\n", i);
			Output(p->data);
			printf("\n");
			p = p->next;
			i++;
		}
		printf("按回车键继续...\n");
		getchar();
	}
	return TRUE;
}
Status *LocateList(Llist L, char *str)    //在链表中找名字与实参相同的数据,返回数据的位置
{
	//返回的数组中名字不相同的位置的值为-1,
	int i, j;
	Llist p;
	p = L->next;
	j = 0;
	int *a;
	a = (int *)malloc(sizeof(Node)); //为每一个Node大小的成员分配一个指针
	*(a + 0) = -1;                  //*(a+0)值为-1 不变,不使用
	if (NULL == L->next)
	{
		return a;
	}
	else
	{
		i = 1;
		while (NULL != p)

		{
			if (!strcmp(str, p->data.name))
				//相同则将位置i赋到数组的对应位置   
			{
				j++;
				*(a + j) = i;
				i++;
				p = p->next;
			}
			else
				//不同则将该位置对应的数组值置-1  
			{
				j++;
				*(a + j) = -1;
				i++;
				p = p->next;
			}
		}
		return a;
	}
}
Status LocateList_num(Llist L, char *str)      //在链表中找ID与实参相同的数据,返回数据的位置
{
	int i;
	Llist p;
	p = L->next;
	if (NULL == L->next)
	{
		return -1;
	}
	i = 1;
	while (NULL != p)
	{
		if (!strcmp(str, p->data.ID))  //找到返回位置i,没找到返回-1   
		{
			return i;
		}
		else
		{
			p = p->next;
			i++;
		}
	}
	return -1;
}
Status Query(Llist L)      //按姓名搜索信息
{
	char name[12];
	int i;
	DataType e;
	Status flag = 0;
	//标志flag判断是否搜索到信息
	int *q;
	printf("请输入姓名:");
	fgets_wrapper(name, 12, stdin);
	q = LocateList(L, name);
	for (i = 0; i <= ListLength(L); i++)        //只有一个输出一个    有多个同名则同名信息全部输出 
	{
		if (-1 != *(q + i))
		{
			printf("查询到记录,显示如下:\n");
			GetElem(L, *(q + i), &e);
			Output(e);
			flag = 1;
			//查询到信息,将flag置1
			printf("\n");
		}
	}
	if (0 == flag)
	{
		printf("查无此人,按回车键继续...");
		getchar();
	}
	else
	{
		printf("按回车键继续...\n");
		getchar();
	}
	return TRUE;
}
Status Delete(Llist *L)       //按姓名删除信息,同名则按ID删除
{
	char name[12];
	char ID[12];
	int *str;
	DataType e;
	int i = 0, j = 0;
	printf("请输入姓名:");
	fgets_wrapper(name, 12, stdin);
	str = LocateList(*L, name); //接收按姓名定位的返回值(数组)
	for (i = 1; i <= ListLength(*L); i++)
	{
		if (-1 != *(str + i))
		{
			j++;
			//判断返回数组中值为-1的个数  
		}
	}
	if (0 == j)                         //0个则没找到该信息 
	{
		printf("无此人,按回车键继续...\n");
		getchar();
	}
	else if (j == 1)
	{
		for (i = 1; i <= ListLength(*L); i++)
		{
			if (-1 != *(str + i))                   //找到一个,确定其位置,先输出一下再删除  
			{
				printf("有此人,信息如下:\n");

				GetElem(*L, *(str + i), &e);
				Output(e);
				ListDelete(L, *(str + i), &e);
				printf("已删除\n");
				printf("按回车键继续\n");
				getchar();

			}
		}
	}
	else
	{
		for (i = 1; i <= ListLength(*L); i++)          //有同名信息,逐个输出
		{
			if (-1 != *(str + i))
			{
				printf("有此人,信息如下:\n");
				GetElem(*L, *(str + i), &e);
				Output(e);
			}
		}
		printf("有多个同名好友,按ID号删除\n");
		printf("请输入ID:");
		fgets_wrapper(ID, 12, stdin);
		j = LocateList_num(*L, ID); //获取要删除ID的位置,先输出再删除即可
		if (-1 != j)
		{
			GetElem(*L, j, &e);
			Output(e);
			ListDelete(L, j, &e);
			printf("已删除\n");
			printf("按回车键继续...\n");
			getchar();
		}
		else
		{
			printf("查无此人,按回车键继续...\n");
			getchar();
		}
	}
	return TRUE;
}
Status Readfile(Llist *L)        //将文件里的数据读到链表中
{
	FILE *fp;
	DataType e;
	int i, size;
	if ((fp = fopen(fname, "a+")) == NULL)   //打开文件   标准I/O返回值为指针
	{
		perror("打开文件失败");
		return FALSE;
	}
	fseek(fp, 0, SEEK_END);
	//将文件指针移到文件尾
	size = ftell(fp) / sizeof(DataType); // 计算文件中数据的个数  ftell计算文件大小,除以数据类型的大小
	rewind(fp);                              //将文件指针移到文件头  与fseek(fp,0,SEEK_SET)功能一致
	for (i = 0; i < size; i++)
	{
		fread(&e, sizeof(DataType), 1, fp); //将数据一个一个读到e中
		ListInsert(L, ListLength(*L) + 1, e); //将e尾插进链表
	}
	fclose(fp);
	//标准I/O需要关闭文件
	return TRUE;
}

Status Writefile(Llist *L)          //将数据从链表中写入文件
{
	FILE *fp;
	DataType e;
	Llist p = (*L)->next;
	if ((fp = fopen(fname, "w+")) == NULL)     //打开文件
	{
		perror("打开文件失败");
		return FALSE;
	}
	while (p != NULL)                     //将数据逐个写入文件
	{
		e = p->data;
		fwrite(&e, sizeof(DataType), 1, fp);
		p = p->next;
	}
	fclose(fp); //关闭文件
	return TRUE;
}

int main(int argc, char *argv[])
{
	Llist txl;
	Status flag;
	DataType e;
	char sel;
	flag = InitList(&txl);
	//判断链表初始化是否成功
	if (!flag)
	{
		printf("内存分配失败,按回车键退出...\n");
		getchar();
		exit(0);
	}
	if (FALSE == Readfile(&txl))       //判断读文件是否成功
	{
		printf("文件打开失败\n");
		exit(1);
	}
	while (1)
	{
		sel = menu(menu_1, 7); //调用菜单函数
		switch (sel)
		{ // 数据尾插进入链表
		case '1': memset(&e, 0, sizeof(DataType)); Input(txl, &e); ListInsert(&txl, ListLength(txl) + 1, e); printf("添加成功\n");
			break;
		case '2': List(txl);
			break;
		case '3': Query(txl);
			break;
		case '4': Delete(&txl);
			break;
		case '0': printf("谢谢使用本软件,按回车键退出...\n");
			Writefile(&txl);
			getchar();
			exit(0);
			break;
		default: printf("错误输入\n");
			break;

		}
	}
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值