通讯录(动态内存管理)

本文介绍了如何使用C语言编写一个通讯录管理系统,包括结构体定义、内存动态扩展、增删查改功能以及排序和打印。系统支持联系人信息的录入、删除、查找、修改,以及按姓名首字母排序,并能动态扩容以适应更多联系人存储需求。
摘要由CSDN通过智能技术生成

  前言

使用C语言模拟一个通讯录,通讯录的初始可以存储3个联系人的数据,当存满之后,自动增加2个联系人的空间。

存储的信息包括:姓名、性别、年龄、电话号码、地址

能实现的功能包括:1。新增联系人;2.删除联系人;3.查找联系人:根据姓名查找;4.修改联系人;5.排序联系人:将通讯录中的联系人根据姓名首字母的大小升序排列、6.打印通讯录中的联系人的所有信息、7.退出通讯录

目录

一、通讯录菜单

二、通讯录主函数

三、枚举通讯录选项

四、定义通讯录和联系人

1.定义联系人的信息(结构体)

2.定义通讯录信息(结构体)

五、全局变量声明

六、通过姓名查找联系人的函数

七、通讯录增容函数

八、销毁通讯录函数

九、实现通讯录功能的函数

1.初始化通讯录

2.新增联系人

3.删除联系人

4.查找联系人

5.修改联系人

6.排序联系人

7.打印联系人

十、头文件

十一、完整代码


一、通讯录菜单

设计一个菜单,向用户展示功能,用来和用户交互

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

打印出来的效果 

二、通讯录主函数

函数主体使用do……while循环对输入的选项进行判断,当输入为0时跳出循环,程序结束。不为0时,用switch语句跳转到相对应的功能,代码如下:

void test()
{
	int input = 0;
	Contacts con;
	InitCon(&con);//初始化通讯录
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContacts(&con);//增加联系人
			break;
		case DEL:
			DelContacts(&con);//删除联系人
			break;
		case SEARCH:
			SearchContacts(&con);//查找联系人
			break;
		case MODIFY:
			ModifyContacts(&con);//更改联系人
			break;
		case SORT:
			SortContacts(&con);//排序联系人
			break;
		case PRINT:
			PrintContacts(&con);//打印联系人
			break;
		case EXIT:
			DestoryContacts(&con);//销毁通讯录
			printf("退出通讯录\n");
			break;
		default:
			printf("请输入正确的选项:>\n");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

三、枚举通讯录选项

switch语句会根据输入值,跳入不同的case语句中。上面代码为了可读性将case后面的数值替换成了对应的选项,无法达到switch的效果,因此使用枚举对选项赋值。

//枚举选项
enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SORT,
	PRINT,
};

四、定义通讯录和联系人

1.定义联系人的信息(结构体)

联系人的信息不是单一类型,使用结构体创建一个联系人类型

//创建联系人数据类型
typedef struct Peodata
{
	char name[NAME_MAX];
	char tele[TELE_MAX];
	int age;
	char sxe[SEX_MAX];
	char addr[ADDR_MAX];
}Peodata;

2.定义通讯录信息(结构体)

这里我们创建一个上述联系人结构体类型的指针,用来指向动态内存开辟的空间。同时也创建一个int类型的变量,用来保存联系人的个数。创建一个int型的变量,保存通讯录的容量

//创建通讯录数据类型
typedef struct Contacts
{
	int sz;//联系人的个数
	int capacity;//最大容量
	Peodata* data;//指向存放联系人的地址
}Contacts;

五、全局变量声明

为了方便日后对通讯录的修改和完善,将所有需要指定数组元素个数的数据进行声明

//定义的类型
#define NAME_MAX 20
#define TELE_MAX 11
#define SEX_MAX 5
#define ADDR_MAX 20

六、通过姓名查找联系人的函数

//查找联系人,找到了返回下标,没找到返回-1
static int Searchdata(const Contacts* pc, const char* pn)
{
	assert(pc && pn);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, pn) == 0)
		{
			return i;
		}
	}
	return -1;
}

七、通讯录增容函数

因为我们这个通讯录初始空间是有限的,当联系人的个数等于最大容量的时候,使用realloc函数增加容量

//判断通讯录是否需要增容
static void IsCapacity(Contacts* pc)
{
	assert(pc);
	if (pc->capacity == pc->sz)
	{
		Peodata* tmp = (Peodata*)realloc(pc->data, (pc->capacity + 2) * sizeof(Peodata));
		if (tmp == NULL)
		{
			perror("IsContacts : realloc");
            return;        
		}
		else
		{
			pc->data = tmp;
		}
		pc->capacity += 2;
	}
}

八、销毁通讯录函数

