通讯录(文件版本)

和动态版通讯录相比较,文件版本新增功能:

        文件的读和写。本文涉及到的是文件的二进制输入(fread)和文件的二进制输出(fwrite)

fwrite:

        size_t fwrite(const void* ptr, size_t size, size_t count, FILE* stream);

fread:

        size_t fread(void* ptr, size_t size, size_t count, FILE* stream);

文件读写要注意fopen(打开文件)、fclose(关闭文件)的正确形式

 Contact.h文件(函数声明部分)

#pragma once
#define NAME 10
#define TELE 12
#define ADDR 20
#define DEFAULT 3
#define EXPAND 2

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>

//枚举操作选项
enum Option
{
	EXIT,
	ADD,
	DELETE,
	FIND,
	MODIFY,
	SHOW,
	SORT
};

//每个联系人信息类型
struct Peoinfo
{
	char name[NAME];
	int age;
	char tele[TELE];
	char address[ADDR];
};

//通讯录类型
struct Contact
{
	struct Peoinfo* data;	//指向通讯录信息
	int sz;					//统计联系人个
	int capacity;			//统计通讯录容量
};

//初始化通讯录
int INITIALIZE_Contact(struct Contact* pI);

//读取通讯录文件
void READ_Contact(struct Contact* pV);

//检查通讯录是否已满
void JUDGEFULL_Contact(struct Contact* pJ);

//菜单显示
void menu();

//添加联系人
void ADD_Contact(struct Contact* pA);

//显示联系人
void SHOW_Contact(struct Contact* pSH);

//查询联系人
void FIND_Contact(struct Contact* pF);

//修改联系人
void MODIFY_Contact(struct Contact* pM);

//删除联系人
void DELETE_Contact(struct Contact* pD);

//联系人排序
void SORT_Contact(struct Contact* pSO);

//保存联系人到文件
void SAVE_Contact(struct Contact* pSA);

//退出程序
void EXIT_Contact(struct Contact* pE);

Contact.c文件(函数定义部分)

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"

//菜单显示
void menu()
{
	printf("*****************************\n");
	printf("***** 1.ADD    2.DELETE *****\n");
	printf("***** 3.FIND   4.MODIFY *****\n");
	printf("***** 5.SHOW   6.SORT   *****\n");
	printf("*****       0.EXIT      *****\n");
	printf("*****************************\n");
}

//按姓名查找联系人(没有在头文件中声明,只能在该.c文件中使用)
int FindByName(const struct Contact* C, const char* N)
{
	int i = 0;
	for (i = 0; i < C->sz; i++)
	{
		if (0 == strcmp(&(C->data[i].name), N))
		{
			printf("找到了:\n");
			printf("%-10s%-10s%-20s%-20s\n", "姓名", "年龄", "电话", "地址");
			printf("%-10s%-10d%-20s%-20s\n", &(C->data[i].name), C->data[i].age, &(C->data[i].tele), &(C->data[i].address));
			return i;
		}
	}
	printf("找不到该联系人\n");
	return -1;
}

//按姓名排序(没有在头文件中声明,只能在该.c文件中使用)
int CmpByName(const struct Contact* c1, const struct Contact* c2)
{
	return strcmp(c1->data->name, c2->data->name);
}

//检查通讯录是否已满
void JUDGEFULL_Contact(struct Contact* pJ)
{
	if (pJ->sz == pJ->capacity)
	{
		//扩容
		struct Peoinfo* ptr = realloc(pJ->data, (pJ->capacity + EXPAND) * sizeof(struct Peoinfo));
		if (ptr == NULL)
		{
			printf("通讯录已满,扩容失败\n");
			return;
		}
		else
		{
			pJ->data = ptr;
			pJ->capacity += EXPAND;
			printf("扩容成功,当前容量是%d\n", pJ->capacity);
		}
	}
}

//读取通讯录文件
void READ_Contact(struct Contact* pV)
{
	//打开文件
	FILE* pf = fopen("Contact.dat", "rb");
	if (pf == NULL)
	{
		perror("READ_Contact::fopen");
		return;
	}

	//读文件
	while (fread(pV->data + (pV->sz), sizeof(struct Peoinfo), 1, pf))
	{
		pV->sz++;
		JUDGEFULL_Contact(pV);
	}

	//关闭文件
	fclose(pf);
	pf = NULL;
}

//初始化通讯录
int INITIALIZE_Contact(struct Contact* pI)
{
	pI->data = malloc(DEFAULT * sizeof(struct Peoinfo));
	if (pI->data == NULL)
	{
		printf("INITIALIZE_Contact失败:%s\n", strerror(errno));
		return 0;	//初始化失败返回0
	}
	pI->sz = 0;
	pI->capacity = DEFAULT;
	printf("通讯录初始化成功,当前容量是%d\n", pI->capacity);
	READ_Contact(pI);
	printf("通讯录加载成功\n");
	return 1;		//初始化成功返回1
}

