• c语言:通讯录管理系统(动态分配内存版)


    前言:通讯录管理系统一共三个版本,除此文章以外还有如下俩个版本,大家可以根据需求自取:

    基础增删查改功能版本c语言:通讯录管理系统(增删查改)_luming.02的博客-CSDN博客

    文件保存版本c语言:通讯录管理系统(文件版本)-CSDN博客

            本文是在基础的通讯录管理系统上进行改进(文末有完整代码,欢迎大家使用),如果对于基础的通讯录管理系统有什么不懂的地方,可以参考笔者的上一篇文章 

    目录

    一.基础静态版本 (改进前)

    头文件部分

    函数实现部分

    主函数部分

    二.结构体的更改

    三.扩容的设计

    四.释放空间

    五.最终完整代码 (改进后)

    头文件部分

    函数的实现部分 

    主函数部分


    一.基础静态版本 (改进前)

    这里我们给出基础版本的代码,然后本文后续内容都是基于此进行改进

    我们分为 3 个文件来设计:

    • Contact.h: 包含头文件的声明,对函数的声明,以及宏的申明
    • Contact.cpp: 通讯录管理系统中具体每一个函数的实现
    • test.cpp: 主函数,根据用户的选择进行调用相应的函数

    头文件部分(Contact.h

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #define Name_Max 20
    6. #define Tel_Number 12
    7. #define Sex_Max 5
    8. #define Address_Max 30
    9. #define Contact_Max 100
    10. //联系人结构体
    11. typedef struct PeopleInformation
    12. {
    13. char name[Name_Max];
    14. char telnumber[Tel_Number];
    15. int age;
    16. char sex[Sex_Max];
    17. char address[Address_Max];
    18. }PeoInfor;
    19. //通讯录结构体
    20. typedef struct Contact
    21. {
    22. PeoInfor data[Contact_Max];//结构体数组存放联系人结构体
    23. int size;//记录当前通讯录中有多少个联系人
    24. }Contact;
    25. //目录
    26. void menu();
    27. //初始化通讯录
    28. void InitContact(Contact* cp);
    29. //增加联系人
    30. void AddContact(Contact* cp);
    31. //删除联系人
    32. void DelContact(Contact* cp);
    33. //通过姓名进行查找联系人
    34. int FindPeople(Contact* cp, char name[]);
    35. //展示全部通讯录信息
    36. void ShowContact(const Contact* cp);
    37. //查询联系人
    38. void SeachPeople(Contact* cp);
    39. //修改联系人信息
    40. void ModifyContact(Contact* cp);

    函数实现部分(Contact.cpp

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "Contact.h"
    3. void menu()
    4. {
    5. printf("\n");
    6. printf("-----------------------------\n");
    7. printf("--- 1.添加联系人 -----\n");
    8. printf("--- 2.删除联系人 -----\n");
    9. printf("--- 3.查找联系人 -----\n");
    10. printf("--- 4.修改联系人信息 -----\n");
    11. printf("--- 5.显示全部信息 -----\n");
    12. printf("--- 0.退出通讯录 -----\n");
    13. printf("-----------------------------\n");
    14. }
    15. //初始化通讯录
    16. void InitContact(Contact* cp)
    17. {
    18. //判断非空
    19. assert(cp);
    20. cp->size = 0;
    21. memset(cp->data, 0, sizeof(cp->data));
    22. }
    23. //增加联系人
    24. void AddContact(Contact* cp)
    25. {
    26. //判断非空
    27. assert(cp);
    28. //判断未满
    29. if (cp->size == Contact_Max)
    30. {
    31. printf("通讯录已满,无法再添加新的联系人\n");
    32. return;
    33. }
    34. printf("请输入要添加的联系人的姓名:\n");
    35. scanf("%s", cp->data[cp->size].name);
    36. printf("请输入要添加的联系人的电话号:\n");
    37. scanf("%s", cp->data[cp->size].telnumber);
    38. printf("请输入要添加的联系人的年龄:\n");
    39. scanf("%d", &(cp->data[cp->size].age));
    40. printf("请输入要添加的联系人的性别:\n");
    41. scanf("%s", cp->data[cp->size].sex);
    42. printf("请输入要添加的联系人的住址:\n");
    43. scanf("%s", cp->data[cp->size].address);
    44. cp->size++;
    45. printf("添加成功\n");
    46. }
    47. //通过姓名进行查找联系人
    48. int FindPeople(Contact* cp, char name[])
    49. {
    50. assert(cp);
    51. for (int i = 0; i < cp->size; i++)
    52. {
    53. if (strcmp(cp->data[i].name, name) == 0)
    54. {
    55. return i;
    56. }
    57. }
    58. return -1;
    59. }
    60. //删除联系人
    61. void DelContact(Contact* cp)
    62. {
    63. assert(cp);
    64. char name[Name_Max];
    65. if (cp->size == 0)
    66. {
    67. printf("通讯录为空,无需删除\n");
    68. return;
    69. }
    70. printf("请输入选择删除的联系人的姓名:\n");
    71. scanf("%s", name);
    72. int ret = FindPeople(cp, name);
    73. if (ret == -1)
    74. {
    75. printf("要删除的联系人不存在\n");
    76. return;
    77. }
    78. for (int i = ret; i < cp->size-1 ; i++)
    79. {
    80. cp->data[i] = cp->data[i + 1];
    81. }
    82. cp->size--;
    83. printf("删除成功\n");
    84. }
    85. //查询联系人
    86. void SeachPeople(Contact* cp)
    87. {
    88. assert(cp);
    89. char name[Name_Max];
    90. if (cp->size == 0)
    91. {
    92. printf("通讯录为空\n");
    93. return;
    94. }
    95. printf("请输入选择查找的联系人的姓名:\n");
    96. scanf("%s", name);
    97. int ret = FindPeople(cp, name);
    98. if (ret == -1)
    99. {
    100. printf("要查找的联系人不存在\n");
    101. return;
    102. }
    103. //名字 年龄 性别 电话 地址
    104. //xxx xxx xxx xxx xxx
    105. printf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
    106. //打印个人的信息
    107. printf("%-10s%-5d%-5s%-12s%-30s\n", cp->data[ret].name, cp->data[ret].age, cp->data[ret].sex, cp->data[ret].telnumber, cp->data[ret].address);
    108. }
    109. //展示全部通讯录信息
    110. void ShowContact(const Contact* cp)
    111. {
    112. assert(cp);
    113. if (cp->size == 0)
    114. {
    115. printf("通讯录为空\n");
    116. return;
    117. }
    118. //名字 年龄 性别 电话 地址
    119. //xxx xxx xxx xxx xxx
    120. printf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
    121. for (int i = 0; i < cp->size; i++)
    122. {
    123. //打印每个人的信息
    124. printf("%-10s%-5d%-5s%-12s%-30s\n",cp->data[i].name, cp->data[i].age, cp->data[i].sex, cp->data[i].telnumber, cp->data[i].address);
    125. }
    126. }
    127. //修改联系人信息
    128. void ModifyContact(Contact* cp)
    129. {
    130. assert(cp);
    131. char name[Name_Max];
    132. if (cp->size == 0)
    133. {
    134. printf("通讯录为空\n");
    135. return;
    136. }
    137. printf("请输入选择修改的联系人的姓名:\n");
    138. scanf("%s", name);
    139. int ret = FindPeople(cp, name);
    140. if (ret == -1)
    141. {
    142. printf("要修改的联系人信息不存在\n");
    143. return;
    144. }
    145. printf("请输入要修改的联系人的姓名:\n");
    146. scanf("%s", cp->data[ret].name);
    147. printf("请输入要修改的联系人的电话号:\n");
    148. scanf("%s", cp->data[ret].telnumber);
    149. printf("请输入要修改的联系人的年龄:\n");
    150. scanf("%d", &(cp->data[ret].age));
    151. printf("请输入要修改的联系人的性别:\n");
    152. scanf("%s", cp->data[ret].sex);
    153. printf("请输入要修改的联系人的住址:\n");
    154. scanf("%s", cp->data[ret].address);
    155. printf("修改成功\n");
    156. }

    主函数部分(test.cpp

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "Contact.h"
    3. //枚举,增加程序的可读性
    4. enum options
    5. {
    6. EXIT,
    7. ADD,
    8. DEL,
    9. SEACH,
    10. MODIFY,
    11. SHOW
    12. };
    13. int main()
    14. {
    15. int input = 0;
    16. //创建通讯录
    17. Contact con;
    18. //初始化通讯录
    19. InitContact(&con);
    20. do
    21. {
    22. menu();
    23. printf("请输入你的选择: ");
    24. scanf("%d", &input);
    25. switch (input)
    26. {
    27. //增加联系人信息
    28. case ADD:
    29. AddContact(&con);
    30. break;
    31. //删除联系人信息
    32. case DEL:
    33. DelContact(&con);
    34. break;
    35. //查找某个联系人的信息
    36. case SEACH:
    37. SeachPeople(&con);
    38. break;
    39. //修改某个联系人的信息
    40. case MODIFY:
    41. ModifyContact(&con);
    42. break;
    43. //展示通讯录内的每一个联系人的信息
    44. case SHOW:
    45. ShowContact(&con);
    46. break;
    47. //退出通讯录管理系统
    48. case EXIT:
    49. printf("通讯录已退出\n");
    50. break;
    51. //预防非法输入
    52. default:
    53. printf("输入错误,请重新输入\n");
    54. break;
    55. }
    56. }while(input);
    57. return 0;
    58. }

    二.结构体的更改

            动态的分配内存就意味着通讯录这个结构体要动态的分配内存,根据通讯录内的信息进行分配,所以我们在这里对于通讯录结构体进行更改

    1. //通讯录结构体
    2. typedef struct Contact
    3. {
    4. PeoInfor* data;//结构体数组存放联系人结构体
    5. int size;//记录当前通讯录中有多少个联系人
    6. int capacity;//记录当前存放的容量
    7. }Contact;
    •         在这里我们将 data 从一个结构体数组改成了结构体指针,然后后续再使用 这个指针指向我们动态开辟的内存就完成了我们的需求设计
    •         并且新增了个变量 capacity 用来记录当前通讯录内的最大容量,当联系人的数量和容量相同的时候,也就是通讯录满容的时候,我们再使用 realloc 重新分配新的内存空间

    三.扩容的设计

            我们封装一个函数方便我们添加新的联系人的时候进行扩容,先判断当前通讯录是否已满,如果满了就进行扩容,每一次扩容扩展 2 个联系人结构体的大小

    •         首先是判断部分,当当前通讯录的容量等于通讯录内实际存放的数据的大小的时候,我们就判定为通讯录已满,然后我们使用 realloc 开辟新的空间,比之前大 2 个联系人结构体的大小
    •         为了程序的健全性,我们也要判断开辟空间是否成功,如果成功就通过 ptr指针 指向联系人的数据部分,用 data 接收,如果开辟失败,我们就打印报错信息
    1. void CheckContact(Contact* cp)
    2. {
    3. if (cp->size == cp->capacity)
    4. {
    5. PeoInfor* ptr = (PeoInfor*)realloc(cp->data, (cp->capacity + 2) * sizeof(PeoInfor));
    6. if (ptr != NULL)
    7. {
    8. cp->data = ptr;
    9. cp->capacity += 2;
    10. printf("增容成功\n");
    11. }
    12. else
    13. {
    14. perror("AddContact->realloc");
    15. return;
    16. }
    17. }
    18. }

    四.释放空间

            由程序员申请开辟的空间也应当由程序员设置进行释放,在这个通讯录管理系统中也是如此,我们需要找到合适的释放位置,也就是当用户退出通讯录的时候,我们手动进行对开辟的空间进行释放,以避免造成内存泄漏

            那我们这里就封装一个释放空间的函数:

    1. //销毁通讯录
    2. void DestoryContact(Contact* cp)
    3. {
    4. free(cp->data);
    5. cp->data = NULL;
    6. cp->size = 0;
    7. cp->capacity = 0;
    8. }

    五.最终完整代码 (改进后)

    头文件部分(Contact.h:

    1. #pragma once
    2. #pragma once
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define Name_Max 20
    8. #define Tel_Number 12
    9. #define Sex_Max 5
    10. #define Address_Max 30
    11. #define Contact_Max 100
    12. #define Contact_SZ 3
    13. //联系人结构体
    14. typedef struct PeopleInformation
    15. {
    16. char name[Name_Max];
    17. char telnumber[Tel_Number];
    18. int age;
    19. char sex[Sex_Max];
    20. char address[Address_Max];
    21. }PeoInfor;
    22. //通讯录结构体
    23. typedef struct Contact
    24. {
    25. PeoInfor* data;//结构体数组存放联系人结构体
    26. int size;//记录当前通讯录中有多少个联系人
    27. int capacity;//记录当前存放的容量
    28. }Contact;
    29. //目录
    30. void menu();
    31. //初始化通讯录
    32. void InitContact(Contact* cp);
    33. //增加联系人
    34. void AddContact(Contact* cp);
    35. //删除联系人
    36. void DelContact(Contact* cp);
    37. //通过姓名进行查找联系人
    38. int FindPeople(Contact* cp, char name[]);
    39. //展示全部通讯录信息
    40. void ShowContact(const Contact* cp);
    41. //查询联系人
    42. void SeachPeople(Contact* cp);
    43. //修改联系人信息
    44. void ModifyContact(Contact* cp);
    45. //扩容
    46. void CheckContact(Contact* cp);
    47. //销毁通讯录
    48. void DestoryContact(Contact* cp);

    函数的实现部分 (Contact.cpp

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "Contact.h"
    3. void menu()
    4. {
    5. printf("\n");
    6. printf("-----------------------------\n");
    7. printf("--- 1.添加联系人 -----\n");
    8. printf("--- 2.删除联系人 -----\n");
    9. printf("--- 3.查找联系人 -----\n");
    10. printf("--- 4.修改联系人信息 -----\n");
    11. printf("--- 5.显示全部信息 -----\n");
    12. printf("--- 0.退出通讯录 -----\n");
    13. printf("-----------------------------\n");
    14. }
    15. //初始化通讯录
    16. void InitContact(Contact* cp)
    17. {
    18. //判断非空
    19. assert(cp);
    20. cp->size = 0;
    21. cp->capacity = Contact_SZ;
    22. cp->data =(PeoInfor*)calloc(cp->capacity, sizeof(PeoInfor));
    23. if (cp->data == NULL)
    24. {
    25. perror("InitContact->calloc");
    26. return;
    27. }
    28. }
    29. void CheckContact(Contact* cp)
    30. {
    31. if (cp->size == cp->capacity)
    32. {
    33. PeoInfor* ptr = (PeoInfor*)realloc(cp->data, (cp->capacity + 2) * sizeof(PeoInfor));
    34. if (ptr != NULL)
    35. {
    36. cp->data = ptr;
    37. cp->capacity += 2;
    38. printf("增容成功\n");
    39. }
    40. else
    41. {
    42. perror("AddContact->realloc");
    43. return;
    44. }
    45. }
    46. }
    47. //增加联系人
    48. void AddContact(Contact* cp)
    49. {
    50. //判断非空
    51. assert(cp);
    52. //判断满后扩容
    53. CheckContact(cp);
    54. printf("请输入要添加的联系人的姓名:\n");
    55. scanf("%s", cp->data[cp->size].name);
    56. printf("请输入要添加的联系人的电话号:\n");
    57. scanf("%s", cp->data[cp->size].telnumber);
    58. printf("请输入要添加的联系人的年龄:\n");
    59. scanf("%d", &(cp->data[cp->size].age));
    60. printf("请输入要添加的联系人的性别:\n");
    61. scanf("%s", cp->data[cp->size].sex);
    62. printf("请输入要添加的联系人的住址:\n");
    63. scanf("%s", cp->data[cp->size].address);
    64. cp->size++;
    65. printf("添加成功\n");
    66. }
    67. //通过姓名进行查找联系人
    68. int FindPeople(Contact* cp, char name[])
    69. {
    70. assert(cp);
    71. for (int i = 0; i < cp->size; i++)
    72. {
    73. if (strcmp(cp->data[i].name, name) == 0)
    74. {
    75. return i;
    76. }
    77. }
    78. return -1;
    79. }
    80. //删除联系人
    81. void DelContact(Contact* cp)
    82. {
    83. assert(cp);
    84. char name[Name_Max];
    85. if (cp->size == 0)
    86. {
    87. printf("通讯录为空,无需删除\n");
    88. return;
    89. }
    90. printf("请输入选择删除的联系人的姓名:\n");
    91. scanf("%s", name);
    92. int ret = FindPeople(cp, name);
    93. if (ret == -1)
    94. {
    95. printf("要删除的联系人不存在\n");
    96. return;
    97. }
    98. for (int i = ret; i < cp->size - 1; i++)
    99. {
    100. cp->data[i] = cp->data[i + 1];
    101. }
    102. cp->size--;
    103. printf("删除成功\n");
    104. }
    105. //查询联系人
    106. void SeachPeople(Contact* cp)
    107. {
    108. assert(cp);
    109. char name[Name_Max];
    110. if (cp->size == 0)
    111. {
    112. printf("通讯录为空\n");
    113. return;
    114. }
    115. printf("请输入选择查找的联系人的姓名:\n");
    116. scanf("%s", name);
    117. int ret = FindPeople(cp, name);
    118. if (ret == -1)
    119. {
    120. printf("要查找的联系人不存在\n");
    121. return;
    122. }
    123. //名字 年龄 性别 电话 地址
    124. //xxx xxx xxx xxx xxx
    125. printf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
    126. //打印个人的信息
    127. printf("%-10s%-5d%-5s%-12s%-30s\n", cp->data[ret].name, cp->data[ret].age, cp->data[ret].sex, cp->data[ret].telnumber, cp->data[ret].address);
    128. }
    129. //展示全部通讯录信息
    130. void ShowContact(const Contact* cp)
    131. {
    132. assert(cp);
    133. if (cp->size == 0)
    134. {
    135. printf("通讯录为空\n");
    136. return;
    137. }
    138. //名字 年龄 性别 电话 地址
    139. //xxx xxx xxx xxx xxx
    140. printf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
    141. for (int i = 0; i < cp->size; i++)
    142. {
    143. //打印每个人的信息
    144. printf("%-10s%-5d%-5s%-12s%-30s\n", cp->data[i].name, cp->data[i].age, cp->data[i].sex, cp->data[i].telnumber, cp->data[i].address);
    145. }
    146. }
    147. //修改联系人信息
    148. void ModifyContact(Contact* cp)
    149. {
    150. assert(cp);
    151. char name[Name_Max];
    152. if (cp->size == 0)
    153. {
    154. printf("通讯录为空\n");
    155. return;
    156. }
    157. printf("请输入选择修改的联系人的姓名:\n");
    158. scanf("%s", name);
    159. int ret = FindPeople(cp, name);
    160. if (ret == -1)
    161. {
    162. printf("要修改的联系人信息不存在\n");
    163. return;
    164. }
    165. printf("请输入要修改的联系人的姓名:\n");
    166. scanf("%s", cp->data[ret].name);
    167. printf("请输入要修改的联系人的电话号:\n");
    168. scanf("%s", cp->data[ret].telnumber);
    169. printf("请输入要修改的联系人的年龄:\n");
    170. scanf("%d", &(cp->data[ret].age));
    171. printf("请输入要修改的联系人的性别:\n");
    172. scanf("%s", cp->data[ret].sex);
    173. printf("请输入要修改的联系人的住址:\n");
    174. scanf("%s", cp->data[ret].address);
    175. printf("修改成功\n");
    176. }
    177. //销毁通讯录
    178. void DestoryContact(Contact* cp)
    179. {
    180. free(cp->data);
    181. cp->data = NULL;
    182. cp->size = 0;
    183. cp->capacity = 0;
    184. }

    主函数部分(test.cpp

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "Contact.h"
    3. //枚举,增加程序的可读性
    4. enum options
    5. {
    6. EXIT,
    7. ADD,
    8. DEL,
    9. SEACH,
    10. MODIFY,
    11. SHOW
    12. };
    13. int main()
    14. {
    15. int input = 0;
    16. //创建通讯录
    17. Contact con;
    18. //初始化通讯录
    19. InitContact(&con);
    20. do
    21. {
    22. menu();
    23. printf("请输入你的选择: ");
    24. scanf("%d", &input);
    25. switch (input)
    26. {
    27. //增加联系人信息
    28. case ADD:
    29. AddContact(&con);
    30. break;
    31. //删除联系人信息
    32. case DEL:
    33. DelContact(&con);
    34. break;
    35. //查找某个联系人的信息
    36. case SEACH:
    37. SeachPeople(&con);
    38. break;
    39. //修改某个联系人的信息
    40. case MODIFY:
    41. ModifyContact(&con);
    42. break;
    43. //展示通讯录内的每一个联系人的信息
    44. case SHOW:
    45. ShowContact(&con);
    46. break;
    47. //退出通讯录管理系统
    48. case EXIT:
    49. DestoryContact(&con);
    50. printf("通讯录已退出\n");
    51. break;
    52. //预防非法输入
    53. default:
    54. printf("输入错误,请重新输入\n");
    55. break;
    56. }
    57. } while (input);
    58. return 0;
    59. }

    本次分享就到此为止了,感谢您的支持,如有错误,欢迎积极指正

  • 相关阅读:
    观察者(observer)模式(一)
    (Note)在Excel中选中某一行至最后一行的快捷键操作
    Flink实时数仓同步:切片表实战详解
    greenplum数据库-锁
    电脑监控软件内网版和外网版哪个好?
    牵手时代少年团,来伊份讲了一个“新鲜”故事
    python自学入门(打卡十一)2022-11-27
    读取图片文件MetaFile放入Windows剪切板
    新能源汽车动态
    Unity图形节点插件xNode简单使用说明
  • 原文地址:https://blog.csdn.net/m0_69519887/article/details/133637075