【C语言】实现简单通讯录系统(源码)

文章目录

  • 一、通讯录简介
  • 二、自定义的函数操作数据
    • 1.定义使用的常量和通讯录个人信息类
    • 2.初始化通讯录
    • 3.往通讯录中添加联系人
    • 4.删除通讯录中的某个联系人
    • 5.查找通讯录中的某个联系人
    • 6.修改通讯录中某个联系人的信息
    • 7.打印现存通讯录中的联系人的信息
    • 8.把通讯录中的联系人按名字排序
  • 三、优化
    • 1.使用枚举类
    • 2.释放动态开辟的内存
    • 3. 保存数据
    • 4.加载数据
  • 四、源码
    • 1、contact.c
    • 2、contact.h
    • 3、test.c


一、通讯录简介

  实现一个通讯录,通讯录可以动态开辟空间,因此可以存入很多数据,每个人的信息包括:姓名、性别、年龄、电话、住址。
  提供了一些函数去操作数据

二、自定义的函数操作数据

1.定义使用的常量和通讯录个人信息类

//宏定义,定义经常使用的常量
#define NAME_MAX 20  //姓名长度
#define SEX_MAX 5	 //性别长度
#define ADDR_MAX 30  //地址长度
#define TELE_MAX 12  //电话长度
#define DEFAULT_SZ 3  //通讯录初始化时可存放数据个数
#define INC_SZ 2      //每次扩容个数

//定义的通讯录个人信息结构体
typedef struct PeoInfo 
{
	char name[NAME_MAX];	//名字
	int age;				//年龄
	char sex[SEX_MAX];		//性别
	char addr[ADDR_MAX];	//地址
	char tele[TELE_MAX];	//电话
}PeoInfo;

//通讯录
typedef struct Contact
{
	PeoInfo* data;//指向存放人的信息的空间
	int sz;//存放已存信息人的个数
	int capacity;//当前通讯录的容量
}Contact;

2.初始化通讯录

void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;//sz表示现存通讯录中人的个数
	//calloc动态开辟可以存放3个PeoInfo的内存
	PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ,sizeof(PeoInfo));;
	if (ptr == NULL)
	{
		//如果内存开辟失败,打印出开辟失败的原因
		perror("InitContact:calloc");
		return ;
	}
	pc->data = ptr;//如果内存开辟成功,将data指向开辟好的内存的地址
	pc->capacity = DEFAULT_SZ;
}

3.往通讯录中添加联系人

void AddContact(Contact* pc)
{
	assert(pc);
	//检查内存是否够用,如果不够,使用calloc调整已经开辟好的空间的大小
	check_capacity(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].addr);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);

	pc->sz++;
}

//判断内存是否够用
void check_capacity(Contact* pc)
{
	//判断通讯录中现存的数据是否跟最大存储数据个数相同
	if (pc->sz == pc->capacity)
	{
		//如果数据已满,增加容量,每次增加两个可以存放个人信息的内存
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data,(pc->capacity + 2)*sizeof(PeoInfo));
		if (ptr == NULL)
		{
			//打印开辟失败的原因
			perror("check_capacity:realloc");
			return;
		}
		pc->data = ptr;//将开辟好的内存的地址再次赋值给data
		pc->capacity += INC_SZ;//将可存放最大数据个数+2
		printf("增容成功.\n");
	}
}

4.删除通讯录中的某个联系人

void DelContact(Contact* pc)
{
	if (pc->sz == 0)
	{
		//如果通讯录中联系人的个数为0.则没有可以删除的数据
		printf("通讯录为空,无法删除\n");
		return;
	}
	//找到要删除的人   调用自定义函数查找联系人
	int ret=FindByName(pc);//DwlContact(Contact* pc)这里的形参本来就是地址,所以调用FindByName(Contact* pc)直接传入pc即可
	if (ret == -1)
	{
		//FindByName返回-1表示通讯录中没有此联系人
		printf("要删除的人不存在\n");
		return;
	}
	//如果ret!=-1 表示找到,根据返回位置删除该联系人
	int i = 0;
	for (i = 0; i < pc->sz - 1; i++)
	{
		//如果删除的是中间的联系人,则后面的联系人补删除的联系人的空间
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;//删除一个联系人后,现存联系人个数sz-1
	printf("删除成功\n");
}

5.查找通讯录中的某个联系人

int FindByName(Contact* pc)
{
	//临时变量,存放从键盘读入的联系人的名字
	char name[NAME_MAX] = { 0 };
	printf("请输入名字:");
	scanf("%s", name);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)//找到联系人
		{
			//返回该联系人的位置
			return i;
		}
	}
	//没找到,返回-1
	return -1;
}

