当前位置: 首页 > news >正文

C语言小程序-通讯录(动态内存管理)

通讯录

  • 初始化通讯录
    • 相关功能的实现(增删查改显排)
      • 最终的代码

设计思路讲解:
我们以手机上的通讯录为例,用C来设计一个简单的通讯录版本
通讯录的功能参照手机上的版本应该有增加,删除,修改,查找,因为我们的代码最终是在终端显示的,所以我们再给出一个显示通讯录的功能,以及最后对通讯录进行排序的功能。

我们使用结构体来集合关于通讯录中联系人的信息(定义为PeoInfo),这就需要我们要有一个关于PeoInfo的集合来存放多个人的信息,集合的大小可以由动态内存函数来开辟,内存空间不足时自动增加空间以便增添联系人。

删除时,有很多的方法,可以将要删除的联系人的信息全部改为0,然后qsort一下就ok了。也可以用该联系人后面的联系人覆盖掉要删除的,这样也能实现。方法还有很多,这里不一一给出了。

修改时我们要先输入该联系人的名字,然后重新输入信息。

查找也是要先输入联系人的名字,然后显示联系人的信息,我们发现在实现删除,修改查找等功能时,都要涉及到输入联系人的名字进行插查询,所以我们在写代码时,可以将这一功能封装成一个函数,以减少我们重复的代码。

显示通讯录就很容易实现了,只需要将所有的联系人信息全部打印出来就好了,这里可以使用循环来解决。

排序我们就使用qsort进行,可以按照名字,年龄,或者其他的信息来进行排
序,这个取决于程序员自己。

接下来我们就来开始对各个功能的代码实现,在最后会给出最后的代码。有基础的小伙伴可以直接跳到最后查看最终代码。

初始化通讯录

首先要创建一个通讯录出来才能对其初始化,前面我们说过使用PeoInfo来收集联系人的信息

struct PeoInfo
{
char name[MAX_NAME];
char sex[SEX];
int age;
char telephone[TelePhone];
};

大小我们统一使用宏定义来操作,方便我们后续的修改。
只有一个结构体行吗??
肯定是不行的,因为我们还需要一个集合体来存放PeoInfo的信息,所以还要有一个结构体,这个结构体包含我们的PeoInfo。

//通讯录结构体
struct Contact
{
//创建sz的目的是为了在进行添加删除等操作时,好找到元素的下标
int sz;
struct PeoInfo* arr;
int capacity;//容量大小.
};

这还给出了sz和capacity两个参数,capacity是记录通讯录结构体的大小,sz是用来记录当前联系人的个数,以方便我们后续的增加,删除和查找等功能的实现,这一点如果能想到的话,后面的实现就很容易了,因为后续的大多功能都是以这两个参数为工具进行的。

结构体创建好了之后,我们就要对其初始化了,除了capacity需要给定一个初始大小之外,剩下的都要全部初始化为0。

//初始化为全0;
void InitContact(struct Contact* pc)
{
assert(pc);
pc->sz = 0;
pc->capacity = 3;//默认容量大小是3
pc->arr = (struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));
if (pc->arr == NULL)
{
strerror(errno);
return; //exit(-1)
}
}

我们把有关通讯录的实现的代码放到contact.c的文件中,把所有包含的头文件放在contact.h的头文件当中,把代码的主主体躯干放在test.c的测试文件当中。

相关功能的实现(增删查改显排)

剩下功能的实现以及注意事项我们在代码中注释了,大家留意一下就好,另外我把上面初始化的代码也一并在这里给大家展示出来,这里的代码就是contact.c中的代码啦~

#include "contact.h"

//初始化为全0;
void InitContact(struct Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = 3;//默认容量大小是3
	pc->arr = (struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));
	if (pc->arr == NULL)
	{
		strerror(errno);//打印错误信息
		return;
	}
}

