C语言建立txt版通讯录(柔性数组,动态内存,文件读取)

txt中包含了标题行和序号这些不需要录入结构体的内容,搞得函数很复杂,仔细考虑完善了一些异常情况,很多地方加了注释,代码有些繁杂没时间去进一步优化缩减,在输入读取中文时遇到问题,调试了半天终于发现是因为isspace这个函数,看来以后要少用这个函数,先这样吧,等以后学数据结构会有更好的通讯录。

Contact_txt.h 头文件

#ifndef __Contact_txt_H__
#define __Contact_txt_H__
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#include<errno.h>#define PATH_FILE "Contact_txt.txt"
#define NUM_MEM_INI 10
#define NUM_MEM_ALT 5
#define MAX_NAME 20+1
#define MAX_TELEPHONE 11+1
#define MAX_ADDRESS 40+1enum Choice{quit,add,modify,show,Delete,clear};typedef struct contact{char name[MAX_NAME];char telephone[MAX_TELEPHONE];char address[MAX_ADDRESS];
}Contact;typedef struct contacts{int sz_now;int sz_max;Contact members[];
}Contacts;char *my_fgets(char *p,int n,FILE *fp);
int menu(void);
void InitializeContact(Contacts **p);
void CheckContact(Contacts *p);
int RecordRow(Contacts *p,FILE *fp);
void LoadFile(Contacts *p,FILE *fp);
void SaveFile(Contacts *p,FILE *fp);
int SearchContact(const Contacts *p,const char *target);
void AddContact(Contacts *p);
void ModifyContact(Contacts *p);
void ShowContact(const Contacts *p);
void DeleteContact(Contacts *p);
void ClearContact(Contacts *p);#endif

Contact_txt_function.cpp

