文件操作的内容,我们在上文已经学习了,那么如果有不明白的小伙伴请看这篇文章
【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兔年新年快乐!!!