c-通讯录【动态通讯录,文件版本通讯录】

一、通讯录的结构

首先如何实现一个通讯录呢?

a.根据日常生活我们知道一个通讯录包括:

1.可以保存多少个联系人的信息

2.增加联系人

3.删除指定联系人

4.查找指定联系人的信息

5.修改指定联系人的信息

6.显示所有联系人的信息

b.而每一个联系人,我们也需要填写相关信息:

1.名字 2.年龄 3.性别 4.电话 5.住址

根据以上需求,我们可以有目的的开始编写代码。

c.为了增加代码的可读性我们将代码分为三个部分:

1.test.c          -测试代码

2.contact.h    -函数声明

3.contact.c    -函数实现

二、代码实现

a.首先,我们先写主函数及通讯录菜单---test.c中内容

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

}
enum Option
{
	EXIT,
	ADD,
	SHOW,
	DEL,
	SEARCH,
	MODIFY,
	SORT//按照什么排序
};//这里用到了枚举常量,为了增加代码的可读性,在switch中体现,在菜单中方便选择读者想用的选项

int main()
{
	Contact con;//定义一个通讯录变量
	int input = 0;//接收选择数字
	InitContact(&con);
	do
	{
		menu();
		printf("请输入你的选择->");
		scanf("%d", &input);
		switch (input)
		{

		case ADD:
			AddContact(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SEARCH:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case EXIT:
			SaveContact(&con);
			DestroyContact(&con);
			printf("退出通讯录");
			break;
		default:
			printf("选择错误,请重新选择");
			break;
		}
	} while (input);
		
	return 0;
}

这里可以观察到因为我们使用了枚举常量,代码的观赏性提高。

b.接着我们可以在contact.h中声明我们所创立的函数

#pragma once
#include
#include
#include
#include
#define NAME_MAX 10
#define SEX_MAX 10
#define TELE_MAX 20
#define ADDR_MAX 40
#define MAX 100
#define SZ 3
#define INCREACE 2
typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tele_num[TELE_MAX];
	char addr[ADDR_MAX];
}PeoInfo;
typedef struct Contact
{
	PeoInfo* data;//用来指向任务信息的指针 媒介
	int sz;//用来记录通讯录人数
	int capacity;//用来记录通讯录容量
}Contact;


void InitContact(Contact* pc);//初始化通讯录

void AddContact(Contact* pc);//添加联系人

void ShowContact(Contact* pc);//显示所有联系人

void DelContact(Contact* pc);//删除所指定的联系人

void SearchContact(Contact* pc);//查找指定的联系人

void ModifyContact(Contact* pc);//修改指定联系人

void DestroyContact(Contact* pc);//销毁通讯录

void SaveContact(Contact* pc);//保存通讯录到文件

void LoadContact(Contact* pc);//从文件中导出通讯录

现在我们将开始分析以上代码:

typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tele_num[TELE_MAX];
	char addr[ADDR_MAX];
}PeoInfo;

这里创建了一个结构体用于建立人物信息,并且设立了结构体变量PeoInfo,便于灵活处理任务信息。

typedef struct Contact
{
	PeoInfo* data;//用来指向任务信息的指针 媒介
	int sz;//用来记录通讯录人数
	int capacity;//用来记录通讯录容量
}Contact;

这里便用结构体来建立通讯录信息,且设立了结构体变量Contact,便于通讯录中人数的记录,扩容等等。

void InitContact(Contact* pc);//初始化通讯录

void AddContact(Contact* pc);//添加联系人

void ShowContact(Contact* pc);//显示所有联系人

void DelContact(Contact* pc);//删除所指定的联系人

void SearchContact(Contact* pc);//查找指定的联系人

void ModifyContact(Contact* pc);//修改指定联系人

void DestroyContact(Contact* pc);//销毁通讯录

void SaveContact(Contact* pc);//保存通讯录到文件

void LoadContact(Contact* pc);//从文件中导出通讯录

以上代码就是我们所需要用到的主要函数的声明,我们在传入参数时传入的是通讯录变量的指针,方便更改与查找。

