C语言实现通讯录(动态内存进阶版)

一.前言

这是通讯录的最简单的版本:通讯录低配版
我们之前写的通讯录是借助数组来寄存信息的,但是这样会有一个弊端:你不知道你的通讯录将来要装多少个人的信息,你的数组的每个元素都是一个结构体的大小。如果你为了省事直接定义数组的大小为100个,这样你有100个联系人信息需要保存可以理解,但是你没有呢?你只有50个人的信息,但是你开辟了100个联系人信息的空间,这些是不是就浪费了。
所以我们通过动态内存的开辟来改进我们的通讯录,让这个通讯录可大可小,节省空间。如果对动态内存开辟这块不太了解可以看看这个文章C语言动态内存管理

二.对代码进行修改

2.1结构体的修改

struct Contact
{
	int size;                       //此时已经放的成员的信息
	struct Contact_Person* data;    //指向动态内存的地址
	int capaticy;                   //最多能存放的成员的信息
};

首先要修改的肯定是结构体里的定义,把数组改成一个指针(这个指针指向的是动态内存的地址)。但是名字最好和之前的数组名保持一直,这样我们在后面用的时候就不用改了,因为数组名和现在的指针指向的都是一块我们需要用到的空间的地址,只是一个是静态的空间,一个是动态的空间
因为我们的空间在不够的时候要用realloc函数扩容,所以我们需要多定义一个变量capacity,为了让系统知道什么时候该扩容。

2.2增加的几个宏定义信息

#define  SIZE_M    3       //动态内存开辟刚开始可以存3个成员信息
#define  SIZE_A    2       //动态内存空间不够每次增加2个成员信息

2.3初始化函数修改

void Init_Contact(struct Contact* con)
{
	con->size = 0;
	con->data = (struct Contact_Person*)calloc(SIZE_M, sizeof(struct Contact_Person));
	con->capaticy = SIZE_M;
	if (con->data == NULL)
		return;
}

初始化函数,我们把动态内存的开辟放在初始化函数里,这样在刚开始就能直接开辟好一块空间。

2.4扩容函数

static int Add_capaticy(struct Contact* con)
{
	if (con->size == con->capaticy)
	{
		con->capaticy += SIZE_A;
		struct Contact_Person* ptr = (struct Contact_Person*)realloc(con->data, (con->capaticy) * sizeof(struct Contact_Person));
		if (ptr == NULL)
		{
			return 0;
		}
		else
		{
			con->data = ptr;
			printf("扩容成功\n");
			return 1;
		}
	}
	else
		return 1;
}

用if语句先判断当前存的联系人的数量是否和最大容量是否相等。如果不等说明还没到最大值,就不需要扩容,如果相等说明存的空间已经到顶了,需要扩容。
既然是扩容,首先我们要把最大容量提升2个。
然后就是扩容的操作了。
这里设置返回值,因为假如扩容失败的话,它是直接返回的,如果我们后面其他的函数用到这个函数的话,返回失败了,它也会继续往下进行。所有我们设置一个返回值,返回1是说明扩容成功或者不需要扩容。返回0,说明扩容失败,在其他函数用到时,发现返回值时0的话,就不进行其他操作,直接退出了。

2.5添加联系人函数

void Add_contact(struct Contact* con)
{
	system("cls");
	int flag = Add_capaticy(con);
	if (flag)
	{
		printf("请输入联系人名字:");
		scanf("%s", con->data[con->size].name);
		printf("请输入联系人性别:");
		scanf("%s", con->data[con->size].sex);
		printf("请输入联系人电话:");
		scanf("%s", con->data[con->size].phone);
		printf("请输入联系人地址:");
		scanf("%s", con->data[con->size].location);
		con->size++;
	}
	else
		return;
}

这里就用到了之前的扩容函数,每增加一个成员就判断一次是否需要扩容,不需要或者增容完就返回1,继续下面的操作。如果返回0就直接退出。