//增加联系人
void ADDContact(struct Contact* pc)
{
	assert(pc);
	//如果空间已满的话,要先增加一定的空间
	if (pc->sz == pc->capacity)
	{
		//增加容量
		struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->arr, (pc->capacity + 2)*sizeof(struct PeoInfo));//一次扩充两个大小的空间
		if (ptr == NULL)
		{
			strerror(errno);//对应的头文件<string.h>, <errno.h>
			return;
		}
		else
		{
			pc->capacity += 2;
			pc->arr = ptr;
			ptr = NULL;
			printf("增容成功!\n");
		}
	}

	//增加
	printf("请输入名字:>");
	scanf("%s", pc->arr[pc->sz].name);
	printf("请输入性别:>");
	scanf("%s", pc->arr[pc->sz].sex);
	printf("请输入年龄:>");
	scanf("%d", &(pc->arr[pc->sz].age));
	printf("请输入电话:>");
	scanf("%s", pc->arr[pc->sz].telephone);

	//sz++指向下一个空白的元素,方便下次直接添加联系人
	pc->sz++;
	printf("成功增加联系人\n");
}

//将查找指定联系人封装成一个函数,因为在后续的功能中还要用到这个
int FindByName(const struct Contact* pc, char* n)
{
	assert(pc && n);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		//strcmp比较两个字符串是否相同
		if (0 == strcmp(pc->arr[i].name, n))
		{
			return i;
		}
	}
	return -1;
}

//删除void DeleContact(struct Contact* pc);

void DeleContact(struct Contact* pc)
{
	assert(pc);
	char n[MAX_NAME];
	printf("请输入查找联系人的名字:>");
	scanf("%s", n);
	int ret = FindByName(pc, n);
	if (ret == -1)
		printf("该联系人不存在\n");
	else
	{
		//删除
		for (int j = ret; j < pc->sz - 1; j++)
		{
			pc->arr[j] = pc->arr[j + 1];
		}
		//记得减减!!!!
		pc->sz--;
		printf("成功删除指定联系人\n");
		//方法2,qsort排序,将要删除的人的数据改为0,再qsort排序一下也行,同样记得pc->sz--;
	}


}

//修改
void ModifyContact(struct Contact* pc)
{
	assert(pc);
	printf("请输入要修改人的名字:>");
	char name[MAX_NAME];
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (ret == -1)
		printf("要修改的人不存在\n");
	else
	{
		//将要修改的人的信息重新录入,并提示修改成功!
		printf("请输入名字:>");
		scanf("%s", pc->arr[ret].name);
		printf("请输入性别:>");
		scanf("%s", pc->arr[ret].sex);
		printf("请输入年龄:>");
		scanf("%d", &(pc->arr[ret].age));
		printf("请输入电话:>");
		scanf("%s", pc->arr[ret].telephone);

		printf("修改成功\n");
	}
}

//查找
void SearchContact(const struct Contact* pc)
{
	assert(pc);
	char name[MAX_NAME];
	printf("请输入要查找的人的名字:>");
	scanf("%s", name);
	//查找一下指定的人是否存在
	int ret = FindByName(pc, name);
	if (ret == -1)
		printf("要查找的人不存在\n");
	else
	{
		printf("%-20s\t%-5s\t%-5s\t%-12s\n", "姓名", "性别", "年龄", "电话");
		printf("%-20s\t%-5s\t%-5d\t%-12s\n", pc->arr[ret].name,
			pc->arr[ret].sex,
			pc->arr[ret].age,
			pc->arr[ret].telephone);
	}
}

//显示联系人
void ShowContact(const struct Contact* pc)
{
	assert(pc);
	int i = 0;
	printf("%-20s\t%-5s\t%-5s\t%-12s\n", "姓名", "性别", "年龄", "电话");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-5s\t%-5d\t%-12s\n", pc->arr[i].name,
			pc->arr[i].sex,
			pc->arr[i].age,
			pc->arr[i].telephone);
	}
}

//按照名字排
//大家也可以自己写一个使用年龄排序的代码
int cmp_name(const void* e1, const void* e2)
{
	return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);//这里排的是升序
}

void SortContact(const struct Contact* pc)
{
	assert(pc);
	qsort(pc->arr, pc->sz, sizeof(pc->arr[0]), cmp_name);
	printf("排序成功!结果如下:\n");
	//在tect.c文件中在调用一次ShowContact函数即可
}

//退出通讯录的最后一定要记得释放空间!!!!!
void Destroy(struct Contact* pc) 
{
	free(pc->arr);
	pc->arr = NULL;
}

最终的代码

下面就给出有关test.c和contact.h的相关代码。
test.c

#include "contact.h"

enum ST
{
	退出通讯录,//0
	增加联系人,//1
	删除联系人,//2
	修改联系人,//3
	查找联系人,//4
	显示联系人,//5
	排序联系人//6
};

