C语言实现可增容动态通讯录详细过程

目录
  • 创建可自动扩容的通讯录
  • 添加用户信息
  • 删除用户信息
  • 查找联系人
  • 修改用户信息
  • 以名字将用户排序
  • 销毁通讯录

创建可自动扩容的通讯录

这里我们想实现通讯录自动扩容,不够了能扩大内存,变得稍微有点智能,就不得不用到开辟内存的函数malloc和realloc,这两个函数又和free离不开关系

所以这里我给大家简单的介绍一下这三个库函数

malloc:这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针

void *malloc( size_t size );

如果开辟成功,则返回一个指向开辟好空间的指针。

如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。

返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己

来决定。

如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器

这里给大家简单的演示一下:

int main()
{
	int arr[5] = { 0 };
	int* ptr = NULL;
	ptr = (int*)malloc(5 * sizeof(int));//开辟5个大小为int整型的空间给ptr
	//判断是否开辟成功
	if (ptr == NULL)
	{
		perror(malloc);//打印错误信息
		return;
	}
	free(ptr);//释放内存
    ptr = NULL;//消除野指针问题
	return 0;
}

realloc:realloc函数的出现让动态内存管理更加灵活。

有时会我们发现过去申请的空间太小了,有时我们又会觉得申请的空间过大了,那为了合理的时使用内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整

void* realloc (void* ptr, size_t size);

ptr 是要调整的内存地址

size 调整之后新大小

返回值为调整之后的内存起始位置。

这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间

值得我们注意的是这个函数的开辟内存有两种情况:

情况1

当原有空间之后有足够大的空间的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。

情况2

当原有空间之后没有足够大的空间时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小

的连续空间来使用。这样函数返回的是一个新的内存地址

free:用来释放内存的,这个函数是搭配开辟内存的函数使用且非常关键,如果开辟了内存不及时释放的话会造成内存释放等严重后果,若重复释放也会有不良影响,所以需要我们注意。

当我们了解了上面三个函数过后我们来试着建立一个可扩容的通讯录

这里我们先创建一个结构体用来存放用户的信息

//在这里进行初始化赋值,若以后有变只需在这一个地方改变
#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
typedef struct PeoInfo
{
	char name[NAME_MAX];//姓名
	char sex[SEX_MAX];//性别
	int age;//年龄
	char tele[TELE_MAX];//电话号码
	char addr[ADDR_MAX];//地址
} PeoInfo;

当我们的用户变多,我们所需要的这样的结构体也需要增加,我们可以在创建一个包含这个结构体的结构体,里面记录用户个数和记录当前通讯录的最大容量

typedef struct Contact
{
	PeoInfo* data;//可以存放人的信息(可增长)
	int sz;//记录通讯中已经保存的信息个数
	int capacity;//记录通讯录当前的最大容量
}Contact;

当数量大于3时我们就应该扩容并初始化,具体实现

//通讯录初始状态的容量大小
#define DEFAULT_SZ 3
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	pc->data = (PeoInfo*)malloc(pc->capacity * sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact::malloc");
		return;
	}
	memset(pc->data, 0, pc->capacity * sizeof(PeoInfo));
}
void CheckCapacity(Contact* pc)
{
	//增容(当用户等于最大容量时)
	if (pc->sz == pc->capacity)
	{
        //开辟两个大小为PeoInfo的内存并且强制类型转换为PeoInfo*类型放在tmp地址处
		PeoInfo* tmp = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));
		if (tmp != NULL)
		{
			pc->data = tmp;//将tmp地址给到pc->data达到连续存放的目的
		}
		else
		{
			perror("CheckCapacity::realloc");//开辟失败打印错误信息
			return;
		}
		pc->capacity += 2;//开辟成功后及时更新最大容量
		printf("增容成功\n");
	}
}

添加用户信息

实现:

