深圳幻海软件技术有限公司 欢迎您!

C语言之通讯录(动态 存储文件版)

2023-04-02

目录 前言一.基本思路 二.代码的实现 2.1通讯录菜单 2.2通讯录的定义及功能 2.3函数实现  2.3.1初始化通讯录    2.3.2文件信息传递到通讯录里 2.3.3扩容

目录

 前言

一.基本思路

 二.代码的实现

  2.1通讯录菜单

 2.2通讯录的定义及功能

 2.3函数实现 

 2.3.1初始化通讯录     

 2.3.2文件信息传递到通讯录里

 2.3.3扩容通讯录

 2.3.4增加联系人 

2.3.5删除联系人

2.3.6查询联系人

2.3.7修改联系人

2.3.8打印通讯录

2.3.9信息保留在文件中

 2.3.10销毁空间退出程序

三.完整代码

 3.1Text.c文件

3.2Contact.h文件

3.3Contact.c文件

总结


 前言

文件存储版的通讯录 是在通讯录的基础上添加了文件操作
在了解通讯录(文件存储版)之前,我们得好好学习一下  文件操作
只有掌握了操作文件,才能明白文件存储版的通讯录

一.基本思路

       1.通讯录是由多人的信息组合,信息:姓名,年龄,性别,地址等。

       2.通讯录的大小,存放的人数,此使用动态存储,更加方便存储和利用空间。

       3.通讯录的基本功能:增加联系人、删除联系人、查找联系人,修改联系人

       4.保存通讯录文档,方便下次使用。

   注:通讯录分三种:静态、动态、文件三种。而此文章讲述的是动态存储的文件版通讯录

           静态:大小固定,存储的人数有明确限制,无法改变,使用数组实现。

           动态:存储人数可以调节,可以随着人数的增加而增加,选择一个初始大小,之后可进行扩充操作,  可更好的利用空间。

           文件:该通讯录是在以上两种通讯录之一上加上存储文件的操作,在程序执行结束后都无法保存,录入的信息在程序结束时就会消失。为了保存录入的信息,可以通过文件操作来实现。

 二.代码的实现

  2.1通讯录菜单

                  菜单能够实现和用户的交互。需要选择增、删、查、改的功能。

                 所以,通讯录需要一个菜单。

                代码如下:

  1. void menu()
  2. {
  3. printf("*********************************\n");
  4. printf("*******1.添加 2.删除*******\n");
  5. printf("*******3.查找 4.修改*******\n");
  6. printf("*******5.显示 6.保存*******\n");
  7. printf("*******0.退出 *******\n");
  8. printf("*********************************\n");
  9. }
  10. //使用函数指针数组
  11. void (*(p[7]))(Contact*) = { Exit,AddContact,DeleteContact,SearchContact,ModifyContact,PrintContact,SaveContact };
  12. int main()
  13. {
  14. //Contact cl; 这是下面代码结构体的
  15. //InitContact(&cl);
  16. int input;
  17. do {
  18. menu();
  19. printf("请输入->");
  20. scanf("%d", &input);
  21. if (input <= 6)
  22. p[input](&cl);
  23. else
  24. printf("输入错误\n");
  25. }while (input != 0);
  26. }

 为了方便,我们使用了函数指针数组,void (*(p[7]))(Contact*)   

 2.2通讯录的定义及功能

                    通讯录需要姓名、性别、年龄及电话,此时我们需要使用结构体来定义。还需要定义函数:增、删、查、改、打印学生信息、保存通讯录。

             代码如下:

  1. #include<stdio.h>
  2. #include<malloc.h>
  3. #include<stdlib.h>
  4. #include<string.h>
  5. typedef struct PeoInfo
  6. {
  7. char name[10];//姓名
  8. int age; //年龄
  9. char sex[3]; //性别
  10. int phone[12];//电话
  11. }PeoInfo;
  12. typedef struct Contact
  13. {
  14. int size; //当前存储的人数
  15. int capacity; //通讯录容量大小
  16. contact* data; //结构体指针,访问个人信息
  17. }Contact;
  18. //初始化通讯录
  19. void InitContact(Contact* pc);
  20. //增加联系人
  21. void AddContact(Contact* pc);
  22. //删除联系人
  23. void DeleteContact(Contact* pc);
  24. //查找联系人
  25. void SearchContact(Contact* pc);
  26. //修改联系人
  27. void ModifyContact(Contact* pc);
  28. //显示通讯录
  29. void PrintContact(Contact* pc);
  30. //扩容通讯录
  31. void CheckCapacity(Contact* pc);
  32. //保存信息到文件
  33. void SaveContact(Contact* pc);
  34. //文件信息传递到通讯录
  35. void LoadContact(Contact* pc);
  36. //销毁空间,退出程序
  37. void Exit(Contact* pc);

 2.3函数实现 

