动态开辟内存的通讯录C语言实现

 

目录

前言

改进通讯录的类型

改进初始化函数

改进添加联系人函数

增加销毁通讯录信息的功能

完整代码


前言

  在此之前我们就已经实现了静态通讯录的一些功能,但是这个静态的通讯录的空间大小从开始就写定了,不能随意改变,例如我们给定大小为300个人的通讯录,但是我最多只有200个好友,其余的100个空间就相当于闲置浪费了,但是我们有些人跑业务需要500个甚至更多的空间,但是空间又不足。我们对于空间的需求大小,是程序运行时才知道,原来静态开辟的空间大小就不能够满足所需,我们便要进行动态开辟了。

  于是我们就可以实现用多少,给多少的空间大小,既不会浪费空间也不会空间不足。

  由于之前的静态通讯录比较详细,此篇重点讲解修改的地方

我们改进后的通讯录主要特点:

①:开始提供3个联系人大小的空间

②:需要添加联系人的时候扩容,每次扩容空间大小+2(也有常用的空间变为原来的2倍)

改进通讯录的类型

原来的通讯录类型:

struct Contact//大通讯录,可以记录很多人
{
	struct PeoInfo date[MAX];//嵌套结构体   //存放1000个人的信息
	int size;//记录当前的联系人个数
};

现在的通讯录类型:

struct Contact//大通讯录,可以记录很多人
{
	struct PeoInfo * date;//date指针指向动态内存开辟的一块空间
	int size;//记录当前的联系人个数
	int capacity;//记录容量
};

既然我们需要动态内存开辟,我们必然少不了一个指向动态内存开辟的一个指针变量。而且随着联系人的增多,我们的容量就会慢慢变小,于是就会涉及到扩容问题,我们需要定义一个新的容量变量capacity。

改进初始化函数

void ContactInit(struct Contact* ps)//初始化通讯录,联系人个数置0
{
	//初始化开辟一块空间用malloc
	ps->date=(struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));//初始化3个联系人的空间
	if (ps->date == NULL)
	{
		return;
	}
	ps->size = 0;
	ps->capacity = 3;
}

用malloc函数开辟一块空间,返回给date指针。当前为初始化联系人个数为size=0,容量为capacity=3。

改进添加联系人函数

static int  ContactCheck(struct Contact* ps)//检查当前通讯录是否已经满了,满了则扩容,扩容时失败则返回1
{
	if (ps->size == ps->capacity)
	{
		struct PeoInfo* ptr =(struct PeoInfo*) realloc(ps->date, ps->capacity+2);//用一个ptr指针来接收首地址
		if (ptr != NULL)
		{
			ps->date = ptr;
			ps->date += 2;
			return 0;//成功扩容
		}
		else
		{
			return 1;//扩容失败
		}
	}
}
void ContactAdd(struct Contact* ps)
{
	int flag = ContactCheck(ps);
	if (flag == 1)
	{
		printf("空间不足,增加失败\n");
		return;
	}
	
		printf("请输入姓名:>");
		scanf("%s", ps->date[ps->size].name);
		printf("请输入年龄:->");
		scanf("%d", &(ps->date[ps->size].age));
		printf("请输入性别:>");
		scanf("%s", ps->date[ps->size].sex);
		printf("请输入电话号码:>");
		scanf("%s", ps->date[ps->size].tele);
		printf("请输入地址:>");
		scanf("%s", ps->date[ps->size].address);
		ps->size++;
		printf("添加成功\n");
	
}

老规矩我们要先检查通讯录是否已经满了,满了则扩容容量capacity加2,扩容时失败则返回1,记得size++。设置一个flag标记,让可读性更佳!

增加销毁通讯录信息的功能


void DestroyContact(struct Contact* ps)
{
	free(ps->data);//释放动态开辟空间
	ps->data = NULL;
}

除了添加函数ContactAdd和检查函数ContactCheck函数需要动态内存开辟外,其他的功能函数均不需要修改,但内存开辟最重要的一点就是就得内存释放,避免造成内存泄漏

完整代码

test.dynamicContact.c:


#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
	printf("************************\n");
	printf("*****    Contact   *****\n");
	printf("*****    0.Exit    *****\n");
	printf("***1.Add    2.Delete ***\n");
	printf("***3.Search 4.Modify ***\n");
	printf("***5.Show   6.Sort   ***\n");
	printf("************************\n");
	printf("\n");
}
int main()
{
	int input = 0;
	struct Contact con;//con就是通讯录,就是记录1000个人和现有联系人个数
	ContactInit(&con);//初始化
	do
	{
		menu();
		printf("请输入数字来选择接下来的操作:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:          //case 1:
			ContactAdd(&con);
			break;
		case DELETE:
			ContactDelete(&con);
			break;
		case SEARCH:
			ContactSearch(&con);
			break;
		case MODIFY:
			ContactModify(&con);
			break;
		case SHOW:
			ContactShow(&con);
			break;
		case EXIT:
			printf("退出通讯录");
		case SORT:
			ContactSort(&con);
			break;
		default:
			printf("选择错误,请重新选择");
			break;
		}


	} while (input);
	return 0;
}

contact.c :

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"

void ContactInit(struct Contact* ps)//初始化通讯录,联系人个数置0
{
	//初始化开辟一块空间用malloc
	ps->date=(struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));//初始化3个联系人的空间
	if (ps->date == NULL)
	{
		return;
	}
	ps->size = 0;
	ps->capacity = 3;
}