因为使用了动态内存分配函数,为了避免出现内存泄漏的现象,退出通讯录的时候,需要将像内存申请的空降释放。同时为避免出现野指针将创建的指针置为空

//销毁通讯录
void DestoryContacts(Contacts* pc)
{
	assert(pc);
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	printf("通讯录被销毁\n");
}

九、实现通讯录功能的函数

1.初始化通讯录

用calloc函数像堆区申请3个联系人结构体大小的空间,并将申请好的空间地址传给给之前创建好的指针。

//初始化通讯录
void InitCon(Contacts* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = 3;
	pc->data = (Peodata*)calloc(pc->capacity, sizeof(Peodata));
	if (pc->data == NULL)
	{
		perror("InitCon : calloc");
		return;
	}
}

2.新增联系人

当通讯录中没有人的时候,count的值为0,数组的下标也是0,新增的信息要放在数组下标为0处;当通讯录中有1个人时,count为1时,新增的信息要放在数组的下标为1处。按此规律count的值正好等于等于要新增的信息所存放的数组的下标

//增加联系人
void AddContacts(Contacts* pc)
{
	assert(pc);
	IsCapacity(pc);//判断通讯录是否需要增容

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

3.删除联系人

封装一个函数FindByName,通过输入名字查找要删除的联系人

//删除联系人
void DelContacts(Contacts* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	char name[NAME_MAX] = { 0 };
	printf("请输入您要删除联系人的姓名:>");
	scanf("%s", name);
	int ret = Searchdata(pc, name);
	if (ret == -1)
	{
		printf("联系人不存在\n");
		return;
	}
	memmove(&pc->data[ret], &pc->data[ret + 1], (pc->sz - ret) * sizeof(pc->data[0]));
	pc->sz--;
}

4.查找联系人

//查找联系人
void SearchContacts(const Contacts* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	char name[NAME_MAX] = { 0 };
	printf("请输入您要查找联系人的姓名:>");
	scanf("%s", name);
	int ret = Searchdata(pc, name);
	if (ret == -1)
	{
		printf("联系人不存在\n");
		return;
	}
	printf("%-20s %-5s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("%-20s %-5s %-5d %-15s %-20s\n", pc->data[ret].name, pc->data[ret].sxe, pc->data[ret].age, pc->data[ret].tele, pc->data[ret].addr);
}

5.修改联系人

//更改联系人
void ModifyContacts(Contacts* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	char name[NAME_MAX] = { 0 };
	printf("请输入您要更改联系人的姓名:>");
	scanf("%s", name);
	int ret = Searchdata(pc, name);
	if (ret == -1)
	{
		printf("联系人不存在\n");
		return;
	}
	printf("请输入姓名:>");
	scanf("%s", pc->data[ret].name);
	printf("请输入性别:>");
	scanf("%s", pc->data[ret].sxe);
	printf("请输入年龄:>");
	scanf("%d", &pc->data[ret].age);
	printf("请输入电话:>");
	scanf("%s", pc->data[ret].tele);
	printf("请输入住址:>");
	scanf("%s", pc->data[ret].addr);
}

6.排序联系人

//qsort判断函数
int Cmpdata(const void* e1, const void* e2)
{
	return strcmp(((Peodata*)e1)->name, ((Peodata*)e2)->name);
}
//排序联系人
void SortContacts(Contacts* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), Cmpdata);
	printf("排序完成\n");
}

7.打印联系人

这里我用for循环

//打印联系人
void PrintContacts(const Contacts* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	printf("%-20s %-5s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s %-5s %-5d %-15s %-20s\n", pc->data[i].name, pc->data[i].sxe, pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
	}
}

十、头文件

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

十一、完整代码

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

//变量的声明
#define NAME_MAX 20
#define TELE_MAX 11
#define SEX_MAX 5
#define ADDR_MAX 20

//创建联系人数据类型
typedef struct Peodata
{
	char name[NAME_MAX];
	char tele[TELE_MAX];
	int age;
	char sxe[SEX_MAX];
	char addr[ADDR_MAX];
}Peodata;

//创建通讯录数据类型
typedef struct Contacts
{
	int sz;//联系人的个数
	int capacity;//最大容量
	Peodata* data;//指向存放联系人的地址
}Contacts;

//枚举选项
enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SORT,
	PRINT,
};


//函数的声明

//初始化通讯录
void InitCon(Contacts* pc);

//增加联系人
void AddContacts(Contacts* pc);

//删除联系人
void DelContacts(Contacts* pc);

//查找联系人
void SearchContacts(const Contacts* pc);

//更改联系人
void ModifyContacts(Contacts* pc);

//排序联系人
void SortContacts(Contacts* pc);

//打印联系人
void PrintContacts(const Contacts* pc);

