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

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

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

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

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

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

头文件部分(Contact.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<string.h>
#define Name_Max 20
#define Tel_Number 12
#define Sex_Max 5
#define Address_Max 30
#define Contact_Max 100
//联系人结构体
typedef struct PeopleInformation
{
  char name[Name_Max];
  char telnumber[Tel_Number];
  int age;
  char sex[Sex_Max];
  char address[Address_Max];
}PeoInfor;
//通讯录结构体
typedef struct Contact
{
  PeoInfor data[Contact_Max];//结构体数组存放联系人结构体
  int size;//记录当前通讯录中有多少个联系人
}Contact;
//目录
void menu();
//初始化通讯录
void InitContact(Contact* cp);
//增加联系人
void AddContact(Contact* cp);
//删除联系人
void DelContact(Contact* cp);
//通过姓名进行查找联系人
int FindPeople(Contact* cp, char name[]);
//展示全部通讯录信息
void ShowContact(const Contact* cp);
//查询联系人
void SeachPeople(Contact* cp);
//修改联系人信息
void ModifyContact(Contact* cp);

函数实现部分(Contact.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
void menu()
{
  printf("\n");
  printf("-----------------------------\n");
  printf("---   1.添加联系人      -----\n");
  printf("---   2.删除联系人      -----\n");
  printf("---   3.查找联系人      -----\n");
  printf("---   4.修改联系人信息  -----\n");
  printf("---   5.显示全部信息    -----\n");
  printf("---   0.退出通讯录      -----\n");
  printf("-----------------------------\n");
}
//初始化通讯录
void InitContact(Contact* cp)
{
  //判断非空
  assert(cp);
  cp->size = 0;
  memset(cp->data, 0, sizeof(cp->data));
}
//增加联系人
void AddContact(Contact* cp)
{
  //判断非空
  assert(cp);
  //判断未满
  if (cp->size == Contact_Max)
  {
    printf("通讯录已满,无法再添加新的联系人\n");
    return;
  }
  printf("请输入要添加的联系人的姓名:\n");
  scanf("%s", cp->data[cp->size].name);
  printf("请输入要添加的联系人的电话号:\n");
  scanf("%s", cp->data[cp->size].telnumber);
  printf("请输入要添加的联系人的年龄:\n");
  scanf("%d", &(cp->data[cp->size].age));
  printf("请输入要添加的联系人的性别:\n");
  scanf("%s", cp->data[cp->size].sex);
  printf("请输入要添加的联系人的住址:\n");
  scanf("%s", cp->data[cp->size].address);
  cp->size++;
  printf("添加成功\n");
}
//通过姓名进行查找联系人
int FindPeople(Contact* cp, char name[])
{
  assert(cp);
  for (int i = 0; i < cp->size; i++)
  {
    if (strcmp(cp->data[i].name, name) == 0)
    {
      return i;
    }
  }
  return -1;
}
//删除联系人
void DelContact(Contact* cp)
{
  assert(cp);
  char name[Name_Max];
  if (cp->size == 0)
  {
    printf("通讯录为空,无需删除\n");
    return;
  }
  printf("请输入选择删除的联系人的姓名:\n");
  scanf("%s", name);
  int ret = FindPeople(cp, name);
  if (ret == -1)
  {
    printf("要删除的联系人不存在\n");
    return;
  }
  for (int i = ret; i < cp->size-1 ; i++)
  {
    cp->data[i] = cp->data[i + 1];
  }
  cp->size--;
  printf("删除成功\n");
}
//查询联系人
void SeachPeople(Contact* cp)
{
  assert(cp);
  char name[Name_Max];
  if (cp->size == 0)
  {
    printf("通讯录为空\n");
    return;
  }
  printf("请输入选择查找的联系人的姓名:\n");
  scanf("%s", name);
  int ret = FindPeople(cp, name);
  if (ret == -1)
  {
    printf("要查找的联系人不存在\n");
    return;
  }
  //名字  年龄  性别    电话    地址
  //xxx   xxx    xxx    xxx     xxx
  printf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
  //打印个人的信息
  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);
}
//展示全部通讯录信息
void ShowContact(const Contact* cp)
{
  assert(cp);
  if (cp->size == 0)
  {
    printf("通讯录为空\n");
    return;
  }
  //名字  年龄  性别    电话    地址
  //xxx   xxx    xxx    xxx     xxx
  printf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
  for (int i = 0; i < cp->size; i++)
  {
    //打印每个人的信息
    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);
  }
}
//修改联系人信息
void ModifyContact(Contact* cp)
{
  assert(cp);
  char name[Name_Max];
  if (cp->size == 0)
  {
    printf("通讯录为空\n");
    return;
  }
  printf("请输入选择修改的联系人的姓名:\n");
  scanf("%s", name);
  int ret = FindPeople(cp, name);
  if (ret == -1)
  {
    printf("要修改的联系人信息不存在\n");
    return;
  }
  printf("请输入要修改的联系人的姓名:\n");
  scanf("%s", cp->data[ret].name);
  printf("请输入要修改的联系人的电话号:\n");
  scanf("%s", cp->data[ret].telnumber);
  printf("请输入要修改的联系人的年龄:\n");
  scanf("%d", &(cp->data[ret].age));
  printf("请输入要修改的联系人的性别:\n");
  scanf("%s", cp->data[ret].sex);
  printf("请输入要修改的联系人的住址:\n");
  scanf("%s", cp->data[ret].address);
  printf("修改成功\n");
}