注:当通讯录退出的时候,把信息写到文件。
       当通讯录初始化后,加载文件的信息到通讯录中。

 2.3.1初始化通讯录     

              通讯录是动态的,所以需要扩容,给一定空间。

  1. void InitContact(Contact* pc)
  2. {
  3. // 此时通讯录是空的,应先为通讯录分配空间
  4. pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * 4);
  5. // 如果分配成功,将通讯录的size设为0,capacity设为初识大小
  6. pc->size = 0;
  7. pc->capacity = 4;
  8. //将文档的信息传递到动态内存里,函数实现在下方
  9. LoadContact(pc);
  10. }

 2.3.2文件信息传递到通讯录里

将文件的信息加载到通讯录里

  1. void LoadContact(Contact* pc)
  2. {
  3. // 以读的形式打开文件
  4. FILE* pf = fopen("contact.txt", "rb");
  5. if (pf == NULL)
  6. {
  7. perror("fopen");
  8. return;
  9. }
  10. // 将文件中的内容加载到通讯录中
  11. // 这里用fread函数,当fread函数读取的联系人信息数为0时,说明读取结束
  12. PeoInfo tmp = { 0 }; // 定义一个联系人信息的结构体,便于读取
  13. int i = 0;
  14. while (fread(&tmp, sizeof(PeoInfo), 1, pf))
  15. {
  16. CheckCapacity(pc); // 在这个函数中查看数组是否需要扩容,若需要,则扩容
  17. pc->data[i] = tmp;
  18. pc->size++;
  19. i++;
  20. }
  21. // 关闭文件
  22. fclose(pf);
  23. pf = NULL;
  24. return;
  25. }

 2.3.3扩容通讯录

        添加联系人之前,需要判断通讯录是否满员,满员则需要扩容

  1. void CheckCapacity(Contact* pc)
  2. {
  3. // 判断通讯录是否已满,若满,进行扩容
  4. if (pc->size == pc->capacity)
  5. {
  6. PeoInfo* tmp = (PeoInfo*)realloc(pc, sizeof(PeoInfo) * 4);
  7. if (tmp == NULL)
  8. {
  9. printf("realloc fail\n");
  10. return;
  11. }
  12. pc->data = tmp;
  13. // 若扩容成功,增大capacity
  14. pc->capacity *= 2;
  15. }
  16. }

 2.3.4增加联系人 

            需要添加联系人的各项信息。

  1. void AddContact(Contact* pc)
  2. {
  3. int num = 0;
  4. printf("添加人数:");
  5. scanf("%d", &num);
  6. // 输入要添加的联系人的信息
  7. // 这里pc->data为结构体数组,pc->data[pc->size]为其中的元素,也就是某一个联系人的信息
  8. for (int i = 0; i < num; i++)
  9. {
  10. //判断通讯录是否满人
  11. CheckCapacity(pc);
  12. printf("请输入名字\n");
  13. scanf("%s", pc->data[pc->size].name);
  14. printf("请输入性别\n");
  15. scanf("%s", pc->data[pc->size].sex);
  16. printf("请输入年龄\n");
  17. scanf("%d", &pc->data[pc->size].age);
  18. printf("请输入电话\n");
  19. scanf("%s", pc->data[pc->size].phone);
  20. pc->size++; // 将存入的联系人的数量加1
  21. }
  22. }

2.3.5删除联系人

      需要找到该联系人的下标值,然后进行删除。

  1. void DeleteContact(Contact* pc)
  2. {
  3. int ret = 0;//记录寻找的下标值
  4. printf("请输入要删除的联系人的名字\n");
  5. char name[20];
  6. scanf("%s", name);
  7. // 定义一个新函数find,用来查找是否有这个联系人
  8. // 如果有,返回联系人的下标,如果没有,返回-1
  9. for (int i = 0; i < pc->size; i++)
  10. {
  11. if (strcmp(pc->data[i].name, name) == 0)
  12. {
  13. ret = i; break;
  14. }
  15. }
  16. if (ret)
  17. {
  18. printf("不存在");
  19. }
  20. else {
  21. for (int i = ret; i < pc->size - 1; i++)
  22. {
  23. pc->data[i] = pc->data[i + 1];
  24. }
  25. pc->size--;
  26. }
  27. }

