通讯录的实现(优化版:动态增长,文件保存)

目录

一、前言

二、通讯录的实现

1.关于通讯录的前期准备

(1)关于全局变量的定义

(2)菜单的实现

(3)关于联系人结构体的创建

(4)实现菜单选项的功能

2、通讯录的功能实现

(1)初始化通讯录

(2)增加联系人

(3)删除联系人 

(4)打印通讯录

 (5)查找联系人

(6)修改联系人

 (7)排序通讯录

 总结:

test.c

 contact.c

 contact.h

 感谢阅读!!!


一、前言

本文将会用c语言实现一个通讯录的系统,并且存储若干人的信息,每个人的信息包括:姓名,性别,年龄,电话号码,住址。此通讯录系统的功能包括: 1.增加联系人 2.删除对应的联系人 3.查找联系人 4.修改联系人的信息 5.排序此通讯录 6.打印出通讯录每个人的信息

二、通讯录的实现

1.关于通讯录的前期准备

(1)关于全局变量的定义

为了实现这些变量,并且方便后期的处理数组大小,所以我们可以利用宏来实现这个功能

#define MAX 1000

#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
(2)菜单的实现

首先关于一个通讯录,建立一个菜单是很重要的,菜单能够实现和用户的交互。

因此我们需要建立一个菜单,并且菜单立马应该包括通讯录立马该有的功能,以便于用户的操作

代码如下:

void menu()
{
	printf("**************************************\n");
	printf("*****    1.add        2.del      *****\n");
	printf("*****    3.search     4.modify   *****\n");
	printf("*****    5.show       6sort      *****\n");
	printf("*****    0.exit                  *****\n");
	printf("**************************************\n");
}

效果大致这样就可以;

(3)关于联系人结构体的创建

这里我们需要利用结构体来实现实现前言中的通讯录功能以及联系人信息,我将利用两个结构体来构建我们需要的东西。(大小设置为1000)(最多存放1000个人的信息)

struct PeoInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
};

struct contact
{
	struct PeoInfo date[MAX];
	int size;
};
(4)实现菜单选项的功能

我们需要根据菜单里面的选项来选择进行我们需要实现的功能,比如我们想假如一个用户信息,我们就输入1就会进行用户假如的操作,我们想退出程序我们输入0就可以退出。我选择利用枚举变量的形式来实现,讲操作变成数字,利用switch选择语句来实现各自的功能。

使用枚举的好处就是方便了我们补充函数内容的时候方便得知那个数字对应那个功能

enum option
{
	EXIT,//0
	ADD,//1
	DEL,//2
	SEARCH,//3
	MODIFY,//4
	SHOW, //5
	SORT,//6
};

然后使用switch的时候便会方便许多,如下

	int input = 0;
	//创建结构体数组
	struct contact con;
	//初始化结构体数组
	Initcon(&con);
do {
	menu();
	printf("请输入你的选择:>");
	scanf("%d", &input);
	switch (input)
	{
	case ADD:
		Addcontact(&con);
		break;
	case DEL:
		Delcontact(&con);
		break;
	case SEARCH:
		Searchcontact(&con);
		break;
	case MODIFY:
		Modifycontact(&con);
		break;
	case SHOW:
		Showcontact(&con);
		break;
	case SORT:
		SortContact(&con);
		break;
	case EXIT:
		printf("退出通讯录\n");
		break;
	default:
		printf("输入错误,请重新输入:>\n");
		break;
	}

} while (input);

我们case的后面不在是1 2 3 而是对应功能的名字,是不是很方便呢

2、通讯录的功能实现

(1)初始化通讯录

第一步初始化的话,我们要知道要将通讯录初始化什么内容,初始化的目的就是为了避免因不进行初始化导致存的是随机值,从而造成不必要的麻烦,一般的初始化就是放0或者为空;这里我们可以浅浅用一个memset函数来实现,当然别忘了引用string的头文件,然后sz的初始化很简单就是初始化为0。

	memset(ps->date, 0, sizeof(ps->date));
	ps->size = 0;

代码就是这么简单,但是我们为了书写的时候便于看,一般分多个项目进行写一个小游戏;

这里只展示函数的实现部分(下同)

void Initcon(struct contact* ps)
{
	assert(ps!=NULL);
	memset(ps->date, 0, sizeof(ps->date));
	ps->size = 0;
}
(2)增加联系人