6.修改通讯录中某个联系人的信息

void ModifyContact(Contact* pc)
{
	assert(pc);
	//查找联系人
	int pos = FindByName(pc);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
		return;
	}
	//修改联系人
	printf("请输入姓名:");
	scanf("%s", pc->data[pos].name);
	printf("请输入年龄:");
	scanf("%d", &pc->data[pos].age);
	printf("请输入性别:");
	scanf("%s", pc->data[pos].sex);
	printf("请输入地址:");
	scanf("%s", pc->data[pos].addr);
	printf("请输入电话:");
	scanf("%s", pc->data[pos].tele);
}

7.打印现存通讯录中的联系人的信息

void ShowContact(const Contact* pc)
{
	printf("%-10s\t%-4s\t%-5s\t%-7s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-10s\t%-4d\t%-5s\t%-7s\t%-12s", pc->data[i].name, pc->data[i].age, 
								pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);
		printf("\n");
	}
}

8.把通讯录中的联系人按名字排序

void Sort(Contact* pc)
{
	if (pc->sz >= 2) 
	{
		//使用库函数qsort  qsort函数需要传入一个函数的地址作为比较方法
		qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_struct_name);
	}
	ShowContact(pc);
}
//自定义函数比较方法,使用名字排序,也可自定义其他方法进行拍排序
int cmp_struct_name(const void* e1, const void* e2)
{
	return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
}

三、优化

1.使用枚举类

  使用枚举类,然后定义菜单的case会比较方便,清楚明了知道每一个case的实现作用是什么

enum MyEnum
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MOD,
	SHOW,
	SORT
};


do {
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			//增
			AddContact(&con);
			break;
		case DEL:
			//删
			DelContact(&con);
			break;
		case SEARCH:
			//查
			i=FindByName(&con);
			if (i >= 0) {
				printf("%-10s\t%-4s\t%-5s\t%-7s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
				printf("%-10s\t%-4d\t%-5s\t%-7s\t%-12s\n", con.data[i].name, con.data[i].age, con.data[i].sex, con.data[i].addr, con.data[i].tele);
			}
			else if (i < 0) {
				printf("找不到");
				}
			break;
		case MOD:
			//改存入的信息
			ModifyContact(&con);
			break;
		case SHOW:
			//打印现存数据
			ShowContact(&con);
			break;
		case SORT:
			Sort(&con);
			break;
		case EXIT:
			Destory_Contact(&con);
			printf("退出通讯录.\n");
			break;
		default:
			printf("选择错误:\n");
			break;

		}


	} while (input);

2.释放动态开辟的内存

  动态开辟内存使用结束后,最好手动释放一下

//释放colloc申请的空间
void Destory_Contact(Contact* pc)
{
	free(pc->data);//将开辟的内存释放
	pc->data = NULL;//将指针置为空
	pc->capacity = 0;
	pc->sz = 0;
	pc = NULL;
}

3. 保存数据

  程序退出的时候通讯录中的信息一般不会保存,所有我们创建一个Contact.txt的文本文件用来存放通讯录中的联系人的信息,在方便保存信息和加载通讯录中的联系人信息

void SaveContact(Contact* pc)
{
	//写数据
	//1, 打开文件
	FILE* pf = fopen("contact.txt", "wb");
	if (NULL == pf)
	{
		perror("SaveContact");
	}
	else
	{
		//写数据
		int i = 0;
		for (i = 0; i < pc->sz; i++)
		{
			fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
		}
		fclose(pf);
		pf = NULL;
		printf("保存成功\n");
	}
}

4.加载数据

  我们通过前面的退出程序时将数据保存到Contact.txt文件中,在重新运行通讯录的时候我们将已经保存好的数据加载到内存中

void LoadContact(Contact* pc)
{
	//读数据
	//1. 打开文件
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
	}
	else
	{
		//2. 读数据
		PeoInfo tmp = { 0 };
		int i = 0;
		while (fread(&tmp, sizeof(PeoInfo), 1, pf))
		{
			//增容
			check_capacity(pc);
			pc->data[i] = tmp;
			pc->sz++;
			i++;
		}
		fclose(pf);
		pf = NULL;
	}
}

