【C语言】文件操作修改通讯录(升级版本)可以存储数据

news2024/11/23 16:44:01

文件操作的内容,我们在上文已经学习了,那么如果有不明白的小伙伴请看这篇文章

【C语言】小王带您实现文件操作(简单图示讲解)_小王学代码的博客-CSDN博客

通讯录我们在之前也学习实现了静态、动态通讯录

【C语言】使用C语言实现静态、动态的通讯录(简单易懂)_小王学代码的博客-CSDN博客


目录

前言

一、使用文件操作思路

二、使用步骤

1.退出改造

2.初始化改造

3.代码演示

三、文件操作通讯录完整代码

1.Contact.h

2.Contact.c

3.test.c

总结


前言

我们会在前面实现静态、动态数据库的时候,输入一组数据,完成一系列增删改查之后,程序关闭,下次再打开的时候,会发现之前的数据没有了,这是因为,我们的数据都是存放在内存中,当程序结束的时候,自然内存释放了,再打开就没有了。

那么,如果通过文件操作,将程序中的数据,传递给硬盘中,下次使用再拿出可以吗?

当然可行啊,我们就带大家操作一下。

一、使用文件操作思路

我们要在原来通讯录上更改什么?

1.退出保存数据        所以在输入0退出的时候,加上文件操作,使得数据保存到相应的文件中

2.打开程序就提取出之前数据         这个在初始化的时候,使用文件操作,即可

以上两点进行修改就可以完善通讯录,实现可以存取数据的通讯录,更加实用

二、使用步骤

1.退出改造

如图所示:

代码如下:

void SaveContact(Contact* pc) {
	//存入数据
	//使用fwrite 二进制存储吧

	//fopen打开文件
	FILE* pf = fopen("Contact.txt", "wb");
	//判断是否存在文件Contact.txt
	if (NULL == pf) {
		perror("SaveContact::fopen");
	}
	else {
		fwrite(pc->data, sizeof(PeopleInfo), pc->sz, pf);
		//输出之后提示输出完成到Contact.txt中
		printf("保存完成\n");
		//关闭流 并pf置为NULL 防止野指针
		fclose(pf);
		pf = NULL;
	}

}

2.初始化改造

我们想要一开始就得到原来的数据,我们在初始化的时候,就读取Contact.txt文件中的数据即可

图示如下:

代码如下:

//新增代码,读取文件中的数据
void read_Contact(Contact* pc) {
	//读取的时候先进行判断是否
	FILE* pf = fopen("Contact.txt", "r");
	if (NULL == pf) {
		perror("read_Contact::open");
	}
	else {
		PeopleInfo ptr={0};
		int i = 0;
		while (fread(&ptr, sizeof(PeopleInfo), 1, pf)) {
			check_capacity(pc);
			//不够就扩容
			pc->data[i] = ptr;
			pc->sz++;
			i++;
		}
	}
}
void check_capacity(Contact* pc) {
	if (pc->sz == pc->capacity) {
		//使用realloc函数 进行扩容
		PeopleInfo* ptr = (PeopleInfo*)realloc(pc->data, sizeof(PeopleInfo) * (pc->capacity + MAX2));
		if (ptr == NULL) {
			perror("check_capacity");
			return;
		}
		else {
			pc->data = ptr;
			pc->capacity = pc->capacity + MAX2;
			printf("扩容完成\n");
		}
	}
}
//这是动态通讯录的初始化
void InitContact(Contact* pc) {
	//进行初始化的时候,我们当然可以直接
	assert(pc);//断言
	pc->sz = 0;
	PeopleInfo *ptr=(PeopleInfo*)calloc(MAX1,sizeof(PeopleInfo));
	if (ptr == NULL) {
		perror("malloc::data");
		return;
	}
	pc->data = ptr;
	pc->capacity=MAX1;

	read_Contact(pc);
}

3.代码演示

如图所示,这样就可以实现在硬盘文件中输入读取数据,更加贴合实际所需,这就是经过文件操作处理之后的动态通讯录,静态更简单,会了动态,静态就可以实现。


三、文件操作通讯录完整代码

我们分成了三部分,Contact.h         Contact.c         test.c

