上一篇文章,我写了一个简单的动态内存分配空间的通讯录,这一篇文章,我已经将其改成了每次使用完通讯录系统退出时,会自动的保存到文件里,准备进入通讯录系统的时候,可以选择是否读取上次保存文件里的联系人,如果选择读取,那必须,要有messege.txt文件,如果没有会给出提示,那你就可以选择不读取,执行一次,就直接自动生成一个messege.txt文件
注意:如果结构体变量,里面的属性是字符串,如果要修改,要通过strcpy函数来修改
先给大家我的思路:
退出时,联系人存入文件: 先要定义一个规则每个人通讯录人的每个属性都存一行,一个人存5行,再存个换行方便读取文件时,根据换行符的个数%6的值判断存的是什么属性代码:
//在退出通讯录的时候把信息到保存到文件中 void save_File(const char* fileName,list* p){ FILE* fp = fopen(fileName, "w+"); if (fp == NULL){ printf("FILE OPEN ERREO!!\n"); return; } //每个人通讯录人的每个属性都存一行,一个人存5行,再存个换行 for (int i = 0; i < p->count; i++){ fprintf(fp,"%s\n",p->num[i].name); //存姓名 fprintf(fp,"%s\n",p->num[i].age); //存年龄 fprintf(fp,"%s\n",p->num[i].sex); //存性别 fprintf(fp,"%s\n",p->num[i].phone); //存电话 fprintf(fp,"%s\n",p->num[i].address); //存地址 fprintf(fp, "\n"); fflush(fp); } fclose(fp); } 进入通讯录是,读取文件: 定义一个count,表示遇到的第几个\n一次读取一个字符,然后保存到一个字符数组里,如果读到字符为\n,如果count%6等于1,就把字符串放入,name里面如果读到字符为\n,如果count%6等于2,就把字符串放入,age里面如果读到字符为\n,如果count%6等于3,就把字符串放入,sex里面如果读到字符为\n,如果count%6等于4,就把字符串放入,phone里面如果读到字符为\n,如果count%6等于5,就把字符串放入,adress里面如果读到字符为\n,如果count%6等于0,那么就把p指向的count++代码:
// 添加一个函数,在通讯录打开的时候,可以把文件中的信息加载到通讯录中 void load_File(const char* fileName, list* p){ FILE* fp = fopen(fileName, "r"); if (fp == NULL){ printf("FILE LOAD ERREO!!\n"); return; } //定义一个count,表示遇到的第几个\n //一次读取一个字符,然后保存到一个字符数组里, //如果读到字符为\n,如果count%6==1,就把字符串放入,name里面 //如果读到字符为\n,如果count%6==0,那么就把p指向的count++ char c; int count = 0; char str[50] = { '\0' }; int i = 0; //str下标 while ((c = fgetc(fp)) != -1){ if (c != '\n'){ str[i] = c; i++; } else{ str[i] = '\0'; //就算遇到/0,也要添加到str,不然录取姓名为徐文文,年龄就变成20文 i++; count++; if (count % 6 == 1){ strcpy(p->num[p->count].name, str); //结构体变量的内容的修改,如果是字符串,必须用strcpy修改 i = 0; //清空 } else if (count % 6 == 2){ strcpy(p->num[p->count].age, str); i = 0; //清空 } else if (count % 6 == 3){ strcpy(p->num[p->count].sex, str); i = 0; //清空 } else if (count % 6 == 4){ strcpy(p->num[p->count].phone, str); i = 0; //清空 } else if (count % 6 == 5){ strcpy(p->num[p->count].address, str); i = 0; //清空 } else if (count % 6 == 0){ p->count += 1; i = 0; //清空 } else{ printf("load error!\n"); return; } } } fclose(fp); printf("读取成功,欢迎光临(:\n"); }注意:读取文件之前,要判断有多少个联系人,看开始开辟的10个练习人的空间够不够,如果不够再开辟,通过扫描文件换行符的个数/6等于联系人的个数,如果联系人的个数>=10,则让记录换行符的count一直++,直到%10等于0为止,然后再开辟空间,如果小于10,就可以不用管 代码:
int load_FILE_Flag = 1; printf("请选择是否读取上一次存入联系人的文件?\n"); //如果没有文件需要自己在项目路径下创建,或者选择0,第一次过后,自动生成文件 printf("####### 1.yes 0.no #######\n"); scanf("%d", &load_FILE_Flag); if (load_FILE_Flag){ //先要读取文件里有多少个/n,然后除以6,如果>=10, //把zeroCount/=6,然后让其%10==0,如果不余0,就zeroCount++, //最后再把spaceSize=zeroCount,然后再给p开辟更大的空间 FILE* fp = fopen("messege.txt", "r"); int zeroCount = 0; //换行符的数量 char ch; while ((ch=fgetc(fp)) != -1){ if (ch == '\n'){ zeroCount += 1; } } if ((zeroCount = zeroCount / 6) >= 10){ //现在zeroCount就知道文件里存了几个Person数据了,然后让其变成%10==0 while ((zeroCount % 10) != 0){ zeroCount += 1; } spaceSize =zeroCount; //现在开辟空间 Person* temp = (Person*)realloc(p.num, spaceSize*sizeof(Person)); if (temp == NULL){ printf("num没有改变内存大小成功\n"); return; } p.num = temp == NULL ? p.num : temp; } fclose(fp); load_File("messege.txt", &p); }最后给大家,献上我的所有代码,如果想试试效果的,可以复制粘贴,去玩玩
addressList.h #ifndef _ADDRESSLIST_H_ #define _ADDRESSLIST_H_ #include<stdio.h> #include<Windows.h> #include<string.h> #include<stdlib.h> #pragma warning(disable:4996) #pragma once typedef struct person{ char name[20]; char sex[10]; char age[5]; char phone[20]; char address[50]; }Person; typedef struct List{ Person* num; //通讯录 //本来是Person num[1000]; int count; //统计人员,从0开始 }list; // 添加一个函数,在通讯录打开的时候,可以把文件中的信息加载到通讯录中 void load_File(const char* fileName, list* p); //在退出通讯录的时候把信息到保存到文件中 void save_File(const char* fileName, list* p); //添加联系人 void add(list *p); //删除联系人 void del(list *p); //查找联系人,找到后返回在数组里的下标 int find(list *p, char* name); //修改联系人 void update(list *p); //显示所有联系人信息 void show(list *p); //删除所有联系人 int delAll(list *p); //查找人,输出信息 void findName(list *p); //以名字排序所有联系人 void sortName(list *p); int cmp(const void* str, const void* str2); #endif addressList.c #include"addressList.h" // 添加一个函数,在通讯录打开的时候,可以把文件中的信息加载到通讯录中 void load_File(const char* fileName, list* p){ FILE* fp = fopen(fileName, "r"); if (fp == NULL){ printf("FILE LOAD ERREO!!\n"); return; } //定义一个count,表示遇到的第几个\n //一次读取一个字符,然后保存到一个字符数组里, //如果读到字符为\n,如果count%6==1,就把字符串放入,name里面 //如果读到字符为\n,如果count%6==0,那么就把p指向的count++ char c; int count = 0; char str[50] = { '\0' }; int i = 0; //str下标 while ((c = fgetc(fp)) != -1){ if (c != '\n'){ str[i] = c; i++; } else{ str[i] = '\0'; //就算遇到/0,也要添加到str,不然录取姓名为徐文文,年龄就变成20文 i++; count++; if (count % 6 == 1){ strcpy(p->num[p->count].name, str); //结构体变量的内容的修改,如果是字符串,必须用strcpy修改 i = 0; //清空 } else if (count % 6 == 2){ strcpy(p->num[p->count].age, str); i = 0; //清空 } else if (count % 6 == 3){ strcpy(p->num[p->count].sex, str); i = 0; //清空 } else if (count % 6 == 4){ strcpy(p->num[p->count].phone, str); i = 0; //清空 } else if (count % 6 == 5){ strcpy(p->num[p->count].address, str); i = 0; //清空 } else if (count % 6 == 0){ p->count += 1; i = 0; //清空 } else{ printf("load error!\n"); return; } } } fclose(fp); printf("读取成功,欢迎光临(:\n"); } //在退出通讯录的时候把信息到保存到文件中 void save_File(const char* fileName,list* p){ FILE* fp = fopen(fileName, "w+"); if (fp == NULL){ printf("FILE OPEN ERREO!!\n"); return; } //每个人通讯录人的每个属性都存一行,一个人存5行,再存个换行 for (int i = 0; i < p->count; i++){ fprintf(fp,"%s\n",p->num[i].name); //存姓名 fprintf(fp,"%s\n",p->num[i].age); //存年龄 fprintf(fp,"%s\n",p->num[i].sex); //存性别 fprintf(fp,"%s\n",p->num[i].phone); //存电话 fprintf(fp,"%s\n",p->num[i].address); //存地址 fprintf(fp, "\n"); fflush(fp); } fclose(fp); } //查找人,输出信息 void findName(list *p){ char findName[20] = { 0 }; int i = 0; printf("请输入查找的联系人的姓名:\n"); scanf("%s", findName); i = find(p, findName); if (i != -1){ printf("姓名=%s 性别=%s 年龄=%s 电话=%s 地址=%s\n", p->num[i].name, p->num[i].sex, p->num[i].age, p->num[i].phone, p->num[i].address); } else if (i == 0){ printf("bug\n"); } else{ printf("您查找的联系人,通讯录不存在\n"); } } int cmp(const void* str, const void* str2){ return strcmp((*(Person*)str).name, (*(Person*)str2).name); } //以名字排序所有联系人 void sortName(list *p){ if (p->count == 0){ printf("通讯录为空\n"); return; } qsort(p->num, p->count, sizeof(p->num[0]), &cmp); printf("排序完成\n"); } //删除所有联系人 int delAll(list *p){ if (p->count == 0){ printf("通讯录为空"); return; } int result = -1; printf("您确定要删除所有联系人?\n"); printf("删除请按1,不删除请按0\n"); scanf("%d", &result); if (result){ p->count = 0; printf("删除成功\n"); return result; } else{ printf("删除失败\n"); return result; } } //显示所有联系人信息 void show(list *p){ if (p->count == 0){ printf("通讯录为空\n"); return; } for (int i = 0; i < p->count; i++){ printf("姓名=%s 性别=%s 年龄=%s 电话=%s 地址=%s\n", p->num[i].name, p->num[i].sex, p->num[i].age, p->num[i].phone, p->num[i].address); } } //修改联系人 void update(list *p){ char name[20] = { 0 }; printf("请输入与您要修的联系人的姓名\n"); scanf("%s", name); int result = find(p, name); //去查找需要修改的联系人,如果有返回1,如果没有找到返回-1 int flag = 1; //如果玩家修改完毕,变成0,控制循环 if (result != -1){ while (flag){ int choose = -1; //让玩家选择修改什么 printf("#######选择修改的属性#######\n"); printf("##########0.exit ###########\n"); printf("##########1.name ###########\n"); printf("##########2.sex ############\n"); printf("##########3.age ############\n"); printf("##########4.phone ##########\n"); printf("##########5.address ########\n"); scanf("%d", &choose); switch (choose){ case 0: flag = 0; break; case 1: printf("请输入准备修改的新名字:\n"); scanf("%s", p->num[result].name); break; case 2: printf("请输入准备修改的新性别:\n"); scanf("%s", p->num[result].name); break; case 3: printf("请输入准备修改的新年龄:\n"); scanf("%d", &(p->num[result].name)); break; case 4: printf("请输入准备修改的新手机号:\n"); scanf("%s", p->num[result].name); break; case 5: printf("请输入准备修改的新住址:\n"); scanf("%s", p->num[result].name); break; } } printf("修改成功\n"); } else{ printf("该联系人不存在,修改失败\n"); } } //删除联系人 void del(list *p){ char name[20] = { 0 }; printf("请输入要删除人的姓名:\n"); scanf("%s", name); int result = find(p, name); //因为这里的p已经是list类型的指针,p里放的就是通讯录的地址 int n = -1; if (result != -1){ printf("您确定要删除该联系人?\n"); printf("删除请按1,不删除请按0\n"); scanf("%d", &n); if (n){ //如果要删除该联系人,则把后面的人全部往前移 for (int i = result; i < p->count; i++){ p->num[i] = p->num[i + 1]; } p->count--; printf("删除成功\n"); } else{ printf("删除失败\n"); } } else{ printf("您要删除的联系人不存在\n"); } } //查找联系人,找到后返回在数组里的下标 int find(list *p, char* name){ for (int i = 0; i < p->count; i++){ if (strcmp(p->num[i].name, name) == 0){ return i; //如果名字相同,就返回数组的下标 } } return -1; } //添加联系人 void add(list *p){ //先判断是否通讯录满 if (p->count == 1000){ printf("通讯录已满,不能添加\n"); return; } printf("请输入您要添加联系人的姓名:\n"); scanf("%s", p->num[p->count].name); printf("请输入您要添加联系人的性别:\n"); scanf("%s", p->num[p->count].sex); printf("请输入您要添加联系人的年龄:\n"); scanf("%s", &(p->num[p->count].age)); printf("请输入您要添加联系人的电话:\n"); scanf("%s", p->num[p->count].phone); printf("请输入您要添加联系人的地址:\n"); scanf("%s", p->num[p->count].address); printf("添加成功\n"); p->count++; } main.c #include"addressList.h" /* 把一个写好了可以供1000个人存储的通讯录,改为动态的增长空间 分析:定义一个全局变量spaceSize给它在初始值为10,然后在main函数里,开始给p.num初始化开辟10**sizeof(Person)个字节大小的空间 添加联系人时,如果count==spaceSize,那么再添加10个空间, 删除联系人后,如果count==(spaceSize-10),说明,现在多了10个空间,那么减少10个空间, 清空所有联系时,如果玩家选择了清空,清空后,又把空间变为初始的10个大小 */ /* 实现一个通讯录; 通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址 提供方法: 添加联系人信息 删除指定联系人信息 查找指定联系人信息 修改指定联系人信息 显示所有联系人信息 清空所有联系人 以名字排序所有联系人 */ /* 思路: A:先定义一个Person结构体类型,里面是每个人的信息,再定义一个list结构体类型,代表通讯录类型,里面变量num结构体数组,装的通讯录每个人,变量count,表示通讯录里的人数 B:要定义一个全局变量,这个变量就是通讯录:list p C: 增删改查,显示,清空,排序,我们实参用list* p来接受,实参传p的地址,因为结构体太大,结构体传参每次不发生降维,值拷贝,所有传地址,用指针接受 D:增加:先判断通讯录是否为满,录好玩家输入的信息,然后存到通讯里,p->num[p->count].姓名... ,最后一定要记得,p->count++; (注释:我们写一个find方法,通过名字,找通讯录里对应名字下标,如果找到就返回对应名字下标,如果找不到就返回-1) E:删:先判断通讯里是否为空,让玩家输入姓名,然后通过find方法,判断找到没有,如果找到了,就把num(返回的下标+1---count)之间的元素往前移,覆盖了,删除的元素 F:改:用find方法,找到了,就再让玩家选择改什么属性,然后一改就OK,这个很简单 G:查:先判断通讯录是否为空,让玩家输入姓名,然后find方法,如果找到了,打印下标元素, H:显示:从0到count遍历,依次打出即可 J:清空:直接让count=0;即可,即使数组里面还是有数据,但是别人看不到 K:排序,用qsort方法即可,传入通讯录数组,个数count,大小 sizeof(p->num[0]),自己再根据规则写一下cmp,提示:cmp里面直接用strcmp,就可以判断大小 */ list p; //通讯录 //起始动态开辟的大小, //添加联系人时,如果count==spaceSize,那么再添加10个空间, //删除联系人时,如果count==(spaceSize-10),那么减少10个空间, //清空所有联系时,如果玩家选择了清空,清空后,又把空间变为初始的10个大小 int spaceSize = 10; void menu(){ printf("#####################################\n"); printf("############0.退出通讯录 ############\n"); printf("############1.添加联系人信息 ########\n"); printf("############2.删除指定联系人信息 ####\n"); printf("############3.查找指定联系人信息 ####\n"); printf("############4.修改指定联系人信息 ####\n"); printf("############5.显示所有联系人信息 ####\n"); printf("############6.清空所有联系人 ########\n"); printf("############7.以名字排序所有联系人 ##\n"); printf("#####################################\n"); } int main(){ p.count = 0; //给count初始化为0 p.num = (Person*)malloc(spaceSize*sizeof(Person)); //先给p的num一个person结构体的大小,如果需要添加联系人,便把p.num用realloc函数,改变动态开辟内存大小为(count+1) if (p.num == NULL){ printf("malloc ERROR!\n"); return -1; } int load_FILE_Flag = 1; printf("请选择是否读取上一次存入联系人的文件?\n"); //如果没有文件需要自己在项目路径下创建,或者选择0,第一次过后,自动生成文件 printf("####### 1.yes 0.no #######\n"); scanf("%d", &load_FILE_Flag); if (load_FILE_Flag){ //先要读取文件里有多少个/n,然后除以6,如果>=10, //把zeroCount/=6,然后让其%10==0,如果不余0,就zeroCount++, //最后再把spaceSize=zeroCount,然后再给p开辟更大的空间 FILE* fp = fopen("messege.txt", "r"); int zeroCount = 0; //换行符的数量 char ch; while ((ch=fgetc(fp)) != -1){ if (ch == '\n'){ zeroCount += 1; } } if ((zeroCount = zeroCount / 6) >= 10){ //现在zeroCount就知道文件里存了几个Person数据了,然后让其变成%10==0 while ((zeroCount % 10) != 0){ zeroCount += 1; } spaceSize =zeroCount; //现在开辟空间 Person* temp = (Person*)realloc(p.num, spaceSize*sizeof(Person)); if (temp == NULL){ printf("num没有改变内存大小成功\n"); return; } p.num = temp == NULL ? p.num : temp; } fclose(fp); load_File("messege.txt", &p); } int flag = 1; int choose = -1; while (flag){ menu(); printf("请选择=>"); scanf("%d", &choose); switch (choose){ case 0: flag = 0; break; case 1: if (spaceSize == p.count){ //当count和spaceSize相等,那么把spaceSize+=10,改变num的内存动态大小 spaceSize += 10; Person* temp = (Person*)realloc(p.num, spaceSize*sizeof(Person)); if (temp == NULL){ printf("num没有改变内存大小成功\n"); return; } p.num = temp == NULL ? p.num : temp; } add(&p); //printf("现在num的动态开辟的大小:%d\n", sizeof(p.num)); break; case 2: del(&p); //删除结束后,又把num的动态开辟的内存大小重新设置 if (p.count == (spaceSize - 10)){ spaceSize -= 10; Person* temp = (Person*)realloc(p.num, spaceSize*sizeof(Person)); if (temp == NULL){ printf("num没有改变内存大小成功\n"); } p.num = temp == NULL ? p.num : temp; } //printf("现在num的动态开辟的大小:%d\n", sizeof(p.num)); break; case 3: //printf("现在count:%d\n", p.count); findName(&p); break; case 4: update(&p); break; case 5: show(&p); break; case 6: if (delAll(&p)){ //删除结束后,又把num的动态开辟的内存大小重新设置 spaceSize = 10; Person* temp = (Person*)realloc(p.num, spaceSize*sizeof(Person)); if (temp == NULL){ printf("num没有改变内存大小成功\n"); return; } p.num = temp == NULL ? p.num : temp; } break; case 7: sortName(&p); break; default: printf("输入有误,请重新输入!!!\n"); break; } } printf("再见\n"); save_File("messege.txt", &p); free(p.num); system("pause"); return 0; }