c.最后我们在contact.c中进行函数具体实现,(注意:每编写完一个函数,一定要运行一次程序,方便进行调试找到我们的错误)

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void CheckCapacity(Contact* pc);
void LoadContact(Contact* pc)
{
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	PeoInfo tmp = { 0 };
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))//只要不为0就能一直运行
	{
		CheckCapacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;

	}
	fclose(pf);
	pf = NULL;
}
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = SZ;
	pc->data = calloc(pc->capacity, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
	LoadContact(pc);
}
void  CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INCREACE) * sizeof(PeoInfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += INCREACE;
			printf("增容成功!\n");
		}
		else
		{
			perror(" AddContact->realloc");
			return;
		}
	}
	

}
void AddContact(Contact* pc)
{
	assert(pc);
	CheckCapacity(pc);//检查容量是否充足,不足则增加
	printf("请输入姓名:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入手机号码:");
	scanf("%s", pc->data[pc->sz].tele_num);
	printf("请输入住址:");
	scanf("%s", pc->data[pc->sz].addr);
	pc->sz++;
	printf("添加成功\n");
}
void ShowContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法打印");
		return;
	}
	int i = 0;
	printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-12s%-30s\n", pc->data[i].name,
			pc->data[i].age, pc->data[i].sex, pc->data[i].tele_num,
			pc->data[i].addr);
	}
}
static int FindByName(Contact* pc,char name[] )
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(name, pc->data[i].name) == 0)
		{
			return i;
		}
		else
		{
			return -1;
		}
	}
}
void DelContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	printf("请输入要删除的人的名字:");
	scanf("%s", name);
	int i = 0;
	int inc = FindByName(pc,name);
	if (inc != -1)
	{
		int i = inc;
		for (i = inc; i < pc->sz-1; i++)
		{
			pc->data[i] = pc->data[i + 1];//最后一个pc->data[sz-2]==pc->data[sz-1]
			
		}
		pc->sz--;
		printf("删除成功\n");
	}
	else
	{
		printf("所要删除的人不存在\n");
		return;
	}
}
void SearchContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法查找\n");
		return;
	}
	printf("请输入查找的人的名字:");
	scanf("%s", name);
	int inc = FindByName(name, pc);
	if (inc == -1)
	{
		printf("查找失败,没有这个人\n");
		return;
	}
	printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	int i = inc;
	printf("%-20s%-5d%-5s%-12s%-30s\n", pc->data[i].name,
		pc->data[i].age, pc->data[i].sex, pc->data[i].tele_num,
		pc->data[i].addr);
}
void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX];

	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法查找\n");
		return;
	}
	printf("请输入修改的人的名字:");
	scanf("%s", name);
	int inc = FindByName(pc,name);
	if (inc == -1)
	{
		printf("查找失败,没有这个人\n");
		return;
	}
	printf("请输入姓名:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入手机号码:");
	scanf("%s", pc->data[pc->sz].tele_num);
	printf("请输入住址:");
	scanf("%s", pc->data[pc->sz].addr);
	printf("修改成功!");
}
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->sz = 0;
	pc->capacity = 0;
}
void SaveContact(Contact* pc)
{
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
	}
	fclose(pf);
	pf = NULL;
}

以上就是文件版本contact.c中所有的代码,接下来我们开始进行简略分析:

文件版本:void InitContact(Contact* pc)

void InitContact(Contact* pc)//初始化通讯录
{
	assert(pc);//断言
	pc->sz = 0;//相当于来记录人数
	pc->capacity = SZ;//一个初始通讯录,人物最大容量,
//在添加联系人的时候与sz进行比较,用于判断是否需要扩容
	pc->data = calloc(pc->capacity, sizeof(PeoInfo));//动态内存分配为存放数据开辟空间
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");//利用perror来进行报错
		return;
	}
	LoadContact(pc);
}

assert用法:

#include

void assert (int expression)

作用是实现计算表达式expression ,若其值为0,打印错误信息,调用abort来终止程序。

在此的作用是检查传入参数pc的合法性

动态版本:(区别就是,在初始化时不将信息录入文件)

void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = SZ;
	pc->data = calloc(pc->capacity, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
	
}

普通版本:(省略)

文件版本(同动态):void CheckCapacity(Contact* pc)

