C语言版动态通讯录(增、删、改、查(查重)、去重、排序、导出)


C语言版动态通讯录(增、删、改、查(查重)、去重、排序、导出)


在程序员的路上越走越猿

一段学习过后,想写小东西加深下印象和理解,便开始了我的动态通讯录之旅。

整体框架及实现

通讯录主体
typedef struct content
{
//姓名
char name[Max_name];
//电话
char tel[Max_tel];
//性别
char sex[2];
//年龄
int age;
//住址
char addr[Max_adre];
//生日
char birthday[5];
//公司
char company[20];
}Content;

通讯录功能说明:

1、通讯录基础功能:增、删、改、查。
2、查重(以姓名查重)。
3、排序(以姓名拼音排序)。
4、文件导出,以自定义文件名及类型的形式进行导出。
5、文件去重。
6、数据保存加载(程序关闭后二次打开可以加载历史记录信息)。

编译环境–Visual Studio 2022**
**如果程序出现访问内存被破坏的问题,请照如下设置。
编译器参数设置

主菜单界面

在这里插入图片描述

详细代码

1、Contact.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#include <errno.h>
#define Max_name 11
#define Max_tel 12
#define Max_adre 10
#define init_capcity 5
#define Max_capcity 1000
#define Max_filename 20
//通讯录内容体

typedef struct content
{
	//姓名
	char name[Max_name];
	//电话
	char tel[Max_tel];
	//性别
	char sex[2];
	//年龄
	int age;
	//住址
	char addr[Max_adre];
	//生日
	char birthday[5];
	//公司
	char company[20];
}Content;

//通讯录结构体  
typedef struct contact
{
	int Capcity;
	int size;
	Content* data;
}Contact;

//统计数组
typedef struct MyStruct
{
	int num;
	char cou[0];
} count;
enum contact_option
{
	EXIT,
	ADD,
	DEL,
	EDIT,
	SEARCH,
	SHOW,
	SORT,
	EXPORT,
	DeDuplication,
};


Contact* capcity_Expansion(Contact* p, int num);
int Init_contact(Contact* p, FILE* fp);
void MENU();
char Del_Contact(Contact* p);
void Add_Contact(Contact* p);
void Sort_Contact(Contact* p);
void Show_Contact(Contact* p);
void DeDuplication_Contact(Contact* p);
char Edit_Contact(Contact* p);
int Export_Contact(Contact* p);
void Contact_main();
void Load_Contact(Contact* p);
void Save_Contact(Contact* p);
count* Search_Contact(Contact* p, char name[Max_name]);

2、Contact.c

#include"Contact.h"

//interface 调用入口

void Contact_main()
{
	//读取本地文件
	FILE* fp;
	fp = fopen("MyContact.dat", "rb+");
	while (fp == NULL)
	{
		perror("Failed to load local file:");
		printf("Created a file named MyContact.txt!\n");
		fp = fopen("MyContact.dat", "wb+");

	}
	static int user_input = 0;
	Contact My_contact;
	//初始化通讯录
	Init_contact(&My_contact, fp);
	do
	{
		MENU();
		printf("Please Select >>\n");
		scanf("%d", &user_input);
		switch (user_input)
		{
		case ADD:
			Add_Contact(&My_contact);
			break;
		case DEL:
			Del_Contact(&My_contact);
			break;
		case EDIT:
			Edit_Contact(&My_contact);
			break;
		case SEARCH:
			//调用显示
			char name[Max_name];
			printf("请输入要查询的人的姓名: >>\n");
			scanf("%s", name);
			Contact* p = &My_contact;
			count* index_name = Search_Contact(p, name);
			int num = index_name->num;
			if (num >= 1)
			{
				//打印所有符合筛选条件的人的信息
				printf("%-11s\t%-12s\t%-3s\t%-10s\t%-3s\t%-4s\t%-20s\n\n", "姓名", "电话", "性别", "地址", "年龄", "生日", "公司");
				int j;
				int k = 0;
				for (j = index_name->cou[0]; j <= index_name->num; j++)
				{
					printf(" %-11s\t%-12s\t%-3s\t%-10s\t%-3d\t%-4s\t%-20s\n",
						p->data[index_name->cou[k]].name,
						p->data[index_name->cou[k]].tel,
						p->data[index_name->cou[k]].sex,
						p->data[index_name->cou[k]].addr,
						p->data[index_name->cou[k]].age,
						p->data[index_name->cou[k]].birthday,
						p->data[index_name->cou[k]].company);
					k += 1;
				}
			}
			break;
		case SHOW:
			Show_Contact(&My_contact);
			break;
		case SORT:
			Sort_Contact(&My_contact);
			break;
		case EXPORT:
			Export_Contact(&My_contact);
			break;
		case DeDuplication:
			DeDuplication_Contact(&My_contact);
		case EXIT:
			Save_Contact(&My_contact);
			printf(">>>welcome to use it ! <<<\n");
			exit;
			break;
		default:
			printf("Input error ! Please tyr again!! >> \n");
			break;
		}
	} while (user_input);
}
void MENU()
{
	printf("\n\n");
	printf("====================================================\n");
	printf("===----------------------------------------------===\n");
	printf("===********       My Contact V1.0        ********===\n");
	printf("===----------------------------------------------===\n");
	printf("===********    1、添加       2、删除     ********===\n");
	printf("===----------------------------------------------===\n");
	printf("===********    3、修改       4、查询     ********===\n");
	printf("===----------------------------------------------===\n");
	printf("===********    5、显示       6、排序     ********===\n");
	printf("===----------------------------------------------===\n");
	printf("===********    7、导出       8、去重     ********===\n");
	printf("===----------------------------------------------===\n");
	printf("===********           0、退出            ********===\n");
	printf("===----------------------------------------------===\n");
	printf("====================================================\n");
	printf("\n\n");
	return 0;
}