#include "Contact_txt.h"char *my_fgets(char *p,int n,FILE *fp){char *gets,*find;if((gets=fgets(p,n,stdin))&&*gets!=10)if(find=strchr(gets,10))*find=0;elsewhile(getchar()!=10);elsereturn 0;
return gets;}int menu(void){char choice_menu[]="\nAMSDC";int choice=0;char *position=NULL;fputs("***************Menu***************\n",stdout);fputs("   A)add   M)modify   S)show\n",stdout);fputs("   D)delete  C)clear  Enter)quit\n",stdout);fputs("**********************************\n",stdout);while(fputs("Your choice:->",stdout),!(position=strchr(choice_menu,toupper(choice=fgetc(stdin)))))while(getchar()!=10);if(choice!=10)//如果不退出就清除缓存while(getchar()!=10);
return (position-choice_menu);}void InitializeContact(Contacts **p){//初始化Contactsif(!(*p=(Contacts *)malloc(sizeof(Contacts)+NUM_MEM_INI*sizeof(Contact)))){printf("%s\n",strerror(errno));exit(1);}(*p)->sz_now=0;(*p)->sz_max=NUM_MEM_INI;
}void CheckContact(Contacts *p){//检测Contacts,增减动态内存if((p->sz_now>=p->sz_max)||(p->sz_max-p->sz_now>NUM_MEM_ALT)){Contacts *ptemp=(Contacts *)realloc(p,sizeof(Contacts)+(p->sz_now+NUM_MEM_ALT)*sizeof(Contact));if(ptemp)p=ptemp;p->sz_max=p->sz_now+NUM_MEM_ALT;}
}int RecordRow(Contacts *p,FILE *fp){//保存fp中一行数据存入Contactschar temp_ch=0;char temp_str[MAX_ADDRESS]={0};int flag_data=0;int i_target=0;//结构体标签编码for(;temp_ch=fgetc(fp);){if(temp_ch!=32&&temp_ch!=10&&temp_ch!=EOF){//有中文千万不要用isspaceif(!flag_data){//跳过序号项while((temp_ch=fgetc(fp))!=32&&temp_ch!=10&&temp_ch!=EOF)fseek(fp,1,SEEK_CUR);flag_data=1;                  }else{//读取数据存入结构体fseek(fp,-1,SEEK_CUR);fscanf(fp,"%s",!i_target?p->members[p->sz_now].name:(i_target==1?p->members[p->sz_now].telephone:p->members[p->sz_now].address));i_target++;}}if(temp_ch==10){p->sz_now++;CheckContact(p);return 1;}if(temp_ch==EOF){p->sz_now++;CheckContact(p);return 0;}}
return 0;}void LoadFile(Contacts *p,FILE *fp){//读取fp中的数据存入Contacts结构体if(fopen_s(&fp,PATH_FILE,"r")){perror("LoadFile");fputs("Creat File 《"PATH_FILE"》 now.\n",stdout);return;}elsefputs("Open file 《"PATH_FILE"》 succeed.\n",stdout);int temp_ch=0;while((temp_ch=fgetc(fp))!=10&&temp_ch!=EOF)//跳过标题行fseek(fp,1,SEEK_CUR);for(;RecordRow(p,fp););//保存fp中每一行数据存入Contactsif(!p->sz_now)fputs("No data found.\n",stdout);elseprintf("Load %d members data.\n",p->sz_now);if(feof(fp)){//检测fp文件读取是意外终止还是成功结束if(ferror(fp))perror("ended error");//else//  fputs("ended successfully.\n",stdout);}fclose(fp);//提前退出函数时记得关闭文件,否则SaveFile时perror:permission denied
}void SaveFile(Contacts *p,FILE *fp){//将Contacts结构体的数据存入fpif(fopen_s(&fp,PATH_FILE,"w")){perror("SaveFile");exit(EXIT_FAILURE);}size_t len_name=0,len_address=0,len_index=0;for(int i=0;i<p->sz_now;i++){if((strlen(p->members[i].name))>len_name)len_name=strlen(p->members[i].name);if((strlen(p->members[i].address))>len_address)len_address=strlen(p->members[i].address); }for(int i=p->sz_now;i;i/=10,len_index++);fprintf(fp,"NO.%-*cName%-*cTelephone%-*cAddress\n",len_index-3+1,32,len_name<4?1:len_name-4+1,32,MAX_TELEPHONE-9,32,len_address-7+1);for(int i=0;i<p->sz_now;i++){fprintf(fp,"%-*d%-*s%-*s%-*s",len_index+2+1,i+1,len_name<4?4+1:len_name+1,p->members[i].name,MAX_TELEPHONE,p->members[i].telephone,len_address,p->members[i].address);if(i!=p->sz_now-1)//最后一行结尾不输入\nfputc(10,fp);}fclose(fp);
}int SearchContact(const Contacts *p,const char *target){//在Contacts结构体中查找member返回其序号for(int i=0;i<p->sz_now;i++){if(!strcmp(p->members[i].name,target))return i;}fputs("No data found.\n",stdout);
return -1;}void AddContact(Contacts *p){//增加memberprintf("NO.%d:name:->",p->sz_now+1);if(!my_fgets(p->members[p->sz_now].name,MAX_NAME,stdin))return;printf("NO.%d:telephone:->",p->sz_now+1);my_fgets(p->members[p->sz_now].telephone,MAX_TELEPHONE,stdin);printf("NO.%d:address:->",p->sz_now+1);my_fgets(p->members[p->sz_now].address,MAX_ADDRESS,stdin);p->sz_now++;
}void ModifyContact(Contacts *p){//修改memberchar target_name[MAX_NAME]={0};int target_index=-1;fputs("Input the name to modify:->",stdout);if(!my_fgets(target_name,MAX_NAME,stdin))return;if((target_index=SearchContact(p,target_name))!=-1){fputs("Input the new data\n",stdout);printf("NO.%d:name:->",target_index+1);if(!my_fgets(p->members[target_index].name,MAX_NAME,stdin)){for(int i=target_index;i<p->sz_now-1;i++)memcpy(&(p->members[i]),&(p->members[i+1]),sizeof(Contact));memset(&(p->members[p->sz_now-1]),0,sizeof(Contact));p->sz_now--;return;}           printf("NO.%d:telephone:->",target_index+1);my_fgets(p->members[target_index].telephone,MAX_TELEPHONE,stdin);printf("NO.%d:address:->",target_index+1);my_fgets(p->members[target_index].address,MAX_ADDRESS,stdin);}
}void ShowContact(const Contacts *p){//显示列表size_t len_name=0,len_address=0,len_index=0;for(int i=0;i<p->sz_now;i++){if((strlen(p->members[i].name))>len_name)len_name=strlen(p->members[i].name);if((strlen(p->members[i].address))>len_address)len_address=strlen(p->members[i].address);  }for(int i=p->sz_now;i;i/=10,len_index++);for(int i=0;i<(int)(4+len_index+len_name+4+1+MAX_TELEPHONE+1+len_address+7+1);fputc('*',stdout),i++);fputc(10,stdout);printf("NO.%-*cName%-*cTelephone%-*cAddress\n",len_index-3+1,32,len_name<4?1:len_name-4+1,32,MAX_TELEPHONE-9,32,len_address-7+1);for(int i=0;i<p->sz_now;i++)printf("%-*d%-*s%-*s%-*s\n",len_index+2+1,i+1,len_name<4?4+1:len_name+1,p->members[i].name,MAX_TELEPHONE,p->members[i].telephone,len_address,p->members[i].address);for(int i=0;i<(int)(4+len_index+len_name+4+1+MAX_TELEPHONE+1+len_address+7+1);fputc('*',stdout),i++);fputc(10,stdout);
}void DeleteContact(Contacts *p){//删除memberchar target_name[MAX_NAME]={0};int target_index=-1;fputs("Input the name to delete:->",stdout);if(!my_fgets(target_name,MAX_NAME,stdin))return;if((target_index=SearchContact(p,target_name))!=-1){for(int i=target_index;i<p->sz_now-1;i++)memcpy(&(p->members[i]),&(p->members[i+1]),sizeof(Contact));memset(&(p->members[p->sz_now-1]),0,sizeof(Contact));p->sz_now--;return;}
}void ClearContact(Contacts *p){//清空Contactsmemset(p,0,p->sz_now*sizeof(Contact));p->sz_now=0;
}

