• 通讯录的实现(初版)


         我们在对于通讯录的实现会以下出现4个版本:静态版本,动态版本,文件版本,数据库版本,在此篇博客中我们实现的是静态版本,也是最容易理解的版本,其他的版本会在接下来的博客中陆续实现。

    目录

    一、代码思路

    1.1 多文件的形式

    1.2 通讯录需要实现的功能

    1.3 基本思路总结

    二、代码各部分实现

    2.1 结构体的定义

    2.2 主函数大体思路

    2.3 菜单部分

    2.4 初始化通讯录

    2.5 在通讯录中增加学生信息

    2.6 展示通讯录的信息

    2.7 查找函数

    2.8 删除指定联系人

    2.9 查找指定联系人

    2.10 修改指定联系人

    2.11 对通讯录的数据进行排序

    2.11.1 按照姓名排序

    2.11.2 按照年龄排序

    三、分文件的形式

    3.1 test.c文件

    3.2 contact.c文件

    3.3 contact.h文件

    四、代码运行结果


    一、代码思路

    1.1 多文件的形式

         对于通讯录这个程序来说,实现通讯录的代码长度偏长,我们最好将代码分为三个文件,其次在一个工程中,养成分文件写代码的习惯必不可少,在此处我们将通讯录的实现分为三个文件来写:

          

         一般来说,我们会在头文件中写函数的声明,即需要的其他头文件。 

    1.2 通讯录需要实现的功能

         对于一个通讯录我们在写之前需要预想一下需要实现的功能:

    1. 增加联系人
    2. 删除联系人
    3. 修改联系人
    4. 查找指定联系人
    5. 排序
    6. 显示通讯录的信息

    1.3 基本思路总结

    二、代码各部分实现

    2.1 结构体的定义

         首先通讯录中的每个学生是一个复杂对象,他有姓名,性别,电话,年龄,地址等特性,所以我们想到构造一个结构体类型来描述这一复杂对象:

    注意:在这里我们想要使代码具有扩展性,所以在这里的个数在前面使用#define定义。

    1. #define MAX 100
    2. #define MAX_NAME 20
    3. #define MAX_SEX 6
    4. #define MAX_TELE 12
    5. #define MAX_ADDR 30
    1. struct PeoInfo
    2. {
    3. char name[MAX_NAME];
    4. char sex[MAX_SEX];
    5. char tele[MAX_TELE];
    6. int age;
    7. char addr[MAX_ADDR];
    8. };

         其次,我们要描述一个通讯录,要有每个学生的信息以及学生的数量,也是一个复杂对象,构造结构体来实现:

    1. struct Contact
    2. {
    3. struct PeoInfo data[MAX];
    4. int sz;
    5. };

    2.2 主函数大体思路

         我们在实现各个功能时,首先要有一个大致的思路,即要实现哪些函数,函数的名字,以及在什么情况下调用函数。

    1. int main()
    2. {
    3. int input = 0;
    4. struct Contact con; //创建通讯录
    5. InitContact(&con); //对通讯录初始化
    6. do
    7. {
    8. menu();
    9. printf("请选择:\n");
    10. scanf("%d", &input);
    11. switch (input)
    12. {
    13. case 1:
    14. AddContact(&con); //在通讯录中增加信息
    15. break;
    16. case 2:
    17. DelContact(&con); //在通讯录中删除指定联系人
    18. break;
    19. case 3:
    20. SearchContact(&con); //查找指定联系人
    21. break;
    22. case 4:
    23. ModifyContact(&con); //修改指定联系人
    24. break;
    25. case 5:
    26. ShowContact(&con); //展示通讯录的内容
    27. break;
    28. case 6:
    29. SortContact(&con); //对通讯录里的学生按照姓名进行排序
    30. break;
    31. case 0:
    32. printf("退出通讯录\n");
    33. break;
    34. default:
    35. printf("输入错误,请重新选择\n");
    36. break;
    37. }
    38. } while (input);
    39. return 0;
    40. }

         我们发现在上面我没写代码时每次写case语句,例如写case 1时我们要去菜单函数看要实现什么功能,发现对应的是增加功能时再去写增加函数,相对来说比较麻烦,所以在这里我们可以使用枚举常量来实现,增加代码的可读性和可维护性。

    1. enum Option
    2. {
    3. EXIT, //默认为0
    4. ADD, //1
    5. DEL, //2
    6. SEARCH, //3
    7. MODIFY, //4
    8. SHOW, //5
    9. SORT //6
    10. };

         对于枚举常量来说如果不赋初值默认第一个常量是0,然后依次相加,正好与case ADD与case 1等价,同理替换其他的。

    1. int main()
    2. {
    3. int input = 0;
    4. struct Contact con; //创建通讯录
    5. InitContact(&con); //对通讯录初始化
    6. do
    7. {
    8. menu();
    9. printf("请选择:\n");
    10. scanf("%d", &input);
    11. switch (input)
    12. {
    13. case ADD:
    14. AddContact(&con); //在通讯录中增加信息
    15. break;
    16. case DEL:
    17. DelContact(&con); //在通讯录中删除指定联系人
    18. break;
    19. case SEARCH:
    20. SearchContact(&con); //查找指定联系人
    21. break;
    22. case MODIFY:
    23. ModifyContact(&con); //修改指定联系人
    24. break;
    25. case SHOW:
    26. ShowContact(&con); //展示通讯录的内容
    27. break;
    28. case SORT:
    29. SortContact(&con); //对通讯录里的学生按照姓名进行排序
    30. break;
    31. case EXIT:
    32. printf("退出通讯录\n");
    33. break;
    34. default:
    35. printf("输入错误,请重新选择\n");
    36. break;
    37. }
    38. } while (input);
    39. return 0;
    40. }

    2.3 菜单部分

         我们在设计程序的时候,需要给用户提示这个通讯录能够实现什么功能,可以对通讯录进行什么操作,这个时候菜单就显得格外重要。

    1. void menu()
    2. {
    3. printf("*******************************************************\n");
    4. printf("************ 1.add 2.del ***************\n");
    5. printf("************ 3.search 4.modify ***************\n");
    6. printf("************ 5.show 6.sort ***************\n");
    7. printf("************ 0.exit ***************\n");
    8. printf("*******************************************************\n");
    9. }

    2.4 初始化通讯录

         我们创建了通讯录,此时通讯录中没有任何数据,我们要对它进行初始化。

    1. void InitContact(struct Contact* pc)
    2. {
    3. pc->sz = 0;
    4. memset(pc->data, 0, 100 * sizeof(struct PeoInfo));
    5. }

         在这里,我们使用了memset函数,将通讯录的数据置为0,其次,我们需要更改通讯录里面的内容,所以我们在这里传参传的是通讯录的地址。

    2.5 在通讯录中增加学生信息

         我们在通讯录中添加学生信息的前提是通讯录没有满,所以在函数中我们需要判断通讯录中的学生数量,其次在传参的时候,我们可能不小心传成空指针,所以在这里我们可以使用assert函数进行判断。

    1. void AddContact(struct Contact* pc)
    2. {
    3. assert(pc);
    4. //增加信息的前提是通讯录没有满
    5. if (pc->sz == MAX)
    6. {
    7. printf("通讯录已满\n");
    8. return;
    9. }
    10. printf("请输入姓名:\n");
    11. scanf("%s", pc->data[pc->sz].name);
    12. printf("请输入性别:\n");
    13. scanf("%s", pc->data[pc->sz].sex);
    14. printf("请输入年龄:\n");
    15. scanf("%d", &pc->data[pc->sz].age);
    16. printf("请输入电话:\n");
    17. scanf("%s", &pc->data[pc->sz].tele);
    18. printf("请输入地址:\n");
    19. scanf("%s", pc->data[pc->sz].addr);
    20. pc->sz++;
    21. printf("成功添加联系人\n");
    22. }

    2.6 展示通讯录的信息

    1. void ShowContact(struct Contact* pc)
    2. {
    3. int i = 0;
    4. printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
    5. for (i = 0; i < pc->sz; i++)
    6. {
    7. printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
    8. }
    9. }

    2.7 查找函数

         在下面的删除指定联系人函数和查找指定联系人函数都需要查找函数,所以我们先实现查找函数,我们在这里通过姓名寻找,查找到了返回下标。

    1. static int FindByName(struct Contact* pc, char name[])
    2. {
    3. int i = 0;
    4. for (i = 0; i < pc->sz; i++)
    5. {
    6. if (strcmp(pc->data[i].name, name) == 0)
    7. {
    8. return i;
    9. }
    10. }
    11. return -1;
    12. }

    2.8 删除指定联系人

          在这里有两种方式删除指定联系人,一种是使用memmove函数,关于memmove函数的介绍及实现在之前的字符与字符串函数的博客中已经详细讲过,可以去回看。

    方式一:
     

    1. void DelContact(struct Contact* pc)
    2. {
    3. printf("请输入联系人的姓名:\n");
    4. char name[20];
    5. scanf("%s", name);
    6. int ret = FindByName(pc, name);
    7. if (ret == -1)
    8. {
    9. printf("要查找的联系人不存在\n");
    10. }
    11. else
    12. {
    13. memmove(&(pc->data[ret]), &(pc->data[ret + 1]), (pc->sz - ret) * sizeof(struct PeoInfo));
    14. }
    15. pc->sz--;
    16. printf("成功删除\n");
    17. }

    方式二:

    1. void DelContact1(struct Contact* pc)
    2. {
    3. printf("请输入联系人的姓名:\n");
    4. char name[20];
    5. scanf("%s", name);
    6. int ret = FindByName(pc, name);
    7. if (ret == -1)
    8. {
    9. printf("要查找的联系人不存在\n");
    10. }
    11. else
    12. {
    13. int j = 0;
    14. for (j = ret; j < pc->sz - 1; j++)
    15. {
    16. pc->data[j] = pc->data[j + 1];
    17. }
    18. }
    19. pc->sz--;
    20. printf("成功删除\n");
    21. }

    2.9 查找指定联系人

         先判断联系人是否存在,如果不存在,则输出不存在,如果存在输出此联系人的其他信息。

    1. void SearchContact(struct Contact* pc)
    2. {
    3. char name[MAX];
    4. printf("请输入查找人的名字:\n");
    5. scanf("%s", &name);
    6. int ret = FindByName(pc, name);
    7. if (ret == -1)
    8. {
    9. printf("要查找的联系人不存在\n");
    10. }
    11. else
    12. {
    13. printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
    14. printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[ret].name, pc->data[ret].sex, pc->data[ret].age, pc->data[ret].tele, pc->data[ret].addr);
    15. }
    16. }

    2.10 修改指定联系人

    1. void ModifyContact(struct Contact* pc)
    2. {
    3. char name[MAX];
    4. printf("请输入要修改的人的姓名:\n");
    5. scanf("%s", &name);
    6. int ret = FindByName(pc, name);
    7. if (ret == -1)
    8. {
    9. printf("要修改的联系人不存在\n");
    10. }
    11. else
    12. {
    13. printf("请输入姓名:\n");
    14. scanf("%s", pc->data[pc->sz].name);
    15. printf("请输入性别:\n");
    16. scanf("%s", pc->data[pc->sz].sex);
    17. printf("请输入年龄:\n");
    18. scanf("%d", &pc->data[pc->sz].age);
    19. printf("请输入电话:\n");
    20. scanf("%s", &pc->data[pc->sz].tele);
    21. printf("请输入地址:\n");
    22. scanf("%s", pc->data[pc->sz].addr);
    23. printf("修改成功\n");
    24. }
    25. }

    2.11 对通讯录的数据进行排序

         在这里排序的时候我们使用qsort函数进行排序,关于qsort函数我们在<指针进阶>博客里面详细解释过,不理解的朋友可以回看。

    2.11.1 按照姓名排序

         qsort排序时,我们需要给qsort函数传一个比较函数,按照姓名排序时,我们传的比较函数是CmpByName函数。

    1. int CmpByName(const void* e1, const void* e2)
    2. {
    3. return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
    4. }
    1. void SortContact(struct Contact* pc)
    2. {
    3. qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByName);
    4. }

    2.11.2 按照年龄排序

    1. int CmpByAge(const void* e1, const void* e2)
    2. {
    3. return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
    4. }
    1. void SortContact(struct Contact* pc)
    2. {
    3. qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
    4. //qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByName);
    5. }

    三、分文件的形式

    3.1 test.c文件

    1. #include "contact.h"
    2. void menu()
    3. {
    4. printf("*******************************************************\n");
    5. printf("************ 1.add 2.del ***************\n");
    6. printf("************ 3.search 4.modify ***************\n");
    7. printf("************ 5.show 6.sort ***************\n");
    8. printf("************ 0.exit ***************\n");
    9. printf("*******************************************************\n");
    10. }
    11. int main()
    12. {
    13. int input = 0;
    14. struct Contact con; //创建通讯录
    15. InitContact(&con); //对通讯录初始化
    16. do
    17. {
    18. menu();
    19. printf("请选择:\n");
    20. scanf("%d", &input);
    21. switch (input)
    22. {
    23. case ADD:
    24. AddContact(&con); //在通讯录中增加信息
    25. break;
    26. case DEL:
    27. DelContact(&con); //在通讯录中删除指定联系人
    28. break;
    29. case SEARCH:
    30. SearchContact(&con); //查找指定联系人
    31. break;
    32. case MODIFY:
    33. ModifyContact(&con); //修改指定联系人
    34. break;
    35. case SHOW:
    36. ShowContact(&con); //展示通讯录的内容
    37. break;
    38. case SORT:
    39. SortContact(&con); //对通讯录里的学生按照姓名进行排序
    40. break;
    41. case EXIT:
    42. printf("退出通讯录\n");
    43. break;
    44. default:
    45. printf("输入错误,请重新选择\n");
    46. break;
    47. }
    48. } while (input);
    49. return 0;
    50. }

    3.2 contact.c文件

    1. #include "contact.h"
    2. void InitContact(struct Contact* pc)
    3. {
    4. pc->sz = 0;
    5. memset(pc->data, 0, 100 * sizeof(struct PeoInfo));
    6. }
    7. void AddContact(struct Contact* pc)
    8. {
    9. assert(pc);
    10. //增加信息的前提是通讯录没有满
    11. if (pc->sz == MAX)
    12. {
    13. printf("通讯录已满\n");
    14. return;
    15. }
    16. printf("请输入姓名:\n");
    17. scanf("%s", pc->data[pc->sz].name);
    18. printf("请输入性别:\n");
    19. scanf("%s", pc->data[pc->sz].sex);
    20. printf("请输入年龄:\n");
    21. scanf("%d", &pc->data[pc->sz].age);
    22. printf("请输入电话:\n");
    23. scanf("%s", &pc->data[pc->sz].tele);
    24. printf("请输入地址:\n");
    25. scanf("%s", pc->data[pc->sz].addr);
    26. pc->sz++;
    27. printf("成功添加联系人\n");
    28. }
    29. static int FindByName(struct Contact* pc, char name[])
    30. {
    31. int i = 0;
    32. for (i = 0; i < pc->sz; i++)
    33. {
    34. if (strcmp(pc->data[i].name, name) == 0)
    35. {
    36. return i;
    37. }
    38. }
    39. return -1;
    40. }
    41. void DelContact(struct Contact* pc)
    42. {
    43. printf("请输入联系人的姓名:\n");
    44. char name[20];
    45. scanf("%s", name);
    46. int ret = FindByName(pc, name);
    47. if (ret == -1)
    48. {
    49. printf("要查找的联系人不存在\n");
    50. }
    51. else
    52. {
    53. memmove(&(pc->data[ret]), &(pc->data[ret + 1]), (pc->sz - ret) * sizeof(struct PeoInfo));
    54. }
    55. pc->sz--;
    56. printf("成功删除\n");
    57. }
    58. void DelContact1(struct Contact* pc)
    59. {
    60. printf("请输入联系人的姓名:\n");
    61. char name[20];
    62. scanf("%s", name);
    63. int ret = FindByName(pc, name);
    64. if (ret == -1)
    65. {
    66. printf("要查找的联系人不存在\n");
    67. }
    68. else
    69. {
    70. int j = 0;
    71. for (j = ret; j < pc->sz - 1; j++)
    72. {
    73. pc->data[j] = pc->data[j + 1];
    74. }
    75. }
    76. pc->sz--;
    77. printf("成功删除\n");
    78. }
    79. void ShowContact(struct Contact* pc)
    80. {
    81. int i = 0;
    82. printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
    83. for (i = 0; i < pc->sz; i++)
    84. {
    85. printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
    86. }
    87. }
    88. void SearchContact(struct Contact* pc)
    89. {
    90. char name[MAX];
    91. printf("请输入查找人的名字:\n");
    92. scanf("%s", &name);
    93. int ret = FindByName(pc, name);
    94. if (ret == -1)
    95. {
    96. printf("要查找的联系人不存在\n");
    97. }
    98. else
    99. {
    100. printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
    101. printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[ret].name, pc->data[ret].sex, pc->data[ret].age, pc->data[ret].tele, pc->data[ret].addr);
    102. }
    103. }
    104. void ModifyContact(struct Contact* pc)
    105. {
    106. char name[MAX];
    107. printf("请输入要修改的人的姓名:\n");
    108. scanf("%s", &name);
    109. int ret = FindByName(pc, name);
    110. if (ret == -1)
    111. {
    112. printf("要修改的联系人不存在\n");
    113. }
    114. else
    115. {
    116. printf("请输入姓名:\n");
    117. scanf("%s", pc->data[pc->sz].name);
    118. printf("请输入性别:\n");
    119. scanf("%s", pc->data[pc->sz].sex);
    120. printf("请输入年龄:\n");
    121. scanf("%d", &pc->data[pc->sz].age);
    122. printf("请输入电话:\n");
    123. scanf("%s", &pc->data[pc->sz].tele);
    124. printf("请输入地址:\n");
    125. scanf("%s", pc->data[pc->sz].addr);
    126. printf("修改成功\n");
    127. }
    128. }
    129. int CmpByName(const void* e1, const void* e2)
    130. {
    131. return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
    132. }
    133. int CmpByAge(const void* e1, const void* e2)
    134. {
    135. return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
    136. }
    137. void SortContact(struct Contact* pc)
    138. {
    139. qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
    140. //qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByName);
    141. }

    3.3 contact.h文件

    1. #pragma once
    2. #define _CRT_SECURE_NO_WARNINGS 1
    3. #define MAX 100
    4. #define MAX_NAME 20
    5. #define MAX_SEX 6
    6. #define MAX_TELE 12
    7. #define MAX_ADDR 30
    8. enum Option
    9. {
    10. EXIT, //默认为0
    11. ADD, //1
    12. DEL, //2
    13. SEARCH, //3
    14. MODIFY, //4
    15. SHOW, //5
    16. SORT //6
    17. };
    18. #include
    19. #include
    20. #include
    21. #include
    22. struct PeoInfo
    23. {
    24. char name[MAX_NAME];
    25. char sex[MAX_SEX];
    26. char tele[MAX_TELE];
    27. int age;
    28. char addr[MAX_ADDR];
    29. };
    30. struct Contact
    31. {
    32. struct PeoInfo data[MAX];
    33. int sz;
    34. };
    35. //初始化通讯录
    36. void InitContact(struct Contact * pc);
    37. //在通讯录中增加信息
    38. void AddContact(struct Contact * pc);
    39. //在通讯录中删除指定联系人
    40. void DelContact(struct Contact* pc);
    41. //展示通讯录的内容
    42. void ShowContact(struct Contact* pc);
    43. //查找指定联系人
    44. void SearchContact(struct Contact* pc);
    45. //修改指定联系人
    46. void ModifyContact(struct Contact* pc);
    47. //排序
    48. void SortContact(struct Contact* pc);

    四、代码运行结果

     

  • 相关阅读:
    【嵌入式Linux】开发实践及补充杂文
    wordpress 安装主题显示要配置FTP的解决办法
    深入理解 C 语言的内存管理
    大数据基础问题:在Hive中如何实现全增量统一的UDTF、内置函数、聚合、Join等计算引擎常见算子?
    BrokenPipeError错误和python subprocess.run()超时参数在Windows上无效
    观察者模式、订阅者发布者模式、vtk中的观察者模式
    【STM32系统】基于STM32设计的按键PWM控制舵机窗帘&柜子&门禁&家居等控制系统——文末资料下载
    springboot罗亚方舟考研资料库网站设计与实现毕业设计源码302302
    word已排序好的参考文献,插入新的参考文献,序号更新
    数据分析 第三周 (numpy数组的处理 , numpy数组的运用与画图的结合)笔记
  • 原文地址:https://blog.csdn.net/m0_62692838/article/details/127578193