基于顺序表 --- 实现简易【通讯录】

简介: 基于顺序表 --- 实现简易【通讯录】

1. 多文件操作

SeqList.h //用于定义顺序表的结构,增删查改等函数的声明
SeqList.c //用于实现增删查改等函数
Contact.h //用于定义通讯录的结构,通讯录中联系人的增删查改等函数的声明
Contact.c //用于实现通讯录中增删查改等函数
Test.h //用于测试上述实现的函数,和菜单界面

2. 通讯录的主要功能

1.初始化通讯录

2.销毁通讯录

3.展示联系人数据

4.增加联系人数据

5.判断指定联系人是否存在

6.删除联系人数据

7.查找联系人数据

8.修改联系人数据

对通讯录中各个功能的展示:

3. 通讯录的实现

想要基于顺序表实现通讯录,首先我们需要一个顺序表。由于顺序表的实现比较简单,这里直接给出,不进行详细说明 (如想要详细了解顺序表的实现,请前往我的主页查看)

说明:下面两个文件中注释的部分是在顺序表类型替换后(由整型替换为结构体类型)的不适用的部分。读者不必在意。

SeqList.h

在这个头文件中由于要用上Contact.h中定义的peoInfo,所以要包含Contact.h

#pragma once
#include <stdio.h>
#include  <stdlib.h>
#include <assert.h>
#include "Contact.h"
//typedef int SQDataType;
typedef peoInfo SQDataType;
typedef struct SeqList
{
  SQDataType* arr;
  int size;
  int capacity;
}SL;
void SLInit(SL* ps);
void SLDestory(SL* ps);
//void SLPrint(SL ps);
void SLPushBack(SL* ps, SQDataType x);
void SLPushFront(SL* ps, SQDataType x);
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);
//void SLFind(const SL* ps, SQDataType x);
void SLInsert(SL* ps, int pos, SQDataType x);
void SLErase(SL* ps, int pos);

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 
#include "SeqList.h"
void SLInit(SL* ps)
{
  ps->arr = (SQDataType*)malloc(sizeof(SQDataType) * 4);
  if (ps->arr == NULL)
  {
    perror("malloc fail!\n");
    return ;
  }
  ps->capacity = 4;
  ps->size = 0;
}
void SLDestory(SL* ps)
{
  free(ps->arr);
  ps->arr = NULL;
  ps->capacity = 0;
  ps->size = 0;
}
void CheckCapacity(SL* ps,SQDataType x)
{
  if (ps->size == ps->capacity)
  {
    SQDataType* tmp = (SQDataType*)realloc(ps->arr, sizeof(SQDataType) * ps->capacity * 2);
    if (tmp == NULL)
    {
      perror("realloc fail!\n");
      return ;
    }
    else
    {
      ps->arr = tmp;
      ps->capacity *= 2;
    }
  }
}
//void SLPrint(SL ps)
//{
//  for (int i = 0; i < ps.size; i++)
//  {
//    printf("%d ", ps.arr[i]);
//  }
//  printf("\n");
//
//}
void SLPushBack(SL* ps, SQDataType x)
{
  assert(ps);
  CheckCapacity(ps, x);
  ps->arr[ps->size] = x;
  ps->size++;
}
void SLPushFront(SL* ps, SQDataType x)
{
  assert(ps);
  CheckCapacity(ps, x);
  int i = ps->size;
  for (i = ps->size; i > 0; i--)
  {
    ps->arr[i] = ps->arr[i - 1];
  }
  ps->arr[i] = x;
  ps->size++;
}
void SLPopBack(SL* ps)
{
  assert(ps);
  if (ps->size == 0)
  {
    printf("无数据可删除!\n");
    return;
  }
  ps->size--;
}
void SLPopFront(SL* ps)
{
  assert(ps);
  if (ps->size == 0)
  {
    printf("无数据可删除!\n");
    return;
  }
  for (int i = 0; i < ps->size; i++)
  {
    ps->arr[i] = ps->arr[i + 1];
  }
  ps->size--;
}
//void SLFind(const SL* ps, SQDataType x)
//{
//  assert(ps);
//  if (ps->size == 0)
//  {
//    printf("无数据!\n");
//    return;
//  }
//
//  for (int i = 0; i < ps->size; i++)
//  {
//    if (ps->arr[i] == x)
//    {
//      printf("找到了\n");
//      return;
//    }
//  }
//
//  printf("找不到\n");
//}
void SLInsert(SL* ps, int pos, SQDataType x)
{
  assert(ps && pos < ps->size && ps->size>0);
  CheckCapacity( ps, x);
  int i = ps->size;
  for ( i = ps->size; i > pos; i--)
  {
    ps->arr[i] = ps->arr[i - 1];
  }
  ps->arr[i] = x;
  ps->size++;
}
void SLErase(SL* ps, int pos)
{
  assert(pos < ps->size && ps->size>0);
  for (int i = pos; i < ps->size; i++)
  {
    ps->arr[i] = ps->arr[i + 1];
  }
  ps->size--;
}