void menu()
{
	printf("****************************************\n");
	printf("*****1.增加联系人    2.删除联系人*********\n");
	printf("*****3.修改联系人    4.查找联系人*********\n");
	printf("*****5.显示联系人    6.排序联系人*********\n");
	printf("*****0.退出通讯录               *********\n");
	printf("****************************************\n");
}
int main()
{
	int input = 0;
	//创建通讯录
	struct Contact contact;
	//初始化通讯录数组
	InitContact(&contact);

	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 增加联系人:
			ADDContact(&contact);
			system("pause");
			system("cls");
			break;
		case 删除联系人:
			DeleContact(&contact);
			system("pause");
			system("cls");
			break;
		case 修改联系人:
			ModifyContact(&contact);
			system("pause");
			system("cls");
			break;
		case 查找联系人:
			SearchContact(&contact);
			system("pause");
			system("cls");
			break;
		case 显示联系人:
			ShowContact(&contact);
			system("pause");
			system("cls");
			break;
		case 排序联系人:
			//qsort排序
			SortContact(&contact);
			ShowContact(&contact);
			system("pause");
			system("cls");
			break;
		case 0:
			//释放指针-当程序退出的时候,释放掉自己开创的空间,防止内存泄露!!
			Destroy(&contact);
			printf("再见!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (input);
	
	return 0;
}

contact.h

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

//方便以后的修改
#define MAX_NAME 30
#define SEX 6
#define TelePhone 13

//联系人信息
struct PeoInfo
{
	char name[MAX_NAME];
	char sex[SEX];
	int age;
	char telephone[TelePhone];
};

//通讯录结构体
struct Contact
{
	//创建sz的目的是为了在进行添加删除等操作时,好找到元素的下标
	int sz;
	struct PeoInfo* arr;
	int capacity;//容量大小.
};

void InitContact(struct Contact* pc);

void ADDContact(struct Contact* pc);

void DeleContact(struct Contact* pc);

void ModifyContact(struct Contact* pc);

void SearchContact(const struct Contact* pc);

void ShowContact(const struct Contact* pc);

void SortContact(const struct Contact* pc);

void Destroy(struct Contact* pc);

热心老铁,在线答疑!

相关文章:

  • L2W3作业 TensorFlow教程
  • 开发中 — — 异常与日志处理
  • C++——入门详解(上)
  • 盘点六大程序员接单网站,务必收藏!
  • Java算法解题小记
  • java-php-python-springboot小说网站计算机毕业设计
  • 医药研发团队怎么利用RPA智能员工降低运营成本
  • 计算机学院2022级新生周赛(一)题解
  • 6191. 好路径的数目 并查集
  • HTML5 web
  • MySql5.1+版本主从同步配置(bin_log)模式
  • 什么是线程的拒绝策略核心线程数打满后就直接创建新线程吗
  • leetcode: 312. 戳气球
  • 通信原理学习笔记6-1:数字解调——基础解调链路、匹配滤波器和AWGN信道最佳接收机
  • 就是因为不能接受一些观念,所以阻碍了你真正赚到钱
  • ES6 学习笔记(一)let,const和解构赋值
  • ES6--对象的扩展
  • go语言学习初探(一)
  • javascript从右向左截取指定位数字符的3种方法
  • js如何打印object对象
  • Laravel 菜鸟晋级之路
  • MySQL主从复制读写分离及奇怪的问题
  • spring-boot List转Page
  • Tornado学习笔记(1)
  • 仿天猫超市收藏抛物线动画工具库
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 前端之React实战:创建跨平台的项目架构
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 微信小程序--------语音识别(前端自己也能玩)
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 项目实战-Api的解决方案
  • 优秀架构师必须掌握的架构思维
  • 智能网联汽车信息安全
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • ​Python 3 新特性:类型注解
  • ​你们这样子,耽误我的工作进度怎么办?
  • #ifdef 的技巧用法
  • (1)SpringCloud 整合Python
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)ssm学生管理系统 毕业设计 141543
  • (九)c52学习之旅-定时器
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (五)IO流之ByteArrayInput/OutputStream
  • (一)WLAN定义和基本架构转
  • .bashrc在哪里,alias妙用
  • .NET CORE Aws S3 使用
  • .NET Framework Client Profile - a Subset of the .NET Framework Redistribution
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .NET应用架构设计:原则、模式与实践 目录预览
  • [].shift.call( arguments ) 和 [].slice.call( arguments )
  • [AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]