• 动态内存管理改造简易通讯录


    动态通讯录

    本章内容基于上章内容实现,具体情况若有不清楚,请先查看上一篇文章。
    动态通讯录实现了,动态开辟,如果存放满了,再开辟空间进行存储,相对静态更方便一些。

    动态通讯录需要改造的地方

    我们基于静态通讯录之上,来改造一下实现动态通讯录
    需要改造的地方有:
    结构体的改造
    初始化函数
    添加函数
    退出通讯录

    结构体的改造

    静态的结构体是data是max也就是100。

    typedef struct PeoInfo
    {
    	char name[NAME_MAX];
    	int age;
    	char sex[SEX_MAX];
    	char tele[TELE_MAX];
    	char addr[ADDR_MAX];
    }PeoInfo;
    
    typedef struct Contact
    {
    	PeoInfo data[MAX];//存放成员数据
    	int sz;//记录当前通讯录人数
    }Contact;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Contact结构体中data数组是限定的,也就是100个。

    动态通讯录的结构体代码如下:

    typedef struct PeoInfo
    {
    	char name[NAME_MAX];
    	int age;
    	char sex[SEX_MAX];
    	char tele[TELE_MAX];
    	char addr[ADDR_MAX];
    }PeoInfo;
    typedef struct Contact
    {
    	PeoInfo* data;//存放成员数据
    	int sz;//记录当前通讯录人数
    	int capacity;//记录当前通讯录容量
    }Contact;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在静态的基础之上,我们改动了data从数组改编成了指针指向的是动态内存开辟的PeoInfo,以及多了一个参数capacity来记录当前通讯录容量。

    改造初始化函数

    静态的初始化函数是这样的

    void InitContact(Contact* pc)
    {
    	assert(pc);
    
    	pc->sz = 0;
    	memset(pc->data, 0, sizeof(pc->data));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    直接把data成员里面全部赋值为0。

    void InitContact(Contact* pc)
    {
    	assert(pc);
    
    	pc->sz = 0;
    	pc->capacity = DEFAULT_SZ;
    	pc->data = calloc(pc->capacity,sizeof(PeoInfo));
    	if (pc->data == NULL)
    	{
    		perror("InitContact->calloc");
    		return;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    动态我们开辟一块内存用来存放PeoInfo的信息,而他的地址则让data指针指向即可,我们用if语句查看是否data指针为空,为空则提示一下calloc函数出错。

    改造添加函数

    添加函数与静态的不同则是通讯录不会再满了,因为我们满了我们会动态在开辟空间即可。

    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].tele);
    	printf("请输入住址:");
    	scanf("%s", pc->data[pc->sz].addr);
    
    	//
    	pc->sz++;
    	printf("添加联系人成功!\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    上面是静态的添加函数,接下来看一下动态的添加函数。

    void ADDContact(Contact* pc)
    {
    	assert(pc);
    	if (pc->sz == pc->capacity)
    	{
    		PeoInfo* ptr = realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));
    		if (ptr != NULL)
    		{
    			pc->data = ptr;
    			pc->capacity += DEFAULT_INC;
    			printf("增加联系人空间成功\n");
    		}
    		else
    		{
    			perror("ADDContact->realloc");
    		}
    	}
    	//增加信息
    	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].tele);
    	printf("请输入住址:");
    	scanf("%s", pc->data[pc->sz].addr);
    
    	//
    	pc->sz++;
    	printf("添加联系人成功!\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    我们首先判断通讯录由动态开辟的空间是否已满,满了则开辟新的空间,用realloc函数开辟即可,之后赋给PeoInfo类型的ptr指针。如果该指针不为空,那么再把ptr指针赋给data指针,之后让通讯录容量+2,在这里是为了方便测试,所以只加2,最后用printf函数提醒一下增加联系人空间成功,否则则提醒一下realloc函数出错。之后就可以正常添加信息。增加通讯录容量也可以单独封装成一个函数,感兴趣的话可以尝试一下。

    改造退出通讯录

    动态开辟空间在程序结束时都要释放出去,防止有不可预料的结果产生,所以退出通讯录也要稍微 改造一下,静态直接退出即可不需要函数,所以我们直接看动态的退出通讯录。

    void DestoryContact(Contact* pc)
    {
    	free(pc->data);//释放动态内存空间
    	pc->data = NULL;//赋为空指针
    	pc->sz = 0;//释放完人数当然为0
    	pc->capacity = 0;//释放完,通讯录容量也自然为0
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这个十分简单,释放掉动态空间的地址,然后把该指针赋值为空指针,然后sz为零,capacity为零即可。

    改造后的全部代码

    为大家奉上完整的代码,方便参考调试。

    test.c

    #define  _CRT_SECURE_NO_WARNINGS
    #include"contact.h"
    enum Option
    {
    	EXIT,
    	ADD,
    	DEL,
    	SEARCH,
    	MODIFY,
    	SHOW,
    	SORT,
    	EMPTY
    };
    void menu();
    int main()
    {
    	int input = 0;
    	Contact con;
    	InitContact(&con);
    	do
    	{
    		menu();
    		printf("请输入你想选择的操作:");
    		scanf("%d", &input);
    		switch (input)
    		{
    		case EXIT:
    			DestoryContact(&con);
    			printf("退出通讯录成功");
    			break;
    		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:
    			SortContact(&con);
    			break;
    		case EMPTY:
    			InitContact(&con);
    			printf("清空通讯录成功\n");
    			break;
    		default:
    			printf("输入错误\n");
    			break;
    		}
    
    
    	} while (input);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    contact.c

    #define  _CRT_SECURE_NO_WARNINGS
    #include "contact.h"
    void menu()
    {
    	printf("*****************************\n");
    	printf("*****0.EXIT****1.ADD*********\n");
    	printf("*****2.DEL*****3.SEARCH******\n");
    	printf("*****4.MODIFY**5.SHOW********\n");
    	printf("*****6.SORT****7.EMPTY*******\n");
    }
    void InitContact(Contact* pc)
    {
    	assert(pc);
    
    	pc->sz = 0;
    	pc->capacity = DEFAULT_SZ;
    	pc->data = calloc(pc->capacity,sizeof(PeoInfo));
    	if (pc->data == NULL)
    	{
    		perror("InitContact->calloc");
    		return;
    	}
    }
    //void CheckCapacity(Contact* pc)
    //{
    //	if (pc->sz == pc->capacity)
    //	{
    //		PeoInfo* ptr = realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));
    //		if (ptr != NULL)
    //		{
    //			pc->sz = ptr;
    //			pc->capacity += DEFAULT_INC;
    //			printf("增加联系人空间成功\n");
    //		}
    //		else
    //		{
    //			perror("ADDContact->realloc");
    //		}
    //	}
    //}
    void ADDContact(Contact* pc)
    {
    	assert(pc);
    	if (pc->sz == pc->capacity)
    	{
    		PeoInfo* ptr = realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));
    		if (ptr != NULL)
    		{
    			pc->data = ptr;
    			pc->capacity += DEFAULT_INC;
    			printf("增加联系人空间成功\n");
    		}
    		else
    		{
    			perror("ADDContact->realloc");
    		}
    	}
    	//增加信息
    	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].tele);
    	printf("请输入住址:");
    	scanf("%s", pc->data[pc->sz].addr);
    
    	//
    	pc->sz++;
    	printf("添加联系人成功!\n");
    }
    
    void SHOWContact(const Contact* pc)
    {
    	assert(pc);
    	if (pc->sz == 0)
    	{
    		printf("通讯录为空,无需打印\n");
    		return;
    	}
    	int i = 0;
    	//名字  年龄  性别  电话    地址
    	//xxx   xxx  xxx  xxx     xxx
    	printf("%-20s%-10s%-10s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
    	for (i = 0; i < pc->sz; i++)
    	{
    		//打印每个人的信息
    		printf("%-20s%-10d%-10s%-12s%-30s\n",
    			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
    	}
    }
    int FindByName(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)
    {
    	char name[NAME_MAX];
    	assert(pc);
    	if (pc->sz == 0)
    	{
    		printf("通讯录为空,不可删除\n");
    		return;
    	}
    	printf("请输入你想删除的联系人:");
    	scanf("%s", name);
    	int ret = FindByName(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)
    {
    	assert(pc);
    	char name[NAME_MAX];
    	printf("请输入想查找的联系人");
    	scanf("%s", &name);
    	int ret = FindByName(pc, name);
    	if (ret == -1)
    	{
    		printf("该联系人不存在!\n");
    		return;
    	}
    	printf("%-20s%-10s%-10s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
    	printf("%-20s%-10d%-10s%-12s%-30s\n",
    		pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
    }
    void ModifyContact(Contact* pc)
    {
    	assert(pc);
    	char name[NAME_MAX];
    	printf("请输入想修改的联系人");
    	scanf("%s", &name);
    	int ret = FindByName(pc, name);
    	if (ret == -1)
    	{
    		printf("该联系人不存在!\n");
    		return;
    	}
    	printf("请输入姓名:");
    	scanf("%s", pc->data[ret].name);
    	printf("请输入年龄:");
    	scanf("%d", &(pc->data[ret].age));
    	printf("请输入性别:");
    	scanf("%s", pc->data[ret].sex);
    	printf("请输入电话号码:");
    	scanf("%s", pc->data[ret].tele);
    	printf("请输入住址:");
    	scanf("%s", pc->data[ret].addr);
    	printf("修改联系人成功!\n");
    }
    int compare_name(const void* base, const void* src)
    {
    	return strcmp(((PeoInfo*)base)->name, ((PeoInfo*)src)->name);
    }
    int compare_age(const void* base, const void* src)
    {
    	return (((PeoInfo*)base)->age - ((PeoInfo*)src)->age);
    }
    void SortContact(Contact* pc)
    {
    	int ret = 0;
    	printf("1按名字排序,2按年龄排序\n");
    	scanf("%d", &ret);
    	if (ret == 1)
    	{
    		qsort(pc->data, pc->sz, sizeof(PeoInfo), compare_name);
    		SHOWContact(pc);
    		printf("名字排序成功\n");
    	}
    	else if (ret == 2)
    	{
    		qsort(pc->data, pc->sz, sizeof(PeoInfo), compare_age);
    		SHOWContact(pc);
    		printf("年龄排序成功\n");
    	}
    	else
    	{
    		printf("选择错误,返回操作");
    	}
    
    }
    void DestoryContact(Contact* pc)
    {
    	free(pc->data);
    	pc->data = NULL;
    	pc->sz = 0;
    	pc->capacity = 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210

    contact.h

    #define  _CRT_SECURE_NO_WARNINGS
    #pragma once
    #include
    #include
    #include
    #include
    #define NAME_MAX 20
    #define SEX_MAX 10
    #define TELE_MAX 12
    #define ADDR_MAX 30
    
    #define MAX 100
    #define DEFAULT_SZ 3
    #define DEFAULT_INC 2
    
    typedef struct PeoInfo
    {
    	char name[NAME_MAX];
    	int age;
    	char sex[SEX_MAX];
    	char tele[TELE_MAX];
    	char addr[ADDR_MAX];
    }PeoInfo;
    
    //typedef struct Contact
    //{
    //	PeoInfo data[MAX];//存放成员数据
    //	int sz;//记录当前通讯录人数
    //}Contact;
    typedef struct Contact
    {
    	PeoInfo* data;//存放成员数据
    	int sz;//记录当前通讯录人数
    	int capacity;//记录当前通讯录容量
    }Contact;
    void menu();
    void InitContact(Contact* pc);
    void ADDContact(Contact* pc);
    void SHOWContact(const Contact* pc);
    void DELContact(Contact* pc);
    void SearchContact(Contact* pc);
    void ModifyContact(Contact* pc);
    void SortContact(Contact* pc);
    void DestoryContact(Contact* pc);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    最后各位看客老爷万福金安。
    在这里插入图片描述

  • 相关阅读:
    Linux系统常用的工具
    双Orin PCIe RC&EP模式互通
    2023.11.8 hadoop学习-概述,hdfs dfs的shell命令
    炽热如初 向新而生|ISC2022 HackingClub白帽峰会圆满举办!
    零知识证明以及其在 BSV 区块链中的应用简介
    如何将 Autofac 整合进 Net6.0 Core MVC 项目中
    万字整理 | 深入理解编译系统
    1秒奇迹!你的桌面文件夹也可以瞬间整洁
    文件打包后输出 - Java实现
    python pip安装超时使用国内镜像
  • 原文地址:https://blog.csdn.net/V5Jackeylove/article/details/133844873