【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…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...

DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...

使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...