通信录详解————(自动扩容、文件保存)

在通讯录中, 可以做到基本的增删查改,也可以实现通讯录自动扩容,也可以将输入的联系人的信息保存到文件当中,不会因为程序的退出而内存销毁,而是保存到文件当中,因此在下次打开程序时,也可以将文件保存的联系人的信息读取出来,真正的做到了通讯录保存的功能

 

添加联系人: 

排序+显示联系人:

查找联系人:

更改联系人的信息:

删除信息人:

 当删除李华时,我们再将通讯录打印出来,就可以看到李华的信息已经被删除了

退出程序:

再次打开程序时,之前输入的联系人的信息也能够保存下来:

我会在文章的后面将原代码贴上:contact.h  contact.c  test.c

码字不易,如有用,望诸君点赞收藏一波!

一、通讯录的基本:

用到的头文件:
 

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

define的常量:

#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_NUM 17
#define MAX_ADDR 30
#define MAX 3
#define Add_MAX 2

结构体定义联系人的基本信息:姓名、性别、年龄、电话号码、家庭住址

typedef struct PeoInfo
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	int age;
	char num[MAX_NUM];
	char addr[MAX_ADDR];

}PeoInfo;

 通讯录的基本要素:

typedef struct Contact
{
	PeoInfo* data;//一个指向联系人类型空间的指针
	int sz;//记录通讯录里的人数
	int num;//记录通讯录空间的大小
}Contact;

 二、初始化通讯录

在初始化通讯的时候,开始时用calloc在内存中定义一处空间,当要读取上一次写的通讯录的信息是,首先要判断通讯录是否满了,当程序发现通讯满了的时候,要用realloc将空间扩大,做到了通讯录的自动增容

void AddCapacity(Contact* pc);
//读取原来的文件
void ReadContact(Contact* pc)
{
	//打开文件
	FILE* ps = fopen("Contact.txt", "rb");
	if (ps == NULL)
	{
		perror("ReadContact");
		return;
	}

	//读文件
	PeoInfo tmp = { 0 };
	while (fread(&tmp, sizeof(PeoInfo), 1, ps)) //fread的正常是返回值为读取的个数,异常时是比读取个数小,这里读取个数是是1,异常时会返回0,while结束
	{
		if (pc->sz == pc->num)
		{
			AddCapacity(pc);
		}
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}
	//关闭文件
	fclose(ps);
	ps = NULL;
}

//动态初始化通讯录
void IniContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->num = MAX;
	pc->data = (PeoInfo*)calloc(pc->num, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("IniContact->calloc");
		return;
	}
	ReadContact(pc);
}

//增容通讯录
void AddCapacity(Contact* pc)
{
	PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->num + Add_MAX) * sizeof(PeoInfo));
	if (ptr == NULL)
	{
		perror("realloc");
		return 1;
	}
	else
	{
		pc->data = ptr;
		pc->num += Add_MAX;
		//printf("增容成功\n");
	}
}

三、 增加联系人

很容易实现,代码如下:
 

//增加联系人
void AddContact(Contact* pc)
{
	assert(pc);
	//判断通讯录是否满了
	if (pc->sz == pc->num)
	{
		AddCapacity(pc);
	}
	

	printf("请输入姓名:\n");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入性别:\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入年龄:\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入电话:\n");
	scanf("%s", pc->data[pc->sz].num);
	printf("请输入地址:\n");
	scanf("%s", pc->data[pc->sz].addr);
    
	pc->sz++;
	printf("添加成功!\n");
}

 四、显示联系人

就是将来联系人的信息打印出来

代码如下:

//显示联系人
void ShowContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("没有联系人,请添加联系人\n");
	}
	else
	{
		int i = 0;
		printf("%-7s\t%-7s\t%-6s\t%-15s\t%-20s\t\n", "姓名", "性别", "年龄", "电话号码", "家庭地址");
		for (i = 0; i < pc->sz; i++)
		{
			printf("%-7s\t%-7s\t%-6d\t%-15s\t%-20s\t\n", 
				pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].num, pc->data[i].addr);
		}
	}
	
}

五、删除联系人

 在删除联系人的时候,首先要查找到想要删除的联系人所在数组的坐标,因此我包装了一个函数FindPeople,专门查找联系人,返回所查找的联系人的坐标。

当拿到要删除的联系人的位置后,只需将后一个人的联系人的信息覆盖要删除的联系人的信息,然后将记录通讯录里联系人数量的 sz--,这样,如果想要删除最后一名联系人的时候,即使最后一个联系人的信息没办法覆盖,但是我们已经无法读取最后一个联系人的信息(因为sz已经减1了),因此也变相的完成的删除。

//查找人
int FindPeople(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;

	}
	return -1;
}
//删除联系人
void DelContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,请添加联系人\n");
		return;
	}

	printf("请输入要删除的姓名:\n");
	char name[MAX_NAME];
	scanf("%s", name);
	int ret = FindPeople(pc, name);
	if (ret == -1)
	{
		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");
	
	
}

