C语言小程序:通讯录(文件版)

article/2025/9/3 17:37:36

在静态版本的通讯录里面实现了通讯录的基本逻辑,但是空间大小是固定的,这样子就会显得很不灵活,会有浪费空间和空间不足的问题,所以在动态版本的通讯里面我们通过动态内存开辟使用malloc函数给通讯录动态的开辟一块空间,如果空间不够就使用realloc函数来扩容,这样子就实现了动态化的通讯录,解决了浪费空间和空间不足的问题,但是以上两个版本的通讯录在程序运行起来之后,将联系人的信息存起来之后,退出程序之后再次进入程序之前保存的联系人的信息就不见了,那么就可以在动态版本的基础上将其改变为文件版本,之前的通讯录的信息存放在一个文件中,下次进入程序的时候可以打开这个文件,获得联系人的信息,那么文件版本就实现了通讯录的动态大小以及联系人的永久储存。

通讯录(静态版)

通讯录(动态版)

目录

 1.保存数据

 2.读取文件

3.完整代码


 

 1.保存数据

 在第一次进入通讯录,添加联系人的信息之后,我们需要在退出通讯录的时候将联系人的信息保存在一个文件里面,以便下一次再进入通讯录的时候进行读取,所以应该在退出通讯录的前面再分装一个函数用来保存联系人的信息。

那这个保存练习人的函数该怎么实现呢?我们需要进行创建文件,然后以二进制的方式进行写文件,需要用到有关文件操作的函数 

源文件:test.c

case EXIT://保存信息SaveContact(&con);//释放通讯录的空间DestroyContact(&con);printf("退出通讯录!\n");break;

 头文件:Contact.h

//保存联系人的信息到文件中
void SaveContact(Contact* pc);

 源文件:Contact.c

//保存联系人的信息
void SaveContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("SaveContact::fopen");return;}//保存信息int i = 0;for (i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(struct PeoInfo), 1, pf);}//关闭文件fclose(pf);pf = NULL;printf("保存成功...\n");
}

 如果程序运行起来之后,添加了几个联系人然后退出程序,这时联系人的信息已经保存到了contact.txt这个文本文件中,如果我们找到这个文件打开它发现里面的东西大部分都不认识,这是因为我们在保存的时候是以二进制的方式进行保存,但是这个文件是一个文本文件,所以就和我们看到的不一样:

 2.读取文件

保存好了文件之后,在下一次进入通讯录的时候就需要打开这个文件,先读取以前保存的联系人的信息,所以就需要在初始化通讯录的部分再分装一个函数来进行读取通讯录

那要怎么读取呢?打开文件的时候需要以二进制读的方式打开,然后读取文件的时候先要判断联系人的个数,然后在此基础上判断是否需要进行对通讯录的扩容,然后再进行读取联系人的数据

源文件:Contact.c

//读取文件
int CheckCapacity(Contact* pc); //对扩容函数进行声明,以方便下面的使用
void LoadContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("LoadContact::fopen");return;}//读取联系人的信息//fread函数的返回值是size_t的整形,所以当读不到数据的时候返回0//因此就可以使用fread函数的返回值作为循环条件来读取数据////创建一个变量将读取到的联系人的信息放在里面,然后再将它放进通讯录里面PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pf)){//因为不知道能读取多少个联系人的信息,所以先要进行容量的判断CheckCapacity(pc);//将读取到的联系人的信息传到通讯录里面pc->data[pc->sz] = tmp;pc->sz++;}//关闭文件fclose(pf);pf = NULL;}//初始化通讯录
void InitContact(Contact* pc)
{pc->data = (PeoInfo*)malloc(DEFUAULT_SZ * sizeof(PeoInfo));if (pc->data == NULL){printf("通讯录初始化失败:%s\n", strerror(errno));return;}pc->sz = 0;pc->capacity = DEFUAULT_SZ;//读取联系人的信息LoadContact(pc);
}int CheckCapacity(Contact* pc)
{//如果满容量了,那就需要扩充PeoInfo的容量了if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr == NULL){printf("CheckCapacity:%s\n", strerror(errno));return 0;}else{pc->data = ptr;  //将扩容之后的地址传给datapc->capacity += INC_SZ;  //给容量加2printf("增容成功,当前容量:%d\n", pc->capacity);return 1;}}return 1;
}

