🚩write in front🚩
🔎大家好,我是謓泽,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎
🏅2021年度博客之星物联网与嵌入式开发TOP5~2021博客之星Top100~阿里云专家博主 & 星级博主~掘金⇿InfoQ~51CTO创作者[新人榜No.7]~周榜257﹣总榜931⇿全网访问量40w+🏅
🆔本文由 謓泽 原创 CSDN首发🙉如需转载还请通知⚠📺创作时间 ↔ 2021年3月18日◬
📝个人主页-謓泽的博客_CSDN博客 📃
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏-YY_謓泽的博客-CSDN博客🎓
✉️我们并非登上我们所选择的舞台,演出并非我们所选择的剧本📩
目录
🚩write in front🚩
概述
增添の功能
Save_Contact() → 保存通讯录信息
读文件操作
模块化代码实现
Ⅰ→ test.c
Ⅱ→address_book.h
Ⅲ→address_book.c
✨最后✨
概述
这个是在之前的动态版本进行添加,如果你不清楚通讯录的静态或者是动态怎么实现。可以看看博主写的前面两篇通讯录的静态和动态的实现↓
🍖链接→🍖【C语言】通讯录《静态内存版本》_謓泽的博客-CSDN博客
🍗链接→🍗【C语言】通讯录《动态内存版本》_謓泽的博客-CSDN博客
增添の功能
相比之前的静态版本还是动态版本。这个信息写到文件版本,无疑是更加完善的。如果你不会文件操作的话,可以看看我前面写过的内存的一篇博客来看看⇣
✨链接→【C语言】内存函数_謓泽的博客-CSDN博客
增添の功能↓
(1)→当通讯录退出的时候,把信息写到文件里面。
(2)→当通讯录初始化的时候,加载文件的信息到通讯录当中去。
在上述的博客当中我们是↓
Destory_Contact(&con);//销毁通讯录
而在这篇博客我们实现的是首先要保存通讯录,也就是保存信息到文件去。那么我们创建一个函数实现保存信息到文件里。
Save_Contact(&con);//保存信息到文件
Save_Contact() → 保存通讯录信息
那么首先我们要实现这个保存通讯录信息到文件的这个函数。
Save_Contact() 代码示例如下↓
//读写信息到文件
void Save_Contact(Contact* pc)
{
FILE* pf = fopen("information.txt","w");
//返回值判断
if (pf == NULL)
{
perror("Save_Contact:");
return;
}
//写文件
int i = 0;
for (i = 0; i < pc->sz; i++)
{
//数组名+i就是数组名下标元素的地址。
fwrite(pc->date + i, sizeof(information), 1, pf);
}
//关闭文件
fclose(pf);
pf = NULL;
}
那么现在我们就可以试一下,那我们就把张三同学的通讯录信息写下。
张三:?????????????,算了为了张三同学的隐私我们就不这样了(o゚v゚)ノ
直接简单一点打印输入数字①来康康吧。
从上述的截屏当中可以知道我们是写入进去东西的。
读文件操作
现在我们保存文件是没有任何的问题了,但是当我们再次运行通讯录的时候。通讯录依然会什么都会没有。所以,此时我们就需要进行读文件的一个操作。
我们在初始化的时候就可以进行读文件的一个操作了,因为在此之前已经有增删查改了。
那我们封装一个函数用read_file()来进行实现。
void read_file(Contact* pc) { FILE* pf = fopen("information.txt", "r"); //返回值判断 if (pf == NULL) { perror("read_file"); return; } //读文件 information tmp = {0};//问题:读文件停止(不知道你写入几个信息)?返回值的问题实际count while (fread(&tmp, sizeof(information), 1, pf))//读不到返回0 { //是否增容 Cap_inc(pc); //存放增容元素 pc->date[pc->sz] = tmp; //加载信息 pc->sz++; } //关闭文件 fclose(pf); pf = NULL; }
让我们来看看是否能进行一个读文件的操作。检测是非常简单的,我们先输入一个张三,再退出程序。然后,再输入一个李四。看看能不能读写上次张三的信息。
输入界面数字:6 即可(o゚v゚)ノ
第一次的输入!
上述的读写操作是成功的。
第二次的输入!
从这里我们可以知道它保存了我们上述的读写的值,也就是读文件的操作我们是成功的了。
模块化代码实现
Ⅰ→ test.c
代码示例如下↓
/* @Note1:当通讯录退出的时候,把信息写道文件。 @Note2:当通讯录初始化的时候,加载文件的信息。 */ #define _CRT_SECURE_NO_WARNINGS 1 #include"a.h" #include<Windows.h> #pragma warning(disable:6031) //颜色函数 void color(short x) { if (x >= 0 && x <= 15) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x); else SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7); } //创建菜单函数 void menu() { color(0);//黑色 system("cls");//清屏 color(12);//白色 printf("¤--------------------------------------------¤\n"); printf("|■■■■■■■■→通讯录v1.0←■■■■■■■■|\n"); printf("|———————————————————————|\n"); printf("|★★★★★→1.increase ■ 2.deLete←★★★★★|\n"); printf("|★★★★★→3.find ■ 4.Revise←★★★★★|\n"); printf("|★★★★★→5.Check ■ 6.Print ←★★★★★|\n"); printf("|★★★★★→0.Exit ■ ←★★★★★|\n"); printf("|———————————————————————|\n"); printf("|■■■■■■■■→通讯录v1.0←■■■■■■■■|\n"); printf("¤--------------------------------------------¤\n"); } enum Number { Exit, Increase, DeLete, Find, Revise, Check, Print, }; int main(void) { menu(); int input = 0; //当然初始化全0:Contact con = {0};也是可以的,当然我们这里的初始化不是这样的原因是可以应对比较复杂的问题。 Contact con;//初始化通讯录 //给date申请一块连续的内存空间存放在堆区上。 InitContact(&con); do { color(5); printf("¤----------------¤\n"); printf("|请输入界面上的数字|:"); scanf("%d", &input); printf("¤----------------¤\n"); color(1); switch (input) { case Exit: //销毁之前先保存。 Save_Contact(&con); //把通讯录里面的内存空间date给释放掉。 Destory_Contact(&con);//销毁通讯录。 printf("══════════════@\n"); printf("退出通讯录v1.0@\n"); printf("══════════════@\n"); break; case Increase: //增加人的信息,放在通讯录当中去。 Add_Contact(&con); break; case DeLete: //删除通讯人的信息 DeLete_Contact(&con); break; case Find: //查找指定通讯录人的信息 Find_Contact(&con); break; case Revise: //修改指定通讯录人的信息 Revise_Contact(&con); break; case Check: //排查通讯录当中人员的信息 Check_Contact(&con); break; case Print: //打印通讯录当中人员的信息。 Print_Contact(&con); break; default:printf("你输入的数字找不到,请重新输入~\n"); } } while (input); return 0; }
Ⅱ→address_book.h
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #include<Windows.h> #include<string.h> #define Max_name 5 #define Max_age 100 #define Max_genger 3 #define Max_address 20 #define Max_telephone 20 //#define num 1000 //静态的存放 #define Defsz 3 //一开始的值 #define Inc 2 //每次的增量 //类型的定义 typedef struct information { //名字、年龄、性别、电话、地址。 char name[Max_name]; char age[Max_age]; char genger[Max_genger]; char telephone[Max_telephone]; char address[Max_address]; }information; //通讯录 - 动态版本 typedef struct Contact { //这里用了个结构体嵌套 information* date;//指向动态内存的申请空间,用于存放联系人的信息。 int sz;//记录当前通讯录有效信息的个数。 int capacity;//表示当前通讯录的最大"容量"大小。 }Contact; //初始化通讯录 void InitContact(Contact* pc); //增加通讯录信息 void Add_Contact(Contact* pc); //打印通讯录的信息 void Print_Contact(const Contact* pc); //删除通讯人的信息 void DeLete_Contact(Contact* pc); //查找指定通讯录人的信息 void Find_Contact(Contact* pc); //修改指定通讯录人的信息 void Revise_Contact(Contact* pc); //排查通讯录当中人员的信息 void Check_Contact(Contact* pc); //销毁通讯录 void Destory_Contact(Contact* pc); //保存通讯录信息到文件 void Save_Contact(Contact* pc); //读文件-加载文件 void read_file(Contact* pc); //检测增容 void Cap_inc(Contact* pc);
Ⅲ→address_book.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"address_book.h" //读文件-加载文件 void read_file(Contact* pc) { FILE* pf = fopen("information.txt", "r"); //返回值判断 if (pf == NULL) { perror("read_file"); return; } //读文件 information tmp = {0};//问题:读文件停止(不知道你写入几个信息)?返回值的问题实际count while (fread(&tmp, sizeof(information), 1, pf))//读不到返回0 { //是否增容 Cap_inc(pc); //存放增容元素 pc->date[pc->sz] = tmp; //加载信息 pc->sz++; } //关闭文件 fclose(pf); pf = NULL; } //动态版本进行初始化 void InitContact(Contact* pc) { pc->date = (information*)malloc(Defsz * sizeof(information)); if (pc->date == NULL) { perror("InitContact"); return; } //如果返回的为空指针的情况 pc->sz = 0;//sz初始化 pc->capacity = Defsz;//当前最大"容量" //读文件-加载文件 read_file(pc); } //增容函数 void Cap_inc(Contact* pc) { //当记录当前通讯录有效信息的个数 等于 表示当前通讯录的最大"容量"大小。 if (pc->sz == pc->capacity) { //给堆区增加"容量",因为空间不够。 information* pa = (information*)realloc(pc->date, (pc->capacity + Inc)*(sizeof(information))); if (pa != NULL) { pc->date = pa;//把这块空间移交到date进行维护 pc->capacity = pc->capacity + Inc;//由于这里我们进行了增容也需要把容量改变成+Inc的值 printf("增加联系人已成功(@^0^)\n"); } //增容失败 else { perror("Add_Contact:"); printf("增加联系人失败!(ToT)/~~~\n"); return; } } } //动态版本增加 void Add_Contact(Contact* pc) { //检测容量 Cap_inc(pc); //增加一个人的信息 printf("\n"); printf("请输入增加人的名字->:"); scanf("%s", pc->date[pc->sz].name);//注意→数组名是首元素地址,所以不用进行取地址. printf("请输入增加人的年龄->:"); scanf("%s", pc->date[pc->sz].age); printf("请输入增加人的性别->:"); scanf("%s", pc->date[pc->sz].genger); printf("请输入增加人的电话->:"); scanf("%s", pc->date[pc->sz].telephone); printf("请输入增加人的地址->:"); scanf("%s", pc->date[pc->sz].address); //成功~ pc->sz++; printf("★恭喜你~添加信息成功★\n"); printf("\n"); } //读写信息到文件 void Save_Contact(Contact* pc) { FILE* pf = fopen("information.txt","w"); //返回值判断 if (pf == NULL) { perror("Save_Contact:"); return; } //写文件 int i = 0; for (i = 0; i < pc->sz; i++) { //数组名+i就是数组名下标元素的地址。 fwrite(pc->date + i, sizeof(information), 1, pf); } //关闭文件 fclose(pf); pf = NULL; } void Print_Contact(const Contact* pc) { int i = 0; //打印标题栏的信息 printf("|-------------------------------------------------------|\n"); printf("|%-3s\t%-3s\t%-3s\t%-11s\t%-10s\t|\n", "名字", "年龄", "性别", "电话", "地址"); for (i = 0; i < pc->sz; i++) { printf("|%-3s\t%-3s\t%-3s\t%-11s\t%-10s\t|\n", pc->date[i].name, pc->date[i].age, pc->date[i].genger, pc->date[i].telephone, pc->date[i].address); } } static int FindByname(Contact* pc, char name[]) { int i = 0; //用for循环进行遍历 for (i = 0; i < pc->sz; i++) { //strcmp()比较字符串 if (strcmp(pc->date[i].name, name) == 0) { return i;//返回下标 } } return -1; } void DeLete_Contact(Contact* pc) { char name[Max_name] = { 0 }; //通讯录为空的时候 if (pc->sz == 0) { printf("通讯录当中没有任何信息\n"); return; } printf("请输入你要删除的名字->:"); scanf("%s", name); //查找要删除的人:有/没有 int ret = FindByname(pc, name); if (ret == -1) { printf("没有查找到当前人的信息\n"); return; } //删除 int i = 0; for (i = ret; i < pc->sz - 1; i++) { pc->date[i] = pc->date[i + 1]; } pc->sz--;//因为我们删除成功下标要减1 printf("★恭喜你~删除信息成功★\n"); printf("\n"); } void Find_Contact(Contact* pc) { char name[Max_name] = { 0 }; printf("请输入你要查找的名字->:"); scanf("%s", name); int ret = FindByname(pc, name); if (ret == -1) { printf("没有查找到当前人的名字\n"); return; } else { printf("|-------------------------------------------------------|\n"); printf("|%-3s\t%-3s\t%-3s\t%-11s\t%-10s\t|\n", "名字", "年龄", "性别", "电话", "地址"); printf("|%-3s\t%-3s\t%-3s\t%-11s\t%-10s\t|\n", pc->date[ret].name, pc->date[ret].age, pc->date[ret].genger, pc->date[ret].telephone, pc->date[ret].address); printf("查找%sの信息成功~\n", pc->date[ret].name); } } void Revise_Contact(Contact* pc) { char name[Max_name] = { 0 }; printf("请输入你要修改通讯录人的名字->:"); scanf("%s", name); int ret = FindByname(pc, name); if (ret == -1) { printf("当前修改人的信息不存在\n"); return; } else { printf("请输入修改人的名字->:"); scanf("%s", pc->date[ret].name);//注意→数组名是首元素地址,所以不用进行取地址. printf("请输入修改人的年龄->:"); scanf("%s", pc->date[ret].age); printf("请输入修改人的性别->:"); scanf("%s", pc->date[ret].genger); printf("请输入修改人的电话->:"); scanf("%s", pc->date[ret].telephone); printf("请输入修改人的地址->:"); scanf("%s", pc->date[ret].address); printf("恭喜你,修改成功~\n"); } } int sort_name_max(const void* e1, const void* e2) { return (strcmp(((struct Contact*)e1)->date->name, ((struct Contact*)e2)->date->name)); } void Check_Contact(Contact* pc) { //qosrt()函数首字母进行排序 qsort(pc->date, pc->sz, sizeof(pc->date[0]), sort_name_max); printf("|-------------------------------------------------------|\n"); printf("|%-3s\t%-3s\t%-3s\t%-11s\t%-10s\t|\n", "名字", "年龄", "性别", "电话", "地址"); int i = 0; for (i = 0; i < pc->sz; i++) { printf("|%-3s\t%-3s\t%-3s\t%-11s\t%-10s\t|\n", pc->date[i].name, pc->date[i].age, pc->date[i].genger, pc->date[i].telephone, pc->date[i].address); } } void Destory_Contact(Contact* pc) { //销毁通讯录实际上就是把date给释放掉,free()函数进行回收即可。 free(pc -> date); pc->date = NULL; pc->sz = 0; pc->capacity = 0; //记得清0☆⌒(*^-゜)v THX!! }
✨最后✨
那么这个就已经实现了通讯录的最终版本了,这个项目适合已经把C语言学完的人做。巩固自己以往的能力,做个这个提升自己逻辑思维和代码能力的一个小的项目。