首先第一步我们完成第一步就可以创建关于加入联系人的函数,这个很简单我们只需要访问通讯录结构体里面的数组中的每个元素然后输入对应值就可以了

void Addcontact(struct contact* ps)
{
	assert(ps != NULL);
	if (ps->size == MAX)
	{
		printf("通讯录已满,无法再进行添加\n");
	}
	else
	{
		printf("情输入姓名:>");
		scanf("%s", ps->date[ps->size].name);
		printf("情输入年龄:>");
		scanf("%d", &(ps->date[ps->size].age));
		printf("情输入性别:>");
		scanf("%s", ps->date[ps->size].sex);
		printf("情输入电话:>");
		scanf("%s", ps->date[ps->size].tele);
		printf("情输入地址:>");
		scanf("%s", ps->date[ps->size].addr);

		ps->size++;//千万要记得++

		printf("录入信息完成\n");
	}
}

(3)删除联系人 

这个操作也不算复杂,我的思路是,首先我们先利用刚刚查找的嘞个查找下标的函数,查找到我们需要寻找删除联系人的坐标,然后对他进行删除,删除之后呢我们需要把后面的元素挨个往前移动,这就要利用for循环,但是对于for循环的次数要多加注意,因为稍不小心就会导致数组越界。

static int Find_by_name(const struct contact* ps, char name[MAX_NAME])
{//static修饰可以使其函数仅可以再本。c生效
	//避免了污染
	assert(ps != NULL);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (strcmp(ps->date[i].name, name) == 0)
			return i;
	}
	return -1;
}
void Delcontact(struct contact* ps)
{
	assert(ps != NULL);
	char name[MAX_NAME];
	printf("请输入要删除联系人的姓名:>");
	scanf("%s", name);
	//查找
	//找到返回pos下标
	//找不到返回-1
	int pos=Find_by_name(ps, name);
	if (pos == -1)
	{
		printf("要删除的联系人不存在\n");
	}
	else
	{
		int j = 0;
		for (j = pos; j <ps->size ; j++)//
			//*******
		{
			ps->date[j] = ps->date[j + 1];
		}
		ps->size--;
		printf("删除成功\n");
	}
}

 

 这个代码其中有一个地方加了 static 这一部分就很妙,就好比如如果别的。c文件再写的时候跟这个函数有关系,就可以避免发生关系,就会使得 Find_by_name这个函数只会在本文件下生效,避免了污染,就好比生物上的物种感染,你可以不用,但不能没有,避免发生麻烦;

(4)打印通讯录

打印通讯录也很简单,利用一个for循环根据sz的大小遍历结构体中的数组每个元素并且打印即可

在正常情况下打印这一步一定要尽早实现,因为,我们每写完一项功能,我们自己认为没问题,并且也可以跑的情况下,我们无法得知跟我们想要实现的功能有什么差别,这时候都需要打印一下,实践出真理;

代码如下:

void Showcontact(const struct contact* ps)
{
	assert(ps != NULL);
	int i = 0;
	if (ps->size == 0)
	{
		printf("通讯录内容为空,无法打印\n");
	}
	else
	{
		for (i = 0; i < ps->size; i++)
		{
			printf("%-20s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");//为了打印出来的内容对其,显得好看对其的打印要一直
			printf("%-20s\t%-3d\t%-5s\t%-12s\t%-20s\n",//就先这跟上面的一样才好看
				ps->date[i].name,
				ps->date[i].age,
				ps->date[i].sex,
				ps->date[i].tele,
				ps->date[i].addr);
		}
		}
}

 

 (5)查找联系人

查找联系人这边我们需要构建一个函数,这个函数需要去根据我们想要寻找的姓名去在通讯录中寻找这个人所对应的位置,加入找到了就可以返回对应位置的下标,否则返回-1。找到之后就和打印通讯录的操作差不多打印出来就好了。然而查找可以通过多种方式,年龄啊,电话啊,这里使用的是姓名


void Searchcontact(const struct contact* ps)
{
	assert(ps != NULL);
	char name[MAX_NAME];
	printf("请输入要查找联系人的姓名:>");
	scanf("%s", name);
	int pos = Find_by_name(ps, name);
	if (pos == -1)
	{
		printf("要查找的联系人不存在\n");
	}
	else
	{
		printf("信息如下:\n");
		printf("%-20s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-20s\t%-3d\t%-5s\t%-12s\t%-20s\n",
			ps->date[pos].name,
			ps->date[pos].age,
			ps->date[pos].sex,
			ps->date[pos].tele,
			ps->date[pos].addr);
	}
}
(6)修改联系人
 