2.3.6查询联系人

找到下标值,从而得到联系人的信息

  1. void SearchContact(Contact* pc)
  2. {
  3. int ret = 0;
  4. printf("请输入要查找的联系人的名字\n");
  5. char name[20];
  6. scanf("%s", name);
  7. // 利用已经定义的find函数进行查找
  8. for (int i = 0; i < pc->size; i++)
  9. {
  10. if (strcmp(pc->data[i].name, name) == 0)
  11. {
  12. ret = i; break;
  13. }
  14. }
  15. if (ret)
  16. {
  17. printf("没有找到该联系人\n");
  18. }
  19. else
  20. {
  21. // 如果找到,打印该联系人的信息,首先打印五个标题
  22. printf("%-10s\t%-10s\t%-5s\t%-15s\n", "姓名", "性别", "年龄", "电话");
  23. printf("%-10s\t%-10s\t%-5d\t%-15s%\n",
  24. pc->data[ret].name,
  25. pc->data[ret].sex,
  26. pc->data[ret].age,
  27. pc->data[ret].phone
  28. );
  29. }
  30. }

2.3.7修改联系人

找到下标值,从而进行各项数据的修改

  1. void ModifyContact(Contact* pc)
  2. {
  3. int ret = 0;
  4. printf("请输入要查找的联系人的名字\n");
  5. char name[20];
  6. scanf("%s", name);
  7. for (int i = 0; i < pc->size; i++)
  8. {
  9. if (strcmp(pc->data[i].name, name) == 0)
  10. {
  11. ret = i; break;
  12. }
  13. }
  14. if (ret)
  15. {
  16. printf("没有找到该联系人\n");
  17. }
  18. else
  19. {
  20. printf("请输入名字\n");
  21. scanf("%s", pc->data[ret].name);
  22. printf("请输入性别\n");
  23. scanf("%s", pc->data[ret].sex);
  24. printf("请输入年龄\n");
  25. scanf("%d", &pc->data[ret].age);
  26. printf("请输入电话\n");
  27. scanf("%s", pc->data[ret].phone);
  28. }
  29. }

2.3.8打印通讯录

打印每个人的具体数据

  1. // 在这个函数内打印所有联系人的信息
  2. void PrintContact(Contact* pc)
  3. {
  4. // 首先打印五个标题
  5. printf("%-10s\t%-10s\t%-5s\t%-15s\n", "姓名", "性别", "年龄", "电话");
  6. // 然后用for循环打印所有联系人的信息
  7. for (int i = 0; i < pc->size; i++)
  8. {
  9. printf("%-10s\t%-10s\t%-5d\t%-15s\n",
  10. pc->data[i].name,
  11. pc->data[i].sex,
  12. pc->data[i].age,
  13. pc->data[i].phone
  14. );
  15. }
  16. }

2.3.9信息保留在文件中

程序退出时,要将销毁空间,并且把数据存入文件里,方便下次调用

  1. void SaveContact(Contact* pc)
  2. {
  3. FILE* p = fopen("contact.txt", "wb");
  4. if (p == NULL)
  5. {
  6. perror("SaveContact");
  7. }
  8. else {
  9. int i = 0;
  10. for (i; i < pc->size; i++)
  11. {
  12. fwrite(pc->data + i, sizeof(PeoInfo), 1, p);
  13. }
  14. fclose(p);
  15. p = NULL;
  16. printf("保存成功");
  17. }
  18. }

 2.3.10销毁空间退出程序

  1. void Exit(Contact* pc)
  2. {
  3. //销毁空间
  4. free(pc->data);
  5. pc->data = NULL;
  6. pc->size = 0;
  7. pc->capacity = 0;
  8. }

三.完整代码

和上面的代码比起来,连贯了Contact.c的各个函数实现。

 3.1Text.c文件

  1. #include"Contact.h"
  2. void menu()
  3. {
  4. printf("*********************************\n");
  5. printf("*******1.添加 2.删除*******\n");
  6. printf("*******3.查找 4.修改*******\n");
  7. printf("*******5.显示 6.保存*******\n");
  8. printf("*******0.退出 *******\n");
  9. printf("*********************************\n");
  10. }
  11. //使用函数指针数组
  12. void (*(p[7]))(Contact*) = { Exit,AddContact,DeleteContact,SearchContact,ModifyContact,PrintContact,SaveContact };
  13. int main()
  14. {
  15. //定义结构体
  16. Contact cl;
  17. InitContact(&cl);
  18. int input;
  19. do {
  20. menu();
  21. printf("请输入->");
  22. scanf("%d", &input);
  23. if (input <= 6)
  24. p[input](&cl);
  25. else
  26. printf("输入错误\n");
  27. } while (input != 0);
  28. }