1.定义通讯录的结构

由于我们这里需要用到SeqList.h中的struct SeqList结构体,很多人觉得只要在Contact .h头文件中包含SeqList.h就行,其实这是错误的,因为在SeqList.h中已经包含了Contact .h头文件是不能交叉包含的

所以我们这里用了另一个方法,叫做前置声明,前置声明的意思是告诉这个头文件我们存在这个顺序表,并且可以使用。

要用到顺序表相关的方法,对通讯录的操作实际上就是对顺序表的操作。

有了前置声明,下面的 Contact * con 就是顺序表中的 SL*sl。

#pragma once
#include <stdio.h>
#include <string.h>
#define MAX_NAME 10
#define MAX_GENDER 10
#define MAX_TEL 20
#define MAX_ADDR 20
//定义联系人数据结构:姓名+性别+年龄+电话+地址
typedef struct PeosonInfo
{
  char name[MAX_NAME];
  char gender[MAX_GENDER];
  int age;
  char tel[MAX_TEL];
  char addr[MAX_ADDR];
}peoInfo;
//前置声明
typedef struct SeqList Contact;
//给顺序表改个名字,叫做通讯录
//注意:这里不能写做typedef SL Contact,而是要用原名。
//因为SL是在struct SeqList定义好了之后才重命名的
//要用到顺序表相关的方法,对通讯录的操作实际上就是对顺序表的操作
//有了前置声明,下面的 Contact* con 就是顺序表中的 SL*sl

2.初始化通讯录

void InitContact(Contact* con)//就是相当于SL* sl
{
  //实际上就是顺序表的初始化
  SLInit(con);
}

3.销毁通讯录

void DestroyContact(Contact* con)
{
  SLDestory(con);
}

4.展示联系人数据

展示联系人不能改变其数据内容,所以可以加const进行保护。

void ShowContact(const Contact* con)
{
  //表头:姓名+性别+年龄+电话+地址
  printf("%-5s %-5s %-5s %-5s %-5s\n", "姓名", "性别", "年龄", "电话", "地址");
  for (int i = 0; i < con->size; i++)
  {
    printf("%-5s %-5s %-5d %-5s %-5s\n",
          con->arr[i].name,
          con->arr[i].gender, 
          con->arr[i].age, 
          con->arr[i].tel,
        con->arr[i].addr);
  } 
  printf("\n");
}

5.增加联系人数据

增加通讯录中联系人的数据,实际上就是对顺序表的插入操作,可以使用头插和尾插。这里是尾插。

void AddContact(Contact* con)
{
  peoInfo info;//定义一个结构体对象
  printf("请输入要添加联系人的姓名:\n");
  scanf("%s", info.name);
  printf("请输入要添加联系人的性别:\n");
  scanf("%s", info.gender);
  printf("请输入要添加联系人的年龄:\n");
  scanf("%d", &(info.age));
  printf("请输入要添加联系人的电话:\n");
  scanf("%s", info.tel);
  printf("请输入要添加联系人的地址:\n");
  scanf("%s", info.addr);
  //往通讯录中添加联系人数据
  SLPushBack(con, info);//与顺序表中尾插函数的参数对应
}

6.判断指定联系人是否存在

这个函数是在删除联系人查找联系人修改联系人中使用的,因为这三个操作都要先判断该联系人是否存在。若存在,则返回该联系人的位置下标,若不存在则返回-1。

int FindByname(const Contact* con, char name[])
{
  for (int i = 0; i < con->size; i++)
  {
    if (strcmp(con->arr[i].name, name) == 0)
    {
      //找到了
      return i;
    }
  }
  //没有找到
  return -1;
}

7.删除联系人数据

删除之前要判断这个人是否存在通讯录中,如果这个人存在,说明我们知道他的位置,直接复用顺序表中的对应函数进行删除。

void DelContact(Contact* con)
{
  //1.判断要删除的人是否存在
  char name[MAX_NAME];
  printf("请输入要删除人的姓名:\n");
  scanf("%s",name);
  int find = FindByname(con, name);
  if (find < 0)
  {
    printf("要删除的联系人不存在!\n");
    return;
  }
  //2.删除:知道了要删除的联系人数据对应的下标
  SLErase(con, find);
  printf("删除成功!\n");
  printf("\n");
}

8.查找联系人数据

在查找之前也要先判断该联系人是否存在,若存在,则打印出该联系人的全部信息;若不存在,则进行提示。

