C语言实现个人通讯录(功能优化)-1

简介: C语言实现个人通讯录(功能优化)
  • 用C语言实现个人通讯录,完成个人通讯录的增加、减少、查找、修改联系人,同时实现通讯录的排序功能和隐藏空间的功能等;
  • 分三个文件实现:Test.c 这个文件用于测试代码,测试功能实现,以及最后的主函数,都可以用这个实现。(注意:在写项目过程中,一定要每实现一个功能就要运行测试,不然,代码过长调试困难)Contact.h文件,用于声明各种定义声明以及内部库的引用,这样可以简化代码,让代码更加可读(类型定义、库函数声明、函数定义、宏定义等)Contact.c这就是最关键的文件,用于对各项函数的实现;

1.基本思路介绍:

1.1基本思路:

  • 我们的基本思路其实在Test.c文件中最能体现:
#include"Contact.h"
int main()
{
  int input;
  //菜单
  mune1();
  //若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
  //若输入为0,则判断为FALSE,跳出循环,退出通讯录

  //创建通讯录:
  Contact con;
  //初始化函数:传入指针减少内存占用
  InitContact(&con);

  do {
    //选项的输入
    printf("请输入选项>:");
    scanf("%d", &input);
    //若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
    //若输入为0,则判断为FALSE,跳出循环,退出通讯录
    switch (input)
    {
    case ADD:
      AddContact(&con);
      break;
    case DEL:
      DelContact(&con);
      break;
    case SEARCH:
      SearchContact(&con);
      break;
    case MODIFY:
      ModifyContact(&con);
      break;
    case SHOW:
      PrintContact(&con);
      break;
    case SORT:
      SortContact(&con);
      break;
    case EXIT:
      //保存到文件中
      SaveContact(&con);
      //销毁通讯录空间
      DestroyContact(&con);
      printf("退出通讯录\n");
      break;
    case Hide_Room:
      //将当前写入文件保存到文件中
      SaveContact(&con);
      //销毁当前空间
      DestroyContact(&con);
      if (EncryptionContact())
      {
        //初始化原本空间,进入加密空间
        Hide_InitContact(&con);
        ShowHide();
        //加密程序空间功能
        func(&con);
        goto judge;
      }
      else
      {
        goto judge;
      }
    default:
      printf("输入错误,请重新输入\n");
      break;
    }
  } while (input);

judge:
  return 0;
}

这里的基本思路就是:


  1. 通讯录的建立:先定义通讯录,在初始化通讯录,也就是为通讯录内部创建空间,以便存放数据;
  2. 功能的选择实现:创建好通讯录接下来我们肯定就是调用功能,我们用循环来实现功能的反复调用,用Switch语句来实现功能的选择(调用)。这里的基本功能是七项(方便展示可以定义一个菜单)


这就是整体基本思路,在Test.c中一目了然。


2.通讯录的具体实现:

2.1 通讯录的建立:

1.我们描述一个人是复杂的,不是一个类型元素可以描述,比如姓名是字符串,年龄是整形,所以这里要采用自定义类型(结构体)来定义联系人信息:

//人的信息
typedef struct PeoInfo
{
  char name[NAME_MAX];
  int age;
  char sex[SEX_MAX];
  char address[ADDR_MAX];
  char phone[PHONE_MAX];
  char class[CLASS_MAX];
}PeoInfo;

这里我们定义了联系人的姓名、年龄、性别、地址、电话、以及分组;

2.个人通讯录相当于一个数组,元素是PeoInfo类型(联系人),这里我们可以采用静态数组,但实际上静态数组在后续的添加人数的时候,扩容比较呆板,所以这里我们选择的是顺序表的数据结构,这更方便于增添人数(当然链表也可以实现,后续补充)


//以顺序表实现
typedef  struct Contact
{
  //创建通讯录
  PeoInfo* data;
  int sz;//记录当前通讯录中的人数
  int capacity;//记录当前通讯录的空间大小
}Contact;