2.6退出

void Delete_Calloc(struct Contact* con)
{
	free(con->data);
	con->data = NULL;
	con->capaticy = 0;
	con->size = 0;
}

在退出之前,我们要把之前开辟的空间释放掉,这个习惯一定要养成,我们现在写的代码可能体现不出来,如果你的代码很多的话,自己开辟的动态内存空间不释放,容易造成内存泄漏。

三.代码

需要代码的可以自取:

3.1text.c文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"

void menu()
{
	printf("****************************************\n");
	printf("********  1.添加      2.删除    ********\n");
	printf("********  3.全部删除  4.修改    ********\n");
	printf("********  5.查找      6.显示    ********\n");
	printf("********  7.排序      0.退出    ********\n");
	printf("****************************************\n");
}

int main()
{
	int input = 0;
	struct Contact con;

	//初始化通讯录信息
	Init_Contact(&con);
	do
	{
		menu();
		printf("请输入->");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			Add_contact(&con);
			break;
		case DELETE:
			Delete_Contact(&con);
			break;
		case DELETE_ALL:
			Init_Contact(&con);
			break;
		case AMEND:
			Amend_Contact(&con);
			break;
		case FIND:
			Find_Contact(&con);
			break;
		case SHOW:
			Show_Contact(&con);
			break;
		case SORT:
			Sort_Contact(&con);
			break;
		case EXIT:
			Delete_Calloc(&con);
			break;
		default:
			printf("输入错误,请重新输入->\n");
			break;
		}
	} while (input);
	return 0;
}

3.2contact.c文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"

//初始化通讯录信息
void Init_Contact(struct Contact* con)
{
	con->size = 0;
	con->data = (struct Contact_Person*)calloc(SIZE_M, sizeof(struct Contact_Person));
	con->capaticy = SIZE_M;
	if (con->data == NULL)
		return;
}

//释放动态内存开辟的空间
void Delete_Calloc(struct Contact* con)
{
	free(con->data);
	con->data = NULL;
	con->capaticy = 0;
	con->size = 0;
}

static int Add_capaticy(struct Contact* con)
{
	if (con->size == con->capaticy)
	{
		con->capaticy += SIZE_A;
		struct Contact_Person* ptr = (struct Contact_Person*)realloc(con->data, (con->capaticy) * sizeof(struct Contact_Person));
		if (ptr == NULL)
		{
			return 0;
		}
		else
		{
			con->data = ptr;
			printf("扩容成功\n");
			return 1;
		}
	}
	else
		return 1;
}

//添加联系人信息
void Add_contact(struct Contact* con)
{
	system("cls");
	int flag = Add_capaticy(con);
	if (flag)
	{
		printf("请输入联系人名字:");
		scanf("%s", con->data[con->size].name);
		printf("请输入联系人性别:");
		scanf("%s", con->data[con->size].sex);
		printf("请输入联系人电话:");
		scanf("%s", con->data[con->size].phone);
		printf("请输入联系人地址:");
		scanf("%s", con->data[con->size].location);
		con->size++;
	}
	else
		return;
}

//显示所有联系人信息
void Show_Contact(struct Contact* con)
{
	system("cls");
	printf("   %-20s%-8s%-12s%-15s\n", "姓名", "性别", "电话", "地址");
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		printf("%d. %-20s%-8s%-12s%-15s\n",
			i + 1,
			con->data[i].name,
			con->data[i].sex,
			con->data[i].phone,
			con->data[i].location
		);
	}
}

//查找联系人,返回他的序号,如果没有找到返回-1
static int Find_Peo(struct Contact* con, char name[NAME])
{
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		if (0 == strcmp(con->data[i].name, name))
			return i;
	}
	return -1;
}