Contact_txt.cpp

#include "Contact_txt.h"int main(int argc,char *argv[]){int choice=0;FILE *fp=NULL;Contacts *plist=NULL;InitializeContact(&plist);//初始化Contacts结构体LoadFile(plist,fp);   //加载txt文件while(1){choice=menu();//不可放在循环判断中,否则直接跳出循环不进入SaveFile()函数switch(choice){case(quit):SaveFile(plist,fp);break;//->记录并退出case(add):AddContact(plist);break;//->增加case(modify):ModifyContact(plist);break;//->修改(姓名为空直接删除该member)case(show):ShowContact(plist);break;//->显示列表case(Delete):DeleteContact(plist);break;//->删除case(clear):ClearContact(plist);break;//->清空default:SaveFile(plist,fp);break;//缺省->记录}if(!choice)break;CheckContact(plist);}if(plist){//清理动态内存free(plist);plist=NULL; }
return 0;}
//

通讯录(柔性数组,动态内存,文件读取、TXT)-C-20220120相关推荐

  1. 【基于动态内存+文件操作】通讯录管理系统

    前言 每一个项目文件的功能说明 打印基本菜单 1.创建一个适合存放联系人信息的结构体和通讯录结构体 2.初始化通讯录(加载上次的联系人,检查容量是否充足) 枚举常量内部内容 (1)增加联系人信息 (2 ...

  2. 通讯录最终版——动态存储+文件处理

    最终版通讯录即从上一个版本修改过来 先看总体代码,我们再看看差异 ps:里面涉及到很多函数的使用,后续我会出专栏来书写这些函数的使用和实例,与常见错误 大家可以通过https://cplusplus. ...

  3. 浅谈C语言动态内存分配及柔性数组

    文章目录 前言 1.动态内存的简单介绍 1.动态内存分配是什么? 2.为什么存在动态内存分配? 3.动态内存分配具体方法 1.动态内存函数 2.动态内存注意事项 2.经典面试题分析 3.C/C++程序 ...

  4. C语言程序设计 | 动态内存管理:动态内存函数介绍,常见的动态内存错误,柔性数组

    动态内存管理目录: 动态内存函数的介绍 常见的动态内存函数的错误 柔性数组 为什么会有动态内存管理呢 我们在日常使用中,创建一个数组,一个变量时都会开辟空间 如: int a; //在栈上开辟一个四字 ...

  5. 动态内存管理 - malloc、calloc、realloc、柔性数组

    目录 一.为什么存在动态内存分配 二.动态内存函数的介绍 1.1 malloc 1.2 free 1) 动态开辟多少个字节的内存空间,返回该空间的起始地址:且开辟的空间使用方法,类似于数组,是一块连续 ...

  6. 《小猫猫大课堂》三轮5——动态内存管理(通讯录动态内存化)

    宝子,你不点个赞吗?不评个论吗?不收个藏吗? 最后的最后,关注我,关注我,关注我,你会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要. 目录 前言 动态内存产生的原因 动态内存函数 malloc ...

  7. C语言动态内存开辟详解(malloc,calloc,realloc,free,柔型数组)

    目录 一.概述 二.相关库函数的使用 1.malloc 2.calloc malloc vs. calloc 异同 3.free的使用 4.realloc 三.易错点 四.C\C++程序的内存开辟规则 ...

  8. 二维数组及其动态内存分配

    一.二维数组的基本概念 1.1 二维数组的内存映像 从内存角度看,二维数组和一维数组一样,在内存中都是连续分布的多个内存单元,并没有本质差别,只是内存的管理方式不一样,如下图所示 一维数组int a[ ...

  9. 使用指针数组+申请动态内存实现英文单词排序

    在实现这一目标前我们首先得知道什么是指针数组和动态内存 1.指针数组 在C语言和C++等语言中,数组元素全为指针变量的数组称为指针数组,指针数组中的元素都必须具有相同的存储类型.指向相同数据类型的指针 ...

  10. 从0开始学c语言 - 34 - 通讯录 -静态、动态、存到文件(三种版本)

    上一篇:从0开始学c语言-33-动态内存管理_阿秋的阿秋不是阿秋的博客-CSDN博客 我发现,理论的学习文章没几个人看,如果是这种实践类型的文章,看的人很多,偏偏我之前都是扔完代码就走了,也没认真写这 ...

最新文章

  1. Qt探秘——谈ui文件的用法
  2. UNITY编辑器模式下static变量的坑
  3. oracle tabe unlock_Oracle 学习之性能优化(四)收集统计信息
  4. python如何入侵服务器的_通过redis入侵服务器的步骤
  5. 收藏 | 北大华为鹏城联合首次提出视觉 Transformer 后量化算法!
  6. 使用python中的networkx来生成一个图
  7. 监控linux内存,系统运维|用 Bash 脚本监控 Linux 上的内存使用情况
  8. 苹果怎么换字体_苹果手机电池不行了怎么办,换什么牌子好?
  9. 内涵段子计算机说唱id,2018中国互联网哈哈榜之2:十大网络流行语
  10. 怎么把荣耀8x的手机备忘录导到电脑里?
  11. linux配置防火墙和重启防火墙
  12. 计算机老是卡顿怎么解决,电脑反应太慢怎么处理_电脑卡顿什么原因-win7之家
  13. Linux 查看进程的几个命令
  14. 某宝上关于PMP低价续证,可信吗?
  15. Cesium学习四:使用entity绘制polygon
  16. Java基础算法题(01):判断101-200之间有多少个素数,并输出所有素数。 素数又叫质数,就是除了1和它本身之外,再也没有整数能被它整除的数。也就是素数只有两个因子。
  17. 猪齿鱼V2.1.0 发布 移动办公、知识在线协作, 项目管理快人一步
  18. 夜莺(Flashcat)V6监控(五):夜莺监控k8s组件(上)
  19. idea如何配置Mybatis简单易懂
  20. ORACLE之数据泵导出

热门文章

  1. 信息系统项目管理 - 范围管理(划重点)
  2. redis源码笔记 - initServer - 刘浩de技术博客 - 博客园
  3. Echarts绘制关系图
  4. 【JAVA】CData Drivers for Amazon v21
  5. IP地址与DNS之间的关系——真正理解DNS
  6. 若依框架刷新页面出现 正在加载系统资源,请耐心等待
  7. 计算机考研张雪峰,张雪峰:这4类大学生不建议考研,与其辛苦考研不如直接就业!...
  8. 快排 (quick sort)
  9. Visual C++ VS C++ Builder
  10. Ameya360代理-ROHM开发出数十毫瓦超低功耗的设备端学习AI芯片