/*
初始化通讯录,加载本地文件读取通讯录信息
函数返回值0:初始化失败、1:初始化成功
*/

int Init_contact(Contact* p, FILE* fp)
{
	assert(p, fp);
	int status;
	Content* tmp = 0;
	tmp = (Content*)malloc(sizeof(Content) * init_capcity);
	if (tmp)
	{
		p->data = tmp;
		p->size = 0;
		p->Capcity = init_capcity;
		Load_Contact(p);
		status = 1;
	}
	else
	{
		printf("%s", strerror(errno));
		status = 0;
	}
	return status;
}

/*扩容方法,返回访问地址*/

Contact* capcity_Expansion(Contact* p, int num)
{
	assert(p);
	Content* tmp = 0;
	tmp = realloc(p->data, sizeof(Content) * (num + p->Capcity));
	if (tmp != NULL)
	{
		printf(">>>>>扩容成功\n");
		p->data = tmp;
		p->Capcity += num;
	}
	else
	{
		printf(">>>>>扩容失败\n");
		printf(">>>>>错误信息:%s\n", strerror(errno));
	}
	return p;
}


/*
用户录入函数,传入录入起始位置索引,无参则默认起始位置传参
返回录入状态,返回1则录入成功,0:录入失败
*/
int UserInput(Contact* p)
{
	assert(p != NULL);
	//判断容量是否满足
	if (p->Capcity < 2)
	{
		//容量不足时,自动扩容,每次加3
		capcity_Expansion(p, 3);
	}
	int status = 0;
	printf("please input name:>>");
	scanf("%s", p->data[p->size].name);
	printf("please input telephone:>>");
	scanf("%s", p->data[p->size].tel);
	printf("please input sex:>>");
	scanf("%s", p->data[p->size].sex);
	printf("please input address:>>");
	scanf("%s", p->data[p->size].addr);
	printf("please input age:>>");
	scanf("%d", &(p->data[p->size].age));
	printf("please input birthday:>>");
	scanf("%s", p->data[p->size].birthday);
	printf("please input company:>>");
	scanf("%s", p->data[p->size].company);
	p->size += 1;
	p->Capcity -= 1;
	status = 1;
	return status;
}

//加载文件函数

void Load_Contact(Contact* p)
{
	//读取本地文件,写入content
	FILE* fp;
	Content TEMP = { 0 };
	fp = fopen("MyContact.dat", "rb+");

	if (fp == NULL)
	{
		perror("File load Fault :");
		return;
	}
	else
	{
		while (fread(&TEMP, sizeof(Content), 1, fp))
		{
			if (p->Capcity <= 2)
			{
				capcity_Expansion(p, 2);
			}
			p->data[p->size] = TEMP;
			p->size += 1;
		}
		printf("File Load Sucess!!\n");
	}
	fclose(fp);
	fp = NULL;
	return;
}

//保存写入函数
void Save_Contact(Contact* p)
{
	assert(p);
	FILE* fp;
	fp = fopen("MyContact.dat", "wb+");
	if (fp == NULL)
	{
		perror("写入失败:");
		return;
	}
	else
	{
		//fwrite(p, sizeof(Content), 1, fp);
		int i;
		for (i = 0; i < p->size; i++)
		{
			/*循环写入*/
			fwrite(&(p->data[i]), sizeof(Content), 1, fp);
		}
		fclose(fp);
		fp = NULL;
		printf("保存成功!!\n");
	}
	return;
}

