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+1
enum 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;
else
while(getchar()!=10);
else
return 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){//初始化Contacts
if(!(*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中一行数据存入Contacts
char 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){//有中文千万不要用isspace
if(!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;
}
else
fputs("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中每一行数据存入Contacts
if(!p->sz_now)
fputs("No data found.\n",stdout);
else
printf("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结构体的数据存入fp
if(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)//最后一行结尾不输入\n
fputc(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){//增加member
printf("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){//修改member
char 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){//删除member
char 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){//清空Contacts
memset(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;}
//