如何用1个C语言函数写出带文件存储的动态内存通讯录!!

C语言通讯录的实现

将自己在学习完C语言之际所写的一个通讯录实现程序分享给大家,这其中包括了对于动态内存管理的知识,和文件操作的知识,或许不是最牛最精简的,但却是最好学习最容易上手的一个动态内存通讯录。

对于每一行代码我都将给出最全面的注释,让你的学习没有丝毫难度

1. 头文件

#define _CRT_SECURE_NO_WARNINGS//windows的弊端,所以需要加上这个,其他系统另当别论
#include <stdio.h>
#include <stdlib.h>
#include <string.h>//字符串函数的使用
#include <windows.h>//用来进行清屏函数的使用
#include <assert.h>//判空函数的使用

//定义通讯录数组的最大值为200 [0-200) 前闭后开
#define MAX_SIZE 200
(对于不想实现动态内存的话,可以将通讯录中人数的指针变为数组即可,而数组的大小就是在这里所定义的200,所以在这个动态内存之中没有使用到静态,因此`MAX_SIZE`没有用武之地,大家也可以将其省略)


//
#define CAPACITY 20

//定义个人联系信息的结构体变量
typedef struct PersonInof {
	char name[1024];//存储姓名
	char phone[1024];//存储电话
}PersonInof;//定义结构体声明

//定义通讯录结构
typedef struct AddressBook {
	PersonInof *persons;//总共可存储的通讯录人数
	int size;//统计放入的个数
	//定义空间 [0- size) 为已使用的空间
	// (size-200) 为未使用的空间
	int capacity;
	//通讯录的容量
}AddressBook;

2. 调用函数

2.1 文件存储函数

//文件的读取和存储操作函数
void SaveFile(AddressBook* address) {
	//文件存储
	//1. 先行打开我们需要写入数据的文件
	FILE* fp = fopen("h:/address.txt", "w");//我自己的文件根目录,大家需要改变
	if (fp == NULL) {
		perror("文件打开操作失败!\n");
		return;
	}

	//2. 使用for循环遍历的方式,将通讯录之中的数据写入到文件之中
	for (int i = 0; i < address->size; i++) {
		fwrite(&address->persons[i], sizeof(PersonInof), 1, fp);
	}
	fclose(fp);
	printf("保存成功!\n");
}


void LoadFile(AddressBook* address) {
	//文件读取
	//1. 打开文件
	FILE* fp = fopen("h:/address.txt", "r");
	if (fp == NULL) {
		perror("文件打开操作失败!\n");
		return;
	}

	//2. 循环读取文件之中的内容,并把数据加载到通讯录结构体之中
	PersonInof tmp = { 0 };
	while (1) {
		int n = fread(&tmp, sizeof(PersonInof), 1, fp);
		if (n < 1) {
			break;
		}
		CheckCapacity(address);
		//判断容量是否超标,进行扩容操作
		address->persons[address->size] = tmp;
		address->size++;
	}
	fclose(fp);

}

2.2 初始化函数

//初始化函数,将通讯录中的信息进行初始化
void Init(AddressBook* address) {
	address->size = 0;//先行使size为0 ,则表示通讯录为空
	address->persons = (PersonInof*)malloc(sizeof(PersonInof) * CAPACITY);
	if (address->persons == NULL)
	{
		perror("use malloc");//报错
		exit(EXIT_FAILURE);//退出
	}
	memset(address->persons, 0, sizeof(PersonInof) * CAPACITY);
	address->capacity = CAPACITY;
}

2.3 检查容量扩容函数

void CheckCapacity(AddressBook* address) {
	//检查是否容量超标,进行扩容
	if (address->size == address->capacity) {
		PersonInof* ptr = (PersonInof*)realloc(address->persons,
			address->capacity * sizeof(PersonInof));
		//进行续接,每次扩大的容量都是一个标准容量capacity
		if (address->persons == NULL)
		{
			//判空
			perror("realloc");
			exit(EXIT_FAILURE);
		}
		else {
			address->persons = ptr;
		}
		printf("扩容成功!\n");
	}
}

2. 4 目录的打印

//打印通讯录的菜单选项
int Menu() {
	printf("============================\n");
	printf("==========通 讯 录==========\n");
	printf("======1.新 增 联 系 人======\n");
	printf("======2.删 除 联 系 人======\n");
	printf("======3.修 改 联 系 人======\n");
	printf("======4.查 找 联 系 人======\n");
	printf("======5.排 序 通 讯 录======\n");
	printf("======6.打 印 通 讯 录======\n");
	printf("======7.清 空 通 讯 录======\n");
	printf("======0.   退  出     ======\n");
	printf("============================\n");
	printf("请输入您的选择:");
	int choice;
	scanf("%d", &choice);//输入我们的选择
	return choice;///返回用户所输入的信息
}

2. 5 功能函数

  1. 增加联系人函数
//增加联系人函数
void AddpersonInof(AddressBook* address) {
	assert(address->persons != NULL);
	CheckCapacity(address);
	PersonInof* info = &address->persons[address->size];
	//这样做是为了方便使用,避免在下面的输入中不断地输入很长地一串
	printf("请输入姓名:");
	scanf("%s", info->name);
	printf("请输入电话:");
	scanf("%s", info->phone);
	printf("成功增加新的联系人!\n");
	address->size ++;
}
  1. 删除联系人函数
