【C语言】通讯录实现(下)

目录
1.进阶通讯录特点(下)
2.实现步骤
(1)保存增加的联系人数据到文件中
(2)加载保存的联系人数据
3.完整C语言通讯录代码
(1)contact.h
(2)test.c
(3)contact.c
4.结语
1.进阶通讯录特点(下)
①基本的增删查改功能;
②通讯录的空间不固定,大小可以调整;
③通过C语言文件操作来储存通讯录信息到硬盘上;
2.实现步骤
基本实现步骤同上、中两篇 【[C语言]通讯录实现(中) - CSDN App】http://t.csdnimg.cn/K5tqO
【【C语言】通讯录实现(上) - CSDN App】http://t.csdnimg.cn/ZrZQk
此外还有文件加载、写入、关闭等实现如下:
(1)保存增加的联系人数据到文件中
void SaveContact(Contact* pc)//保存联系人到文件中
{FILE* pf = fopen("contact.dat", "wb");//打开文件if (pf == NULL)//判断指针是否为空{perror("SaveContact");return;}//写数据int i = 0;for (i = 0; i < pc->sz; i++){fwrite(pc->data+i, sizeof(PeoInfo), 1, pf);//一回写一个大小为PeoInfo的文件//从pc->data+i的位置开始读写到文件中}//关闭文件fclose(pf);pf = NULL;
}
运行后得到一个contact.dat的文件用记事本打开如图:

因为fopen函数的打开方式为“wb”,二进制写入模式所以打开该文件是一堆乱码