四、源码

1、contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"

//静态的版本
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//}

//动态的版本
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));
	if (ptr == NULL)
	{
		perror("InitContact::calloc");
		return;
	}
	pc->data = ptr;
	pc->capacity = DEFAULT_SZ;

	//加载文件信息到通讯录
	LoadContact(pc);
}

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

//静态的版本
//void AddContact(Contact* pc)
//{
//	assert(pc);
//	if (pc->sz == MAX)
//	{
//		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].addr);
//	printf("请输入电话:>");
//	scanf("%s", pc->data[pc->sz].tele);
//
//	pc->sz++;
//}

void check_capacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		//增加容量
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
		if (ptr == NULL)
		{
			perror("check_capacity::realloc");
			return;
		}
		pc->data = ptr;
		pc->capacity += INC_SZ;
		printf("增容成功\n");
	}
}
//动态版本
void AddContact(Contact* pc)
{
	assert(pc);
	check_capacity(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].addr);
	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sz].tele);

	pc->sz++;
}



void ShowContact(const Contact* pc)
{
	assert(pc);
	int i = 0;
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].addr,
			pc->data[i].tele);
	}
}


int FindByName(const Contact* pc, char name[])
{
	assert(pc);

	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

void DelContact(Contact* pc)
{
	assert(pc);

	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	//删除
	//找到要删除的人
	printf("请输入要删除的人的名字:>");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (-1 == ret)
	{
		printf("要删除的人不存在\n");
		return;
	}

	int i = 0;
	//删除
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

void SearchContact(const Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (-1 == pos)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//打印信息
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
	printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].addr,
		pc->data[pos].tele);
}


void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要修改人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (-1 == pos)
	{
		printf("要修改的人不存在\n");
		return;
	}

	printf("请输入名字:>");
	scanf("%s", pc->data[pos].name);
	printf("请输入年龄:>");
	scanf("%d", &(pc->data[pos].age));
	printf("请输入性别:>");
	scanf("%s", pc->data[pos].sex);
	printf("请输入地址:>");
	scanf("%s", pc->data[pos].addr);
	printf("请输入电话:>");
	scanf("%s", pc->data[pos].tele);

	printf("修改完成\n");
}

void SaveContact(Contact* pc)
{
	//写数据
	//1, 打开文件
	FILE* pf = fopen("contact.txt", "wb");
	if (NULL == pf)
	{
		perror("SaveContact");
	}
	else
	{
		//写数据
		int i = 0;
		for (i = 0; i < pc->sz; i++)
		{
			fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
		}
		fclose(pf);
		pf = NULL;
		printf("保存成功\n");
	}
}

void LoadContact(Contact* pc)
{
	//读数据
	//1. 打开文件
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
	}
	else
	{
		//2. 读数据
		PeoInfo tmp = { 0 };
		int i = 0;
		while (fread(&tmp, sizeof(PeoInfo), 1, pf))
		{
			//增容
			check_capacity(pc);
			pc->data[i] = tmp;
			pc->sz++;
			i++;
		}
		fclose(pf);
		pf = NULL;
	}
}

2、contact.h

#pragma once

#include 
#include 
#include 
#include 


#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define TELE_MAX 12

#define DEFAULT_SZ 3
#define INC_SZ 2


//人的信息
typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char addr[ADDR_MAX];
	char tele[TELE_MAX];
}PeoInfo;

//静态版本
//typedef struct Contact
//{
//	PeoInfo data[MAX];//存放人的信息的
//	int sz;//当前已经放的信息的个数
//}Contact;

//动态版本
typedef struct Contact
{
	PeoInfo* data;//指向存放人的信息的空间
	int sz;//当前已经放的信息的个数
	int capacity;//当前通讯录的最大容量
}Contact;

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

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

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

//显示通讯录中的信息
void ShowContact(const Contact* pc);

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

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

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

//加载文件信息到通讯录
void LoadContact(Contact* pc);

3、test.c

#define _CRT_SECURE_NO_WARNINGS 1


#include "contact.h"

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

enum Option
{
	EXIT,//0
	ADD, //1
	DEL, //2
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};

int main()
{
	int input = 0;
	//创建通讯录
	Contact con;
	//初始化通讯录
	InitContact(&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:
			//
			break;
		case EXIT:
			//保存通讯录信息到文件中
			SaveContact(&con);
			DestroyContact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);

	return 0;
}

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