//销毁通讯录
void DestoryContacts(Contacts* pc);
//contacts.c
#include "contacts.h"

//初始化通讯录
void InitCon(Contacts* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = 3;
	pc->data = (Peodata*)calloc(pc->capacity, sizeof(Peodata));
	if (pc->data == NULL)
	{
		perror("InitCon : calloc");
		return;
	}
}

//判断通讯录是否需要增容
static void IsCapacity(Contacts* pc)
{
	assert(pc);
	if (pc->capacity == pc->sz)
	{
		Peodata* tmp = (Peodata*)realloc(pc->data, (pc->capacity + 2) * sizeof(Peodata));
		if (tmp == NULL)
		{
			perror("IsContacts : realloc");
		}
		else
		{
			pc->data = tmp;
		}
		pc->capacity += 2;
	}
}

//增加联系人
void AddContacts(Contacts* pc)
{
	assert(pc);
	IsCapacity(pc);//判断通讯录是否需要增容

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

//查找联系人,找到了返回下标,没找到返回-1
static int Searchdata(const Contacts* pc, const char* pn)
{
	assert(pc && pn);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, pn) == 0)
		{
			return i;
		}
	}
	return -1;
}

//删除联系人
void DelContacts(Contacts* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	char name[NAME_MAX] = { 0 };
	printf("请输入您要删除联系人的姓名:>");
	scanf("%s", name);
	int ret = Searchdata(pc, name);
	if (ret == -1)
	{
		printf("联系人不存在\n");
		return;
	}
	memmove(&pc->data[ret], &pc->data[ret + 1], (pc->sz - ret) * sizeof(pc->data[0]));
	pc->sz--;
}

//查找联系人
void SearchContacts(const Contacts* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	char name[NAME_MAX] = { 0 };
	printf("请输入您要查找联系人的姓名:>");
	scanf("%s", name);
	int ret = Searchdata(pc, name);
	if (ret == -1)
	{
		printf("联系人不存在\n");
		return;
	}
	printf("%-20s %-5s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("%-20s %-5s %-5d %-15s %-20s\n", pc->data[ret].name, pc->data[ret].sxe, pc->data[ret].age, pc->data[ret].tele, pc->data[ret].addr);
}

//更改联系人
void ModifyContacts(Contacts* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	char name[NAME_MAX] = { 0 };
	printf("请输入您要更改联系人的姓名:>");
	scanf("%s", name);
	int ret = Searchdata(pc, name);
	if (ret == -1)
	{
		printf("联系人不存在\n");
		return;
	}
	printf("请输入姓名:>");
	scanf("%s", pc->data[ret].name);
	printf("请输入性别:>");
	scanf("%s", pc->data[ret].sxe);
	printf("请输入年龄:>");
	scanf("%d", &pc->data[ret].age);
	printf("请输入电话:>");
	scanf("%s", pc->data[ret].tele);
	printf("请输入住址:>");
	scanf("%s", pc->data[ret].addr);
}

//qsort判断函数
int Cmpdata(const void* e1, const void* e2)
{
	return strcmp(((Peodata*)e1)->name, ((Peodata*)e2)->name);
}
//排序联系人
void SortContacts(Contacts* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), Cmpdata);
	printf("排序完成\n");
}

//打印联系人
void PrintContacts(const Contacts* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	printf("%-20s %-5s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s %-5s %-5d %-15s %-20s\n", pc->data[i].name, pc->data[i].sxe, pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
	}
}

//销毁通讯录
void DestoryContacts(Contacts* pc)
{
	assert(pc);
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	printf("通讯录被销毁\n");
}
//test.c
#include "contacts.h"


void menu()
{
	printf("******************************\n");
	printf("**** 1.add       2.del    ****\n");
	printf("**** 3.search    4.modify ****\n");
	printf("**** 5.sort      6.print  ****\n");
	printf("**** 0.exit               ****\n");
	printf("******************************\n");
}
void test()
{
	int input = 0;
	Contacts con;
	InitCon(&con);//初始化通讯录
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContacts(&con);//增加联系人
			break;
		case DEL:
			DelContacts(&con);//删除联系人
			break;
		case SEARCH:
			SearchContacts(&con);//查找联系人
			break;
		case MODIFY:
			ModifyContacts(&con);//更改联系人
			break;
		case SORT:
			SortContacts(&con);//排序联系人
			break;
		case PRINT:
			PrintContacts(&con);//打印联系人
			break;
		case EXIT:
			DestoryContacts(&con);//销毁通讯录
			printf("退出通讯录\n");
			break;
		default:
			printf("请输入正确的选项:>\n");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Ljiyu0506

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

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

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

打赏作者

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

抵扣说明:

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

余额充值