六、查找联系人

这个功能也是很简单,首先也要找到想要查找联系人的位置,因此也要用到FindPeople函数,找到联系人的坐标,将其打印在屏幕上就可以了

代码如下:


//查找联系人
void SearchContact(Contact* pc)
{
	char name[MAX_NAME];
	assert(pc);
	printf("请输入要查找的姓名:\n");
	scanf("%s", name);
	int ret = FindPeople(pc, name);
	printf("%-7s\t%-7s\t%-6s\t%-15s\t%-20s\t\n", "姓名", "性别", "年龄", "电话号码", "家庭地址");
	printf("%-7s\t%-7s\t%-6d\t%-15s\t%-20s\t\n",
		pc->data[ret].name, pc->data[ret].sex, pc->data[ret].age, pc->data[ret].num, pc->data[ret].addr);

}

 七、更改联系人

在实现更改联系人这一功能时,也是首先将联系人的位置找到,重新输入联系人的信息即可

代码如下:

//更改联系人
void ModifyContact(Contact* pc)
{
	char name[MAX_NAME];
	assert(pc);
	printf("请输入想要更改联系人的名字:\n");
	scanf("%s", name);
	int ret = FindPeople(pc, name);

	if (ret == -1)
	{
		printf("查无此人!\n");
		return;
	}
	printf("请输入重新更改的姓名:\n");
	scanf("%s", pc->data[ret].name);
	printf("请输入重新更改的性别:\n");
	scanf("%s", pc->data[ret].sex);
	printf("请输入重新更改的年龄:\n");
	scanf("%d", &(pc->data[ret].age));
	printf("请输入重新更改的电话:\n");
	scanf("%s", pc->data[ret].num);
	printf("请输入重新更改的地址:\n");
	scanf("%s", pc->data[ret].addr);

	printf("更改联系人成功!\n");

}

八、排序联系人

排序联系人时,需要用到qsort函数,我们可以设定排序的方式,比如:姓名、年龄、性别、电话,这些都是可以的,在这里我用的是以名字将通讯录排序的

代码如下:
 

//排序比较大小
int cmp(const void* e1, const void* e2)
{
	return strcmp(( * (PeoInfo*)e1).name, ( * (PeoInfo*)e2).name);
}

//排序联系人
void SortContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空!\n");
		return;
	}
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);
	printf("排序成功!\n");
}

九、保存联系人

想要做到在程序退出前面,将所增加的联系人的信息写入文件 Contact.txt 当中去,

代码如下;

//保存通讯录
void ServeContact(Contact* pc)
{
	//打开文件
	FILE* ps = fopen("Contact.txt", "wb");
	if (ps == NULL)
	{
		perror("ServeContact");
		return;
	}

	//写文件
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, ps);
	}

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

十、销毁通讯录

因为通讯录是通过realloc、calloc动态开辟在堆区的,因此,在程序退出的时候,需要手动的将所申请的内存空间释放掉,不然可能会造成内存泄漏。

代码如下:

//销毁通讯录
void DestoryContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->sz = 0;
	pc->num = 0;
}

———————————————————————————————————————————

源码:

contact.h:

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

#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_NUM 17
#define MAX_ADDR 30
#define MAX 3
#define Add_MAX 2

typedef struct PeoInfo
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	int age;
	char num[MAX_NUM];
	char addr[MAX_ADDR];

}PeoInfo;

typedef struct Contact
{
	PeoInfo* data;//一个指向联系人类型空间的指针
	int sz;//记录通讯录里的人数
	int num;//记录通讯录空间的大小
}Contact;

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


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

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

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

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

//更改联系人
 void ModifyContact(Contact* pc);

 //排序联系人
 void SortContact(Contact* pc);

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

 //保存通讯录
 void ServeContact(Contact* pc);

contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"


//静态初始化通讯录
//void IniContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//}

void AddCapacity(Contact* pc);
//读取原来的文件
void ReadContact(Contact* pc)
{
	//打开文件
	FILE* ps = fopen("Contact.txt", "rb");
	if (ps == NULL)
	{
		perror("ReadContact");
		return;
	}

	//读文件
	PeoInfo tmp = { 0 };
	while (fread(&tmp, sizeof(PeoInfo), 1, ps)) //fread的正常是返回值为读取的个数,异常时是比读取个数小,这里读取个数是是1,异常时会返回0,while结束
	{
		if (pc->sz == pc->num)
		{
			AddCapacity(pc);
		}
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}
	//关闭文件
	fclose(ps);
	ps = NULL;
}

//动态初始化通讯录
void IniContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->num = MAX;
	pc->data = (PeoInfo*)calloc(pc->num, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("IniContact->calloc");
		return;
	}
	ReadContact(pc);
}