//删除联系人函数
void DelpersonInof(AddressBook* address) {
	//确定执行删除操作
	printf("执行删除\n");
	if (address->size <= 0) {
		//先行判定通讯录是否为空
		printf("通讯录为空,无需进行删除!\n");
		return;
	}

	printf("请输入您要删除的联系人序号:");
	int id = 0;
	//创建需要删除的联系人序号变量
	scanf("%d", &id);
	//麻烦之处就是需要先行进行查询全部的联系人

	if (id < 0 || id >= address->size) {
		//检查客户输入的程序是否合法
		printf("输入的id非法!无法进行删除\n");
		return;
	}

	PersonInof* last_info = &address->persons[address->size - 1];
	//找到最后一个成员的信息
	PersonInof* to_delete = &address->persons[id];
	//需要删除的成员信息

	*to_delete = *last_info;
	//二者进行互换则可
	address->size--;
	//最后更改size值,保证删除后数量减11
	printf("删除成功!\n");
}
  1. 修改联系人函数
void ModifypersonInof(AddressBook* address) {
	if (address->size <= 0) {
		//同样判断通讯录是否为空
		printf("通讯录为空,无法进行修改\n");
			return;
	}
	int id = 0;
	printf("请输入要修改的联系人序号:");
	//创建联系人序号中间变量
	scanf("%d", &id);
	if (id < 0 || id >= address->size) {
		//检查输入序号是否合法
		printf("输入序号无法查询,修改失败\n");
		return;
	}

	PersonInof* info = &address->persons[id];
	//定义结构体变量类型
	printf("请输入修改后的名字(* 表示不修改):");
	char name[1024] = { 0 };
	scanf("%s", name);
	//若相等则代表不修改
	if (strcmp(name, "*") != 0) {
		strcpy(info->name, name);
	}
	printf("请输入修改后的电话(* 表示不修改):");
	char phone[1024] = { 0 };
	scanf("%s", phone);
	//同理
	if (strcmp(phone, "*") != 0) {
		strcpy(info->phone, phone);
	}
	printf("修改完成!\n");
}

  1. 查找联系人函数
void FindpersonInof(AddressBook* address) {
	printf("查找指定联系人\n");
	printf("请输入要查找的联系人姓名:");
	int N = 0;
	char name[1024] = { 0 };
	//设定输入名字的变量
	scanf("%s", name);
	for (int i = 0; i < address->size; i++) {
		//逐个进行比对,将相等的输出
		PersonInof* info = &address->persons[i];
		if (strcmp(name, info->name) == 0) {
			printf("[%d] %s:%s\n", i, info->name, info->phone);
			N++;
		}
	}
	if (N == 0) {
		printf("未找到您需要查找的联系人信息!\n");
	}
	else {
		printf("查找联系人完毕\n");
	}

}
  1. 排序联系人函数
void SortpersonInof(AddressBook* address) {
	int i = 0;
	int j = 0;
	int k = 0;
	for (i = 0; i < address->size - 1; i++)
	{
		for (j = 0; j < address->size - i - 1; j++)
		{
			if (strcmp(address->persons[i].name, address->persons[i + 1].name) > 0)
			{
				struct PersonInof tmp;
				tmp = address->persons[j];
				address->persons[j] = address->persons[j + 1];
				address->persons[j + 1] = tmp;
			}
		}
	}
}

  1. 打印联系人函数
void PrintpersonInof(AddressBook* address) {
	printf("打印通讯录\n");
	printf("%5s\t%10s\t%15s\t\n","num","name", "phone");
	for (int i = 0; i < address->size; i++) {
		PersonInof* info = &address->persons[i];
		printf("[%d] %s:%s\n",i,info->name,info->phone);
	}
	//逐个打印所存在的通讯录数据
	printf("当前共打印%d条记录\n", address->size);
}
  1. 清空联系人函数
void ClearpersonInof(AddressBook* address) {
	printf("是否要删除全部通讯录?\n");
	printf("Y(y)/N(n)\n");
	//提供确认选项供客户选择
	char choice[1024] = { 0 };
	//回答是则进行最后的删除
	scanf("%c", choice);
	if ((strcmp(choice, "y") == 0) || (strcmp(choice, "Y") == 0)) {
		address->size = 0;
		printf("删除完毕!\n");
		return;
	}
	//否则进行取消操作
	else{
		printf("删除取消!\n");
		return;
	}
}

3. 主函数

int main() {
	AddressBook address;//创建初始变量
	Init(&address);//初始化函数
	LoadFile(&address);
	typedef void(*Func)(AddressBook*);
	//定义函数指针

	//采用转移表地方式来进行菜单地选择
	Func func_table[] = {
		NULL,//为和菜单项地序号匹配,将0地位置置为空
		AddpersonInof,
		DelpersonInof,
		ModifypersonInof,
		FindpersonInof,
		SortpersonInof,
		PrintpersonInof,
		ClearpersonInof,
	};
	while (1) {
		int choice = Menu();
		if (choice < 0 || choice >= sizeof(func_table) / sizeof(func_table[0])) {
			printf("您的输入有误!\n");
			continue;
		}
		if (choice == 0) {
			SaveFile(&address);
			system("cls");
			printf("goodbye!\n");
			break;
		}
		func_table[choice](&address);
	}

	system("pause");
	return 0;
}

4. 实现图

因为我在通讯录之中放置了一些我自己朋友的信息,所有就不一一给大家展示了。
实现图
到这里关于动态内存通讯录的所有程序也就完全执行完毕了,如果哪里还有这不懂得朋友,也是可以直接留言,或者有什么更好主意的朋友也是可以进行相互之间的讨论,以此来相互提高。
完整的代码链接,在我GitHub上,链接如下:通讯录链接
除此之外还有其他的这么多的练手小程序,都是以前编写出来的,需要的朋友也是可以自取!
GitHub图

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章