//添加函数
void Add_Contact(Contact* p)
{
	assert(p);
	if (UserInput(p))
	{
		printf("添加成功!!\n");
		printf("\n\n通讯录容量: <-可用-> -- %d /<-已用-> --%d \n", p->Capcity, p->size);
	}
	else
	{
		printf("添加失败,请重试\n");
	}
	return 0;
}


//删除函数

char Del_Contact(Contact* p)
{
	assert(p);
	//判断通讯录是否为空
	if (p->size == 0)
	{
		printf("the contact is empty\n");
	}
	else
	{
		char name[Max_name] = { 0 };
		printf("please input name:>>\n");
		scanf("%s", name);
		printf("%s", name);
		count* index;
		int i;
		int j = 0;
		index = Search_Contact(p, name);
		int num = index->num;
		for (i = index->cou[j]; i < p->size; i++)
		{
			//如果出现重复元素 
			if ((i + 1) == index->cou[j])
			{
				i = i + 1;
			}
			p->data[i] = p->data[i + 1];
			j++;
		}
		p->size -= num;
		p->Capcity += num;
		printf("delete sucess!!\n");
		free(index);
		index = NULL;
	}

	return 0;
}

//修改函数

char Edit_Contact(Contact* p)
{
	assert(p);
	char name[Max_name];
	printf("请输入要编辑的人的姓名 >>\n");
	scanf("%s", name);
	count* index_name = Search_Contact(p, name);
	int num = index_name->num;
	if (num > 1)
	{
		//打印所有符合筛选条件的人的信息
		printf("%-11s\t%-12s\t%-3s\t%-10s\t%-3s\t%-4s\t%-20s\n\n", "姓名", "电话", "性别", "地址", "年龄", "生日", "公司");
		int j;
		int k = 0;
		for (j = index_name->cou[0]; j <= index_name->num; j++)
		{
			printf(" %-11s\t%-12s\t%-3s\t%-10s\t%-3d\t%-4s\t%-20s\n",
				p->data[index_name->cou[k]].name,
				p->data[index_name->cou[k]].tel,
				p->data[index_name->cou[k]].sex,
				p->data[index_name->cou[k]].addr,
				p->data[index_name->cou[k]].age,
				p->data[index_name->cou[k]].birthday,
				p->data[index_name->cou[k]].company);
			k += 1;
		}
	}
	int i;
	for (i = 0; i < num; i++)
	{
		printf("please input new meassage 第 %d 位:>>", (i + 1));
		scanf("%s", p->data[index_name->cou[i]].name);
		printf("please input new telephone:>>");
		scanf("%d", p->data[index_name->cou[i]].tel);
		printf("please input new sex:>>");
		scanf("%s", p->data[index_name->cou[i]].sex);
		printf("please input new age:>>");
		scanf("%d", &(p->data[index_name->cou[i]].age));
		printf("please input new address:>>");
		scanf("%s", p->data[index_name->cou[i]].addr);
		printf("please input new birthday:>>");
		scanf("%s", p->data[index_name->cou[i]].birthday);
		printf("please input new company:>>");
		scanf("%s", p->data[index_name->cou[i]].company);
	}
	Show_Contact(p);
	return 0;
}

//查询函数
count* Search_Contact(Contact* p, char name[Max_name])
{
	assert(p);
	//定义一个数组,存放符合搜索条件人的信息的索引
	static count* C1;
	C1 = (count*)malloc(sizeof(count) + sizeof(char) * 5);
	if (C1 == NULL)
	{
		printf("%s", strerror(errno));
	}
	C1->num = 0;
	C1->cou[0] = 0;
	int i, j;
	j = 0;
	for (i = 0; i < p->size; i++)
	{
		if (0 == strcmp(name, p->data[i].name))
		{
			C1->cou[j++] = i;
		};
	}
	C1->num = j;
	return C1;
}
//打印函数 打印通讯录
void Show_Contact(Contact* p)
{
	char Input;
	if (p->size == 0)
	{
		printf("Contact is Null,To Add?(Y/N)\n");
		scanf("%s", &Input);
		if (Input == 'y' || Input == 'Y')
		{
			Add_Contact(p);
			Show_Contact(p);

		}
		else
		{
			return(-1);
			/*Exit_Contact();*/
		}
	}
	else
	{
		printf("%-11s\t%-12s\t%-3s\t%-10s\t%-3s\t%-4s\t%-20s\n\n", "姓名", "电话", "性别", "地址", "年龄", "生日", "公司");
		int i = 0;
		for (i = 0; i < p->size; i++)
		{
			printf(" %-11s\t%-12s\t%-3s\t%-10s\t%-3d\t%-4s\t%-20s\n",
				p->data[i].name,
				p->data[i].tel,
				p->data[i].sex,
				p->data[i].addr,
				p->data[i].age,
				p->data[i].birthday,
				p->data[i].company);
		}
		printf("\n\nyour contact capcity meassage: <Used> -- %d /<Usable> --%d \n", p->Capcity, p->size);

	}
	return(-1);
}