通过这个代码我们就可以定义一个通讯录喽!当然接下来就要初始化通讯录,创建空间:


void InitContact(Contact* pc)
{
  assert(pc);
  pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX);
  //在堆上申请空间
  if (pc->data == NULL)
  {
    //检验是否申请成功,方便调试检验;
    perror("malloc error");
  }
  pc->sz = 0;//最初空间人数
  pc->capacity = INIT_MAX;//空间大小
}

这里的代码表示我们在堆上申请空间,申请了INIT_MAX个人数空间,OK这里通讯录的建立就完成咯!


2.2通讯录功能:

通讯录具体有什么功能需要实现呢?这里只需要看一眼Test.h就一目了然了:


#pragma once
//类型的定义和声明放入头文件
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
#include<windows.h>
//宏定义:
#define INIT_MAX 4
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 20
#define PHONE_MAX 12
#define CLASS_MAX 20
//选择菜单
void mune1();
void mune();
//枚举优化选项
enum input
{
  EXIT,
  ADD,
  DEL,
  SEARCH,
  MODIFY,
  SHOW,
  SORT,
  Hide_Room = 110,
};
enum way
{
  S_ByName = 1,
  S_ByAge,
  S_BySex,
  S_ByAddr,
  S_ByPhone,
  S_ByClass,
};
//人的信息
typedef struct PeoInfo
{
  char name[NAME_MAX];
  int age;
  char sex[SEX_MAX];
  char address[ADDR_MAX];
  char phone[PHONE_MAX];
  char class[CLASS_MAX];
}PeoInfo;

//以顺序表实现
typedef  struct Contact
{
  //创建通讯录
  PeoInfo* data;
  int sz;
  int capacity;
}Contact;

//初始化结构体
void InitContact(Contact* pc);
//扩容函数
void CapacityContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//删除联系人
void DelContact(Contact* pc);
//查找联系人
int SearchContact(const Contact* pc);
//查找方法:
// 按名字查找:
  int SearchByName(const Contact* ps);
// 按年龄查找:
  void SearchByAge(const Contact* ps);
// 按性别查找:
  void SearchBySex(const Contact* ps);
// 按地址查找:
  void SearchByAddr(const Contact* ps);
//按分组查找:
  void SearchByClass(const Contact* ps);
// 按电话查找:
  int SearchByPhone(const Contact* ps);
//修改联系人
void ModifyContact(Contact* pc);
//打印通讯录
void PrintContact(const Contact* pc);
//对通讯录成员进行排序
void SortContact(const Contact* pc);
//销毁通讯录内存空间
void DestroyContact(Contact* pc);
//保存通讯录到磁盘
void SaveContact(const Contact* pc);
//加载通讯录信息
void LondContact(Contact* pc);
//通讯录按照名字排序
  void SortContact(const Contact* pc);
//通讯录成员信息交换
  void Swap(PeoInfo* left, PeoInfo* right);
//双指针快排
  void DP_QuickSort(PeoInfo* a, int left, int right);
//选择排序
  void InsertSort(PeoInfo* a, int n);
//隐蔽空间定义
void  Hide_InitContact(Contact* pc);
//隐蔽空间文件调用
  void Hide_LondContact(Contact* pc);
//隐蔽空间密码登录
  bool EncryptionContact();
//进入展示
  void ShowHide();
//隐蔽空间文件保存
  void Hide_SaveContact(const Contact* pc);

void func(Contact* pc);

可以看到.h文件里包含了很多内容:头文件定义,宏定义,自定义类型声明,函数声明等等;

接下来我们就具体实现一下上述功能函数:


3.具体功能函数的实现:

这里就是最重要的地方咯,注意咯!!!


3.1 增添联系人:

增添联系人代码实现:


void AddContact(Contact* pc)
{
  assert(pc);
  //自动扩容
  CapacityContact(pc);

  printf("请输入联系人名字:");
  scanf("%s", pc->data[pc->sz].name);
  printf("请输入联系人年龄:");
  scanf("%d", &(pc->data[pc->sz].age));
  printf("请输入联系人性别:");
  scanf("%s", pc->data[pc->sz].sex);
  printf("请输入联系人地址:");
  scanf("%s", pc->data[pc->sz].address);
  printf("请输入联系人电话:");
  scanf("%s", pc->data[pc->sz].phone);
  printf("请设置联系人组别:");
  scanf("%s", pc->data[pc->sz].class);
  //这里sz记录当前通讯录人数
  pc->sz++;
  return;
}


运行效果:

4b5c8d3ec0ed4627110d7eff3858cf64_caca5da7811c4aebac0a51b5161871d4.png


增添联系人代码比较简单,但要注意一个问题,我们不断添加人数,会达到通讯录初始化的最大空间容量,所以我们需要考虑通讯录的扩容问题,如果我们按照最开始的想法用数组来存储联系人,则不能灵活的更改通讯录容量,需要手动更改代码空间比较麻烦,而用顺序表就可以很好解决这个问题;


void CapacityContact(Contact* pc)
{
  if (pc->sz == pc->capacity)
  {
    pc->data = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * INIT_MAX * 2);
    if (pc->data == NULL)
    {
      perror("realloc error");
    }
    pc->capacity = pc->capacity * 2;
    printf("扩容成功\n");
  }
}

当sz(当前通讯录人数)等于capacity(通讯录空间大小),则可以通过动态内存管理realloc,对原来的空间扩容,可以自动实现就十分方便;


3.2 删除联系人:

1.删除联系人需要考虑,通讯录中是否储存了联系人,判断通讯录是否为空;

2.实际情况中,我们删除是根据人的姓名等信息,所以这里就要具体得到要删除对象的位置,这里就要用查找功能;

3.删除的思想:覆盖+下标索引减小,实现部分空间无法访问,间接的删除;


void DelContact(Contact* pc)
{
  assert(pc);
  if (pc->sz == 0)
  {
    printf("通讯录中无对象可操作!请先增加!");
    mune1();
    return;
  }
  int ret = SearchByName(pc);
  if (ret == -1)
  {
    printf("删除失败请重新操作!");
    mune1();
    return;
  }
  int i = ret;
  for (i = ret; i < pc->sz - 1; i++)
  {
    pc->data[i] = pc->data[i + 1];

  }

  printf("删除成功!\n");
  //这里并不是完全删除,把\0发给int时默认为零,我们sz减减,就相当于访问不到那片空间
  pc->sz--;
  mune1();
}

运行效果:

563c5a56ff4a1881abfc32957eacf348_ecdaeecc71a84343a29d7a7aef146895.png


3.3 查找联系人:

1.这里就用最简单的方法:遍历通讯录对比实现

2.当然这里我提供了六种查找方式,当然最也可以算是五种,因为最后一种分类查找我把它定为分组;


总查找函数:


int SearchContact(const Contact* pc)
{
  assert(pc);
  //多种方式查找:
  mune();
  int input;
  int ret = -1;
  do {
    //选项的输入
    printf("请输入选项>:");
    scanf("%d", &input);
    //若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
    //若输入为0,则判断为FALSE,跳出循环,
    switch (input)
    {
    case S_ByName:
      ret = SearchByName(pc);
      break;
    case S_ByAge:
      SearchByAge(pc);
      break;
    case S_BySex:
      SearchBySex(pc);
      break;
    case S_ByAddr:
      SearchByAddr(pc);
      break;
    case S_ByPhone:
      ret = SearchByPhone(pc);
      break;
    case S_ByClass:
      SearchByClass(pc);
      break;
    case EXIT:
      printf("查找完成,已经返回上一级\n");
      mune1();
      break;
    default:
      printf("该查找方式还待开发哦,请重新输入\n");
      break;
    }
  } while (input);
  return ret;
}