主函数部分(test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
//枚举,增加程序的可读性
enum options
{
  EXIT,
  ADD,
  DEL,
  SEACH,
  MODIFY,
  SHOW
};
int main()
{
  int input = 0;
  //创建通讯录
  Contact con;
  //初始化通讯录
  InitContact(&con);
  do
  {
    menu();
    printf("请输入你的选择: ");
    scanf("%d", &input);
    switch (input)
    {
    //增加联系人信息
    case ADD:
      AddContact(&con);
      break;
    //删除联系人信息
    case DEL:
      DelContact(&con);
      break;
    //查找某个联系人的信息
    case SEACH:
      SeachPeople(&con);
      break;
    //修改某个联系人的信息
    case MODIFY:
      ModifyContact(&con);
      break;
    //展示通讯录内的每一个联系人的信息
    case SHOW:
      ShowContact(&con);
      break;
    //退出通讯录管理系统
    case EXIT:
      printf("通讯录已退出\n");
      break;
    //预防非法输入
    default:
      printf("输入错误,请重新输入\n");
      break;
    }
  }while(input);
  return 0;
}

二.结构体的更改

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

//通讯录结构体
typedef struct Contact
{
  PeoInfor* data;//结构体数组存放联系人结构体
  int size;//记录当前通讯录中有多少个联系人
  int capacity;//记录当前存放的容量
}Contact;

      在这里我们将 data 从一个结构体数组改成了结构体指针,然后后续再使用 这个指针指向我们动态开辟的内存就完成了我们的需求设计

       并且新增了个变量 capacity 用来记录当前通讯录内的最大容量,当联系人的数量和容量相同的时候,也就是通讯录满容的时候,我们再使用 realloc 重新分配新的内存空间

三.扩容的设计

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

首先是判断部分,当当前通讯录的容量等于通讯录内实际存放的数据的大小的时候,我们就判定为通讯录已满,然后我们使用 realloc 开辟新的空间,比之前大 2 个联系人结构体的大小

为了程序的健全性,我们也要判断开辟空间是否成功,如果成功就通过 ptr指针 指向联系人的数据部分,用 data 接收,如果开辟失败,我们就打印报错信息

void CheckContact(Contact* cp)
{
  if (cp->size == cp->capacity)
  {
    PeoInfor* ptr = (PeoInfor*)realloc(cp->data, (cp->capacity + 2) * sizeof(PeoInfor));
    if (ptr != NULL)
    {
      cp->data = ptr;
      cp->capacity += 2;
      printf("增容成功\n");
    }
    else
    {
      perror("AddContact->realloc");
      return;
    }
  }
}

四.释放空间

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

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

//销毁通讯录
void DestoryContact(Contact* cp)
{
  free(cp->data);
  cp->data = NULL;
  cp->size = 0;
  cp->capacity = 0;
}

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

头文件部分(Contact.h:

#pragma once
#pragma once
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#define Name_Max 20
#define Tel_Number 12
#define Sex_Max 5
#define Address_Max 30
#define Contact_Max 100
#define Contact_SZ 3
//联系人结构体
typedef struct PeopleInformation
{
  char name[Name_Max];
  char telnumber[Tel_Number];
  int age;
  char sex[Sex_Max];
  char address[Address_Max];
}PeoInfor;
//通讯录结构体
typedef struct Contact
{
  PeoInfor* data;//结构体数组存放联系人结构体
  int size;//记录当前通讯录中有多少个联系人
  int capacity;//记录当前存放的容量
}Contact;
//目录
void menu();
//初始化通讯录
void InitContact(Contact* cp);
//增加联系人
void AddContact(Contact* cp);
//删除联系人
void DelContact(Contact* cp);
//通过姓名进行查找联系人
int FindPeople(Contact* cp, char name[]);
//展示全部通讯录信息
void ShowContact(const Contact* cp);
//查询联系人
void SeachPeople(Contact* cp);
//修改联系人信息
void ModifyContact(Contact* cp);
//扩容
void CheckContact(Contact* cp);
//销毁通讯录
void DestoryContact(Contact* cp);

函数的实现部分 (Contact.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
void menu()
{
  printf("\n");
  printf("-----------------------------\n");
  printf("---   1.添加联系人      -----\n");
  printf("---   2.删除联系人      -----\n");
  printf("---   3.查找联系人      -----\n");
  printf("---   4.修改联系人信息  -----\n");
  printf("---   5.显示全部信息    -----\n");
  printf("---   0.退出通讯录      -----\n");
  printf("-----------------------------\n");
}
//初始化通讯录
void InitContact(Contact* cp)
{
  //判断非空
  assert(cp);
  cp->size = 0;
  cp->capacity = Contact_SZ;
  cp->data =(PeoInfor*)calloc(cp->capacity, sizeof(PeoInfor));
  if (cp->data == NULL)
  {
    perror("InitContact->calloc");
    return;
  }
}
void CheckContact(Contact* cp)
{
  if (cp->size == cp->capacity)
  {
    PeoInfor* ptr = (PeoInfor*)realloc(cp->data, (cp->capacity + 2) * sizeof(PeoInfor));
    if (ptr != NULL)
    {
      cp->data = ptr;
      cp->capacity += 2;
      printf("增容成功\n");
    }
    else
    {
      perror("AddContact->realloc");
      return;
    }
  }
}
//增加联系人
void AddContact(Contact* cp)
{
  //判断非空
  assert(cp);
  //判断满后扩容
  CheckContact(cp);
  printf("请输入要添加的联系人的姓名:\n");
  scanf("%s", cp->data[cp->size].name);
  printf("请输入要添加的联系人的电话号:\n");
  scanf("%s", cp->data[cp->size].telnumber);
  printf("请输入要添加的联系人的年龄:\n");
  scanf("%d", &(cp->data[cp->size].age));
  printf("请输入要添加的联系人的性别:\n");
  scanf("%s", cp->data[cp->size].sex);
  printf("请输入要添加的联系人的住址:\n");
  scanf("%s", cp->data[cp->size].address);
  cp->size++;
  printf("添加成功\n");
}
//通过姓名进行查找联系人
int FindPeople(Contact* cp, char name[])
{
  assert(cp);
  for (int i = 0; i < cp->size; i++)
  {
    if (strcmp(cp->data[i].name, name) == 0)
    {
      return i;
    }
  }
  return -1;
}
//删除联系人
void DelContact(Contact* cp)
{
  assert(cp);
  char name[Name_Max];
  if (cp->size == 0)
  {
    printf("通讯录为空,无需删除\n");
    return;
  }
  printf("请输入选择删除的联系人的姓名:\n");
  scanf("%s", name);
  int ret = FindPeople(cp, name);
  if (ret == -1)
  {
    printf("要删除的联系人不存在\n");
    return;
  }
  for (int i = ret; i < cp->size - 1; i++)
  {
    cp->data[i] = cp->data[i + 1];
  }
  cp->size--;
  printf("删除成功\n");
}
//查询联系人
void SeachPeople(Contact* cp)
{
  assert(cp);
  char name[Name_Max];
  if (cp->size == 0)
  {
    printf("通讯录为空\n");
    return;
  }
  printf("请输入选择查找的联系人的姓名:\n");
  scanf("%s", name);
  int ret = FindPeople(cp, name);
  if (ret == -1)
  {
    printf("要查找的联系人不存在\n");
    return;
  }
  //名字  年龄  性别    电话    地址
  //xxx   xxx    xxx    xxx     xxx
  printf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
  //打印个人的信息
  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);
}
//展示全部通讯录信息
void ShowContact(const Contact* cp)
{
  assert(cp);
  if (cp->size == 0)
  {
    printf("通讯录为空\n");
    return;
  }
  //名字  年龄  性别    电话    地址
  //xxx   xxx    xxx    xxx     xxx
  printf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
  for (int i = 0; i < cp->size; i++)
  {
    //打印每个人的信息
    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);
  }
}
//修改联系人信息
void ModifyContact(Contact* cp)
{
  assert(cp);
  char name[Name_Max];
  if (cp->size == 0)
  {
    printf("通讯录为空\n");
    return;
  }
  printf("请输入选择修改的联系人的姓名:\n");
  scanf("%s", name);
  int ret = FindPeople(cp, name);
  if (ret == -1)
  {
    printf("要修改的联系人信息不存在\n");
    return;
  }
  printf("请输入要修改的联系人的姓名:\n");
  scanf("%s", cp->data[ret].name);
  printf("请输入要修改的联系人的电话号:\n");
  scanf("%s", cp->data[ret].telnumber);
  printf("请输入要修改的联系人的年龄:\n");
  scanf("%d", &(cp->data[ret].age));
  printf("请输入要修改的联系人的性别:\n");
  scanf("%s", cp->data[ret].sex);
  printf("请输入要修改的联系人的住址:\n");
  scanf("%s", cp->data[ret].address);
  printf("修改成功\n");
}
//销毁通讯录
void DestoryContact(Contact* cp)
{
  free(cp->data);
  cp->data = NULL;
  cp->size = 0;
  cp->capacity = 0;
}

主函数部分(test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
//枚举,增加程序的可读性
enum options
{
  EXIT,
  ADD,
  DEL,
  SEACH,
  MODIFY,
  SHOW
};
int main()
{
  int input = 0;
  //创建通讯录
  Contact con;
  //初始化通讯录
  InitContact(&con);
  do
  {
    menu();
    printf("请输入你的选择: ");
    scanf("%d", &input);
    switch (input)
    {
      //增加联系人信息
    case ADD:
      AddContact(&con);
      break;
      //删除联系人信息
    case DEL:
      DelContact(&con);
      break;
      //查找某个联系人的信息
    case SEACH:
      SeachPeople(&con);
      break;
      //修改某个联系人的信息
    case MODIFY:
      ModifyContact(&con);
      break;
      //展示通讯录内的每一个联系人的信息
    case SHOW:
      ShowContact(&con);
      break;
      //退出通讯录管理系统
    case EXIT:
      DestoryContact(&con);
      printf("通讯录已退出\n");
      break;
      //预防非法输入
    default:
      printf("输入错误,请重新输入\n");
      break;
    }
  } while (input);
  return 0;
}



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

目录
相关文章
|
1月前
|
IDE 编译器 开发工具
【C语言】全面系统讲解 `#pragma` 指令:从基本用法到高级应用
在本文中,我们系统地讲解了常见的 `#pragma` 指令,包括其基本用法、编译器支持情况、示例代码以及与传统方法的对比。`#pragma` 指令是一个强大的工具,可以帮助开发者精细控制编译器的行为,优化代码性能,避免错误,并确保跨平台兼容性。然而,使用这些指令时需要特别注意编译器的支持情况,因为并非所有的 `#pragma` 指令都能在所有编译器中得到支持。
117 41
【C语言】全面系统讲解 `#pragma` 指令:从基本用法到高级应用
|
1月前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
54 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
1月前
|
存储 编译器 C语言
【C语言】C语言的变量和声明系统性讲解
在C语言中,声明和定义是两个关键概念,分别用于告知编译器变量或函数的存在(声明)和实际创建及分配内存(定义)。声明可以多次出现,而定义只能有一次。声明通常位于头文件中,定义则在源文件中。通过合理组织头文件和源文件,可以提高代码的模块化和可维护性。示例包括全局变量、局部变量、函数、结构体、联合体、数组、字符串、枚举和指针的声明与定义。
58 12
|
1月前
|
机器学习/深度学习 人工智能 缓存
【AI系统】推理内存布局
本文介绍了CPU和GPU的基础内存知识,NCHWX内存排布格式,以及MNN推理引擎如何通过数据内存重新排布进行内核优化,特别是针对WinoGrad卷积计算的优化方法,通过NC4HW4数据格式重排,有效利用了SIMD指令集特性,减少了cache miss,提高了计算效率。
52 3
|
1月前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
1月前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
71 6
|
1月前
|
机器学习/深度学习 人工智能 算法
【AI系统】内存分配算法
本文探讨了AI编译器前端优化中的内存分配问题,涵盖模型与硬件内存的发展、内存划分及其优化算法。文章首先分析了神经网络模型对NPU内存需求的增长趋势,随后详细介绍了静态与动态内存的概念及其实现方式,最后重点讨论了几种节省内存的算法,如空间换内存、计算换内存、模型压缩和内存复用等,旨在提高内存使用效率,减少碎片化,提升模型训练和推理的性能。
62 1
|
2月前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
64 6
|
2月前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
2月前
|
机器学习/深度学习 算法 数据挖掘
C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出
本文探讨了C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出。文章还介绍了C语言在知名机器学习库中的作用,以及与Python等语言结合使用的案例,展望了其未来发展的挑战与机遇。
58 1