static int  ContactCheck(struct Contact* ps)//检查当前通讯录是否已经满了,满了则扩容,扩容时失败则返回1
{
	if (ps->size == ps->capacity)
	{
		struct PeoInfo* ptr =(struct PeoInfo*) realloc(ps->date, ps->capacity+2);//用一个ptr指针来接收首地址
		if (ptr != NULL)
		{
			ps->date = ptr;
			ps->date += 2;
			return 0;//成功扩容
		}
		else
		{
			return 1;//扩容失败
		}
	}
}
void ContactAdd(struct Contact* ps)
{
	int flag = ContactCheck(ps);
	if (flag == 1)
	{
		printf("空间不足,增加失败\n");
		return;
	}
	
		printf("请输入姓名:>");
		scanf("%s", ps->date[ps->size].name);
		printf("请输入年龄:->");
		scanf("%d", &(ps->date[ps->size].age));
		printf("请输入性别:>");
		scanf("%s", ps->date[ps->size].sex);
		printf("请输入电话号码:>");
		scanf("%s", ps->date[ps->size].tele);
		printf("请输入地址:>");
		scanf("%s", ps->date[ps->size].address);
		ps->size++;
		printf("添加成功\n");
	
}

int FindByName(char name[MAX_NAME], const struct Contact* ps)//查找联系人,找到了返回下标,没找到返回-1
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (strcmp(ps->date[i].name, name) == 0)//ps指针去找通讯录里的人,后一个name是输入的名字的指针
			return i;
	}
	return -1;
}
void ContactDelete(struct Contact* ps)
{
	char name[MAX_NAME];
	printf("请输入要删除人的姓名:>");
	scanf("%s", name);
	int pos = FindByName(name, ps);
	if (pos == -1)
	{
		printf("无此联系人\n");
	}
	else
	{
		int i = 0;
		for (i = pos; i < ps->size - 1; i++)
		{
			ps->date[i] = ps->date[i + 1];//从要删除的联系人位置起,后一个联系人信息依次覆盖前一个联系人
		}
		printf("删除成功\n");
		ps->size--;
	}
}
void ContactSearch(const struct Contact* ps)//查找指定联系人并打印信息
{
	char name[MAX_NAME];
	printf("请输入要删除人的姓名:>");
	scanf("%s", name);
	int pos = FindByName(name, ps);
	if (pos == -1)
	{
		printf("无此联系人\n");
	}
	else
	{
		printf("%-20s\t%-4s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-20s\n",
			ps->date[pos].name,
			ps->date[pos].age,
			ps->date[pos].sex,
			ps->date[pos].tele,
			ps->date[pos].address);
	}//打印联系人的信息

}

void ContactModify(struct Contact* ps)
{
	char name[MAX_NAME];
	printf("请输入要修改人的姓名:>");
	scanf("%s", name);
	int pos = FindByName(name, ps);
	if (pos == -1)
	{
		printf("无此联系人\n");
	}
	else
	{
		printf("请输入联系人姓名:>");
		scanf("%s", ps->date[pos].name);
		printf("请输入年龄:>");
		scanf("%d", &(ps->date[pos].age));
		printf("请输入性别:>");
		scanf("%s", ps->date[pos].sex);
		printf("请输入电话:>");
		scanf("%s", ps->date[pos].tele);
		printf("请输入住址:>");
		scanf("%s", ps->date[pos].address);
		printf("修改成功\n");

	}
}
void ContactShow(struct Contact* ps)//打印联系人信息
{
	if (ps->size == 0)
	{
		printf("联系人为空\n");
	}
	else
	{
		printf("%-20s\t%-4s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
		//打印第一行信息栏
		int i = 0;
		for (i = 0; i < ps->size; i++)//遍历打印所有的联系人信息
		{
			printf("%-20s\t%-4d\t%-5s\t%-20s\t%-20s\n",
				ps->date[i].name,
				ps->date[i].age,
				ps->date[i].sex,
				ps->date[i].tele,
				ps->date[i].address);
		}
	}
}
int CmpByName(const void* e1, const void* e2)
{
	return strcmp((const char*)e1, (const char*)e2);
}
void ContactSort(struct Contact* ps)//通过名字排序
{
	qsort(ps->date, ps->size, sizeof(struct PeoInfo), CmpByName);

}

//销毁通讯录
void ContactDestory(struct Contact* ps)
{
	free(ps->date);
	ps->date = NULL;
}

contact.h:

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 20
#define MAX_ADDRESS 20

#include <string.h>
#include <stdlib.h>
#include<stdio.h>
enum Option//与结构体数组原理相同
{
	EXIT,//0
	ADD,//1
	DELETE,//2
	SEARCH,//3
	MODIFY,
	SHOW,
	SORT
};
struct PeoInfo//每个联系人的信息
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	int tele[MAX_TELE];
	char address[MAX_ADDRESS];

};

struct Contact//大通讯录,可以记录很多人
{
	struct PeoInfo * date;//date指针指向动态内存开辟的一块空间
	int size;//记录当前的联系人个数
	int capacity;//记录容量
};
void ContactInit(struct Contact* ps);
void ContactAdd(struct Contact* ps);
int FindByName(char name[MAX_NAME], const struct Contact* ps);
void ContactDelete(struct Contact* ps);
void ContactSearch(const struct Contact* ps);
void ContactModify(struct Contact* ps);
void ContactShow(struct Contact* ps);
int CmpByName(const void* e1, const void* e2);
void ContactSort(struct Contact* ps);
void ContactDestory(struct Contact* ps);

谢谢各位博友的支持!

动态开辟内存的通讯录C语言实现

 

上一篇:可存储通讯录


下一篇:3.6 单行子查询返回多行