所有,我们可以先让用户输入想要修改人的信息,然后再重新在add所有信息


void Modifycontact(struct contact* ps)
{
	assert(ps != NULL);
	char name[MAX_NAME];
	printf("请输入要修改联系人的姓名:>");
	scanf("%s", name);
	int pos = Find_by_name(ps, name);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
	}
	else
	{
		printf("情输入姓名:>");
		scanf("%s", ps->date[pos].name);
		printf("情输入年龄:>");
		scanf("%d", &(ps->date[pos].age));
		printf("情输入性别:>");
		scanf("%s", ps->date[pos].sex);
		printf("情输入电话:>");
		scanf("%s", ps->date[pos].tele);
		printf("情输入地址:>");
		scanf("%s", ps->date[pos].addr);
		printf("修改信息完成\n");
	}
}

 但是这样写代码不免显得我们不是很nb,直接替换所有的内容,这样也会让一些本来就不用修改的信息又被修改了一遍,这太不专业了。

我们不妨先查找到需要修改人,然后先让用户查找到需要修改的这个人然后选择是修改什么信息,然后重新输入改后的信息,这个其实就和菜单选项实现很相似,我们需要利用枚举变量,跟do。。。while

enum Information
{
	ERRO,
	NAME,
	AGE,
	SEX,
	TELE,
	ADDR,
};
void Modifycontact(struct contact* ps)
{
	assert(ps != NULL);
	char name[MAX_NAME];
	printf("请输入要修改联系人的姓名:>");
	scanf("%s", name);
	int pos = Find_by_name(ps, name);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
	}
	else
	{
		int input = 0;
		do
		{
			printf("请输入你想修改此用户的哪项信息\n");
			printf(" 0.退出 1.姓名 2.年龄 3.性别 4.电话 5.地址:>\n");
			scanf("%d", &input);
			switch (input)
			{
			case NAME:
				printf("情输入姓名:>");
				scanf("%s", ps->date[pos].name);
				break;
			case AGE:
				printf("情输入年龄:>");
				scanf("%d", &(ps->date[pos].age));
				break;
			case SEX:
				printf("情输入性别:>");
				scanf("%s", ps->date[pos].sex);
				break;
			case TELE:
				printf("情输入电话:>");
				scanf("%s", ps->date[pos].tele);
				break;
			case ADDR:
				printf("情输入地址:>");
				scanf("%s", ps->date[pos].addr);
				break;
			case ERRO:
				printf("修改完成\n");
				break;
			default:
				printf("输入错误,请重新输入:>\n");
				break;
			}
		} while (input);
	}
}

 值得注意的是

这里的第一个没有写EXIT,而是ERRO是因为我们第一次使用枚举的时候已经定义过EXIT了再次定义会有错误,重定义

效果如下

 (7)排序通讯录

这一步如果单靠我们自己实现是很麻烦的,但是c语言的库函数里面右qsort,使用该库函数实现起来就非常的简单

int con_name(const void* e1, const void* e2)
{
	return (strcmp(((struct contact*)e1)->date->name, ((struct contact*)e2)->date->name));
}//这里一定要记得强制类型转换
void SortContact(struct contact* ps)
{
	assert(ps);
	if (ps->size == 0)
	{
		printf("通讯录为空,无法排序\n");
		return;
	}
	qsort(ps->date, ps->size, sizeof(ps->date[0]), con_name);
	printf("排序成功\n");
	Showcontact(ps); 
}

重要的内容说三遍

再写con_name时要记得强制类型转换!

再写con_name时要记得强制类型转换!

再写con_name时要记得强制类型转换!

 总结:

test.c

#define  _CRT_SECURE_NO_WARNINGS

#include"contact.h"

void menu()
{
	printf("**************************************\n");
	printf("*****    1.add        2.del      *****\n");
	printf("*****    3.search     4.modify   *****\n");
	printf("*****    5.show       6sort      *****\n");
	printf("*****    0.exit                  *****\n");
	printf("**************************************\n");
}
int main()
{
	int input = 0;
	//创建结构体数组
	struct contact con;
	//初始化结构体数组
	Initcon(&con);
	do {
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			Addcontact(&con);
			break;
		case DEL:
			Delcontact(&con);
			break;
		case SEARCH:
			Searchcontact(&con);
			break;
		case MODIFY:
			Modifycontact(&con);
			break;
		case SHOW:
			Showcontact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入:>\n");
			break;
		}

	} while (input);
	return 0;
}

 contact.c

