C语言实现动态管理通讯录信息系统(静态通讯录plus版)
文章目录
- 前言:
- 一.动态管理思想
- 1.通讯录结构体声明发生变化
- 2.通讯录结构体初始化发生变化
- 3.通讯录能够动态增容
- 4.通讯录销毁数据
- 二.优化通讯录可持续读写信息
- 1.保存通讯录中的信息到文件中
- 2.加载文件信息到通讯录中
- 三.源码
- 1.text.c
- 2.contact.c
- 3.contact.h
前言:
1.0版本–>静态通讯录
- 在上一个静态版本中,我们在使用的时候会发现有诸多不便,比如通讯录可以存放的信息总量是固定不变的,比如当我们打开通讯录写入数据后,保存再打开时上一次写入的数据消失不见了,本篇将详细讲解如何使用动态内存管理和文件操作解决这两个问题:
一.动态管理思想
1.通讯录结构体声明发生变化
- 首先,在静态通讯录中,结构体的大小是固定好的,比如有20个空间,我们就没法存放30个人的信息,但是只存放3个人的信息那又太浪费了。
- 所以,我们让通讯录结构体一开始只有3个空间,满了后就增容2个空间,这样可以提高空间利用率,需要用到动态内存管理:
原来1.0静态版本:
#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 10
#define ADDRESS_MAX 30
#define TELEPHONE_MAX 12//定义一个结构体类型,这里存放人的信息
typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char address[ADDRESS_MAX];char telephone[TELEPHONE_MAX];
}PeoInfo;
//所有人的都放到这里
typedef struct Contact
{PeoInfo data[MAX];int size;
}Contact;
现在2.0动态版本:
#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define TELE_MAX 12#define DEFAULT_SZ 3
#define INC_SZ 2//人的信息
typedef struct PeoInfo
{char name[NAME_MAX]; //姓名int age; //年龄char sex[SEX_MAX]; //性别char addr[ADDR_MAX]; //住址char tele[TELE_MAX]; //电话号码
}PeoInfo;typedef struct Contact
{PeoInfo* data; //指向存放人的信息的空间int sz; //当前已经放的信息的个数int capacity; //当前通讯录的最大容量
}Contact;
解析:原来的data[MAX]数组存放信息,其大小MAX是固定的,现在通讯录随时会增容,故要改为指针指向每个人的信息,sz值随着通讯录中的人数动态增长:
2.通讯录结构体初始化发生变化
为每个结构体动态分配内存空间
//初始化通讯录
void InitContact(Contact* pc)
{assert(pc);PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SIZE, sizeof(PeoInfo));if (ptr == NULL){perror("InitContact::calloc");return;}pc->data = ptr;pc->size = 0;pc->capacity = DEFAULT_SIZE;
}
3.通讯录能够动态增容
对静态通讯录来说,满了就不能继续添加了。
我们为解决这一问题,给动态通讯录封装一个增容函数,以实现动态扩容:
//检查当前通讯录的容量:
//sz满了才增加容量,不满就没必要增加
void check_capacity(Contact* pc)
{if (pc->sz == pc->capacity){//增加容量PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr == NULL){perror("check_capacity::realloc");return;}pc->data = ptr;pc->capacity += INC_SZ;printf("增容成功\n");}
}
解析:只有当sz(即当前存在通信录中的人数)等于当前最大容量capaciity,即存满了的时候,才扩容,我们定义INC_SZ为每次再增加多少容量。
4.通讯录销毁数据
由于现在的内存空间都是动态分配的,所以数据也都在堆区上,那么每次关闭通讯录的时候都要释放内存,也就是销毁通讯录,以防止内存泄漏:
//销毁通讯录
void DestoryContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->size = 0;pc = NULL;
}
二.优化通讯录可持续读写信息
前面提到,静态版本中,当我们打开通讯录写入数据后,保存再打开时上一次写入的数据消失不见了,为解决这个问题,我们将每次输入到通讯录的信息保存的文件里,这样再打开程序的时候上次的数据仍然存在:
1.保存通讯录中的信息到文件中
//保存通讯录中的信息到文件中
void SaveContact(Contact* pc)
{//写数据//1, 打开文件FILE* pf = fopen("contact.txt", "wb");if (NULL == pf){perror("SaveContact");}else{//写数据int i = 0;for (i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);}fclose(pf);pf = NULL;printf("保存成功\n");}
}
2.加载文件信息到通讯录中
再次打开通讯录需要从文件中读数据:
//加载文件信息到通讯录
void LoadContact(Contact* pc)
{//读数据//1. 打开文件FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("LoadContact");}else{//2. 读数据PeoInfo tmp = { 0 };int i = 0;while (fread(&tmp, sizeof(PeoInfo), 1, pf)){//需不需要增容check_capacity(pc);pc->data[i] = tmp;pc->sz++;i++;}fclose(pf);pf = NULL;}
}
三.源码
1.text.c
#define _CRT_SECURE_NO_WARNINGS 1#include "contatc.h"void menu()
{printf("********************\n");printf("****1.add 2.del****\n");printf("****3.search 4.modify****\n");printf("****5.show 6.sort****\n");printf("****0.exit ****\n");printf("********************\n");
}
enum Option
{EXIT,//0ADD, //1DEL, //2SEARCH,MODIFY,SHOW,SORT
};
int main()
{int input = 0;Contact con;InitContact(&con);do{menu();printf("请选择:>");scanf("%d", &input);switch (input){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:ShowContact(&con);break;case EXIT:SaveContact(&con);DestroyContact(&con);printf("推出通讯录\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}
2.contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"//初始化通讯录
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));if (ptr == NULL){perror("InitContact::calloc");return;}pc->data = ptr;pc->capacity = DEFAULT_SZ;//加载文件信息到通讯录LoadContact(pc);
}//销毁通讯录
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;pc = NULL;
}//检查当前通讯录的容量
void check_capacity(Contact* pc)
{if (pc->sz == pc->capacity){//增加容量PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr == NULL){perror("check_capacity::realloc");return;}pc->data = ptr;pc->capacity += INC_SZ;printf("增容成功\n");}
}//增加联系人
void AddContact(Contact* pc)
{assert(pc);check_capacity(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].addr);printf("请输入电话:>");scanf("%s", pc->data[pc->sz].tele);pc->sz++;
}//显示通讯录中的信息
void ShowContact(const Contact* pc)
{assert(pc);int i = 0;printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");for (i = 0; i < pc->sz; i++){printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].addr,pc->data[i].tele);}
}//根据名字查找信息
int FindByName(const 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)
{assert(pc);char name[NAME_MAX] = { 0 };if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}//删除//找到要删除的人printf("请输入要删除的人的名字:>");scanf("%s", name);int ret = FindByName(pc, name);if (-1 == ret){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(const Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要查找人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){printf("要查找的人不存在\n");return;}//打印信息printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].addr,pc->data[pos].tele);
}//修改指定联系人
void ModifyContact(Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要修改人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){printf("要修改的人不存在\n");return;}printf("请输入名字:>");scanf("%s", pc->data[pos].name);printf("请输入年龄:>");scanf("%d", &(pc->data[pos].age));printf("请输入性别:>");scanf("%s", pc->data[pos].sex);printf("请输入地址:>");scanf("%s", pc->data[pos].addr);printf("请输入电话:>");scanf("%s", pc->data[pos].tele);printf("修改完成\n");
}//保存通讯录中的信息到文件中
void SaveContact(Contact* pc)
{//写数据//1, 打开文件FILE* pf = fopen("contact.txt", "wb");if (NULL == pf){perror("SaveContact");}else{//写数据int i = 0;for (i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);}fclose(pf);pf = NULL;printf("保存成功\n");}
}//加载文件信息到通讯录
void LoadContact(Contact* pc)
{//读数据//1. 打开文件FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("LoadContact");}else{//2. 读数据PeoInfo tmp = { 0 };int i = 0;while (fread(&tmp, sizeof(PeoInfo), 1, pf)){//增容check_capacity(pc);pc->data[i] = tmp;pc->sz++;i++;}fclose(pf);pf = NULL;}
}
3.contact.h
#pragma once
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define TELE_MAX 12#define DEFAULT_SZ 3
#define INC_SZ 2//人的信息
typedef struct PeoInfo
{char name[NAME_MAX]; //姓名int age; //年龄char sex[SEX_MAX]; //性别char addr[ADDR_MAX]; //住址char tele[TELE_MAX]; //电话号码
}PeoInfo;typedef struct Contact
{PeoInfo* data; //指向存放人的信息的空间int sz; //当前已经放的信息的个数int capacity; //当前通讯录的最大容量
}Contact;//初始化通讯录
void InitContact(Contact* pc);//销毁通讯录
void DestroyContact(Contact* pc);//增加联系人
void AddContact(Contact* pc);//删除指定联系人
void DelContact(Contact* pc);//显示通讯录中的信息
void ShowContact(const Contact* pc);//查找指定联系人
void SearchContact(const Contact* pc);//修改指定联系人
void ModifyContact(Contact* pc);//保存通讯录中的信息到文件中
void SaveContact(Contact* pc);//加载文件信息到通讯录
void LoadContact(Contact* pc);
本篇到此结束,码文不易,还请多多支持哦!!
相关文章:

