• C语言之通讯录的实现篇


    目录

    test.c

    主菜单menu

    创建通讯录con

    初始化通讯录InitContact

    增加个人信息AddContact 

    展示个人信息ShowContact

    删除个人信息DelContact

    查找个人信息SearchContact

    修改个人信息ModifyContact

    test.c总代码 

    contact.h

    头文件包含

    PeoInfo_个人信息的设置声明

    Contact_存放个人信息声明

    InitContact_初始化个人信息声明

    AddContact_增加个人信息 

    ShowContact_展示个人信息

    DelContact_删除个人信息

    SearchContact_查找个人信息 

    ModifyContact_修改个人信息

    contact.h总代码 

    contact.c

    InitContact_初始化个人信息

    AddContact_增加个人信息

    ShowContact_展示个人信息

    FindByName查找函数

    DelContact_删除个人信息

    SearchContact_查找个人信息

    ModifyContact_修改个人信息

    contact.c总代码


    今天实现同通讯录的功能。在学习了结构体其他的自定义的类型之后,我们就可以实现一个的通讯录。

    实现一个通讯录:

    1. 可以保存100个人的信息
    2. 增加人的信息
    3. 删除指定联系人的信息
    4. 查找指定联系人的信息
    5. 修改指定联系人的信息
    6. 显示所有联系人的信息
    7. 排序通讯录的信息
    • 一个人的信息包括:名字+年龄+性别+电话+住址

    那接下来我们将从test.c 测试代码  contact.h 声明  contact.c 实现 去实现

    test.c

    主菜单menu

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include"contact.h"
    3. void menu()
    4. {
    5. printf("************************************");
    6. printf("********1.add 2.del************");
    7. printf("********3.search 4.modify*********");
    8. printf("********5.show 6.sort***********");
    9. printf("********0.exit ***********");
    10. printf("************************************");
    11. }
    12. enum Option
    13. {
    14. EXIT,//0
    15. ADD,//1
    16. DEL,//2
    17. SEARCH,//3
    18. MODIFY,//4
    19. SHOW,//5
    20. SORT,//6
    21. };
    22. int main()
    23. {
    24. int input = 0;
    25. Contact con;//创建通讯录con
    26. do
    27. {
    28. menu();
    29. printf("请输入你的选择:>\n");
    30. scanf("%d", &input);
    31. switch (input)//这里为了代码更加清晰用枚举常量
    32. {
    33. case ADD:
    34. break;
    35. case DEL:
    36. break;
    37. case SEARCH:
    38. break;
    39. case MODIFY:
    40. break;
    41. case SHOW:
    42. break;
    43. case SORT:
    44. break;
    45. case EXIT:
    46. printf("退出通讯录\n");
    47. break;
    48. default:
    49. printf("选择错误,请重新选择:>\n");
    50. break;
    51. }
    52. } while (input);
    53. return 0;
    54. }
    •  菜单是根据用户需求而设计
    •  使用枚举常量 为了让程序员写代码 更加清晰

    创建通讯录con

    Contact con;//创建通讯录con

    初始化通讯录InitContact

    InitContact(&con);

    这里需要特别注意的是,结构体传参到底是传值还是传地址??🆗忘了小朋友戳一戳

     C语言之结构体篇_唐唐思的博客-CSDN博客

    增加个人信息AddContact 

    AddContact(&con);

    展示个人信息ShowContact

    ShowContact(&con);//即使这里不需要& 但是出于效率考虑还是需要

    删除个人信息DelContact

    DelContact(&con);

    查找个人信息SearchContact

    SearchContact(&con);

    修改个人信息ModifyContact

    ModifyContact(&con);

    test.c总代码 

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include"contact.h"
    3. void menu()
    4. {
    5. printf("************************************\n");
    6. printf("********1.add 2.del************\n");
    7. printf("********3.search 4.modify*********\n");
    8. printf("********5.show 6.sort***********\n");
    9. printf("********0.exit ***********\n");
    10. printf("************************************\n");
    11. }
    12. enum Option
    13. {
    14. EXIT,//0
    15. ADD,//1
    16. DEL,//2
    17. SEARCH,//3
    18. MODIFY,//4
    19. SHOW,//5
    20. SORT,//6
    21. };
    22. int main()
    23. {
    24. int input = 0;
    25. //创建通讯录
    26. Contact con;
    27. //初始化通讯录
    28. InitContact(&con);
    29. do
    30. {
    31. menu();
    32. printf("请输入你的选择:>\n");
    33. scanf("%d", &input);
    34. switch (input)//这里为了代码更加清晰用枚举常量
    35. {
    36. case ADD:
    37. AddContact(&con);
    38. break;
    39. case DEL:
    40. DelContact(&con);
    41. break;
    42. case SEARCH:
    43. SearchContact(&con);
    44. break;
    45. case MODIFY:
    46. ModifyContact(&con);
    47. break;
    48. case SHOW:
    49. ShowContact(&con);
    50. break;
    51. case SORT:
    52. //SortContact(&con);
    53. break;
    54. case EXIT:
    55. printf("退出通讯录\n");
    56. break;
    57. default:
    58. printf("选择错误,请重新选择:>\n");
    59. break;
    60. }
    61. } while (input);
    62. return 0;
    63. }

    contact.h

    contact.h文件主要是头文件的包含

    头文件包含

    在我们写代码的过程中,会调用库函数,需要包含头文件,和声明函数。

    所以我们将所有函数声明和头文件放到我们.h 文件中。

    当然,在其他.c文件需要使用时,我们只需要包含 我们创造的 头文件"contact.h" 即可

    • 自己创建的头文件用" " 双引号,库函数的头文件用< >
    1. #pragma once
    2. #include
    3. #include
    4. #include

             

    PeoInfo_个人信息的设置声明

    我们怎样去设置一个人的全部信息呢?姓名+年龄+性别+电话+住址 都是需要不同类型的变量去设置,所以我们把它们都放到【结构体】里面。

    1. #define NAME_MAX 20
    2. #define SEX_MAX 20
    3. #define TELE_MAX 20
    4. #define ADDR_MAX 20
    5. typedef struct PeoInfo
    6. {
    7. char name[NAME_MAX];
    8. int age;
    9. char sex[SEX_MAX];
    10. char tele[TELE_MAX];
    11. char addr[ADDR_MAX];
    12. }PeoInfo;
    • typedef是定义结构体类型由struct PeoInfo---> PeoInfo (这样后面使用定义变量时类型就直接写PeoInfo就可以了)
    • 数组【】里面如果是常量 那就后期想修改是非常不方便的,所以我们自己定义NAME_MAX等,后期修改起来更加方便。

    Contact_存放个人信息声明

    如果我想存放100个人的信息,那我们怎样去存放100个人的信息呢?用结构体数组(所谓就是存放结构体类型变量的数组)

    1. #define MAX 100
    2. typedef struct Contact
    3. {
    4. PeoInfo data[MAX];//存放数据
    5. int sz;//记录当前通讯录中存放的人的信息个数
    6. }Contact;//通讯录
    • typedef是定义结构体类型由struct Contact---> Contact (这样后面使用定义变量时类型就直接写Contact就可以了)
    • 数组【】里面如果是常量 那就后期想修改是非常不方便的,所以我们自己定义MAX等,后期修改起来更加方便。
    • 可以通俗理解为:一个结构体类型的数组data里面存放一个一个的结构体数据。一个结构体类型的数据就是PeoInfo

    InitContact_初始化个人信息声明

    初步创建完成我们的通讯录,那我们调试发现通讯录里面全是随机值,所以我们需要封装一个函数去初始化个人信息。

    void InitContact(Contact* pc);

    AddContact_增加个人信息 

    void AddContact(Contact* pc);

    ShowContact_展示个人信息

    void ShowContact(Contact* pc);

    DelContact_删除个人信息

    void DelContact(Contact *pc);

    SearchContact_查找个人信息 

    void SearchContact(Contact* pc);

    ModifyContact_修改个人信息

    void ModifyContact(Contact* pc);

    contact.h总代码 

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #define NAME_MAX 20
    6. #define SEX_MAX 20
    7. #define TELE_MAX 20
    8. #define ADDR_MAX 30
    9. #define MAX 100
    10. typedef struct PeoInfo
    11. {
    12. char name[NAME_MAX];
    13. int age;
    14. char sex[SEX_MAX];
    15. char tele[TELE_MAX];
    16. char addr[ADDR_MAX];
    17. }PeoInfo;
    18. typedef struct Contact
    19. {
    20. PeoInfo data[MAX];//存放数据
    21. int sz;//记录当前通讯录中存放的人的信息个数
    22. }Contact;
    23. //初始化通讯录
    24. void InitContact(Contact* pc);
    25. //增加个人信息
    26. void AddContact(Contact* pc);
    27. //展示个人信息
    28. void ShowContact(Contact* pc);
    29. //删除个人信息
    30. void DelContact(Contact *pc);
    31. //查找个人信息
    32. void SearchContact(Contact* pc);
    33. //修改个人信息
    34. void ModifyContact(Contact* pc);
    35. //排序
    36. //void SortContact(Contact* pc);

    contact.c

    InitContact_初始化个人信息

    1. void InitContact(Contact* pc)
    2. {
    3. assert(pc);
    4. pc->sz = 0;
    5. memset(pc->data, 0, sizeof(pc->data));
    6. }
    • 传地址的结构体访问两种方式:->    *( ). 
    • 关于memset内存函数的复习,戳一戳:C语言之内存函数篇(3)_唐唐思的博客-CSDN博客
    •  data是数组名 访问数组名即访问数组的第一个元素,单独放在sizeof里面,整个数组的大小
    •  不要遗忘assert去断言,这里要修改pc指向的空间修改,所以不需要const修饰。

    完成了我们的通讯录的初始化,感觉要长脑子了。 接下来一步一步实现它的功能。

    AddContact_增加个人信息

    首先,这幅图想说明: data的下标和sz的数值是对应的

    1. void AddContact(Contact* pc)
    2. {
    3. assert(pc);
    4. printf("请输入名字\n");
    5. scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&
    6. printf("请输入年龄\n");
    7. scanf("%d", &(pc->data[pc->sz].age));//
    8. printf("请输入性别\n");
    9. scanf("%s", pc->data[pc->sz].sex);
    10. printf("请输入电话\n");
    11. scanf("%s", pc->data[pc->sz].tele);
    12. printf("请输入地址\n");
    13. scanf("%s", pc->data[pc->sz].addr);
    14. //
    15. pc->sz++;
    16. printf("增加成功\n");
    17. }
    • scanf输入 %d %s
    • scanf输入& 
    • 结构体访问成员

    ShowContact_展示个人信息

    我们改动了通讯录之后,我们都需要去观察一下通讯录,这个时候需要封装函数去实现这个功能 

    1. void ShowContact(const Contact* pc)
    2. {
    3. assert(pc);
    4. if (pc->sz == 0)
    5. {
    6. printf("通讯录为空,无需打印\n");
    7. return 0;
    8. }
    9. int i = 0;
    10. //名字 年龄 性别 电话 地址
    11. //-左对齐
    12. //20是需要20字符的位置来放名字
    13. printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
    14. for (i = 0; i < pc->sz; i++)
    15. {
    16. printf("%-20s%-5d%-5s%-12s%-30s\n",
    17. pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
    18. }
    • const 和 assert
    • 结构体的访问
    •  一定要判断一下通讯录里的是否有数据
    • 格式美观:%-20s  是左对齐20个字符的空间大小
    • %s %d

    FindByName查找函数

    关于查找个人信息函数,我们在删除,查找,修改里面都会用的。

    1. static int FindByName(const Contact* pc, char name[])
    2. {
    3. assert(pc);
    4. int i = 0;
    5. for (i = 0; i < pc->sz; i++)
    6. {
    7. if (strcmp(pc->data[i].name, name) == 0)//遍历一边看是否有相同的名字
    8. {
    9. return i;
    10. }
    11. }
    12. return -1;
    13. }
    • const修饰的指针,assert判断
    • 使用strcmp函数去判断两个字符串是否相等,大小关系 
    • 查找就是把通讯录遍历一遍,找到了就返回下标,找不到就返回-1

    DelContact_删除个人信息

    删除联系人,我们首先需要找到联系人,我们就去封装一个查找的函数【FindByname】:把通讯录遍历一遍,找到了就返回下标,找不到就返回-1。其实我们发现后面 查找 修改 删除的功能都需要用这个函数。

    1. void DelContact(Contact* pc)//删除
    2. {
    3. char name[NAME_MAX];//
    4. assert(pc);
    5. if (pc->sz == 0)
    6. {
    7. printf("通讯录为空,无法删除\n");
    8. return;
    9. }
    10. printf("输入要删除的名字:>");
    11. scanf("%s", name);
    12. int ret = FindByName(pc, name);
    13. if (ret == -1)
    14. {
    15. printf("要删除的人不存在\n");
    16. return;
    17. }
    18. //存在返回这个人的所在data的下标放入ret
    19. int i = 0;
    20. for (i = ret; i < pc -> sz - 1; i++)//注意不要数组越界
    21. {
    22. pc->data[i] = pc->data[i + 1];
    23. }
    24. pc->sz--;
    25. printf("删除成功\n");
    26. }
    • 返回的下标被ret接收,要使用起来,从把下标为ret删除(方法:后面依次覆盖和移动往前) 
    • 注意不要数组越界访问,函数内部 i 值还要+1 可能会造成越界。
    • 如果要删除最后一个数据,直接sz--即可。

     

    SearchContact_查找个人信息

    1. void SearchContact(Contact* pc)
    2. {
    3. char name[NAME_MAX];
    4. assert(pc);
    5. //查找
    6. printf("输入要查找的名字:>");
    7. scanf("%s", name);
    8. int ret = FindByName(pc, name);
    9. if (ret == -1)
    10. {
    11. printf("要查找的人不存在\n");
    12. return;
    13. }
    14. //显示
    15. printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
    16. printf("%-20s%-5d%-5s%-12s%-30s\n",
    17. pc->data[ret].name, pc->data[ret].age,
    18. pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
    19. }//打印的是下标为ret里的元素数据
    •  打印的是下标为ret里的元素数据

    ModifyContact_修改个人信息

    1. void ModifyContact(Contact* pc)
    2. {
    3. char name[NAME_MAX];
    4. assert(pc);
    5. //查找
    6. printf("输入要修改的名字:>");
    7. scanf("%s", name);
    8. int ret = FindByName(pc, name);
    9. if (ret == -1)
    10. {
    11. printf("要修改的人不存在\n");
    12. return;
    13. }
    14. //修改
    15. assert(pc);
    16. printf("请输入名字\n");
    17. scanf("%s", pc->data[ret].name);//name是数组名,不用&
    18. printf("请输入年龄\n");
    19. scanf("%s", &(pc->data[ret].age));
    20. printf("请输入性别\n");
    21. scanf("%s", pc->data[ret].sex);
    22. printf("请输入电话\n");
    23. scanf("%s", pc->data[ret].tele);
    24. printf("请输入地址\n");
    25. scanf("%s", pc->data[ret].addr);
    26. printf("修改成功\n");
    27. }//下标是ret的数组元素内的数据被修改
    • 下标是ret的数组元素内的数据被修改 

    contact.c总代码

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include"contact.h"
    3. //初始化
    4. void InitContact(Contact* pc)
    5. {
    6. assert(pc);
    7. pc->sz = 0;
    8. memset(pc->data, 0, sizeof(pc->data));
    9. }
    10. //增加
    11. void AddContact(Contact* pc)
    12. {
    13. assert(pc);
    14. printf("请输入名字\n");
    15. scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&
    16. printf("请输入年龄\n");
    17. scanf("%d", &(pc->data[pc->sz].age));//
    18. printf("请输入性别\n");
    19. scanf("%s", pc->data[pc->sz].sex);
    20. printf("请输入电话\n");
    21. scanf("%s", pc->data[pc->sz].tele);
    22. printf("请输入地址\n");
    23. scanf("%s", pc->data[pc->sz].addr);
    24. pc->sz++;
    25. printf("增加成功\n");
    26. }
    27. //展示
    28. void ShowContact(const Contact* pc)
    29. {
    30. assert(pc);
    31. if (pc->sz == 0)
    32. {
    33. printf("通讯录为空,无需打印\n");
    34. return 0;
    35. }
    36. int i = 0;
    37. //名字 年龄 性别 电话 地址
    38. //-左对齐
    39. //20是需要20字符的位置来放名字
    40. printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
    41. for (i = 0; i < pc->sz; i++)
    42. {
    43. printf("%-20s%-5d%-5s%-12s%-30s\n",
    44. pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
    45. }
    46. }
    47. //删除,查找,修改都需要使用
    48. int FindByName(const Contact* pc, char name[])
    49. {
    50. assert(pc);
    51. int i = 0;
    52. for (i = 0; i < pc->sz; i++)
    53. {
    54. if (strcmp(pc->data[i].name, name) == 0)
    55. {
    56. return i;
    57. }
    58. }
    59. return -1;
    60. }
    61. //删除
    62. void DelContact(Contact* pc)
    63. {
    64. char name[NAME_MAX];
    65. assert(pc);
    66. if (pc->sz == 0)
    67. {
    68. printf("通讯录为空,无法删除\n");
    69. return;
    70. }
    71. printf("输入要删除的名字:>");
    72. scanf("%s", name);
    73. int ret = FindByName(pc, name);
    74. if (ret == -1)
    75. {
    76. printf("要删除的人不存在\n");
    77. return;
    78. }
    79. //存在返回这个人的所在data的下标放入ret
    80. int i = 0;
    81. for (i = ret; i < pc -> sz - 1; i++)
    82. {
    83. pc->data[i] = pc->data[i + 1];
    84. }
    85. pc->sz--;
    86. printf("删除成功\n");
    87. }
    88. //查找
    89. void SearchContact(Contact* pc)
    90. {
    91. char name[NAME_MAX];
    92. assert(pc);
    93. if (pc->sz == 0)
    94. {
    95. printf("通讯录为空,无法查找\n");
    96. return;
    97. }
    98. //查找
    99. printf("输入要查找的名字:>");
    100. scanf("%s", name);
    101. int ret = FindByName(pc, name);
    102. if (ret == -1)
    103. {
    104. printf("要查找的人不存在\n");
    105. return;
    106. }
    107. //返回下标显示这个的信息🆗
    108. printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
    109. printf("%-20s%-5d%-5s%-12s%-30s\n",
    110. pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
    111. }
    112. //修改
    113. void ModifyContact(Contact* pc)
    114. {
    115. char name[NAME_MAX];
    116. assert(pc);
    117. if (pc->sz == 0)
    118. {
    119. printf("通讯录为空,无法修改\n");
    120. return;
    121. }
    122. //查找
    123. printf("输入要修改的名字:>");
    124. scanf("%s", name);
    125. int ret = FindByName(pc, name);
    126. if (ret == -1)
    127. {
    128. printf("要修改的人不存在\n");
    129. return;
    130. }
    131. //修改
    132. assert(pc);
    133. printf("请输入名字\n");
    134. scanf("%s", pc->data[ret].name);//name是数组名,不用&
    135. printf("请输入年龄\n");
    136. scanf("%d", &(pc->data[ret].age));//
    137. printf("请输入性别\n");
    138. scanf("%s", pc->data[ret].sex);
    139. printf("请输入电话\n");
    140. scanf("%s", pc->data[ret].tele);
    141. printf("请输入地址\n");
    142. scanf("%s", pc->data[ret].addr);
    143. printf("修改成功\n");
    144. }

    信息太多,空间小了;信息太少,空间大了。怎么解决呢?动态内存管理!录入的个人信息,等程序结束之后,就不在了。因为数据是存放在内存中的,只要程序退出,掉电,都会丢失。怎么解决?文件存储,数据库。

    • 排序功能(名字和年龄排序两个方面)
    • 动态内存函数优化通讯录
    • C语言文件操作优化通讯录

    这个等到我们学习完动态内存和文件操作再去讲解。 ✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!希望大家都有好好学习,好好敲代码。好好生活哦。🆗

    代码------→【gitee:唐棣棣 (TSQXG) - Gitee.com

    联系------→【邮箱:2784139418@qq.com】

  • 相关阅读:
    CDH 09Cloudera Manager Kerberos安装配置(markdown新版二)
    如何看待程序员不写注释
    学习SpringSecurity这一篇就够了
    【深入浅出Spring原理及实战】「源码调试分析」深入源码探索Spring底层框架的的refresh方法所出现的问题和异常
    kubesphere 一键部署K8Sv1.21.5版本
    GaussDB数据库SQL系列-层次递归查询
    李飞飞:云原生数据库是大势所趋
    PHP8的类与对象的基本操作之成员方法-PHP8知识详解
    【云原生系列第五章】---Serverless架构中如何避免冷启动带来的影响
    shell之ipcrm命令
  • 原文地址:https://blog.csdn.net/m0_74841364/article/details/133615543