#define  _CRT_SECURE_NO_WARNINGS

#include"contact.h"

void Initcon(struct contact* ps)
{
	assert(ps!=NULL);
	memset(ps->date, 0, sizeof(ps->date));
	ps->size = 0;
}

void Addcontact(struct contact* ps)
{
	assert(ps != NULL);
	if (ps->size == MAX)
	{
		printf("通讯录已满,无法再进行添加\n");
	}
	else
	{
		printf("情输入姓名:>");
		scanf("%s", ps->date[ps->size].name);
		printf("情输入年龄:>");
		scanf("%d", &(ps->date[ps->size].age));
		printf("情输入性别:>");
		scanf("%s", ps->date[ps->size].sex);
		printf("情输入电话:>");
		scanf("%s", ps->date[ps->size].tele);
		printf("情输入地址:>");
		scanf("%s", ps->date[ps->size].addr);
		ps->size++;
		printf("录入信息完成\n");
	}
}

void Showcontact(const struct contact* ps)
{
	assert(ps != NULL);
	int i = 0;
	if (ps->size == 0)
	{
		printf("通讯录内容为空,无法打印\n");
	}
	else
	{
		for (i = 0; i < ps->size; i++)
		{
			printf("%-20s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
			printf("%-20s\t%-3d\t%-5s\t%-12s\t%-20s\n",
				ps->date[i].name,
				ps->date[i].age,
				ps->date[i].sex,
				ps->date[i].tele,
				ps->date[i].addr);
		}
		}
}

static int Find_by_name(const struct contact* ps, char name[MAX_NAME])
{//static修饰可以使其函数仅可以再本。c生效
	//避免了污染
	assert(ps != NULL);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (strcmp(ps->date[i].name, name) == 0)
			return i;
	}
	return -1;
}
void Delcontact(struct contact* ps)
{
	assert(ps != NULL);
	char name[MAX_NAME];
	printf("请输入要删除联系人的姓名:>");
	scanf("%s", name);
	//查找
	//找到返回pos下标
	//找不到返回-1
	int pos=Find_by_name(ps, name);
	if (pos == -1)
	{
		printf("要删除的联系人不存在\n");
	}
	else
	{
		int j = 0;
		for (j = pos; j <ps->size ; j++)//
			//*******
		{
			ps->date[j] = ps->date[j + 1];
		}
		ps->size--;
		printf("删除成功\n");
	}
}

void Searchcontact(const struct contact* ps)
{
	assert(ps != NULL);
	char name[MAX_NAME];
	printf("请输入要查找联系人的姓名:>");
	scanf("%s", name);
	int pos = Find_by_name(ps, name);
	if (pos == -1)
	{
		printf("要查找的联系人不存在\n");
	}
	else
	{
		printf("信息如下:\n");
		printf("%-20s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-20s\t%-3d\t%-5s\t%-12s\t%-20s\n",
			ps->date[pos].name,
			ps->date[pos].age,
			ps->date[pos].sex,
			ps->date[pos].tele,
			ps->date[pos].addr);
	}
}

//void Modifycontact(struct contact* ps)
//{
//	assert(ps != NULL);
//	char name[MAX_NAME];
//	printf("请输入要修改联系人的姓名:>");
//	scanf("%s", name);
//	int pos = Find_by_name(ps, name);
//	if (pos == -1)
//	{
//		printf("要修改的联系人不存在\n");
//	}
//	else
//	{
//		printf("情输入姓名:>");
//		scanf("%s", ps->date[pos].name);
//		printf("情输入年龄:>");
//		scanf("%d", &(ps->date[pos].age));
//		printf("情输入性别:>");
//		scanf("%s", ps->date[pos].sex);
//		printf("情输入电话:>");
//		scanf("%s", ps->date[pos].tele);
//		printf("情输入地址:>");
//		scanf("%s", ps->date[pos].addr);
//		printf("修改信息完成\n");
//	}
//}