C语言实现动态管理通讯录信息系统(静态通讯录plus版)
文章目录前言:一.动态管理思想1.通讯录结构体声明发生变化2.通讯录结构体初始化发生变化3.通讯录能够动态增容4.通讯录销毁数据二.优化通讯录可持续读写信息1.保存通讯录中的信息到文件中2.加载文件信息到通讯录中三.源码1.text.c2.contact.c3.contact.h前言&#x…...

核心技术: springboot 启动类加载时方法执行的几种实现方式, bean声明周期, 启动执行顺序
目录 1. 业务场景 -> 1.1 初始化操作 -> 1.2 业务操作 -> 1.3优势 2. 实现方式(多种方式,不同思想) -> 2.1 定时调度任务(常用四种方式 task ) --> 2.1.1 Timer(单线程) --> 2.1.2 scheduledExecutorService(多线程并发执行,线程池) --> 2.1…...

拒绝背锅:测试项目中的风险管理一定要知道
测试经理除了要管理产品线的质量保障和日常部门事务工作外,另一项比较重要的就是测试项目全流程的管理。 今天不聊整体的测试项目流程如何开展,而是想聊一聊在同行中比较高频出现的一个字眼:风险管理。 什么是风险管理 引用百度上的解释&a…...

20-js本地存储
js本地存储 localStorage localStorage是window下的对象,可以使用window.localStorage调用,也可以直接使用localStorage调用。 浏览器关闭,localStorage也不会消失 示例: <body><h2>localStorage</h2><…...

