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

相关文章
|
18天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
47 1
|
2月前
|
算法 搜索推荐 C语言
【C语言】冒泡排序+优化版
【C语言】冒泡排序+优化版
|
2月前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
32 2
|
2月前
|
存储 C语言
手把手教你用C语言实现通讯录管理系统
手把手教你用C语言实现通讯录管理系统
|
3月前
|
网络协议 C语言
C语言 网络编程(十三)并发的TCP服务端-以进程完成功能
这段代码实现了一个基于TCP协议的多进程并发服务端和客户端程序。服务端通过创建子进程来处理多个客户端连接,解决了粘包问题,并支持不定长数据传输。客户端则循环发送数据并接收服务端回传的信息,同样处理了粘包问题。程序通过自定义的数据长度前缀确保了数据的完整性和准确性。
|
3月前
|
存储 测试技术 C语言
C语言实现链表的各种功能
本文详细介绍了如何使用C语言实现链表的各种功能,包括链表节点结构的定义与操作函数的实现。链表作为一种常用的数据结构,具有节点自由插入删除、动态变化等特点。文中通过`link_list.h`和`link_list.c`两个文件,实现了链表的初始化、插入、删除、查找、修改等核心功能,并在`main.c`中进行了功能测试。这些代码不仅展示了链表的基本操作,还提供了丰富的注释帮助理解,适合作为学习链表的入门资料。
|
3月前
|
网络协议 C语言
C语言 网络编程(十四)并发的TCP服务端-以线程完成功能
这段代码实现了一个基于TCP协议的多线程服务器和客户端程序,服务器端通过为每个客户端创建独立的线程来处理并发请求,解决了粘包问题并支持不定长数据传输。服务器监听在IP地址`172.17.140.183`的`8080`端口上,接收客户端发来的数据,并将接收到的消息添加“-回传”后返回给客户端。客户端则可以循环输入并发送数据,同时接收服务器回传的信息。当输入“exit”时,客户端会结束与服务器的通信并关闭连接。
|
3月前
|
C语言
C语言 网络编程(八)并发的UDP服务端 以进程完成功能
这段代码展示了如何使用多进程处理 UDP 客户端和服务端通信。客户端通过发送登录请求与服务端建立连接,并与服务端新建的子进程进行数据交换。服务端则负责接收请求,验证登录信息,并创建子进程处理客户端的具体请求。子进程会创建一个新的套接字与客户端通信,实现数据收发功能。此方案有效利用了多进程的优势,提高了系统的并发处理能力。
|
3月前
|
C语言
C语言 网络编程(九)并发的UDP服务端 以线程完成功能
这是一个基于UDP协议的客户端和服务端程序,其中服务端采用多线程并发处理客户端请求。客户端通过UDP向服务端发送登录请求,并根据登录结果与服务端的新子线程进行后续交互。服务端在主线程中接收客户端请求并创建新线程处理登录验证及后续通信,子线程创建新的套接字并与客户端进行数据交换。该程序展示了如何利用线程和UDP实现简单的并发服务器架构。
|
4月前
|
存储 数据可视化 C语言
【C语言】C语言 手机通讯录系统的设计 (源码+数据+论文)【独一无二】
【C语言】C语言 手机通讯录系统的设计 (源码+数据+论文)【独一无二】