void Modifycontact(struct contact* ps)
{
	assert(ps != NULL);
	char name[MAX_NAME];
	printf("请输入要修改联系人的姓名:>");
	scanf("%s", name);
	int pos = Find_by_name(ps, name);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
	}
	else
	{
		int input = 0;
		do
		{
			printf("请输入你想修改此用户的哪项信息\n");
			printf(" 0.退出 1.姓名 2.年龄 3.性别 4.电话 5.地址:>\n");
			scanf("%d", &input);
			switch (input)
			{
			case NAME:
				printf("情输入姓名:>");
				scanf("%s", ps->date[pos].name);
				break;
			case AGE:
				printf("情输入年龄:>");
				scanf("%d", &(ps->date[pos].age));
				break;
			case SEX:
				printf("情输入性别:>");
				scanf("%s", ps->date[pos].sex);
				break;
			case TELE:
				printf("情输入电话:>");
				scanf("%s", ps->date[pos].tele);
				break;
			case ADDR:
				printf("情输入地址:>");
				scanf("%s", ps->date[pos].addr);
				break;
			case ERRO:
				printf("修改完成\n");
				break;
			default:
				printf("输入错误,请重新输入:>\n");
				break;
			}
		} while (input);
	}
}



int con_name(const void* e1, const void* e2)
{
	return (strcmp(((struct contact*)e1)->date->name, ((struct contact*)e2)->date->name));
}
void SortContact(struct contact* ps)
{
	assert(ps);
	if (ps->size == 0)
	{
		printf("通讯录为空,无法排序\n");
		return;
	}
	qsort(ps->date, ps->size, sizeof(ps->date[0]), con_name);
	printf("排序成功\n");
	Showcontact(ps); 
}

 contact.h

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

#define MAX 1000

#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30

enum option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW, 
	SORT,
};
enum Information
{
	ERRO,
	NAME,
	AGE,
	SEX,
	TELE,
	ADDR,
};

struct PeoInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
};

struct contact
{
	struct PeoInfo date[MAX];
	int size;
};

void Initcon(struct contact* ps);

void Addcontact(struct contact* ps);

void Showcontact(const struct contact* ps);

void Delcontact(struct contact* ps);

void Searchcontact(const struct contact* ps);

void Modifycontact(struct contact* ps);

优化部分:

 这个通讯录我们不难发现他有一个致命的缺点,就是我们初始化的通讯录大小为1000,但是当我们想要存的内容不足1000的时候,直接开辟1000个元素空间,未免有点浪费空间,又或者说我们存的元素超过1000,那么编译器就会给我们报错,我们就需要继续手动增加空间,所以为了避免这样我们可以利用动态内存分配来定义我们的通讯录结构体。

我们需要多少就开辟多少空间,那么就很智能。

1、通讯录结构体的改进

这边我们可以把之前的结构体里面的数组变成一个指针数组,并且为了考虑这个通讯录来回删除增加的缘故,一个sz来记录数组元素个数是不行的,我们需要在设定一个值为数组最大的空间,当sz和他相等的时候我们就需要扩充这个数组。我们先设定原来容量为3,当达到原本的容量以后,在进行开辟两个空间。

改前的代码 

struct contact
{
	struct PeoInfo date[MAX];
	int size;
};

改后的代码

struct contact
{
	struct PeoInfo *date;
	int size;
	int capacity;
};

 2、初始化结构体的改进

我们思考后大概知道需要改进的内容分别是初始化与增加

这个初始化结构体,我们需要sz初始化为0,并且为指针开辟一块空间,并且赋予capacity一个初始值,我们一开始说过了一开始默认容量为3,那么需要用宏的定义去定义capacity。

改前的代码 

	memset(ps->date, 0, sizeof(ps->date));
	ps->size = 0;

改后的代码 

#define CAPACITY 3

void Initcon(struct contact* ps)
{
	assert(ps != NULL);
	ps->size = 0;
	ps->capacity = CAPACITY;
	ps->date = (struct PeoInfo*)malloc(ps->capacity * sizeof(struct PeoInfo));
	if (ps->date == NULL)
	{
		printf("%s\n", strerror(errno));
		return;
	}
}

 3、add部分的改进 

 add部分改的思路就是,原本的空间不再是1000而是默认的3,所以我们在add的时候需要进行判断是否达到capacity,达不到就进行正常add,达到了就进行增容处理;

改前的代码

void Addcontact(struct contact* ps)
{
	assert(ps != NULL);
	if (ps->size == MAX)
	{
		printf("通讯录已满,无法再进行添加\n");
	}
	else
	{
		printf("情输入姓名:>");
		scanf("%s", ps->date[ps->size].name);
		printf("情输入年龄:>");
		scanf("%d", &(ps->date[ps->size].age));
		printf("情输入性别:>");
		scanf("%s", ps->date[ps->size].sex);
		printf("情输入电话:>");
		scanf("%s", ps->date[ps->size].tele);
		printf("情输入地址:>");
		scanf("%s", ps->date[ps->size].addr);

		ps->size++;//千万要记得++

		printf("录入信息完成\n");
	}
}

 改后的代码