//排序定义函数

int cmp_string(const void* _a, const void* _b)
{
	char* a = (char*)_a;
	char* b = (char*)_b;
	return strcmp(a, b);
}
// 排序函数
void Sort_Contact(Contact* p)
{
	/*
	按照姓姓名首字母排序
	使用排序算法(冒泡)
	*/
	assert(p);
	int i, j;
	for (i = 0; i < p->size; i++)
	{
		for (j = 0; j < (p->size) - i - 1; j++)
		{
			if (*(p->data[j].name) > *(p->data[j + 1].name))
			{
				//首字母拼音在前,则交换顺序
				Content temp;
				temp = p->data[j];
				p->data[j] = p->data[j + 1];
				p->data[j + 1] = temp;

			}
		}
	}
	//调用显示函数打印
	Show_Contact(p);
	return 0;
}

//去重函数

void DeDuplication_Contact(Contact* p)
{
	//遍历通讯录,将姓名相同人的信息进行记录
	assert(p);
	//找出所有重复姓名的索引,将其删除或提示更新数据
	static char REpeat_name[Max_capcity][Max_name];
	int i;
	int k = 0;
	for (i = 0; i < p->size; i++)
	{
		int j;
		for (j = i + 1; j < p->size; j++)
		{
			//如果名字出现过,记录索引

			if (strcmp(p->data[i].name, p->data[j].name) == 0)
			{
				REpeat_name[k][0] = i;
				REpeat_name[k + 1][0] = j;
				k += 2;
			}
		}

	}
	if (k)
	{
		//有重复信息,将重复信息进行显示
		printf("%-11s\t%-12s\t%-3s\t%-10s\t%-3s\t%-4s\t%-20s\n\n", "姓名", "电话", "性别", "地址", "年龄", "生日", "公司");
		for (int i = 0; i < k; i++)
		{
			printf(" %-11s\t%-12s\t%-3s\t%-10s\t%-3d\t%-4s\t%-20s\n",
				p->data[REpeat_name[i][0]].name,
				p->data[REpeat_name[i][0]].tel,
				p->data[REpeat_name[i][0]].sex,
				p->data[REpeat_name[i][0]].addr,
				p->data[REpeat_name[i][0]].age,
				p->data[REpeat_name[i][0]].birthday,
				p->data[REpeat_name[i][0]].company);
		}
		char input_repeat;
		printf("对重复信息进行删除(Y/N)>>\n");
		scanf("%s", &input_repeat);
		if (input_repeat == 'y' || input_repeat == 'Y')
		{
			//删除
			int f = 0;
			for (int i = REpeat_name[f][0]; i < p->size; i++)
			{

				//如果出现重复元素 
				if ((i + 1) == REpeat_name[f + 1][0])
				{
					i = i + 1;
				}
				p->data[i] = p->data[i + 1];
				f++;
			}
			p->size -= k;
			p->Capcity += k;
			printf("delete sucess!!\n");
		}
		else
		{
			return;
		}
	}
	else
	{
		printf("通讯录内无重复姓名信息!>>\n");
		Show_Contact(p);
	}
	return;
}


//将文件导出指定的文件名内(二进制写)

int Export_Contact(Contact* p)
{
	assert(p);
	int status = 0;
	char Filename[Max_filename];
	printf("请输入文件名:>>\n");
	scanf("%s", Filename);
	FILE* fp_export;
	fp_export = fopen(Filename, "wb+");
	if (fp_export == NULL)
	{
		perror("写入失败:");
		return;
	}
	else
	{
		int i;
		for (i = 0; i < p->size; i++)
		{
			/*循环写入*/
			fwrite(&(p->data[i]), sizeof(Content), 1, fp_export);
		}
		fclose(fp_export);
		fp_export = NULL;
		printf("保存成功!!\n");
		status = 1;
	}

	fclose(fp_export);
	fp_export = NULL;
	return status;
}



3、test.c


void main()
{
	
	Contact_main();


	return 0;
}

第一次分享博客,如有问题,还请各位博友不吝赐教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

David_leil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值