头文件:Contact.h

//读取联系人信息
void LoadContact(Contact* pc);

3.完整代码

源文件:test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "Contact.h"//测试通讯录相关的功能void menu()
{printf("**************************************\n");printf("****  1.Add     *****    2.Del    ****\n");printf("****  3.Search  *****    4.Modify ****\n");printf("****  5.Show    *****    6.Sqrt   ****\n");printf("****  7.Clear   *****    0.Exit   ****\n");printf("**************************************\n");
}enum Option
{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SQRT,CLEAR
};int main()
{int input = 0;Contact con;   //创建通讯录变量//初始化通讯录InitContact(&con);  //要修改通讯录里面的内容要传递指针do{menu();printf("请选择通讯录的功能:>");scanf("%d", &input);switch (input){case ADD://添加联系人printf("添加联系人\n");AddContact(&con); //传址调用break;case DEL://删除联系人printf("删除联系人\n");DelContact(&con);break;case SEARCH://查找联系人printf("查找联系人\n");SearchContact(&con);break;case MODIFY://修改联系人printf("修改联系人\n");ModifyContact(&con);break;case SHOW://展示ShowContact(&con);//显示通讯录不需要修改通讯录其实传值调用也可以,但是为了节省空间使用传值调用break;case SQRT://排序联系人SqrtContact(&con);break;case CLEAR://清空联系人aClearContact(&con);break;case EXIT://保存信息SaveContact(&con);//释放通讯录的空间DestroyContact(&con);printf("退出通讯录!\n");break;default:printf("选择错误,请重新选择:>\n");break;}} while (input);return 0;
}

头文件:Contact.h

