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月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
|
12天前
|
监控 Ubuntu API
Python脚本监控Ubuntu系统进程内存的实现方式
通过这种方法,我们可以很容易地监控Ubuntu系统中进程的内存使用情况,对于性能分析和资源管理具有很大的帮助。这只是 `psutil`库功能的冰山一角,`psutil`还能够提供更多关于系统和进程的详细信息,强烈推荐进一步探索这个强大的库。
27 1
|
19天前
|
存储 C语言 C++
数据结构基础详解(C语言) 顺序表:顺序表静态分配和动态分配增删改查基本操作的基本介绍及c语言代码实现
本文介绍了顺序表的定义及其在C/C++中的实现方法。顺序表通过连续存储空间实现线性表,使逻辑上相邻的元素在物理位置上也相邻。文章详细描述了静态分配与动态分配两种方式下的顺序表定义、初始化、插入、删除、查找等基本操作,并提供了具体代码示例。静态分配方式下顺序表的长度固定,而动态分配则可根据需求调整大小。此外,还总结了顺序表的优点,如随机访问效率高、存储密度大,以及缺点,如扩展不便和插入删除操作成本高等特点。
|
24天前
|
存储 大数据 C语言
C语言 内存管理
本文详细介绍了内存管理和相关操作函数。首先讲解了进程与程序的区别及进程空间的概念,接着深入探讨了栈内存和堆内存的特点、大小及其管理方法。在堆内存部分,具体分析了 `malloc()`、`calloc()`、`realloc()` 和 `free()` 等函数的功能和用法。最后介绍了 `memcpy`、`memmove`、`memcmp`、`memchr` 和 `memset` 等内存操作函数,并提供了示例代码。通过这些内容,读者可以全面了解内存管理的基本原理和实践技巧。
|
24天前
|
缓存 Linux C语言
C语言 多进程编程(六)共享内存
本文介绍了Linux系统下的多进程通信机制——共享内存的使用方法。首先详细讲解了如何通过`shmget()`函数创建共享内存,并提供了示例代码。接着介绍了如何利用`shmctl()`函数删除共享内存。随后,文章解释了共享内存映射的概念及其实现方法,包括使用`shmat()`函数进行映射以及使用`shmdt()`函数解除映射,并给出了相应的示例代码。最后,展示了如何在共享内存中读写数据的具体操作流程。
|
1月前
|
缓存 Kubernetes 数据中心
在Docker中,如何控制容器占用系统资源(CPU,内存)的份额?
在Docker中,如何控制容器占用系统资源(CPU,内存)的份额?
|
1月前
|
关系型数据库 MySQL
MySQl优化:使用 jemalloc 分配内存
MySQl优化:使用 jemalloc 分配内存
|
1月前
|
存储 NoSQL 程序员
C语言中的内存布局
C语言中的内存布局
35 0
|
1月前
|
缓存 Ubuntu Linux
在Linux中,如何检查系统的CPU和内存使用情况?
在Linux中,如何检查系统的CPU和内存使用情况?
|
1月前
|
C语言
【C语言篇】字符和字符串以及内存函数详细介绍与模拟实现(下篇)
perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。

热门文章

最新文章