void AddContact(Contact* pc)
{
	assert(pc);
    //动态的版本
	CheckCapacity(pc);//输入前看是否需要扩容
	//录入信息
	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
int FindByName(const Contact* pc, char name[])
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	return -1;
}
//删之前需要先查找是否有这个用户
void DelContact(Contact* pc)
{
	assert(pc);

	if (pc->sz == 0)
	{
		printf("通讯录已空,无法删除\n");
		return;
	}
	//删除
	//1. 找到
	char name[NAME_MAX] = { 0 };
	printf("请输入要删除人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);//通过函数查找
	if (pos == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//2. 删除
	int j = 0;
	for (j = pos; j < pc->sz - 1; j++)
	{
		pc->data[j] = pc->data[j + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

查找联系人

int FindByName(const Contact* pc, char name[])
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	return -1;
}
void SearchContact(const Contact* pc)
{
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex,
		pc->data[pos].tele, pc->data[pos].addr);
}

修改用户信息

//修改信息
void ModifyContact(Contact* pc)
{
	//首先先找到要修改的人
	int input = 0;
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex,
		pc->data[pos].tele, pc->data[pos].addr);
	printf("请选择你要修改的信息:\n");
    //用switch语句可以实现只改某一项的信息
	do
	{
		printf("0.修改完毕  1.姓名  2.年龄  3.性别  4.电话  5.地址\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入修改的名字:>");
			scanf("%s", pc->data[pos].name);
			break;
		case 2:
			printf("请输入修改的年龄:>");
			scanf("%d", &(pc->data[pos].age));//注意取地址
			break;
		case 3:
			printf("请输入修改的性别:>");
			scanf("%s", pc->data[pos].sex);
			break;
		case 4:
			printf("请输入修改的电话:>");
			scanf("%s", pc->data[pos].tele);
			break;
		case 5:
			printf("请输入修改的地址:>");
			scanf("%s", pc->data[pos].addr);
			break;
		}
	} while (input);
	printf("修改成功\n");
}

以名字将用户排序

//以姓名排序(A~Z的顺序)
void SortContact(Contact* pc)
{
	int i = 0;
	for (i = 0; i < pc->sz-1; i++)
	{
		int ret = strcmp(pc->data[i].name, pc->data[i + 1].name);
		if (ret > 0)
		{
			PeoInfo tmp;
			tmp = pc->data[i];
			pc->data[i] = pc->data[i + 1];
			pc->data[i + 1] = tmp;
		}
	}
	printf("排序成功\n");
}

销毁通讯录

当结束时销毁通讯录,释放内存,避免出现内存泄漏等问题

void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	printf("销毁成功\n");
}

这里只展示了功能函数以及我认为一些需要注意的地方,若想看完整版可以去下面的链接看看哦

gitee