void Checkcapacity(struct contact* ps)
{
	if (ps->size == ps->capacity)
	{
		struct PeoInfo* str=realloc(ps->date, (ps->capacity + 2) * sizeof(struct PeoInfo));
		if (str != NULL)
		{
			ps->date = str;
			ps->capacity += 2;
			printf("增容成功\n");
		}
		else
		{
			printf("%s\n", strerror(errno));
			printf("增容失败\n");
		}
	}
}

void Addcontact(struct contact* ps)
{
	assert(ps != NULL);
	Checkcapacity(ps);
	printf("情输入姓名:>");
	scanf("%s", ps->date[ps->size].name);
	printf("情输入年龄:>");
	scanf("%d", &(ps->date[ps->size].age));
	printf("情输入性别:>");
	scanf("%s", ps->date[ps->size].sex);
	printf("情输入电话:>");
	scanf("%s", ps->date[ps->size].tele);
	printf("情输入地址:>");
	scanf("%s", ps->date[ps->size].addr);
	ps->size++;
	printf("录入信息完成\n");
}

  4、释放内存 

 在我们使用完该通讯录以后,因为我们优化后使用了动态内存,所以要进行正规的操作,也就是内存释放

void DestroyContact(struct contact* ps)
{
	assert(ps);
	free(ps->date);
	ps->date = NULL;
	ps->size = 0;
    printf("销毁成功\n");
}

放的地方也就是在

 

5、文件保存

 我们没使用过通讯录的就会像上面所说的步骤一下,初始化,添加,删除,什么的,但是我使用过一次后,再后续使用的时候,是不是应该保存以前使用过的所有信息呢?那么一下操作就是实现该功能,主要知识是涉及到文件操作部分

我们还需要添加一个新的功能选项,也就是保存数据:savecontact

enum option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW, 
	SORT,
	SAVE,
};
//菜单:
void menu()
{
	printf("**************************************\n");
	printf("*****    1.add        2.del      *****\n");
	printf("*****    3.search     4.modify   *****\n");
	printf("*****    5.show       6sort      *****\n");
	printf("*****    7.save       0.exit     *****\n");
	printf("**************************************\n");
}

int main()
{
	int input = 0;
	//创建结构体数组
	struct contact con;
	//初始化结构体数组
	Initcon(&con);
	do {
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
	//...
		case SAVE:
			SaveContact(&con);
			break;
//...
		}

	} while (input);
	return 0;
}

接下来就是实现savecontact

void SaveContact(struct contact* ps)
{
	FILE* pfwrite = fopen("contact.dat", "wb");
	if (pfwrite == NULL)
	{
		printf("SaveContact::%s", strerror(errno));
		return;
	}
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		fwrite(&(ps->date[i]), sizeof(struct PeoInfo), 1, pfwrite);
	}
	fclose(pfwrite);
	pfwrite = NULL;
}

那我们做了以上的操作过后,感觉可以了,但细心思考过后发现,我们还需要进行改代码把初始化部分进行修改,要不然的话每次都会将通讯录初始化为0,这样显然是不可以,改进后的初始化我们想达到的目就是:初始化结果为上次已经输入过的数据; 

void Checkcapacity(struct contact* ps);

void Initcon(struct contact* ps)
{
	assert(ps != NULL);
	ps->size = 0;
	ps->capacity = CAPACITY;
	ps->date = (struct PeoInfo*)malloc(ps->capacity * sizeof(struct PeoInfo));
	if (ps->date == NULL)
	{
		printf("%s\n", strerror(errno));
		return;
	}
	//将文件的信息存贮到通讯录里面
	loadcontact(ps);
}


void loadcontact(struct contact* ps)
{
	struct PeoInfo tmp = { 0 };
	FILE* pfread = fopen("contact.dat", "rb");
	if (pfread == NULL)
	{
		printf("loadcontact::%s\n", strerror(errno));
		return;
	}
	while (fread(&(tmp), sizeof(struct PeoInfo), 1, pfread))
	{
		Checkcapacity(ps);
		ps->date[ps->size] = tmp;
		ps->size++;
	}
	fclose(pfread);
	pfread = NULL;
}