#pragma once//头文件的包含#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>//大小的定义
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 20
#define DEFUAULT_SZ 5
#define INC_SZ 3//表示一个联系人的各种信息
typedef struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
}PeoInfo;//通讯录
typedef struct Contact
{PeoInfo* data;   //用来存放联系人的信息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 ModifyContact(Contact* pc);//排序联系人
void SqrtContact(Contact* pc);//清空联系人
void ClearContact(Contact* pc);//释放内存
void DestroyContact(Contact* pc);//保存联系人的信息到文件中
void SaveContact(Contact* pc);//读取联系人信息
void LoadContact(Contact* pc);

源文件:Contact.c

#define _CRT_SECURE_NO_WARNINGS 1#include "Contact.h"
//通讯录的实现模块//读取文件
int CheckCapacity(Contact* pc); //对扩容函数进行声明,以方便下面的使用
void LoadContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("LoadContact::fopen");return;}//读取联系人的信息//fread函数的返回值是size_t的整形,所以当读不到数据的时候返回0//因此就可以使用fread函数的返回值作为循环条件来读取数据////创建一个变量将读取到的联系人的信息放在里面,然后再将它放进通讯录里面PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pf)){//因为不知道能读取多少个联系人的信息,所以先要进行容量的判断CheckCapacity(pc);//将读取到的联系人的信息传到通讯录里面pc->data[pc->sz] = tmp;pc->sz++;}//关闭文件fclose(pf);pf = NULL;}//初始化通讯录
void InitContact(Contact* pc)
{pc->data = (PeoInfo*)malloc(DEFUAULT_SZ * sizeof(PeoInfo));if (pc->data == NULL){printf("通讯录初始化失败:%s\n", strerror(errno));return;}pc->sz = 0;pc->capacity = DEFUAULT_SZ;//读取联系人的信息LoadContact(pc);
}int CheckCapacity(Contact* pc)
{//如果满容量了,那就需要扩充PeoInfo的容量了if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr == NULL){printf("CheckCapacity:%s\n", strerror(errno));return 0;}else{pc->data = ptr;  //将扩容之后的地址传给datapc->capacity += INC_SZ;  //给容量加2printf("增容成功,当前容量:%d\n", pc->capacity);return 1;}}return 1;
}
//添加联系人
void AddContact(Contact* pc)
{//判断通讯录是否满容量if (0 == CheckCapacity(pc)){printf("空间不够,扩容失败\n");return;}else{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].tele);printf("请输入地址:>");scanf("%s", pc->data[pc->sz].addr);pc->sz++;   //每一次添加完之后sz都要++printf("添加成功\n");}
}//显示通讯录
void ShowContact(const Contact* pc)
{printf("%-10s %-4s %-5s %-12s %-15s\n", "名字", "年龄", "性别", "电话", "地址");int i = 0;for (i = 0; i < pc->sz; i++){printf("%-10s %-4d %-5s %-12s %-15s\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}
}//查找
static int FindByName(const Contact* pc, char name[])
{int i = 0;int pos = 0;for (i = 0; i < pc->sz; i++){//找到所要联系人所在的位置if (0 == strcmp(pc->data[i].name, name)){return i;}}return -1;
}
//删除联系人
void DelContact(Contact* pc)
{char name[MAX_NAME] = { 0 };//判断通讯录是否为空if (0 == pc->sz){printf("通讯录为空,无法删除!\n");return;}printf("请输入你要删除联系人的姓名:>");scanf("%s", name);int pos = FindByName(pc, name);int i = 0;if (pos == -1){printf("找不到所要删除的联系人\n");return;}//进行删除for (i = pos; i < pc->sz - 1; i++) //判断条件这里所要交换的比总数少一个{pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}//查找联系人
void SearchContact(const Contact* pc)
{char name[MAX_NAME] = { 0 };if (pc->sz == 0){printf("通讯录为空,查找不到!");return;}printf("请输入你要查找联系人的姓名:>");scanf("%s", name);int pos = FindByName(pc, name);int i = 0;if (pos == -1){printf("找不到所要查找的联系人\n");return;}//打印导航栏printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");//打印数据printf("%-10s %-4d %-5s %-12s %-30s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);
}//修改联系人
void menu1()
{printf("*********************************\n");printf("******1.姓名*********2.年龄*******\n");printf("******3.性别*********4.电话*******\n");printf("*************5.地址**************\n");printf("*********************************\n");
}
void ModifyContact(Contact* pc)
{int input = 0;char name[MAX_NAME] = { 0 };printf("请输入你要修改的联系人姓名:>");scanf("%s", name);//查找int pos = FindByName(pc, name);int i = 0;if (pos == -1){printf("找不到所要查找的联系人\n");return;}//修改printf("请输入要修改的具体信息:>\n");menu1();scanf("%d", &input);switch (input){case 1:printf("请输入新的姓名:>");scanf("%s", pc->data[pos].name);break;case 2:printf("请输入新的年龄:>");scanf("%d", &pc->data[pos].age);break;case 3:printf("请输入新的性别:>");scanf("%s", pc->data[pos].sex);break;case 4:printf("请输入新的电话:>");scanf("%s", pc->data[pos].tele);break;case 5:printf("请输入新的地址:>");scanf("%s", pc->data[pos].addr);break;default:printf("输入有误,修改失败\n");return;}printf("修改成功\n");
}void menu2()
{printf("***************************\n");printf("******** 1.NAME  **********\n");printf("******** 2.AGE   **********\n");printf("***************************\n");
}//按照名字排序
int cmp_byname(const void* p1, const void* p2)
{return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}//按照年龄来排序
int cmp_byage(const void* p1, const void* p2)
{return ((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age;
}//排序联系人
void SqrtContact(Contact* pc)
{int input = 0;if (pc->sz == 0){printf("通讯录没有联系人,无法排序!\n");return;}menu2();printf("请选择排序的对象:>");scanf("%d", &input);switch (input){case 1:qsort(pc, pc->sz, sizeof(PeoInfo), cmp_byname);break;case 2:qsort(pc, pc->sz, sizeof(PeoInfo), cmp_byage);break;}printf("排序成功\n");//排序成功之后打印一下ShowContact(pc);
}//清空联系人
void ClearContact(Contact* pc)
{//初始化通讯录InitContact(pc);printf("清空成功\n");//初始完之后再打印ShowContact(pc);
}//释放通讯录
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;printf("释放内存....\n");
}//保存联系人的信息
void SaveContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("SaveContact::fopen");return;}//保存信息int i = 0;for (i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(struct PeoInfo), 1, pf);}//关闭文件fclose(pf);pf = NULL;printf("保存成功...\n");
}

关于文件版本的通讯录就分享到这里,感谢大家的阅览!


http://chatgpt.dhexx.cn/article/uWX7NjvM.shtml

相关文章

C语言有趣的小程序

最近闲着没事写了一个C语言小程序,就当作是玩玩。 本小程序的各个功能都是通过dos命令来实现的。 运行结果如下图: 该小程序有以下几个功能: 1、启动计算器 2、新建记事本 3、打开画图板 4、定时关机(15s、30s、60s) 5、显示系统时间或修改 6、重启计算机 小程序源代码…

C语言小程序:通讯录(静态版)

哈喽各位老铁们&#xff0c;今天给大家带来一期通讯录的静态版本的实现&#xff0c;何为静态版本后面会做解释&#xff0c;话不多说&#xff0c;直接开始&#xff01; 关于通讯录&#xff0c;其实也就是类似于我们手机上的通讯录一样&#xff0c;有着各种各样的功能&#xff0c…

C语言小程序分享

本文为大一时所写的文章&#xff08;2017/4/23&#xff09;&#xff0c;文笔还很生疏&#xff0c;在很多问题上认识不深&#xff0c;算是在学校的微信公众号上的一个编程探究模块上的投稿&#xff0c;本人当时也参与了本模块的维护和管理。补档。 上个周末的一个下午&#xff0…

C语言小程序-学生成绩统计系统

C语言小程序-学生成绩统计系统 参考了 另一位博主的代码(https://blog.csdn.net/qq_36503589/article/details/53106983) 我后来写的成绩排序版本链接&#xff1a;https://blog.csdn.net/qq_43617268/article/details/103491760 功能介绍&#xff1a;本程序可以输入50人以内的…

C语言10个经典小程序——小白必备!

网上有很多的人说编程有多么多么无聊。。。。So Boring ! 。。。其实小编想说:不要管别人怎么说,别人说什么,做你自己喜欢做的事就好。坚持下来,你会发现编程的乐趣的。。。。当然,如果你觉得学习编程语言很痛苦,坚持了一段时间后无果,南无果断放弃未必不是一个好的选择…

C语言小程序:如何用代码“画”出一个爱心

利用ASCII编码第三个字符&#xff0c;作为基础&#xff0c;然后利用三个多重循环画出一个爱心出来。要使用控制台改变运行框大小和文字的颜色&#xff0c;黑白的爱心不免有些诡异。 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <math.h> #inclu…

我的第一个c语言小程序

标题&#xff1a;判断题答题小程序 Author: plc6666 软工专业 工科男 格言&#xff1a;总有人间一两风&#xff0c;填我十万八千梦。 文章目录 标题&#xff1a;判断题答题小程序 一.程序的由来二.程序的状况1.程序实现了颜色转换的功能2.程序能随机抽20题&#xff0c;不重复3.…

C语言10个经典小程序

【程序1】 题目&#xff1a;有1、2、3、4个数字&#xff0c;能组成多少个互不相同且无重复数字的三位数&#xff1f;都是多少&#xff1f; 1.程序分析&#xff1a;可填在百位、十位、个位的数字都是1、2、3、4。组成所有的排列后再去       掉不满足条件的排列。 2.程序源…

用 C语言的写出几个小程序

系列文章目录 前言 1、第一章&#xff1a;求出一个整型数组中的最大值 2、第二章&#xff1a;打印出100~999之间所有的水仙花数 3、第三章&#xff1a;输入一个数&#xff0c;打印出n行杨辉三角 4、第四章&#xff1a;小只因跳楼梯问题 5、第五章&#xff1a;创建一个含是…

C语言小程序

1、猜数字游戏 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <time.h>//猜数字游戏 int main() {int guess 0;//生成随机数//0~99 --> 1~100int ret rand() % 100 1;//生成随机数的函数printf("请猜数字 …

服务器登录原理,单点登陆(单点登录原理)

单点登录简介 SSO&CAS是什么 单点登录适合什么场景 单点登录的三种实现方式 CAS的几个重要知识点 CAS的实现过程 单点登录简介 单点登录(SingleSignOn&#xff0c;SSO)&#xff0c;就是通过用户的一次性鉴别登录。当用户在身份认证服务器上登录一次以后&#xff0c;即可获得…

单点登陆 SSO

参考文章 同域下的单点登录 &#xff08;sso.a.com、app1.a.com、app2.a.com&#xff09; 统一通过sso.a.com 登录&#xff0c;但有以下两个问题&#xff1a; 1、Cookie是不能跨域的&#xff0c;我们Cookie的domain属性是sso.a.com&#xff0c;在给app1.a.com和app2.a.com发送…

五、微服务版单点登陆系统(SSO)

微服务版单点登陆系统(SSO)实践 文章目录 微服务版单点登陆系统(SSO)实践一、单点登陆系统简介1. 背景分析2. 单点登陆系统概述3. 单点登陆系统解决方案设计 二、单点登陆系统初步设计1. 服务设计2. 工程结构设计 三、系统基础服务工程设计及实现1. 业务描述2. 表结构设计3. 工…

单点登陆(SSO)

一、背景 在企业发展初期&#xff0c;企业使用的系统很少&#xff0c;通常一个或者两个&#xff0c;每个系统都有自己的登录模块&#xff0c;运营人员每天用自己的账号登录&#xff0c;很方便。但随着企业的发展&#xff0c;用到的系统随之增多&#xff0c;运营人员在操作不同的…

08单点登陆+Oauth2

详情&#xff1a;如看不懂跳转此地 1.1单点登录系统 每个站点都实现了专用登录模块。各站点的登录状态相互不认可&#xff0c;各站点需要逐一手工登录 这样的系统&#xff0c;我们又称之为多点登陆系统。应用起来相对繁琐&#xff08;每次访问资源服务都需要重新登录认证和授…

微服务版单点登陆系统(SSO)

单体架构中的用户的状态的存储是如何实现的? 单点登陆系统概述 单点登录&#xff0c;英文是 Single Sign On&#xff08;缩写为 SSO&#xff09;。即多个站点共用一台认证授权服务器&#xff0c;用户在其中任何一个站点登录后&#xff0c;可以免登录访问其他所有站点。而且&a…

SpringBoot跨系统单点登陆的实现

什么是单点登陆 单点登录&#xff08;英语&#xff1a;Single sign-on&#xff0c;缩写为 SSO&#xff09;&#xff0c;又译为单一签入&#xff0c;一种对于许多相互关连&#xff0c;但是又是各自独立的软件系统&#xff0c;提供访问控制的属性。当拥有这项属性时&#xff0c;…

单点登陆的实现

王昱 yuwang881gmail.com 博客地址 http://yuwang881.blog.sohu.com 摘要 &#xff1a;单点登录&#xff08; SSO &#xff09;的技术被越来越广泛地运用到各个领域的软件系统当中。本文从业务的角度分析了单点登录的需求和应用领域&#xff1b;从技术本身的角度分析了单点…

CAS 单点登陆

一、Tomcat配置SSL 1. 生成 server key 以命令方式换到目录%TOMCAT_HOME%,在command命令行输入如下命令&#xff1a; keytool -genkey -alias tomcat_key -keyalg RSA -storepass changeit -keystore server.keystore -validity 3600 用户名输入域名&#xff0c;如localhos…

单点登陆的测试

今天做了个单点登陆 。 但是怎么测试呢&#xff1f; 下面请看详解&#xff1a; 源码中是这样的&#xff1a; /*** 单点登录改造* * param request* param response* return* throws IOException* throws HttpException* throws IOException*/RequestMapping(value "/rcbS…