//增容通讯录
void AddCapacity(Contact* pc)
{
	PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->num + Add_MAX) * sizeof(PeoInfo));
	if (ptr == NULL)
	{
		perror("realloc");
		return 1;
	}
	else
	{
		pc->data = ptr;
		pc->num += Add_MAX;
		//printf("增容成功\n");
	}
}
//增加联系人
void AddContact(Contact* pc)
{
	assert(pc);
	//判断通讯录是否满了
	if (pc->sz == pc->num)
	{
		AddCapacity(pc);
	}
	

	printf("请输入姓名:\n");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入性别:\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入年龄:\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入电话:\n");
	scanf("%s", pc->data[pc->sz].num);
	printf("请输入地址:\n");
	scanf("%s", pc->data[pc->sz].addr);
    
	pc->sz++;
	printf("添加成功!\n");
}

//显示联系人
void ShowContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("没有联系人,请添加联系人\n");
	}
	else
	{
		int i = 0;
		printf("%-7s\t%-7s\t%-6s\t%-15s\t%-20s\t\n", "姓名", "性别", "年龄", "电话号码", "家庭地址");
		for (i = 0; i < pc->sz; i++)
		{
			printf("%-7s\t%-7s\t%-6d\t%-15s\t%-20s\t\n", 
				pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].num, pc->data[i].addr);
		}
	}
	
}
//查找人
int FindPeople(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;

	}
	return -1;
}
//删除联系人
void DelContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,请添加联系人\n");
		return;
	}

	printf("请输入要删除的姓名:\n");
	char name[MAX_NAME];
	scanf("%s", name);
	int ret = FindPeople(pc, name);
	if (ret == -1)
	{
		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(Contact* pc)
{
	char name[MAX_NAME];
	assert(pc);
	printf("请输入要查找的姓名:\n");
	scanf("%s", name);
	int ret = FindPeople(pc, name);
	printf("%-7s\t%-7s\t%-6s\t%-15s\t%-20s\t\n", "姓名", "性别", "年龄", "电话号码", "家庭地址");
	printf("%-7s\t%-7s\t%-6d\t%-15s\t%-20s\t\n",
		pc->data[ret].name, pc->data[ret].sex, pc->data[ret].age, pc->data[ret].num, pc->data[ret].addr);

}

//更改联系人
void ModifyContact(Contact* pc)
{
	char name[MAX_NAME];
	assert(pc);
	printf("请输入想要更改联系人的名字:\n");
	scanf("%s", name);
	int ret = FindPeople(pc, name);

	if (ret == -1)
	{
		printf("查无此人!\n");
		return;
	}
	printf("请输入重新更改的姓名:\n");
	scanf("%s", pc->data[ret].name);
	printf("请输入重新更改的性别:\n");
	scanf("%s", pc->data[ret].sex);
	printf("请输入重新更改的年龄:\n");
	scanf("%d", &(pc->data[ret].age));
	printf("请输入重新更改的电话:\n");
	scanf("%s", pc->data[ret].num);
	printf("请输入重新更改的地址:\n");
	scanf("%s", pc->data[ret].addr);

	printf("更改联系人成功!\n");

}

//排序比较大小
int cmp(const void* e1, const void* e2)
{
	return strcmp(( * (PeoInfo*)e1).name, ( * (PeoInfo*)e2).name);
}

//排序联系人
void SortContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空!\n");
		return;
	}
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);
	printf("排序成功!\n");
}

//销毁通讯录
void DestoryContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->sz = 0;
	pc->num = 0;
}

//保存通讯录
void ServeContact(Contact* pc)
{
	//打开文件
	FILE* ps = fopen("Contact.txt", "wb");
	if (ps == NULL)
	{
		perror("ServeContact");
		return;
	}

	//写文件
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, ps);
	}

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

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.Sort      6.Show   ****\n");
	printf("****        0.Exit         ****\n");
	printf("*******************************\n");
}

enum Select
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SORT,
	SHOW
};

int main()
{

	int input = 0;
	Contact pc;
	//初始化通讯录
	IniContact(&pc);
	do
	{
		
		menu();
		printf("请输入你的选择:\n");
		scanf("%d", &input);
		
		switch (input)
		{
		case ADD:
			AddContact(&pc);
			break;
		case DEL:
			DelContact(&pc);
			break;
		case SEARCH:
			SearchContact(&pc);
			break;
		case MODIFY:
			ModifyContact(&pc);
			break;
		case SORT:
			SortContact(&pc);
			break;
		case SHOW:
			ShowContact(&pc);
			break;
		case EXIT:
			ServeContact(&pc);
			printf("退出程序\n");
			DestoryContact(&pc);
			break;
		default:
			printf("输入错误,请重新输入:\n");
			break;
		}
	} while (input);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿拉保

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值