这里和test.c中相似,各类查找也差不多相同,这里我就列出一个比较常用的咯!


  • 按照姓名查找:
  int SearchByName(const Contact* ps)
{
  int i = 0;
  char name[NAME_MAX];
  int k = 1;
  printf("请输入需要的联系人名字:");
  scanf("%s", name);
  for (i = 0; i < ps->sz; i++)
  {
    if (strcmp(name, ps->data[i].name) == 0)
    {
      //暂时不考虑重名
      if (k == 1)
      {
        printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
        k--;
      }

      printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
        ps->data[i].name,
        ps->data[i].age,
        ps->data[i].sex,
        ps->data[i].address,
        ps->data[i].phone,
        ps->data[i].class);

      return i;
    }
  }
  printf("无法找到该联系人信息\n");
  return -1;
}

运行效果:

67f5da23e7941ed6ceea92d531b2d09f_addacee02178465da4774883494d35b4.png


(这里存在缺陷:就是重名,因为这里函数要返回int,所以只能用于不重名查找,当然如果重名,我们多掉用两次就可以了,还有就是通讯录里重名应该有其他备注吧哈哈!)


3.4 修改联系人:

这个代码也比较简单思路是:找到,并且输入新信息覆盖即可;


void ModifyContact(Contact* pc)
{
  int ret = -1;
  int i;
  i = SearchByName(pc);
  if (i != ret)
  {
    printf("请输入修改的内容(部分):\n");
    printf("请输入联系人名字:");
    scanf("%s", pc->data[i].name);
    printf("请输入联系人年龄:");
    scanf("%d", &(pc->data[i].age));
    printf("请输入联系人性别:");
    scanf("%s", pc->data[i].sex);
    printf("请输入联系人地址:");
    scanf("%s", pc->data[i].address);
    printf("请输入联系人电话:");
    scanf("%s", pc->data[i].phone);
  }
}


运行效果:

261d42c64aee3aecd4159d8da3ec45b3_ee2bfd3583e24eeab5be9f9cffd6349d.png


3.5 打印通讯录:

这个功能应该最先完成,因为有了它方便调试每个功能的代码;

思路很简单:遍历打印(但要注意格式美化,不然可太挫了)

void PrintContact(const Contact* pc)
{
  assert(pc);
  int i = 0;
  printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
  for (i = 0; i < pc->sz; i++)
  {
    printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
      pc->data[i].name,
      pc->data[i].age,
      pc->data[i].sex,
      pc->data[i].address,
      pc->data[i].phone,
      pc->data[i].class);
  }
}


C语言实现个人通讯录(功能优化)-2

https://developer.aliyun.com/article/1536739

相关文章
|
10天前
|
机器学习/深度学习 搜索推荐 程序员
C语言实现个人通讯录(功能优化)-2
C语言实现个人通讯录(功能优化)
C语言实现个人通讯录(功能优化)-2
|
17天前
|
C语言
C语言学习记录——通讯录(静态内存)
C语言学习记录——通讯录(静态内存)
14 2
|
27天前
|
存储 C语言
C语言实现通讯录
C语言实现通讯录
21 2
|
17天前
|
存储 C语言
C语言学习记录——通讯录(动态内存)
C语言学习记录——通讯录(动态内存)
13 0
|
27天前
|
存储 C语言
动态+静态+文件操作 C语言实现通讯录
通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址
24 0
|
27天前
|
存储 文件存储
升级版通讯录(C语言版)
升级版通讯录(C语言版)
20 0
|
2天前
|
C语言
C语言---函数---请输入乘法口诀表的行,来打印几几乘法表
C语言---函数---请输入乘法口诀表的行,来打印几几乘法表
|
2天前
|
C语言
C语言--函数递归与迭代
C语言--函数递归与迭代
|
2天前
|
C语言 C++
C语言----C语言内存函数
C语言----C语言内存函数
|
2天前
|
C语言
C语言----字符函数和字符串函数(4)
C语言----字符函数和字符串函数