3.2Contact.h文件

  1. #include<stdio.h>
  2. #include<malloc.h>
  3. #include<stdlib.h>
  4. #include<string.h>
  5. typedef struct PeoInfo
  6. {
  7. char name[10];//姓名
  8. int age; //年龄
  9. char sex[3]; //性别
  10. int phone[12];//电话
  11. }PeoInfo;
  12. typedef struct Contact
  13. {
  14. int size; //当前存储的人数
  15. int capacity; //通讯录容量大小
  16. PeoInfo* data; //结构体指针,访问个人信息
  17. }Contact;
  18. //初始化通讯录
  19. void InitContact(Contact* pc);
  20. //增加联系人
  21. void AddContact(Contact* pc);
  22. //删除联系人
  23. void DeleteContact(Contact* pc);
  24. //查找联系人
  25. void SearchContact(Contact* pc);
  26. //修改联系人
  27. void ModifyContact(Contact* pc);
  28. //显示通讯录
  29. void PrintContact(Contact* pc);
  30. //扩容通讯录
  31. void CheckCapacity(Contact* pc);
  32. //销毁并且保存通讯录
  33. void SaveContact(Contact* pc);
  34. void LoadContact(Contact* pc);
  35. void Exit(Contact* pc);

3.3Contact.c文件

  1. #include"Contact.h"
  2. void InitContact(Contact* pc)
  3. {
  4. // 此时通讯录是空的,应先为通讯录分配空间
  5. pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * 4);
  6. // 如果分配成功,将通讯录的size设为0,capacity设为初识大小
  7. pc->size = 0;
  8. pc->capacity = 4;
  9. //将文档的信息传递到动态内存里,函数实现在下方
  10. LoadContact(pc);
  11. }
  12. void LoadContact(Contact* pc)
  13. {
  14. // 以读的形式打开文件
  15. FILE* pf = fopen("contact.txt", "rb");
  16. if (pf == NULL)
  17. {
  18. perror("fopen");
  19. return;
  20. }
  21. // 将文件中的内容加载到通讯录中
  22. // 这里用fread函数,当fread函数读取的联系人信息数为0时,说明读取结束
  23. PeoInfo tmp = { 0 }; // 定义一个联系人信息的结构体,便于读取
  24. int i = 0;
  25. while (fread(&tmp, sizeof(PeoInfo), 1, pf))
  26. {
  27. CheckCapacity(pc); // 在这个函数中查看数组是否需要扩容,若需要,则扩容
  28. pc->data[i] = tmp;
  29. pc->size++;
  30. i++;
  31. }
  32. // 关闭文件
  33. fclose(pf);
  34. pf = NULL;
  35. return;
  36. }
  37. void CheckCapacity(Contact* pc)
  38. {
  39. // 判断通讯录是否已满,若满,进行扩容
  40. if (pc->size == pc->capacity)
  41. {
  42. PeoInfo* tmp = (PeoInfo*)realloc(pc, sizeof(PeoInfo) * 4);
  43. if (tmp == NULL)
  44. {
  45. printf("realloc fail\n");
  46. return;
  47. }
  48. pc->data = tmp;
  49. // 若扩容成功,增大capacity
  50. pc->capacity *= 2;
  51. }
  52. }
  53. void AddContact(Contact* pc)
  54. {
  55. int num = 0;
  56. printf("添加人数:");
  57. scanf("%d", &num);
  58. // 输入要添加的联系人的信息
  59. // 这里pc->data为结构体数组,pc->data[pc->size]为其中的元素,也就是某一个联系人的信息
  60. for (int i = 0; i < num; i++)
  61. {
  62. //判断通讯录是否满人
  63. CheckCapacity(pc);
  64. printf("请输入名字\n");
  65. scanf("%s", pc->data[pc->size].name);
  66. printf("请输入性别\n");
  67. scanf("%s", pc->data[pc->size].sex);
  68. printf("请输入年龄\n");
  69. scanf("%d", &pc->data[pc->size].age);
  70. printf("请输入电话\n");
  71. scanf("%s", pc->data[pc->size].phone);
  72. pc->size++; // 将存入的联系人的数量加1
  73. }
  74. }
  75. void DeleteContact(Contact* pc)
  76. {
  77. int ret = 0;//记录寻找的下标值
  78. printf("请输入要删除的联系人的名字\n");
  79. char name[20];
  80. scanf("%s", name);
  81. // 定义一个新函数find,用来查找是否有这个联系人
  82. // 如果有,返回联系人的下标,如果没有,返回-1
  83. for (int i = 0; i < pc->size; i++)
  84. {
  85. if (strcmp(pc->data[i].name, name) == 0)
  86. {
  87. ret = i; break;
  88. }
  89. }
  90. if (ret)
  91. {
  92. printf("不存在");
  93. }
  94. else {
  95. for (int i = ret; i < pc->size - 1; i++)
  96. {
  97. pc->data[i] = pc->data[i + 1];
  98. }
  99. pc->size--;
  100. }
  101. }
  102. void SearchContact(Contact* pc)
  103. {
  104. int ret = 0;
  105. printf("请输入要查找的联系人的名字\n");
  106. char name[20];
  107. scanf("%s", name);
  108. // 利用已经定义的find函数进行查找
  109. for (int i = 0; i < pc->size; i++)
  110. {
  111. if (strcmp(pc->data[i].name, name) == 0)
  112. {
  113. ret = i; break;
  114. }
  115. }
  116. if (ret)
  117. {
  118. printf("没有找到该联系人\n");
  119. }
  120. else
  121. {
  122. // 如果找到,打印该联系人的信息,首先打印五个标题
  123. printf("%-10s\t%-10s\t%-5s\t%-15s\n", "姓名", "性别", "年龄", "电话");
  124. printf("%-10s\t%-10s\t%-5d\t%-15s%\n",
  125. pc->data[ret].name,
  126. pc->data[ret].sex,
  127. pc->data[ret].age,
  128. pc->data[ret].phone
  129. );
  130. }
  131. }
  132. void ModifyContact(Contact* pc)
  133. {
  134. int ret = 0;
  135. printf("请输入要查找的联系人的名字\n");
  136. char name[20];
  137. scanf("%s", name);
  138. // 利用已经定义的find函数进行查找
  139. for (int i = 0; i < pc->size; i++)
  140. {
  141. if (strcmp(pc->data[i].name, name) == 0)
  142. {
  143. ret = i; break;
  144. }
  145. }
  146. if (ret)
  147. {
  148. printf("没有找到该联系人\n");
  149. }
  150. else
  151. {
  152. printf("请输入名字\n");
  153. scanf("%s", pc->data[ret].name);
  154. printf("请输入性别\n");
  155. scanf("%s", pc->data[ret].sex);
  156. printf("请输入年龄\n");
  157. scanf("%d", &pc->data[ret].age);
  158. printf("请输入电话\n");
  159. scanf("%s", pc->data[ret].phone);
  160. }
  161. }
  162. // 在这个函数内打印所有联系人的信息
  163. void PrintContact(Contact* pc)
  164. {
  165. // 首先打印五个标题
  166. printf("%-10s\t%-10s\t%-5s\t%-15s\n", "姓名", "性别", "年龄", "电话");
  167. // 然后用for循环打印所有联系人的信息
  168. for (int i = 0; i < pc->size; i++)
  169. {
  170. printf("%-10s\t%-10s\t%-5d\t%-15s\n",
  171. pc->data[i].name,
  172. pc->data[i].sex,
  173. pc->data[i].age,
  174. pc->data[i].phone
  175. );
  176. }
  177. }
  178. void SaveContact(Contact* pc)
  179. {
  180. FILE* p = fopen("contact.txt", "wb");
  181. if (p == NULL)
  182. {
  183. perror("SaveContact");
  184. }
  185. else {
  186. int i = 0;
  187. for (i; i < pc->size; i++)
  188. {
  189. fwrite(pc->data + i, sizeof(PeoInfo), 1, p);
  190. }
  191. fclose(p);
  192. p = NULL;
  193. printf("保存成功");
  194. }
  195. }
  196. void Exit(Contact* pc)
  197. {
  198. //销毁空间
  199. free(pc->data);
  200. pc->data = NULL;
  201. pc->size = 0;
  202. pc->capacity = 0;
  203. }

总结

         在写动态存储文件版的通讯录,我们得学会动态存储和文件操作。

         只有不断的掌握知识,我们才能敲代码得心应手,在不断的学习里,逐渐进步。

                                                                                                      -------------小菜TQ02

文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览42750 人正在系统学习中