Contact.h               声明test.c所需要的函数  是头文件

Contact.c               实现Contact.h声明的函数

test.c                      通讯录的主体。主干,实现通讯录的逻辑

1.Contact.h

#define _CRT_SECURE_NO_WARNINGS

//Contact 实现通讯录 头文件
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<malloc.h>
#include<stdlib.h>
#include<search.h>

#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 20
#define TELE_MAX 12


//下面两个define是用于动态通讯录的
#define MAX1 3	//表示第一次容积是多少
#define MAX2 2  //表示一次扩容多少




//构建通讯录所需的结构体
typedef struct PeopleInfo {
	char name[NAME_MAX];//姓名
	int age;//年龄
	char sex[NAME_MAX];//性别
	char addr[ADDR_MAX];//地址
	char tele[TELE_MAX];//电话号码
}PeopleInfo;

//这是静态通讯录  就是data这个数组是固定死的MAX
//typedef struct Contact {
//	PeopleInfo data[MAX];//表示存储的通讯录最大人员数
//	int sz;//表示当前Contact通讯录人员个数
//}Contact;

//实现动态通讯录
typedef struct Contact {
	PeopleInfo *data;//表示存储的通讯录最大人员数
	int sz;//表示当前Contact通讯录人员个数
	int capacity; //表示当前容量  作为扩容的依据
}Contact;

//初始化通讯录
void InitContact(Contact* pc);
//添加通讯录的信息
void addContact(Contact* pc);
//删除通讯录中的信息
void delContact(Contact* pc);
//查找通讯录成员信息
int searchContact(Contact* pc);
//打印
void showContact(Contact* pc);
//改变指定元素
void changeContact(Contact* pc);
//排序,按照名字排序
void sortContact(Contact* pc);

//保存通讯录
void SaveContact(Contact*pc);

//读取通讯录
void read_Contact(Contact*pc);

2.Contact.c

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
//用来实现头文件的代码
//
这是静态初始化
//void InitContact(Contact* pc) {
//	//进行初始化的时候,我们当然可以直接
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//	//memset 函数  这样的话,从data这个数组的地址开始 sizeof(pc->data)个字节,都赋值为0
//}