void Checkcapacity(struct contact* ps)
{
	if (ps->size == ps->capacity)
	{
		struct PeoInfo* str=realloc(ps->date, (ps->capacity + 2) * sizeof(struct PeoInfo));
		if (str != NULL)
		{
			ps->date = str;
			ps->capacity += 2;
			printf("增容成功\n");
		}
		else
		{
			printf("%s\n", strerror(errno));
			printf("增容失败\n");
		}
	}
}

总结:

test.c(优化版)

#define  _CRT_SECURE_NO_WARNINGS

#include"contact.h"

void menu()
{
	printf("**************************************\n");
	printf("*****    1.add        2.del      *****\n");
	printf("*****    3.search     4.modify   *****\n");
	printf("*****    5.show       6sort      *****\n");
	printf("*****    7.save       0.exit     *****\n");
	printf("**************************************\n");
}
int main()
{
	int input = 0;
	//创建结构体数组
	struct contact con;
	//初始化结构体数组
	Initcon(&con);
	do {
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			Addcontact(&con);
			break;
		case DEL:
			Delcontact(&con);
			break;
		case SEARCH:
			Searchcontact(&con);
			break;
		case MODIFY:
			Modifycontact(&con);
			break;
		case SHOW:
			Showcontact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case SAVE:
			SaveContact(&con);
			break;
		case EXIT:
			SaveContact(&con);
			DestroyContact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入:>\n");
			break;
		}

	} while (input);
	return 0;
}
 contact.c(优化版)

#define  _CRT_SECURE_NO_WARNINGS

#include"contact.h"


void Checkcapacity(struct contact* ps);

void Initcon(struct contact* ps)
{
	assert(ps != NULL);
	ps->size = 0;
	ps->capacity = CAPACITY;
	ps->date = (struct PeoInfo*)malloc(ps->capacity * sizeof(struct PeoInfo));
	if (ps->date == NULL)
	{
		printf("%s\n", strerror(errno));
		return;
	}
	//将文件的信息存贮到通讯录里面
	loadcontact(ps);
}


void loadcontact(struct contact* ps)
{
	struct PeoInfo tmp = { 0 };
	FILE* pfread = fopen("contact.dat", "rb");
	if (pfread == NULL)
	{
		printf("loadcontact::%s\n", strerror(errno));
		return;
	}
	while (fread(&(tmp), sizeof(struct PeoInfo), 1, pfread))
	{
		Checkcapacity(ps);
		ps->date[ps->size] = tmp;
		ps->size++;
	}
	fclose(pfread);
	pfread = NULL;
}


void Checkcapacity(struct contact* ps)
{
	if (ps->size == ps->capacity)
	{
		struct PeoInfo* str=realloc(ps->date, (ps->capacity + 2) * sizeof(struct PeoInfo));
		if (str != NULL)
		{
			ps->date = str;
			ps->capacity += 2;
			printf("增容成功\n");
		}
		else
		{
			printf("%s\n", strerror(errno));
			printf("增容失败\n");
		}
	}
}

void Addcontact(struct contact* ps)
{
	assert(ps != NULL);
	Checkcapacity(ps);
	printf("情输入姓名:>");
	scanf("%s", ps->date[ps->size].name);
	printf("情输入年龄:>");
	scanf("%d", &(ps->date[ps->size].age));
	printf("情输入性别:>");
	scanf("%s", ps->date[ps->size].sex);
	printf("情输入电话:>");
	scanf("%s", ps->date[ps->size].tele);
	printf("情输入地址:>");
	scanf("%s", ps->date[ps->size].addr);
	ps->size++;
	printf("录入信息完成\n");
}

void Showcontact(const struct contact* ps)
{
	assert(ps != NULL);
	int i = 0;
	if (ps->size == 0)
	{
		printf("通讯录内容为空,无法打印\n");
	}
	else
	{
		for (i = 0; i < ps->size; i++)
		{
			printf("%-20s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
			printf("%-20s\t%-3d\t%-5s\t%-12s\t%-20s\n",
				ps->date[i].name,
				ps->date[i].age,
				ps->date[i].sex,
				ps->date[i].tele,
				ps->date[i].addr);
		}
		}
}

static int Find_by_name(const struct contact* ps, char name[MAX_NAME])
{//static修饰可以使其函数仅可以再本。c生效
	//避免了污染
	assert(ps != NULL);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (strcmp(ps->date[i].name, name) == 0)
			return i;
	}
	return -1;
}
void Delcontact(struct contact* ps)
{
	assert(ps != NULL);
	char name[MAX_NAME];
	printf("请输入要删除联系人的姓名:>");
	scanf("%s", name);
	//查找
	//找到返回pos下标
	//找不到返回-1
	int pos=Find_by_name(ps, name);
	if (pos == -1)
	{
		printf("要删除的联系人不存在\n");
	}
	else
	{
		int j = 0;
		for (j = pos; j <ps->size ; j++)//
			//*******
		{
			ps->date[j] = ps->date[j + 1];
		}
		ps->size--;
		printf("删除成功\n");
	}
}