void FindContact(const Contact* con)
{
  char name[MAX_NAME];
  printf("请输入要查找的人的姓名:\n");
  scanf("%s", name);
  int find = FindByname(con, name);
  if (find < 0)
  {
    printf("要查找的人不存在!\n");
    return;
  }
  printf("%-5s %-5s %-5s %-5s %-5s\n", "姓名", "性别", "年龄", "电话", "地址");
    printf("%-5s %-5s %-5d %-5s %-5s\n", 
      con->arr[find].name,
      con->arr[find].gender,
      con->arr[find].age,
      con->arr[find].tel,
      con->arr[find].addr);
    printf("\n");
}

9.修改联系人数据

修改联系人之前也要判断此人是否存在,存在才修改,不存在则进行提示。

void ModifyContact(Contact* con)
{
  //1.判断要修改的联系人是否存在
  char name[MAX_NAME];
  printf("请输入要修改人的姓名:\n");
  scanf("%s", name);
  int find = FindByname(con, name);
  if (find < 0)
  {
    printf("要修改的联系人不存在!\n");
    return;
  }
  //联系人存在,直接修改指定下标的联系人信息
  printf("请输入新的联系人的姓名:\n");
  scanf("%s", con->arr[find].name);
  printf("请输入新的联系人的性别:\n");
  scanf("%s", con->arr[find].gender);
  printf("请输入新的联系人的年龄:\n");
  scanf("%d", &(con->arr[find].age));
  printf("请输入新的联系人的电话:\n");
  scanf("%s", con->arr[find].tel);
  printf("请输入新的联系人的地址:\n");
  scanf("%s", con->arr[find].addr);
  printf("修改成功!\n");
  printf("\n");
}

4. 通讯录完整代码

Contact.h

#pragma once
#include <stdio.h>
#include <string.h>
#define MAX_NAME 10
#define MAX_GENDER 10
#define MAX_TEL 20
#define MAX_ADDR 20
//定义联系人数据结构:姓名+性别+年龄+电话+地址
typedef struct PeosonInfo
{
  char name[MAX_NAME];
  char gender[MAX_GENDER];
  int age;
  char tel[MAX_TEL];
  char addr[MAX_ADDR];
}peoInfo;
//前置声明
typedef struct SeqList Contact;
//给通讯录改个名字,叫做通讯录
//注意:这里不能写做typedef SL Contact,而是要用原名。
//因为SL是在struct SeqList定义好了之后才重命名的
//要用到顺序表相关的方法,对通讯录的操作实际上就是对顺序表的操作
//有了前置声明,下面的 Contact* con 就是顺序表中的 SL*sl
//初始化通讯录
void InitContact(Contact* con);
//添加通讯录数据
void AddContact(Contact* con);
//删除通讯录数据
void DelContact(Contact* con);
//展示通讯录数据
void ShowContact(const Contact* con);
//查找通讯录数据
void FindContact(const Contact* con);
//修改通讯录数据
void ModifyContact(Contact* con);
//销毁通讯录数据
void DestroyContact(Contact* con);

Contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
#include "SeqList.h"
//初始化通讯录
void InitContact(Contact* con)//就是相当于SL* sl
{
  //实际上就是顺序表的初始化
  SLInit(con);
}
//销毁通讯录数据
void DestroyContact(Contact* con)
{
  SLDestory(con);
}
//添加通讯录数据
void AddContact(Contact* con)
{
  peoInfo info;
  printf("请输入要添加联系人的姓名:\n");
  scanf("%s", info.name);
  printf("请输入要添加联系人的性别:\n");
  scanf("%s", info.gender);
  printf("请输入要添加联系人的年龄:\n");
  scanf("%d", &(info.age));
  printf("请输入要添加联系人的电话:\n");
  scanf("%s", info.tel);
  printf("请输入要添加联系人的地址:\n");
  scanf("%s", info.addr);
  //往通讯录中添加联系人数据
  SLPushBack(con, info);//与顺序表中尾插函数的参数对应
}
//展示通讯录数据
void ShowContact(const Contact* con)
{
  //表头:姓名+性别+年龄+电话+地址
  printf("%-5s %-5s %-5s %-5s %-5s\n", "姓名", "性别", "年龄", "电话", "地址");
  for (int i = 0; i < con->size; i++)
  {
    printf("%-5s %-5s %-5d %-5s %-5s\n",
          con->arr[i].name,
          con->arr[i].gender, 
          con->arr[i].age, 
          con->arr[i].tel,
        con->arr[i].addr);
  } 
  printf("\n");
}
int FindByname(const Contact* con, char name[])
{
  for (int i = 0; i < con->size; i++)
  {
    if (strcmp(con->arr[i].name, name) == 0)
    {
      //找到了
      return i;
    }
  }
  //没有找到
  return -1;
}
//删除指定位置通讯录数据
void DelContact(Contact* con)
{
  //1.判断要删除的人是否存在
  char name[MAX_NAME];
  printf("请输入要删除人的姓名:\n");
  scanf("%s",name);
  int find = FindByname(con, name);
  if (find < 0)
  {
    printf("要删除的联系人不存在!\n");
    return;
  }
  //2.删除:知道了要删除的联系人数据对应的下标
  SLErase(con, find);
  printf("删除成功!\n");
  printf("\n");
}
//修改通讯录数据
void ModifyContact(Contact* con)
{
  //1.判断要修改的联系人是否存在
  char name[MAX_NAME];
  printf("请输入要修改人的姓名:\n");
  scanf("%s", name);
  int find = FindByname(con, name);
  if (find < 0)
  {
    printf("要修改的联系人不存在!\n");
    return;
  }
  //联系人存在,直接修改指定下标的联系人信息
  printf("请输入新的联系人的姓名:\n");
  scanf("%s", con->arr[find].name);
  printf("请输入新的联系人的性别:\n");
  scanf("%s", con->arr[find].gender);
  printf("请输入新的联系人的年龄:\n");
  scanf("%d", &(con->arr[find].age));
  printf("请输入新的联系人的电话:\n");
  scanf("%s", con->arr[find].tel);
  printf("请输入新的联系人的地址:\n");
  scanf("%s", con->arr[find].addr);
  printf("修改成功!\n");
  printf("\n");
}
//查找通讯录数据
void FindContact(const Contact* con)
{
  char name[MAX_NAME];
  printf("请输入要查找的人的姓名:\n");
  scanf("%s", name);
  int find = FindByname(con, name);
  if (find < 0)
  {
    printf("要查找的人不存在!\n");
    return;
  }
  printf("%-5s %-5s %-5s %-5s %-5s\n", "姓名", "性别", "年龄", "电话", "地址");
    printf("%-5s %-5s %-5d %-5s %-5s\n", 
      con->arr[find].name,
      con->arr[find].gender,
      con->arr[find].age,
      con->arr[find].tel,
      con->arr[find].addr);
    printf("\n");
}