//删除指定联系人信息
void Delete_Contact(struct Contact* con)
{
	system("cls");
	Show_Contact(con);
	printf("请输入需要删除的联系人的姓名:");
	char name[NAME];
	scanf("%s", name);
	int number = 0;
	number = Find_Peo(con, name);
	int i = 0;
	if (number != -1)
	{
		for (i = number; i < con->size - 1; i++)
		{
			con->data[i] = con->data[i + 1];
		}
		con->size--;
	}
	else
		printf("找不到联系人\n");
}

//查找联系人
void Find_Contact(struct Contact* con)
{
	system("cls");
	printf("请输入需要查找的联系人的名字:");
	char name[NAME];
	scanf("%s", name);
	int number = 0;
	number = Find_Peo(con, name);
	if (number != -1)
	{
		printf("%-20s%-8s%-12s%-15s\n", "姓名", "性别", "电话", "地址");
		printf("%-20s%-8s%-12s%-15s\n",
			con->data[number].name,
			con->data[number].sex,
			con->data[number].phone,
			con->data[number].location
		);
	}
	else
		printf("找不到联系人\n");
}

//修改联系人信息
void Amend_Contact(struct Contact* con)
{
	system("cls");
	Show_Contact(con);
	printf("请输入需要修改联系人信息的名字:");
	char name[NAME];
	scanf("%s", name);
	int number = 0;
	number = Find_Peo(con, name);
	if (number != -1)
	{
		printf("请输入联系人名字:");
		scanf("%s", con->data[number].name);
		printf("请输入联系人性别:");
		scanf("%s", con->data[number].sex);
		printf("请输入联系人电话:");
		scanf("%s", con->data[number].phone);
		printf("请输入联系人地址:");
		scanf("%s", con->data[number].location);
	}
	else
		printf("找不到联系人\n");
}

static int Com_Name(const void* e1, const void* e2)
{
	return strcmp(((struct Contact_Person*)e1)->name, ((struct Contact_Person*)e2)->name);
}

//排序联系人信息
void Sort_Contact(struct Contact* con)
{
	system("cls");//排序前把之前信息清理掉
	
	qsort(con->data, con->size, sizeof(struct Contact_Person), Com_Name);

	Show_Contact(con);//排序完显示一下
}

3.3contact.h文件

#pragma once
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

#define  SIZE      10      //通讯录的大小,能装10个成员的信息
#define  NAME      20      //联系人名字数组的长度
#define  SEX       8       //联系人性别数组的长度
#define  PHONE     12      //联系人电话数组的长度
#define  LOCATION  15      //联系人地址数组的长度
#define  SIZE_M    3       //动态内存开辟刚开始可以存3个成员信息
#define  SIZE_A    2       //动态内存空间不够每次增加2个成员信息


enum catalog
{
	EXIT,      //退出
	ADD,       //添加联系人信息
	DELETE,    //删除联系人信息
	DELETE_ALL,//删除所有人信息
	AMEND,     //修改联系人信息
	FIND,      //查找联系人
	SHOW,      //显示所有联系人信息
	SORT,      //排序联系人信息
};

//联系人信息
struct Contact_Person
{
	char name[NAME];          //联系人姓名
	char sex[SEX];            //联系人性别
	char phone[PHONE];        //联系人电话
	char location[LOCATION];  //联系人地址
};

//通讯录
struct Contact
{
	int size;                       //此时已经放的成员的信息
	struct Contact_Person* data;    //指向动态内存的地址
	int capaticy;                   //最多能存放的成员的信息
};

//初始化通讯录信息
void Init_Contact(struct Contact* con);

//添加联系人信息
void Add_contact(struct Contact* con);

//显示所有联系人信息
void Show_Contact(struct Contact* con);

//删除指定联系人信息
void Delete_Contact(struct Contact* con);

//查找联系人
void Find_Contact(struct Contact* con);

//修改联系人信息
void Amend_Contact(struct Contact* con);

//排序联系人信息
void Sort_Contact(struct Contact* con);

//释放动态内存开辟的空间
void Delete_Calloc(struct Contact* con);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值