到此这篇关于C语言实现可增容动态通讯录详细过程的文章就介绍到这了,更多相关C语言动态通讯录内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言编程动态内存开辟实现升级版通讯录教程示例

    目录 前言 一.存放联系人信息 二.通讯录初始化 三.增加联系人 四.销毁通讯录 后记 前言 所谓动态内存开辟的通讯录,就是我需要多少联系人,就给多少联系人,防止给定一个联系人上限,需要增加联系人无法扩容,而联系人没有上限那么多又会造成内存浪费. 本文继之前的静态通讯录作出改进,有兴趣的同学可以看看之前的文章:C语言实现静态通讯录 一.存放联系人信息 这里是用struct PeoInfodata结构体指针指向通讯录,而不再直接 struct PeoInfo data[Max] 用结构体数组定义通

  • C语言动态与静态分别实现通讯录详细过程

    目录 前言: 一.静态通讯录的实现 1.环境的分工逻辑 2.待实现的功能 3.contact.h 4.contact.c 5.test.c 6.实现效果 二.通讯录动态的实现 1.contact.h 2.contact.c 3.test.c 前言: 通讯录相信每一个人都了解过 它的功能包括简单包括:增删查改 这一期就来实现一个C语言实现的通讯录 续上次所聊到的--动态内存的分配 那么我会从标题所给的两个方式来实现 一.静态通讯录的实现 1.环境的分工逻辑 由于过程有点长,便于理解,所以一共会用到

  • C语言模拟实现动态通讯录

    目录 1.模拟实现通讯录总体架构一览图 2.文件执行任务 3.分模块实现 测试模块 test.c 头文件 功能函数声明 contact.h 功能函数逐一实现 1.模拟实现通讯录总体架构一览图 2.文件执行任务 3.分模块实现 测试模块 test.c 1.为了更好地展示,制作一个菜单,在菜单中有 添加,删除,查找,修改,排序,清空,退出的选项. 2.因为起先要进入程序一趟,所以用do····while循环(输入选项来看具体操作,退出还是其他操作) #include "contact.h"

  • C语言与C++动态通讯录超详细实现流程

    目录 1.思路以及要实现的功能 2.详细步骤 2.1 打印菜单界面(建一个源文件test.c) 2.2 主函数 2.3 初始化函数与加载函数 2.4 增加联系人函数AddContact 2.5 删除联系人函数DelContact 2.6 查找联系人函数与打印函数 2.7 修改信息函数ModifyContact 2.8 排序函数SortContact 2.9 保存信息函数与销毁数据函数 3.源码 1.思路以及要实现的功能 通讯录就是为了存储许多联系人的不同方面的信息如名字.电话.地址.年龄.性别等

  • C语言静态与动态通讯录的实现流程详解

    目录 静态通讯录 contact.h contact.c test.c 动态通讯录 contact.h contact.c qsort.c test.c 本次通讯录的代码已经放到我的Gitee仓库中,感兴趣的小伙伴可以去看看 Gitee 静态通讯录 在我们学习完C语言的结构体.指针以及动态内存管理之后,我们就可以实现一些有意思的小项目了,通过这些小项目可以加深我们对于相关知识的理解. 静态通讯录主要要求有 静态大小,可以记录10个人的信息(大小自己定) 记录的信息如下:名字.性别.年龄.电话.住

  • C语言实现通讯录的方法(包括静态版本和动态版本)

    目录 1.静态通讯录的实现 实现的方法: 2.动态通讯录的实现 实现的方法: 3.总结 1.静态通讯录的实现 实现的方法: 我们采用的方法就是工程形势,实现将功能和定义以及测试分成三个文件,其中定义放在.h文件,实现和测试放在.c文件当中. (1)contact.h文件的基本实现: #pragma once//防止头文件重复定义 #define NAME_MAX 20 #define SEX_MAX 5 #define TELE_MAX 12 #define ADDR_MAX 30 #defin

  • C语言静态动态两版本通讯录实战源码

    目录 正片开始 静态版本 头文件( phonebook.h) 接口(test.c) 功能板块(phonebook.c) 1. 初始化: 2. 增添: 3.查找 4.删除 5.修改 6.排序 7.全览 静态版全部代码 test.c(接口) phonebook.h(头文件) phonebook.c(功能) 动态版 动态初始化: 扩容函数 动态版全部代码 test.c phonebook.h 正片开始 这里为了方便对照,我搬出整个程序的前后修改版本,并分别作为静态和动态版本,实际差距并不大,提供出来只

  • C语言实现可增容动态通讯录详细过程

    目录 创建可自动扩容的通讯录 添加用户信息 删除用户信息 查找联系人 修改用户信息 以名字将用户排序 销毁通讯录 创建可自动扩容的通讯录 这里我们想实现通讯录自动扩容,不够了能扩大内存,变得稍微有点智能,就不得不用到开辟内存的函数malloc和realloc,这两个函数又和free离不开关系 所以这里我给大家简单的介绍一下这三个库函数 malloc:这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针 void *malloc( size_t size ); 如果开辟成功,则返回一个指

  • C语言 推理证明带环链表详细过程

    目录 什么是带环链表: 判断链表是否带环: 环形链表 I 找带环形链表入环的第一个结点: 环形链表 II 什么是带环链表: 带环链表是链表最后一个结点的指针域不是指向空指针,而是指向链表之前的结点,这样就形成了环状的链表结构. 如图所示: 判断链表是否带环: 那么问题来了,如何判断一个链表是否带环呢? 这里我们再次运用了快慢指针,但是快慢指针又该如何具体设置呢? 判断思路: 先定义一个快指针fast,一个慢指针slow. 快指针一定是比慢指针先进环的,当slow进环时,fast指针便开始了追sl

  • 利用C语言实现页面置换算法的详细过程

    目录 操作系统实验 页面置换算法(FIFO.LRU.OPT) 概念: 题目: 代码 总结 操作系统实验 页面置换算法(FIFO.LRU.OPT) 概念: 1.最佳置换算法(OPT)(理想置换算法):从主存中移出永远不再需要的页面:如无这样的页面存在,则选择最长时间不需要访问的页面.于所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率. 2.先进先出置换算法(FIFO):是最简单的页面置换算法.这种算法的基本思想是:当需要淘汰一个页面时,总是选择

  • C语言基础应用处理学生打分 计算时间 最少硬币问题详细过程

    第一题: 最少硬币问题(简单版) 假设有三种面值的硬币,分别为10.5.1.接收一个整数作为金额数,计算要达到该金额数,每个面值的硬币最少需要多少枚. 输出结果演示: 参考答案: #include <stdio.h> typedef struct StructrueMoneyBox { int n10; int n5; int n1; } MoneyBox; int main(void) { MoneyBox change = {0, 0, 0}; int face_value[4] = {1

  • C语言实现可保存的动态通讯录的示例代码

    目录 一.Contact.h 二.Contact.c 1.判断是否增容 2.初始化通讯录 3.打印 4.增加联系人信息 5.通过名字查找 6.删除联系人信息 7.查找信息 8.修改信息 9.排序 10.清空通讯录 11.保存通讯录为文件 三.text.c 四.错误写法分享 五.动图展示 一.Contact.h #pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <assert.h> #

  • C语言 栈的表示和实现详细介绍

    C语言 栈的表示和实现详细介绍 定义:栈是限定仅在表尾进行插入和删除操作的线性表. 栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表.它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来).栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针. 栈是允许在同一端进行插入和删除操作的特殊线性表.允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom):栈底固定,而栈顶浮动:

随机推荐