void Searchcontact(const struct contact* ps)
{
	assert(ps != NULL);
	char name[MAX_NAME];
	printf("请输入要查找联系人的姓名:>");
	scanf("%s", name);
	int pos = Find_by_name(ps, name);
	if (pos == -1)
	{
		printf("要查找的联系人不存在\n");
	}
	else
	{
		printf("信息如下:\n");
		printf("%-20s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-20s\t%-3d\t%-5s\t%-12s\t%-20s\n",
			ps->date[pos].name,
			ps->date[pos].age,
			ps->date[pos].sex,
			ps->date[pos].tele,
			ps->date[pos].addr);
	}
}



void Modifycontact(struct contact* ps)
{
	assert(ps != NULL);
	char name[MAX_NAME];
	printf("请输入要修改联系人的姓名:>");
	scanf("%s", name);
	int pos = Find_by_name(ps, name);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
	}
	else
	{
		int input = 0;
		do
		{
			printf("请输入你想修改此用户的哪项信息\n");
			printf(" 0.退出 1.姓名 2.年龄 3.性别 4.电话 5.地址:>\n");
			scanf("%d", &input);
			switch (input)
			{
			case NAME:
				printf("情输入姓名:>");
				scanf("%s", ps->date[pos].name);
				break;
			case AGE:
				printf("情输入年龄:>");
				scanf("%d", &(ps->date[pos].age));
				break;
			case SEX:
				printf("情输入性别:>");
				scanf("%s", ps->date[pos].sex);
				break;
			case TELE:
				printf("情输入电话:>");
				scanf("%s", ps->date[pos].tele);
				break;
			case ADDR:
				printf("情输入地址:>");
				scanf("%s", ps->date[pos].addr);
				break;
			case ERRO:
				printf("修改完成\n");
				break;
			default:
				printf("输入错误,请重新输入:>\n");
				break;
			}
		} while (input);
	}
}



int con_name(const void* e1, const void* e2)
{
	return (strcmp(((struct contact*)e1)->date->name, ((struct contact*)e2)->date->name));
}
void SortContact(struct contact* ps)
{
	assert(ps);
	if (ps->size == 0)
	{
		printf("通讯录为空,无法排序\n");
		return;
	}
	qsort(ps->date, ps->size, sizeof(ps->date[0]), con_name);
	printf("排序成功\n");
	Showcontact(ps); 
}

void SaveContact(struct contact* ps)
{
	FILE* pfwrite = fopen("contact.dat", "wb");
	if (pfwrite == NULL)
	{
		printf("SaveContact::%s", strerror(errno));
		return;
	}
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		fwrite(&(ps->date[i]), sizeof(struct PeoInfo), 1, pfwrite);
	}
	fclose(pfwrite);
	pfwrite = NULL;
}

void DestroyContact(struct contact* ps)
{
	assert(ps);
	free(ps->date);
	ps->date = NULL;
	ps->size = 0;
	printf("销毁成功\n");
}
  contact.h(优化版)
#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<errno.h>


#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
#define CAPACITY 3
enum option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW, 
	SORT,
	SAVE,
};
enum Information
{
	ERRO,
	NAME,
	AGE,
	SEX,
	TELE,
	ADDR,
};

struct PeoInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
};

struct contact
{
	struct PeoInfo *date;
	int size;
	int capacity;
};

void Initcon(struct contact* ps);

void Addcontact(struct contact* ps);

void Showcontact(const struct contact* ps);

void Delcontact(struct contact* ps);

void Searchcontact(const struct contact* ps);

void Modifycontact(struct contact* ps);

void SortContact(struct contact* ps);

void DestroyContact(struct contact* ps);

void SaveContact(struct contact* ps);

void loadcontact(struct contact* ps);

 感谢阅读!!!

  • 33
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值