在添加,录入通讯录信息时,需要检查通讯录是否有足够空间,有人物信息。

void  CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INCREACE) * sizeof(PeoInfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += INCREACE;
			printf("增容成功!\n");
		}
		else
		{
			perror(" AddContact->realloc");
			return;
		}
	}
}

文件版本(同动态):void AddContact(Contact* pc)

void AddContact(Contact* pc)
{
	assert(pc);
	CheckCapacity(pc);//检查容量是否充足,不足则增加
	printf("请输入姓名:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入手机号码:");
	scanf("%s", pc->data[pc->sz].tele_num);
	printf("请输入住址:");
	scanf("%s", pc->data[pc->sz].addr);
	pc->sz++;
	printf("添加成功\n");
}

使用:void realloc(void* ptr,size_t size);

据实际情况,size是调整后的新大小,返回值为调整后内存起始地址。 

文件版本(同动态):void ShowContact(Contact* pc)

void ShowContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法打印");
		return;
	}
	int i = 0;
	printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-12s%-30s\n", pc->data[i].name,
			pc->data[i].age, pc->data[i].sex, pc->data[i].tele_num,
			pc->data[i].addr);
	}
}

文件版本(同动态):static int FindByName(Contact* pc,char name[] )

在查找,修改,删除人物信息的时候需要先判断该人物是否存在

static int FindByName(Contact* pc,char name[] )
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(name, pc->data[i].name) == 0)
		{
			return i;
		}
		else
		{
			return -1;
		}
	}
}

文件版本(同动态版本):void DelContact(Contact* pc)

void DelContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	printf("请输入要删除的人的名字:");
	scanf("%s", name);
	int i = 0;
	int inc = FindByName(pc,name);
	if (inc != -1)
	{
		int i = inc;
		for (i = inc; i < pc->sz-1; i++)
		{
			pc->data[i] = pc->data[i + 1];//最后一个pc->data[sz-2]==pc->data[sz-1]
			
		}
		pc->sz--;
		printf("删除成功\n");
	}
	else
	{
		printf("所要删除的人不存在\n");
		return;
	}
}

文件版本(同动态):void SearchContact(Contact* pc)

void SearchContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法查找\n");
		return;
	}
	printf("请输入查找的人的名字:");
	scanf("%s", name);
	int inc = FindByName(name, pc);
	if (inc == -1)
	{
		printf("查找失败,没有这个人\n");
		return;
	}
	printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	int i = inc;
	printf("%-20s%-5d%-5s%-12s%-30s\n", pc->data[i].name,
		pc->data[i].age, pc->data[i].sex, pc->data[i].tele_num,
		pc->data[i].addr);
}

文件版本(同动态):void ModifyContact(Contact* pc)

void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX];
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法查找\n");
		return;
	}
	printf("请输入修改的人的名字:");
	scanf("%s", name);
	int inc = FindByName(pc, name);
	if (inc == -1)
	{
		printf("查找失败,没有这个人\n");
		return;
	}
	printf("请输入姓名:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入手机号码:");
	scanf("%s", pc->data[pc->sz].tele_num);
	printf("请输入住址:");
	scanf("%s", pc->data[pc->sz].addr);
	printf("修改成功!");
}

文件版本(同动态):void DestroyContact(Contact* pc)

void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->sz = 0;
	pc->capacity = 0;
}

文件版本(动态版本无):void SaveContact(Contact* pc)

void SaveContact(Contact* pc)
{
	FILE* pf = fopen("contact.txt", "wb");//“wb”为了输出数据,打开一个二进制文件
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
       //将人物数据pc->data + 1大小为1个sizeof(PeoInfo)写入pf中
	}
	fclose(pf);//记得关闭
	pf = NULL;//防止pf成为野指针
}

文件版本(动态版本无):void LoadContact(Contact* pc)

void LoadContact(Contact* pc)
{
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	PeoInfo tmp = { 0 };
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))//只要不为0就能一直运行
	{
		CheckCapacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;

	}
	fclose(pf);
	pf = NULL;
}

以上就是我们动态/文件版本通讯录的程序。

感谢观看,第一次写博客,若有不足请多多指教,我会努力改进的!

你可能感兴趣的:(c语言,c语言,开发语言)