//这是动态通讯录的初始化
void InitContact(Contact* pc) {
	//进行初始化的时候,我们当然可以直接
	assert(pc);//断言
	pc->sz = 0;
	PeopleInfo *ptr=(PeopleInfo*)calloc(MAX1,sizeof(PeopleInfo));
	if (ptr == NULL) {
		perror("malloc::data");
		return;
	}
	pc->data = ptr;
	pc->capacity=MAX1;

	read_Contact(pc);
}
静态通讯录
//void addContact(Contact* pc) {
//	assert(pc);
//	if (pc->sz == MAX) {
//		printf("通讯录已满,无法添加\n");
//		return;
//	}
//	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);
//	printf("添加完成,请继续操作\n");
//	pc->sz++;
//}
//动态通讯录
void check_capacity(Contact* pc) {
	if (pc->sz == pc->capacity) {
		//使用realloc函数 进行扩容
		PeopleInfo* ptr = (PeopleInfo*)realloc(pc->data, sizeof(PeopleInfo) * (pc->capacity + MAX2));
		if (ptr == NULL) {
			perror("check_capacity");
			return;
		}
		else {
			pc->data = ptr;
			pc->capacity = pc->capacity + MAX2;
			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);
	printf("添加完成,请继续操作\n");
	pc->sz++;
}
void delContact(Contact* pc) {
	assert(pc);
	printf("请选择删除的目标:>");
	if (pc->sz == 0) {
		return;
	}
	//删除的话只需要找到对应的要删除的数据,比如以名字为准,先找到,然后再讲其后面的元素覆盖前面的
	int pos = searchContact(pc);
	//换位置
	if (pos == -1) {
		printf("没有查找到该成员\n");
		return;
	}
	for (int i = pos; i < pc->sz - 1; i++) {
		pc->data[i] = pc->data[i + 1];
	}

	pc->sz--;//直接--不用管换位置之后最后一个数字的问题
	printf("删除完成\n");
}


int  searchContact(Contact* pc) {
	assert(pc);
	char name[20];
	int pos = -1;
	scanf("%s", name);
	//查询
	for (int i = 0; i < pc->sz; i++) {
		if (strcmp(pc->data[i].name, name) == 0) {
			pos = i;
		}
	}
	
	return pos;
}

void showContact(Contact* pc) {
	assert(pc);
	if (pc->sz == 0) {
		return;
	}//可以有可无
	printf("%-20s\t%-5s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
	for (int i = 0; i < pc->sz; i++) {
		printf("%-20s\t%-5d\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);
	}
	printf("打印完成\n");
}



void changeContact(Contact* pc) {
	assert(pc);
	//先找到
	int pos = searchContact(pc);
	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 sortContact(Contact* pc) {
	assert(pc);
	if (pc->sz == 0) {
		printf("通讯录中暂无元素\n");
		return;
	}
	Contact s;
	InitContact(&s);
	for (int i = 0; i < pc->sz-1; i++) {
		for (int j = 0; j < pc->sz-1-i; j++) {
			if (strcmp(pc->data[j].name, pc->data[j + 1].name)==1) {
				s.data[j] = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = s.data[j];
			}
		}
	}
}

int compare(const void* e1, const void* e2) {
	return *((int*)e1) - *((int*)e2);
}
void sort(Contact*pc) {
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), compare);
}
//int main()
//
//{
//	qsort()
//	return 0;
//}

void SaveContact(Contact* pc) {
	//存入数据
	//使用fwrite 二进制存储吧

	//fopen打开文件
	FILE* pf = fopen("Contact.txt", "wb");
	//判断是否存在文件Contact.txt
	if (NULL == pf) {
		perror("SaveContact::fopen");
	}
	else {
		fwrite(pc->data, sizeof(PeopleInfo), pc->sz, pf);
		//输出之后提示输出完成到Contact.txt中
		printf("保存完成\n");
		//关闭流 并pf置为NULL 防止野指针
		fclose(pf);
		pf = NULL;
	}

}
void read_Contact(Contact* pc) {
	//读取的时候先进行判断是否
	FILE* pf = fopen("Contact.txt", "r");
	if (NULL == pf) {
		perror("read_Contact::open");
	}
	else {
		PeopleInfo ptr={0};
		int i = 0;
		while (fread(&ptr, sizeof(PeopleInfo), 1, pf)) {
			check_capacity(pc);
			//不够就扩容
			pc->data[i] = ptr;
			pc->sz++;
			i++;
		}
	}
}

3.test.c

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"

//这边进行主要的通讯录流程操作

void menu() {
	printf("***********************************************\n");
	printf("******      1.add           2.del        ******\n");
	printf("******      3.search        4.change     ******\n");
	printf("******      5.show          6.sort       ******\n");
	printf("******      0.exit                       ******\n");
	printf("***********************************************\n");

}
void test() {
	//打印选择菜单

	int input = 0;
	int pos = 0;
	Contact pc;
	//Contact pc={0};
	//当然可以这样初始化,但是不一定后来初始化都这样,所以有InitContact()
	InitContact(&pc);
	
	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input) {
			case 1:
				addContact(&pc);
				break;
			case 2:
				delContact(&pc);
				break;
			case 3:
				pos = searchContact(&pc);
				if (pos == -1) {
					printf("没有查找到该成员\n");
				}
				else {
					printf("%-20s\t%-5d\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);
				}
				break;
			case 4:
				changeContact(&pc);
				break;
			case 5:
				showContact(&pc);
				break;
			case 6:
				sort(&pc);
				break;
			case 0:
				SaveContact(&pc);
				printf("退出通讯录\n");
				free(pc.data);
				break;
			default:
				break;
			}
	} while (input);
}
int main()
{
	test();
	return 0;
}

总结

本文通过文件操作实现了,通讯录的数据存储到硬盘上,并可以从硬盘中读取数据到程序中,所以这是更加贴合实际所需了,我们介绍了主要文件操作运用的地方,以及实现方式,并附带了完整的代码,希望友友们,能看懂并理解这样的程序。

小王在这里提前祝大家2023兔年新年快乐!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/169909.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享80个PHP源码,总有一款适合您

PHP源码 分享80个PHP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 80个PHP源码下载链接&#xff1a;https://pan.baidu.com/s/1yJ1aR6vt2kDjiVyqj0gPuw?pwdlfl9 提取码&#xff…

深信服EDR任意用户登录与命令执行漏洞

深信服EDR任意用户登录与命令执行漏洞1.深信服EDR简介2.深信服EDR漏洞2.1.后台任意用户登录漏洞2.1.1.漏洞描述2.1.2.影响版本2.1.3.漏洞复现2.2.任意命令执行漏洞2.2.1.漏洞描述2.2.2.影响版本2.2.3.漏洞复现2.2.3.1.构建URL2.2.3.2.效果1.深信服EDR简介 终端检测响应平台&…

C生万物 | 使用宏将一个整数的二进制位的奇数位和偶数位交换

&#x1f451;作者主页&#xff1a;Fire_Cloud_1 &#x1f3e0;学习社区&#xff1a;烈火神盾 &#x1f517;专栏链接&#xff1a;万物之源——C 淋漓尽致——位运算✒题目分析 && 实现思路[位运算]1、获取这个整数的奇数位和偶数位2、使用移位运算使【奇变偶】【偶变奇…

如何通过限流算法防止系统过载

限流算法&#xff0c;顾名思义&#xff0c;就是指对流量进行控制的算法&#xff0c;因此也常被称为流控算法。 我们在日常生活中&#xff0c;就有很多限流的例子&#xff0c;比如地铁站在早高峰的时候&#xff0c;会利用围栏让乘客们有序排队&#xff0c;限制队伍行进的速度&am…

扫雷——“C”

各位uu们我又来啦&#xff0c;今天&#xff0c;小雅兰给大家介绍的又是一个小游戏&#xff0c;就是扫雷这款游戏&#xff0c;这个游戏和我昨天给大家介绍的三子棋游戏有异曲同工之妙&#xff0c;相信很多人都玩过&#xff0c;话不多说&#xff0c;我们进入正题吧. 《扫雷》是一…

【学习笔记】【Pytorch】十七、模型测试套路

【学习笔记】【Pytorch】十七、模型测试套路一、内容概述二、模型测试套路代码实现一、内容概述 利用已经训练好的模型&#xff0c;然后给它提供输入&#xff0c;判断输出是否正确&#xff0c;即模型的应用测试。 在模型测试也会有一些坑&#xff1a; 神经网络的输入一般是4…

【错误记录】Kotlin 代码编译时报错 ( Variable ‘name‘ must be initialized | 初始化块定义在所有属性之后 )

文章目录一、报错信息二、问题分析三、解决方案 ( 初始化块定义在所有属性之后 )一、报错信息 在 Kotlin 中 , init 初始化块 要 定义在所有成员属性之后 ; 如果在 init 初始化块 中 , 使用到了 成员属性 , 有可能出现 编译时报错信息 ; 报错代码示例 : class Hello{init {va…

seata安装及配置

1.下载 下载地址&#xff1a;https://github.com/seata/seata/tags 本文选用seata-1.4.2版 2.解压 tar -zxvf seata-server-1.4.2.tar.gz 3. 初始化数据库 登录mysql&#xff0c;然后创建数据库和数据表&#xff1a; -- -------------------------------- The script used…

【Java】【系列篇】【Spring源码解析】【三】【体系】【Environment体系】

整体结构图 本篇文章仅作简单了解&#xff0c;详细还等到Springboot系列里面详解PropertyResolver 作用 用于针对任何基础源解析属性(Property)的接口 方法解析 // 查看规定指定的key是否有对应的value 对应key的值是null的话也算是不能解析 boolean containsProperty(Stri…

持续丰富营销玩法 东风标致408X引领品牌向上焕新

1月5日&#xff0c;东风标致408X首秀——XSHOW开演&#xff0c;标致全球战略车型408X正式在中国亮相&#xff0c;定位为“新法式无界座驾”&#xff0c;它是东风标致全面向电动化、智能化、网联化的发展的一款汽车&#xff0c;也是引领东风标致向上焕新的一款全新车型。作为东风…

十五天学会Autodesk Inventor,看完这一系列就够了(终章),答疑

众所周知&#xff0c;Autocad是一款用于二维绘图、详细绘制、设计文档和基本三维设计&#xff0c;现已经成为国际上广为流行的绘图工具。Autodesk Inventor软件也是美国AutoDesk公司推出的三维可视化实体模拟软件。因为很多人都熟悉Autocad&#xff0c;所以再学习Inventor&…

python SciPy 优化器

SciPy 优化器SciPy 的 optimize 模块提供了常用的最优化算法函数实现&#xff0c;我们可以直接调用这些函数完成我们的优化问题&#xff0c;比如查找函数的最小值或方程的根等。NumPy 能够找到多项式和线性方程的根&#xff0c;但它无法找到非线性方程的根&#xff0c;如下所示…

工具类库 Hutool介绍与使用(请记得收藏)

工具类库 Hutool介绍 Hutool是一个小而全的Java工具类库&#xff0c;通过静态方法封装&#xff0c;降低相关API的学习成本&#xff0c;提高工作效率&#xff0c;使Java拥有函数式语言般的优雅&#xff0c;让Java语言也可以“甜甜的”。Hutool中的工具方法来自于每个用户的精雕…

VMware vCenter上用OVF模板部署虚拟机

前言 在我们项目操作过程中&#xff0c;使用VMware vCenter系统&#xff0c;经常会出现使用原有部署环境来部署虚拟机&#xff0c;供项目组使用&#xff0c;此时我们克隆虚拟机就要用到OVF模板来克隆操作&#xff0c;这是一个非常实用的功能。 一、打开Vcenter&#xff0c;选定…

Redis学习笔记2_数据结构

Redis数据结构Redis数据结构二、数据结构2.1Redis核心对象2.2底层数据结构2.2.1 SDS-simple dynamic stringsds内存布局sds的操作为什么使用SDS&#xff0c;SDS的优势&#xff1f;2.2.2 listlist内存布局2.2.3 dictdict内存布局2.2.4 zskiplistzskiplist内存布局2.2.5 intsetin…

前端实现登录拼图验证

前言 不知各位朋友现在在 web 端进行登录的时候有没有注意一个变化&#xff0c;以前登录的时候是直接账号密码通过就可以直接登录&#xff0c;再后来图形验证码&#xff0c;数字结果运算验证&#xff0c;到现在的拼图验证。这一系列的转变都是为了防止机器操作&#xff0c;但对…

Python 第六章 函数

6.1函数的定义和调用6.1.1定义函数格式&#xff1a;def 函数名 ([参数列表]):["""文档字符串"""]函数体[return 语句]6.1.2函数调用格式&#xff1a;函数名([参数列表])python中函数可以嵌套定义例如&#xff1a;def add_modify(a,b):resultabpr…

Vue3响应式原理解析

前言 今年上半年开始&#xff0c;自己开始在新项目中使用 Vue3 进行开发&#xff0c;相比较于 Vue2 来说&#xff0c;最大的变化就是 composition Api 代替了之前的 options Api&#xff0c;更像是 React Hooks 函数式组件的编程方式。 Vue3相对于Vue2响应式原理也发生了变化…

vue日期组件el-date-picker中更改默认日期格式并且实时显示的方法

在项目中有一个需求是这样的,要求实时显示他的当前默认时间,并且不能修改 使用了默认:default-value"currentTime"属性之后,新增的时候会报错,前端与后端传递的数据不匹配 因为默认时间被new date() 解析之后返回的数据是默认时间形式的,格式不符 方法如下: 第一步&a…

Elasticsearch入门 - Mac上Elasticsearch和Kibana的安装运行与简单使用

文章目录一&#xff0c;Mac上Elasticsearch和Kibana的安装1.1 环境与下载1.2 安装与运行1.3 问题1.3.1 elasticsearch安装后其他机器不能访问1.3.2 kibana安装后其他机器不能访问二&#xff0c;Elasticsearch在Kibana的常见命令2.1 查看集群的健康状态2.2 索引2.2.1 查看所有索…