Test.c

void menu()
{
  printf("**************    通讯录    *************\n");
  printf("******* 1.添加联系人  2.删除联系人 *******\n");
  printf("******* 3.查找联系人  4.修改联系人 *******\n");
  printf("******* 5.展示联系人  0.退出通讯录   *****\n");
  printf("******************************************\n");
}
enum option
{
  Exit,
  addcontact,
  delcontact,
  findcontact,
  modifycontact,
  showcontact
};
int main()
{
  //TestSeqList();
  //ContactTest();
  Contact con;
  InitContact(&con);
  int input = 1;
  do
  {
    menu();
    printf("请选择:");
    scanf("%d", &input);
    switch (input)
    {
    case Exit:
      printf("退出通讯录!\n");
      break;
    case addcontact:
      AddContact(&con);
      break;
    case delcontact:
      DelContact(&con);
      break;
    case findcontact:
      FindContact(&con);
      break;
    case modifycontact:
      ModifyContact(&con);
      break;
    case showcontact:
      ShowContact(&con);
      break;
    default:
      printf("选择错误,请重新选择!\n");
      break;
    }
  } while (input);
  return 0;
}
目录
相关文章
|
4月前
|
存储
基于静态顺序表实现通讯录
基于静态顺序表实现通讯录
|
11月前
通讯录的实现(增删查改排序)(2)
本课题模拟通讯录的实现,包括: 1.增加联系人的信息 2.删除联系人 3.查找联系人 4.修改联系人信息 5.对联系人进行排序
34 0
|
11月前
|
Go
通讯录的实现(增删查改排序)(1)
本课题模拟通讯录的实现,包括: 1.增加联系人的信息 2.删除联系人 3.查找联系人 4.修改联系人信息 5.对联系人进行排序
63 0
|
1月前
|
Java C++
【C项目】顺序表
【C项目】顺序表
|
2月前
|
存储 C语言
顺序表项目实战(基于动态顺序表实现通讯录)
顺序表项目实战(基于动态顺序表实现通讯录)
|
4月前
顺序表应用——通讯录实现
顺序表应用——通讯录实现
46 0
|
4月前
|
存储
【数据结构】----顺序表项目-通讯录
【数据结构】----顺序表项目-通讯录
20 0
|
4月前
|
存储 算法
|
4月前
顺序表的应用之通讯录
学习了顺序表之后,我们也得知道它的实际用途吧!所以,我们今天来学习一下通讯录的实现。
35 0
|
4月前
|
C语言
【通讯录项目 (2 / 3)】基于顺序表的通讯录实现——顺序表功能实现
顺序表的功能我们已经实现,我们使用的是最简单的顺序表,所以整个过程看起来没有困难。在下一篇文章中我们将进行通讯录的实现。 在通讯录里,顺序表的类型不在是简单的" int ",而是结构体类型。 下面给出通讯录的基本功能供大家参考预习。
33 0