如上图所示生成了contact.dat文件
(2)加载保存的联系人数据
void LoadContact(Contact* pc)//加载已保存的联系人数据
{//打开文件FILE* pf = fopen("contact.dat", "rb");//以二进制形式读文件PeoInfo tmp = { 0 };//创建一个变量来存放读到的数据while (fread(&tmp, sizeof(PeoInfo), 1, pf))//while循环一直读到文件末尾没有数据为止{if (CheckCapacity(pc) == 0) //要先检查当前通讯录容量是否够存放保存的联系人{printf("无法加载联系人哦~\n"); //CheckCapacity为0时表示无法增容可能没办法开辟空间return;}pc->data[pc->sz] = tmp; //将保存的联系人写入当前通讯录pc->sz++; //写入一个sz通讯录联系人数量加一和增加联系人函数一样}printf("已保存的联系人加载成功啦~\n");return;
}
3.完整C语言通讯录代码
(1)contact.h
#pragma once
//定义的的头文件contact.h
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30#define DEFAULT_SZ 3
#define INT_SZ 2
enum OPTION//用枚举来定义变量
{EXIT,//0ADD,//1DEL,//2...SEARCH,MODIFY,SHOW,SORT
};//声明类型
typedef struct PeoInfo //创建一个结构体来储存联系人相关信息
{char name[MAX_NAME];char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];int age;
}PeoInfo;//通讯录
typedef struct Contact
{PeoInfo* data;//创建一个PeoInfo指针来指向存放数据的空间int sz;//用来记录联系人的个数int capacity;//记录通讯录当前最大容量
}Contact;//函数声明
void InitContact(Contact* pc);
void AddContact(Contact* pc);
void ShowContact(const Contact* pc);
void DelContact(Contact* pc);
void SearchContact(const Contact* pc);
void DestroyContact(Contact* pc);
void SaveContact(Contact* pc);
void LoadContact(Contact* pc);//加载已保存的联系人数据
(2)test.c
#define _CRT_SECURE_NO_WARNINGS 1
//test.c文件--流程
#include"contact.h"
void menu()//菜单
{printf("*******Contact******\n");printf("*** 1.ADD 2.DEL ***\n");printf("***** 3.SEARCH *****\n");printf("***** 4.MODIFY *****\n");printf("** 5.SHOE 6.SORT **\n");printf("****** 0.EXIT ******\n");}
int main()//主函数
{int sec = 1;Contact con;InitContact(&con);//初始化通讯录LoadContact(&con);while (sec){menu();scanf("%d", &sec);switch (sec)//选择不同的功能{case EXIT://退出SaveContact(&con);DestroyContact(&con);printf("您已退出\n");break;case ADD://加AddContact(&con);break;case DEL://删DelContact(&con);break;case SEARCH://查SearchContact(&con);break;case MODIFY://改break;case SHOW://显示ShowContact(&con);break;case SORT://分类break;default:printf("选择错误,请重新输入\n");}printf("\n");}return 0;
}
(3)contact.c
#define _CRT_SECURE_NO_WARNINGS 1
//contact函数实现contact.c源文件
#include"contact.h"int CheckCapacity(Contact* pc);
void LoadContact(Contact* pc)//加载已保存的联系人数据
{//打开文件FILE* pf = fopen("contact.dat", "rb");//读文件PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pf)){if (CheckCapacity(pc) == 0){printf("无法加载联系人哦~\n");return;}pc->data[pc->sz] = tmp;pc->sz++;}printf("已保存的联系人加载成功啦~\n");return;
}
int Search_by_name(const Contact* pc)//查找函数
{char name[MAX_NAME] = { 0 };scanf("%s",name);int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}void InitContact(Contact* pc) //初始化通讯录函数
{//memset(pc->data, 0, sizeof(pc->data));//静态版本assert(pc);pc->data = malloc(DEFAULT_SZ * sizeof(PeoInfo));//开辟空间if (pc->data == NULL)//判断指针是否为空{perror("InitContact");return;}pc->capacity = DEFAULT_SZ;//使用了宏定义DEFAULT_SZ=3容量pc->sz = 0;
}int CheckCapacity(Contact* pc)//增容函数 加联系人时如果空间不够就增容
{if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INT_SZ)*sizeof(PeoInfo));//如果容量满了用realloc函数增容,INT_SZ宏定义为2if (ptr == NULL){perror("CheckCapacity");return 0;}else{pc->data = ptr;//将增容后的指针赋给pc->datapc->capacity += INT_SZ;//capacity相应增加printf("增容成功\n");}return 1;}return 1;
}void AddContact(Contact* pc)//增加联系人
{assert(pc);/*if (pc->sz == MAX){printf("联系人已满\n");return;}*/if (0 == CheckCapacity(pc)){printf("无法增容哦~\n");return;}printf("请输入要添加的联系人名字、性别、年龄、电话、地址:\n");scanf("%s %s %d %s %s",pc->data[pc->sz].name, pc->data[pc->sz].sex,&pc->data[pc->sz].age, pc->data[pc->sz].tele,pc->data[pc->sz].addr);printf("您已经成功添加%s\n", pc->data[pc->sz].name);pc->sz++;return;
}void ShowContact(const Contact* pc)//显示联系人
{assert(pc);if (pc->sz == 0){printf("您还未添加联系人哦~快选择1去添加吧~\n");return;}int i = 0;printf("%-10s\t%-5s\t%-5s\t%-15s\t%-30s\t\n", "名字", "性别", "年龄", "电话", "住址");for (i = 0; i < pc->sz; i++){printf("%-10s\t%-5s\t%-5d\t%-15s\t%-30s\t\n",pc->data[i].name, pc->data[i].sex,pc->data[i].age, pc->data[i].tele,pc->data[i].addr);}return;
}void DelContact(Contact* pc)//删除联系人
{assert(pc);if (pc->sz == 0){printf("您还没有加联系人哦~快选择1去添加吧~\n");return;}printf("请输入要删除的联系人的名字:\n");int flag = Search_by_name(pc);if (flag == -1){printf("没有找到该联系人哦~\n");return;}int j = 0;for (j = flag; j < pc->sz - 1; j++){pc->data[j] = pc->data[j + 1];}printf("您已经成功删除该联系人\n");pc->sz--;return;
}void SearchContact(const Contact* pc)//查找联系人并打印
{printf("请输入要查找的联系人的名字:\n");int i = Search_by_name(pc);if (i == -1){printf("没有找到该联系人哦~\n");return;}else{printf("%-10s\t%-5s\t%-5d\t%-15s\t%-30s\t\n",pc->data[i].name, pc->data[i].sex,pc->data[i].age, pc->data[i].tele,pc->data[i].addr);}return;
}//释放空间
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;
}void SaveContact(Contact* pc)//保存增加的联系人到文件中
{FILE* pf = fopen("contact.dat", "wb");//打开文件if (pf == NULL)//判断指针是否为空{perror("SaveContact");return;}//写数据int i = 0;for (i = 0; i < pc->sz; i++){fwrite(pc->data+i, sizeof(PeoInfo), 1, pf);//一回写一个大小为PeoInfo的文件//从pc->data+i的位置开始读写到文件中}//关闭文件fclose(pf);pf = NULL;
}
4.结语
三版通讯录循序渐进,从最开始的定容增删查改等功能的实现(上篇),到可以不定容的通讯录(中篇),最后到可以保存数据到文件并从文件中加载保存的联系人(下篇),我们不仅学会了一些基本函数的写法,还学了动态内存函数malloc,realloc等函数的用法,并熟悉了c语言文件的基本操作。
相关文章:
【C语言】通讯录实现(下)
目录 1.进阶通讯录特点(下) 2.实现步骤 (1)保存增加的联系人数据到文件中 (2)加载保存的联系人数据 3.完整C语言通讯录代码 (1)contact.h (2)test.c (3)contact.c 4.结语 1.…...
数据结构与算法面试系列-03
1. 一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高? 程序代码 package com.jingxuan.system;public class Sphere {public static void main(String[] args) {double s = 0;double t = 100;for (int i…...
elk之基本crud
写在前面 本文看下工作中用的最多的CRUD。让我们一起来做一个帅帅的CRUD BOY吧!!! 1:基本操作 Create 格式1(指定ID):PUT 索引名称/_create/文档ID {文档json} 格式2(不指定ID):POST 索引名称…...
搭建gitlab仓库
yum安装gitlab仓库 搭建gitlab仓库 配置yum源 vim /etc/yum.repos.d/gitlab-ce.repo [gitlab-ce] namegitlab-ce baseurlhttps://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7 gpgcheck0 Repo_gpgcheck0 Enabled1 Gpgkeyhttps://packages.gitlab.com/gpg.keysudo yum ins…...
C语言-算法-最短路
【模板】Floyd 题目描述 给出一张由 n n n 个点 m m m 条边组成的无向图。 求出所有点对 ( i , j ) (i,j) (i,j) 之间的最短路径。 输入格式 第一行为两个整数 n , m n,m n,m,分别代表点的个数和边的条数。 接下来 m m m 行,每行三个整数 u …...
【操作系统·考研】I/O管理概述
1.I/O设备 1.1 块设备 信息交换以数据块为单位,它属于有结构设备。 块设备传输速率较高,可寻址,且可对该设备随机地的读写。 栗子🌰:磁盘。 1.2 字符设备 信息交换以字符为单位,属于无结构类型。 字符…...
Linux实验记录:使用vsftpd服务传输文件
前言: 本文是一篇关于Linux系统初学者的实验记录。 参考书籍:《Linux就该这么学》 实验环境: VmwareWorkStation 17——虚拟机软件 RedHatEnterpriseLinux[RHEL]8——红帽操作系统 备注: 为了解决在多样复杂的设备之间解决传…...
实习|基于SSM的实习管理系统设计与实现(源码+数据库+文档)
实习管理系统目录 目录 基于SSM的实习管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员功能介绍 (1)管理员登录 (2)实训方向管理 (3)公告信息管理 (4࿰…...
商品介绍和规则参数图片映射和IP设置
虚拟路径映射配置: registry.addResourceHandler("/image/productIntroImgs/**").addResourceLocations("file:D:\\java1234-mall-v3\\productIntroImgs\\");registry.addResourceHandler("/image/productParaImgs/**").addResourceL…...
【React】前端React 代码中预览展示excel文件
封装了ExcelView来展示excel文件,支持显示loading 1.安装依赖 npm i js-preview/excel源码 import React, { useEffect, useRef, useState } from react import jsPreviewExcel, { JsExcelPreview } from js-preview/excel import js-preview/excel/lib/index.cs…...
QButtonGroup使用介绍
一、简介 QButtonGroup是PyQt5库中的一个组件,主要用于组织和管理一组按钮。通过QButtonGroup,可以方便地实现单选框或多选框功能,统一处理按钮的信号,并且可以为按钮分组设定ID以进行识别。 1、原始工程 from PyQt5.Qt import …...
最近nvm安装报错的原因找到了——npm原淘宝镜像正式到期!
前言 📫 大家好,我是南木元元,热爱技术和分享,欢迎大家交流,一起学习进步! 🍅 个人主页:南木元元 目录 背景 错误原因 问题排查 淘宝镜像 证书到期 问题解决 结语 背景 我们…...
docker面试问题二
如何防止Docker容器中的漏洞和攻击? 防止Docker容器中的漏洞和攻击是一个多层次、多方面的任务,涉及从镜像构建、容器运行到网络安全的整个生命周期。以下是一些关键措施: 使用官方和受信任的镜像: 总是从官方源或受信任的第三方…...
嵌入式中C 语言中的三块技术难点
C 语言在嵌入式学习中是必备的知识,甚至大部分操作系统都要围绕 C 语言进行,而其中有三块技术难点,几乎是公认级别的“难啃的硬骨头”。 今天就来带你将这三块硬骨头细细拆解开来,一定让你看明白了。 0x01 指针 指针是公认最难理…...
基于SSM的个性化旅游攻略定制系统设计与实现(有报告)。Javaee项目。ssm项目。
演示视频: 基于SSM的个性化旅游攻略定制系统设计与实现(有报告)。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构…...
[React源码解析] Fiber (二)
在React15及以前, Reconciler采用递归的方式创建虚拟Dom, 但是递归过程不可以中断, 如果组件的层级比较深的话, 递归会占用线程很多时间, 那么会造成卡顿。 为了解决这个问题, React16将递归的无法中断的更新重构为异步的可中断更新, Fiber架构诞生。 文章目录 1.Fiber的结构2…...
Nginx 多项目部署,vue刷新404 解决方案
网上找的资料大多都解决不了,废话不多说直接告诉你解决方法。 环境是 TP6 VUE前端官网 VUE 后台管理 部署 两个项目 刷新 404 解决方案 Nginx 配置 直接贴图 如果解决了,给我顶起来,让更多人 快速的解决。...
[C++]类和对象(中)
一:类的六个默认成员函数 如果一个类中什么成员都没有,简称为空类。空类中并不是什么都没有,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。默认成员函数:用户没有显式实现,编译器会生成的成员函数称为…...
Kubernetes operator(五)api 和 apimachinery 篇
云原生学习路线导航页(持续更新中) 本文是 Kubernetes operator学习 系列第五篇,主要对 k8s.io/api 和 k8s.io/apimachinery 两个项目 进行学习基于 kubernetes v1.24.0 代码分析Kubernetes operator学习系列 快捷链接 Kubernetes operator&a…...
接口自动化测试中解决接口间数据依赖
在实际的测试工作中,在做接口自动化测试时往往会遇到接口间数据依赖问题,即API_03的请求参数来源于API_02的响应数据,API_02的请求参数又来源于API_01的响应数据。 因此通过自动化方式测试API_03接口时,需要预先请求API_02接口&a…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...
