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

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;}
//

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fleet1126

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值