//添加联系人
void ADD_Contact(struct Contact* pA)
{
	//判断通讯录是否已满
	JUDGEFULL_Contact(pA);
	//新建联系人
	printf("请输入姓名:\n");
	scanf("%s", &((pA->data[pA->sz]).name));
	printf("请输入年龄:\n");
	scanf("%d", &((pA->data[pA->sz]).age));
	printf("请输入电话:\n");
	scanf("%s", &((pA->data[pA->sz]).tele));
	printf("请输入地址:\n");
	scanf("%s", &((pA->data[pA->sz]).address));
	printf("添加成功\n");
	pA->sz++;
}

//显示联系人
void SHOW_Contact(struct Contact* pSH)
{
	printf("%-10s%-10s%-20s%-20s\n", "姓名", "年龄", "电话", "地址");
	//%-10s:10指的是打印出来显示10个字符的长度空间;-10指的是左对齐(-号)占据10个字符长度空间载打印下一个数据
	//如果是%10s,则是右对齐打印10个字符长度空间再打印下一个数据
	int i = 0;
	for (i = 0; i < pSH->sz; i++)
	{
		printf("%-10s%-10d%-20s%-20s\n", &(pSH->data[i].name), pSH->data[i].age, &(pSH->data[i].tele), &(pSH->data[i].address));
	}
}

//查询联系人
void FIND_Contact(struct Contact* pF)
{
	char name[20] = { 0 };
	printf("请输入联系人姓名:\n");
	scanf("%s", name);
	FindByName(pF, name);
}

//修改联系人
void MODIFY_Contact(struct Contact* pM)
{
	char name[20] = { 0 };
	printf("请输入要修改的联系人姓名:\n");
	scanf("%s", name);
	int i = FindByName(pM, name);
	if (i != -1)
	{
		printf("请输入姓名:\n");
		scanf("%s", &(pM->data[i].name));
		printf("请输入年龄:\n");
		scanf("%d", &(pM->data[i].age));
		printf("请输入电话:\n");
		scanf("%s", &(pM->data[i].tele));
		printf("请输入地址:\n");
		scanf("%s", &(pM->data[i].address));
		printf("修改成功\n");
	}
}

//删除联系人
void DELETE_Contact(struct Contact* pD)
{
	char name[20] = { 0 };
	printf("请输入要修改的联系人姓名:\n");
	scanf("%s", name);
	int i = FindByName(pD, name);
	if (i != -1)
	{
		printf("确认删除请输入:1\n取消删除请输入:2\n");
		int j = 0;
		scanf("%d", &j);
		if (1 == j)
		{
			for (j = i; j < pD->sz - 1; j++)
			{
				pD->data[j] = pD->data[j + 1];
			}
			printf("删除联系人成功\n");
			pD->sz--;
		}
	}
	return;
}

//联系人排序
void SORT_Contact(struct Contact* pSO)
{
	qsort(pSO->data, pSO->sz, sizeof(pSO->data[0]), CmpByName);//注意qsort()函数的传参问题,练习各类数据的qsort排序
}

//保存联系人到文件
void SAVE_Contact(struct Contact* pSA)
{
	//打开文件
	FILE* pf = fopen("Contact.dat", "wb");
	if (pf == NULL)
	{
		perror("SAVE_Contact::fopen");
		return;
	}

	//写文件
	int i = 0;
	for (i = 0; i < pSA->sz; i++)
	{
		fwrite(pSA->data+i, sizeof(struct Peoinfo), 1, pf);
	}
	printf("通讯录已成功保存到文件\n");
	//关闭文件
	fclose(pf);
	pf = NULL;
}

//退出程序
void EXIT_Contact(struct Contact* pE)
{
	free(pE->data);
	pE->data = NULL;
	printf("该内存块已被释放回收\n");
}

 test.c文件(通讯录的实现部分)

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"

int main()
{
	int input;
	struct Contact C;
	struct Contact* p = &C;
	if (0 == INITIALIZE_Contact(p))
	{
		printf("通讯录创建失败\n");
		return 0;
	}
	else
	{
		do
		{
			menu();
			printf("请选择\n");
			scanf("%d", &input);
			switch (input)
			{
			case ADD:
				ADD_Contact(p);
				break;
			case DELETE:
				DELETE_Contact(p);
				break;
			case FIND:
				FIND_Contact(p);
				break;
			case MODIFY:
				MODIFY_Contact(p);
				break;
			case SHOW:
				SHOW_Contact(p);
				break;
			case SORT:
				SORT_Contact(p);
				break;
			case EXIT:
				SAVE_Contact(p);
				EXIT_Contact(p);
				break;
			default:
				break;
			}
		} while (input);
	}
	return 0;
}

程序运行首先读取文件中已保存的通讯录信息:

 程序关闭保存通讯录到文件:

猜你喜欢

转载自blog.csdn.net/libj2023/article/details/131755039