ABAP 辨析ON INPUT|REQUEST|CHAIN-INPUT|CHAIN-REQUEST
1、逻辑流 在屏幕开发中,存在如下逻辑流: PBO(Process Before Output):屏幕输出之前触发 PAI(Process After Input):用户在屏幕中执行操作触发 POH(Process On Help-…...

LeetCode:逆波兰式;
150. 逆波兰表达式求值 给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意: 有效的算符为 、-、* 和 / 。每个操作数(运算对象)都可以是一个整…...

为什么阳康后,感觉自己变傻了?
不少人在阳康后出现脑力下降的情况,好像脑子里被雾笼罩。脑雾并不是新名词,已经存在了十几年。以前慢性疲劳综合征患者和脑震荡患者会用它来形容自己的症状。脑雾其实是认知障碍,它可由多种原因引起。比如过度劳累、长期酗酒、缺乏睡眠、久坐…...

考公和大厂40万年薪的offer,选哪个?
眼看毕业将至,相信很多小伙伴已经摩拳擦掌,在为毕业季就业做准备了。2023年高校毕业生规模预计1158万人,同比增加82万人。在资深人力资源服务家汪张明看来,2023年的就业态势不仅是大学毕业生数量有增加,还存在一定的存…...

多线程环境下调用 HttpWebRequest 并发连接限制
.net 的 HttpWebRequest 或者 WebClient 在多线程情况下存在并发连接限制,这个限制在桌面操作系统如 windows xp , windows 7 下默认是2,在服务器操作系统上默认为10. 如果不修改这个并发连接限制,那么客户端同时可以建立的 http 连接数就只有…...

vue3-element-admin搭建
vue3-element-admin 是基于 vue-element-admin 升级的 Vue3 Element Plus 版本的后台管理前端解决方案,是 有来技术团队 继 youlai-mall 全栈开源商城项目的又一开源力作功能清单技术栈清单技术栈 描述官网Vue3 渐进式 JavaScript 框架 https://v3.cn.vuejs.org/Ty…...

蓝海创意云vLive虚拟直播亮相2023昆山元宇宙产品展览会
2月15日-19日,由中国计算机行业协会“元宇宙创见未来”2023元宇宙产品展览会在江苏昆山隆重召开,共吸引了省内外32家企业参展,展出近百款元宇宙产品或技术,涵盖芯片、显示、VR、AR等硬件设备,以及工业、文旅、娱乐、教…...

ThreadLocal线程变量
首先看下ThreadLocal的set()方法存数据的过程,首先获取当前的线程中保持的ThreadLocalMap,每个线程的ThreadLocalMap都是不一样的,因此存储的值是不同的。 public void set(T value) {Thread t Thread.currentThread();ThreadLocalMap map …...

【linux安装redis详解】小白如何安装部署redis,linux安装部署只需5步骤(图文结合,亲测有效)
【写在前面】前端时间接触了一下redis,也是迫于页面查询响应太慢,没办法听说redis这个可持久化内存数据库,于是乎便想着在自己的机器上安装一套,接下来就重点和大家说说怎么从小白开始摸索redis 目录1、下载2、安装2.1 创建文件存…...

2023只会“点点点”,被裁只是时间问题,高薪的自动化测试需要掌握那些技能?
互联网已然是存量市场了,对人员规模的需求正在放缓。在存量市场里,冗余人员和低效人员会被淘汰、被外包。而优秀的人才也会一直受到招聘方的青睐。所以我们就看到了近期行业里冰火两重天的一幕,一边是大量的低端测试工程师被淘汰、求职屡屡碰…...

C语言【柔性数组】
柔性数组🫅什么是柔性数组🫅柔性数组的使用🫅柔性数组的优势🫅什么是柔性数组 也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。 C99 中,结构中的最后一…...

AcWing275. 传纸条
AcWing275. 传纸条小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排坐成一个 m行 n 列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的…...

圆角矩形的绘制和曲线均匀化
摘要: 圆角矩形是软件 UI 等视觉设计中的常见表达,一种常见的绘制方法是将矩形的四角替换为与边相切的四分之一圆弧,然而这种绘制方式会在连接处产生视觉上的切折感,这是因为圆弧和直线的连接处只满足 G1G^1G1 连续性。本文探究了…...

【Linux】环境变量,命令行参数,main函数三个参数保姆教学
目录 ☃️1.奇奇怪怪的现象和孤儿进程 ☃️2.环境变量 ☃️3.深刻理解main函数的前两个参数和命令行参数 ☃️1.奇奇怪怪的现象和孤儿进程 首先回顾一下之前我们学过的fork()创建子进程 fork(void)的返回值有两种 注意fork()头…...

美国访问学者生活中有哪些饮食文化特点?
美国的教育毋庸置疑,排在世界数一数二的位置,美食美景更是数不胜数,那么他们有哪些饮食习惯,下面51访学网小编为你们详细介绍这些内容吧。 一、美国饮食文化特点 1、美国的饮食文化体现科学、适度、快捷,以满足人体的…...

RxJava中的Subject
要使用Rxjava首先要导入两个包,其中rxandroid是rxjava在android中的扩展 implementation io.reactivex:rxandroid:1.2.1implementation io.reactivex:rxjava:1.2.0Subject Subject 既可以是一个 Observer 也可以是一个 Observerable,它是连接 Observer 和…...

vue-element-admin在git 上 clone 之后无法install
一. 无法install的原因因为vue-element-admin引入的富文本编辑插件所导致 由于tui-editor变更 名字 导致 依赖查询找不到对应的版本二. 解决的办法先删掉package.json中tui-editor:1.3.3找到 \src\components\MarkdownEditor\index.vue 把所有的import 替换成下面4个import cod…...

Linux线程调度实验
Linux线程调度实验 1.获取线程属性 #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> #include <time.h> #include <stdlib.h> #include <errno.h> #define _GNU_SOURCE#define handle_error…...

洛谷P5735 【深基7.例1】距离函数 C语言/C++
【深基7.例1】距离函数 题目描述 给出平面坐标上不在一条直线上三个点坐标 (x1,y1),(x2,y2),(x3,y3)(x_1,y_1),(x_2,y_2),(x_3,y_3)(x1,y1),(x2,y2),(x3,y3),坐标值是实数,且绝对值不超过 100.00,求围成的三角形周长。保留两位…...

企业什么要建设自有即时通讯软件系统
随着科技的不断发展,各种即时通讯软件也不断发展进步,而这也与企业的发展息息相关,因为每个人,每个企业都有属于自己的机密,属于自己的隐私。 钉钉,企业微信,等公有的即时通讯软件给企业带来便利…...

LocalDNS
目录 文章目录目录本节实战DNS优化1、dns 5s 超时问题解决办法2、NodeLocal DNSCache实验软件关于我最后本节实战 实战名称💘 实战:NodeLocal DNSCache-2022.7.30(测试成功)💘 实战:NodeLocal DNSCache-2023.2.21(测试成功) DNS优…...

线程池种类和拒绝策略
1、newCachedThreadPool():可缓存的线程池,核心线程数量为0,最大线程数量为INT_MAX。线程空闲时间超过60秒被回收。适合处理大量小任务。 2、newFixedThreadPool()。固定线程个数的线程池,线程都是核心线程,没有应急线…...

Python制作9行最简单音乐播放器?不,我不满足
嗨害大家好鸭~我是小熊猫 好久不见啦~这次就来给大家整个大福利 ~ 源码资料电子书:点击此处跳转文末名片获取 最简单的9行代码音乐播放器如下: import time import pygamefile r歌曲路径 pygame.mixer.init() print(正在播放,file) track pygame.mixer.music.lo…...

零基础小白如何学会数据分析?
随着数字经济、大数据时代的发展,数据已然成为当下时代最重要的盈利资源,让企业在做决策和计划方案时更有针对性和依据,能提前预测市场发展方向,做好布局。由此而产生的数据分析岗位也逐渐被更多企业重视,特别是中大型…...

【Linux】vim的使用及常用快捷键(不会使用vim?有这篇文章就够了)
🔥🔥 欢迎来到小林的博客!! 🛰️博客主页:✈️小林爱敲代码 🛰️欢迎关注:👍点赞🙌收藏✍️留言 目录💖vim的基本概念vi…...

刷完这19道leetcode二分查找算法,不信进不了大厂
对于二分题,其实就是设定一个中间值 mid, 然后通过这个值进行一个判断 check(mid), 通过这个函数的返回值,判断将不可能的一半剪切掉; 在刷题的时候需要注意主要是两部分,check 函数的定义以及边界的选择(…...