评论

收藏

[C++] C语言之通讯录的模拟实现

编程语言 编程语言 发布于:2021-08-10 15:04 | 阅读数:512 | 评论:0

C语言之通讯录的模拟实现在C语言学习结束之际,谨以此篇文章来对C语言的学习告一段落。
纲要:

  • 通讯录的静态版本
  • 通讯录的动态版本
  • 通讯录的带文件版本
因为三种实现方法除了储存形式不同,其他都基本相同,所以我们重点论述静态版本的实现,以及它们不同的储存方式。

一.通讯录的静态版本
为什么叫它为静态版本呢,因为在此部分的储存是以数组来储存的,那对于各种各样的信息,我们要拿什么数组来存放它呢?当然是结构体数组了,所以我们来定义一个结构体来表示个人信息:
//采用宏的目的是方便日后修改
#define NAME_MAX 20
#define SEX_MAX 5
#define PNUM_MAX 13
#define ADDR_MAX 20
#define MAX 10
//存放个人信息的结构体
typedef struct Data
{
  char name[NAME_MAX];//姓名
  int age;//年龄
  char sex[SEX_MAX];//性别
  char pnum[PNUM_MAX];//电话
  char addr[ADDR_MAX];//地址
} Data;
现在有了个人信息的结构体,我们需要再来一个结构体来存放它的数组及数组内有效信息的个数,即:
//存放MAX个个人信息的通讯录
typedef struct Contact
{
  Data data[MAX];
  int size;
} Contact;
那么,准备工作做好之后,我们就开始正式实现了,首先我们肯定是要先创建一个通讯录,这时我们再来想一想,我们就这样创建之后,我们是否可以直接使用呢?
对此我们来看一张图片:
DSC0000.png

我们发现,现在它里面都放着一些随机值,所以我们需要将其初始化一下,来方便我们的使用:
void ContactInit(Contact *p)
{
  //保证p不为NULL
  assert(p);
  //置零
  memset(p->data, 0, sizeof(p->data));
  p->size = 0;
}
我们再来看一下结果:
DSC0001.png

我们发现,现在它内部已经被我们置为了0;接着我们做的就是添加联系人了,不过在此之前,我们不妨先做一个菜单来显示我们都有一些什么功能:
void menu()
{
  //打印菜单
  printf("******************************************\n");
  printf("******    1.add     2.del     ******\n");
  printf("******    3.search  4.modify  ******\n");
  printf("******    5.show    6.sort    ******\n");
  printf("******    7.help    0.exit    ******\n");
  printf("******************************************\n");
}
接着是我们的帮助选项:
//打印帮助信息
void ContactHelp(Contact *p)
{
  printf("*******************************************\n");
  printf("******   add ---- 添加联系人信息  ******\n");
  printf("******   del ---- 删除联系人信息  ******\n");
  printf("******  search ---- 查找联系人信息  ******\n");
  printf("******  modify ---- 修改联系人信息  ******\n");
  printf("******  show ---- 展示联系人信息  ******\n");
  printf("******  help ---- 帮助信息      ******\n");
  printf("******  sort ---- 排序联系人信息  ******\n");
  printf("******  exit ---- 退出通讯录    ******\n");
  printf("*******************************************\n");
}
以及我们来用枚举来定义一些常量,方便在switch()结构中 来辨别它走了哪条路线:
//枚举来作为常量使得在看代码时比较清晰
enum choice
{
  EXIT,
  ADD,
  DEL,
  SEARCH,
  MODIFY,
  SHOW,
  SORT,
  HELP
};
以及写出我们的选择结构:我们采用do-while循环
void test()
{
  Contact list;//定义一个通讯录
  Contact *p = &list;//赋址
  //初始化
  ContactInit(p);
  int input = 0;
  do
  {
    menu();
    printf("请输入你的选择:> ");
    scanf("%d", &input);
    switch (input)
    {
      case ADD:
        ContactAdd(p);
        break;
      case DEL:
        ContactDel(p);
        break;
      case SEARCH:
        ContactSearch(p);
        break;
      case MODIFY:
        ContactModify(p);
        break;
      case SHOW:
        ContactShow(p);
        break;
      case SORT:
        ContactSort(p);
        break;
      case HELP:
        ContactHelp(p);
        break;
      case EXIT:
        ContactExit(p);
        break;
      default:
        printf("输入非法!");
    }
  } while (input);
}
这样的好处是当用户输入0时循环便自己停止,不用我们再次去判断当用户输入0时我们要退出的问题,接下来我们就来填写我们函数的内容了:
1.添加联系人
//添加联系人
void ContactAdd(Contact *p)
{
  //断言保证p不为NULL
  assert(p);
  //如果联系人容量已经等于最大容量了
  if(p->size==MAX)
  {
    printf("通讯录已满,请删除一些后继续添加!\n");
    return ;
  }
  Data person;//记录联系人信息
  printf("请输入联系人的姓名:>");
  scanf("%s", person.name);
  printf("请输入联系人的年龄:>");
  scanf("%d", &person.age);
  printf("请输入联系人的性别:>");
  scanf("%s", person.sex);
  printf("请输入联系人的电话:>");
  scanf("%s", person.pnum);
  printf("请输入联系人的住址:>");
  scanf("%s", person.addr);
  //将联系人信息存到通讯录中
  p->data[p->size] = person;
  p->size++;
}
DSC0002.png

我们要是观察到我们输入的信息,最好就是把我们所输入的信息给打印出来:
2.展示联系人
//展示联系人信息
void ContactShow(Contact *p)
{
  if (p->size == 0)
  {
    printf("通讯录中并无一人!\n");return ;
  }
  int i = 0;
  printf("  姓名\t性别\t  年龄\t   电话\t\t地址\n");
  for (i = 0; i < p->size; i++)
  {
    printf("   %-5s\t%s\t%d\t%s\t%s\n", p->data[i].name,
         p->data[i].sex,
         p->data[i].age,
         p->data[i].pnum,
         p->data[i].addr);
  }
}
测试结果:
DSC0003.png

DSC0004.png

接下来就是删除联系人了
3.删除联系人
首先删除联系人肯定需要查找信息,又因为后面的几个函数也要用到它,所以我们单独来写一个查找模块:
//查找模块
int ContactFind(Contact *p, char *FindData)
{
  assert(p);
  int i = 0;
  for (i = 0; i < p->size; i++)
  {
    if (strcmp(p->data[i].name, FindData) == 0)
    {
      return i;//找到就返回下标
    }
  }
  return -1;//找不到就返回-1
}
删除:
//删除联系人
void ContactDel(Contact *p)
{
  assert(p);
  char DelName[NAME_MAX] = {0};
  printf("请输入你要删除的联系人姓名:>");
  scanf("%s", DelName);
  int ret = ContactFind(p, DelName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    int j = 0;
    for (j = ret; j < p->size; j++)
    {
      //从前往后依次挪动覆盖
      p->data[j] = p->data[j + 1];
    }
    //删除完成之后,联系人个数减一
    p->size--;
  }
}
DSC0005.png

DSC0006.png

DSC0007.png

4.查找联系人信息
//查找联系人
void ContactSearch(Contact *p)
{
  assert(p);
  char SearchName[NAME_MAX];
  printf("请输入你要查找的联系人姓名:>\n");
  scanf("%s",SearchName);
  //查找有无此人
  int ret = ContactFind(p,SearchName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    printf("你所查找的联系人信息为:\n");
    printf("  姓名\t性别\t  年龄\t   电话\t\t地址\n");
    printf("   %-5s\t%s\t%d\t%s\t%s\n", p->data[ret].name,
         p->data[ret].sex,
         p->data[ret].age,
         p->data[ret].pnum,
         p->data[ret].addr);
  }
}
DSC0008.png

DSC0009.png

5.修改联系人信息
//修改联系人信息
void ContactModify(Contact *p)
{
  assert(p);
  char ModifyName[NAME_MAX];
  printf("请输入你要修改的联系人姓名:>");
  scanf("%s",ModifyName);
  int ret = ContactFind(p,ModifyName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    Data person;//记录联系人信息
    printf("请输入联系人的姓名:>");
    scanf("%s", person.name);
    printf("请输入联系人的年龄:>");
    scanf("%d", &person.age);
    printf("请输入联系人的性别:>");
    scanf("%s", person.sex);
    printf("请输入联系人的电话:>");
    scanf("%s", person.pnum);
    printf("请输入联系人的住址:>");
    scanf("%s", person.addr);
    //将联系人信息存到通讯录中
    p->data[ret] = person;
  }
}
DSC00010.png

DSC00011.png

6.排序联系人 --- 我们使用 qsort 来排序
enum sort_by
{
  NAME=1,
  SEX,
  AGE,
  PNUM,
  ADDR
};
void sort_menu()
{
  printf("       SORT_MENU      \n");
  printf("******************************\n");
  printf("****    1.name    ****\n");
  printf("****    2.sex     ****\n");
  printf("****    3.age     ****\n");
  printf("****    4.pnum    ****\n");
  printf("****    5.addr    ****\n");
  printf("******************************\n");
}
int sort_by_name(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->name, ((Data *) s2)->name);
}
int sort_by_sex(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->sex, ((Data *) s2)->sex);
}
int sort_by_age(const void *s1, const void *s2)
{
  return ((Data *) s1)->age - ((Data *) s2)->age;
}
int sort_by_pnum(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->pnum, ((Data *) s2)->pnum);
}
int sort_by_addr(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->addr, ((Data *) s2)->addr);
}

//排序联系人
void ContactSort(Contact *p)
{
  assert(p);
  int choice;
  sort_menu();
  printf("请选择排序的参考量:>");
  scanf("%d", &choice);
  switch (choice)
  {
    case NAME:
      qsort(p->data, p->size, sizeof(Data), sort_by_name);
      break;
    case SEX:
      qsort(p->data, p->size, sizeof(Data), sort_by_sex);
      break;
    case AGE:
      qsort(p->data, p->size, sizeof(Data), sort_by_age);
      break;
    case PNUM:
      qsort(p->data, p->size, sizeof(Data), sort_by_pnum);
      break;
    case ADDR:
      qsort(p->data, p->size, sizeof(Data), sort_by_addr);
      break;
    default:
      printf("输入有误,请检查输入!\n");
  }
}
DSC00012.png

DSC00013.png

到这,我们的静态通讯录就完了,但是我们仍可对用户操作优化一下,如:及时的清屏等,以及暂停:
例:
do
  {
    menu();
    printf("请输入你的选择:>");
    scanf("%d", &input);
    system("cls");
    switch (input)
    {
      case QUIT:
        printf("退出通讯录!\n");
        break;
      case ADD:
        add(p);
        system("pause");
        system("cls");
        break;
      case DEL:
        del(p);
        system("pause");
        system("cls");
        break;
      case SEARCH:
        search(p);
        system("pause");
        system("cls");
        break;
      case MODIFY:
        modify(p);
        system("pause");
        system("cls");
        break;
      case SHOW:
        show(p);
        system("pause");
        system("cls");
        break;
      case SORT:
        sort(p);
        system("pause");
        system("cls");
        break;
      case HELP:
        help();
        system("pause");
        system("cls");
        break;
      default:
        printf("非法输入,请检查输入!\n");
        system("pause");
        system("cls");
        break;
    }
  } while (input);
这样我们的界面看起来就干净多了,但是有没有发现,我们为了达到这个效果,我们写了很多重复的代码!
那这样我们应该怎么办呢 --- 还记得我们之前所提到的函数指针数组吗?
void test2()
{
  Contact list;//定义一个通讯录
  Contact *p = &list;//赋址
  //初始化
  ContactInit(p);
  //用一个函数指针数组来存放函数指针
  void (*fun[])(Contact *) ={ContactExit,
                 ContactAdd,
                 ContactDel,
                 ContactSearch,
                 ContactModify,
                 ContactShow,
                 ContactSort,
                 ContactHelp};
  int input = 0;//存放用户选择的信息
  do{
    menu();
    printf("请输入你的选择:>");
    scanf("%d", &input);
    system("cls");
    if(input>=0&&input<=sizeof(fun))
    {
      fun[input](p);
      system("cls");
    }
    else
    {
      system("cls");
      printf("输入非法,请检查输入!\n");
    }
  }while(input);
}
这样是不是代码就少了很多!
所以完整代码如下:
DSC00014.gif DSC00015.gif
//确保文件只包含一次
#ifndef CONTACT_CONTACT_H
#define CONTACT_CONTACT_H
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <assert.h>
//采用宏的目的是方便日后修改
#define NAME_MAX 20
#define SEX_MAX 8
#define PNUM_MAX 13
#define ADDR_MAX 20
#define MAX 10
//存放个人信息的结构体
typedef struct Data
{
  char name[NAME_MAX];//姓名
  int age;//年龄
  char sex[SEX_MAX];//性别
  char pnum[PNUM_MAX];//电话
  char addr[ADDR_MAX];//地址
} Data;
//存放MAX个个人信息的通讯录
typedef struct Contact
{
  Data data[MAX];
  int size;
} Contact;
//枚举来作为常量使得在看代码时比较清晰
enum choice
{
  EXIT,
  ADD,
  DEL,
  SEARCH,
  MODIFY,
  SHOW,
  SORT,
  HELP
};
enum sort_by
{
  NAME=1,
  SEX,
  AGE,
  PNUM,
  ADDR
};

//初始化通讯录
void ContactInit(Contact *p);
//添加联系人
void ContactAdd(Contact* p);
//删除联系人
void ContactDel(Contact* p);
//查找联系人
void ContactSearch(Contact* p);
//修改联系人信息
void ContactModify(Contact* p);
//展示联系人信息
void ContactShow(Contact* p);
//排序联系人
void ContactSort(Contact* p);
//打印帮助
void ContactHelp(Contact* p);
//退出通讯录
void ContactExit(Contact* p);


#endif //CONTACT_CONTACT_H
Contact.h
#include "Contact.h"
// 强调!!!
//调试请加setbuf(stdout,NULL)!!!

//查找模块
int ContactFind(Contact *p, char *FindData)
{
  assert(p);
  int i = 0;
  for (i = 0; i < p->size; i++)
  {
    if (strcmp(p->data[i].name, FindData) == 0)
    {
      return i;//找到就返回下标
    }
  }
  return -1;//找不到就返回-1
}
void ContactInit(Contact *p)
{
  //保证p不为NULL
  assert(p);
  //置零
  memset(p->data, 0, sizeof(p->data));
  p->size = 0;
}

//添加联系人
void ContactAdd(Contact *p)
{
  //断言保证p不为NULL
  assert(p);
  //如果联系人容量已经等于最大容量了
  if (p->size == MAX)
  {
    printf("通讯录已满,请删除一些后继续添加!\n");
    return;
  }
  Data person;//记录联系人信息
  printf("请输入联系人的姓名:>");
  scanf("%s", person.name);
  printf("请输入联系人的年龄:>");
  scanf("%d", &person.age);
  printf("请输入联系人的性别:>");
  scanf("%s", person.sex);
  printf("请输入联系人的电话:>");
  scanf("%s", person.pnum);
  printf("请输入联系人的住址:>");
  scanf("%s", person.addr);
  //将联系人信息存到通讯录中
  p->data[p->size] = person;
  p->size++;
}
//删除联系人
void ContactDel(Contact *p)
{
  assert(p);
  char DelName[NAME_MAX] = {0};
  printf("请输入你要删除的联系人姓名:>");
  scanf("%s", DelName);
  int ret = ContactFind(p, DelName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    int j = 0;
    for (j = ret; j < p->size; j++)
    {
      //从前往后依次挪动覆盖
      p->data[j] = p->data[j + 1];
    }
    //删除完成之后,联系人个数减一
    p->size--;
  }
}
//查找联系人
void ContactSearch(Contact *p)
{
  assert(p);
  char SearchName[NAME_MAX];
  printf("请输入你要查找的联系人姓名:>");
  scanf("%s", SearchName);
  //查找有无此人
  int ret = ContactFind(p, SearchName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    printf("你所查找的联系人信息为:\n");
    printf("  姓名\t性别\t  年龄\t   电话\t\t地址\n");
    printf("   %-5s\t%s\t%d\t%s\t%s\n", p->data[ret].name,
         p->data[ret].sex,
         p->data[ret].age,
         p->data[ret].pnum,
         p->data[ret].addr);
  }
}
//修改联系人信息
void ContactModify(Contact *p)
{
  assert(p);
  char ModifyName[NAME_MAX];
  printf("请输入你要修改的联系人姓名:>");
  scanf("%s", ModifyName);
  int ret = ContactFind(p, ModifyName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    Data person;//记录联系人信息
    printf("请输入联系人的姓名:>");
    scanf("%s", person.name);
    printf("请输入联系人的年龄:>");
    scanf("%d", &person.age);
    printf("请输入联系人的性别:>");
    scanf("%s", person.sex);
    printf("请输入联系人的电话:>");
    scanf("%s", person.pnum);
    printf("请输入联系人的住址:>");
    scanf("%s", person.addr);
    //将联系人信息存到通讯录中
    p->data[ret] = person;
  }
}
//展示联系人信息
void ContactShow(Contact *p)
{
  if (p->size == 0)
  {
    printf("通讯录中并无一人!\n");
    return;
  }
  int i = 0;
  printf("  姓名\t性别\t  年龄\t   电话\t\t地址\n");
  for (i = 0; i < p->size; i++)
  {
    printf("   %-5s\t%s\t%d\t%s\t%s\n", p->data[i].name,
         p->data[i].sex,
         p->data[i].age,
         p->data[i].pnum,
         p->data[i].addr);
  }
}
void sort_menu()
{
  printf("       SORT_MENU      \n");
  printf("******************************\n");
  printf("****    1.name    ****\n");
  printf("****    2.sex     ****\n");
  printf("****    3.age     ****\n");
  printf("****    4.pnum    ****\n");
  printf("****    5.addr    ****\n");
  printf("******************************\n");
}
int sort_by_name(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->name, ((Data *) s2)->name);
}
int sort_by_sex(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->sex, ((Data *) s2)->sex);
}
int sort_by_age(const void *s1, const void *s2)
{
  return ((Data *) s1)->age - ((Data *) s2)->age;
}
int sort_by_pnum(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->pnum, ((Data *) s2)->pnum);
}
int sort_by_addr(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->addr, ((Data *) s2)->addr);
}

//排序联系人
void ContactSort(Contact *p)
{
  assert(p);
  int choice;
  sort_menu();
  printf("请选择排序的参考量:>");
  scanf("%d", &choice);
  switch (choice)
  {
    case NAME:
      qsort(p->data, p->size, sizeof(Data), sort_by_name);
      break;
    case SEX:
      qsort(p->data, p->size, sizeof(Data), sort_by_sex);
      break;
    case AGE:
      qsort(p->data, p->size, sizeof(Data), sort_by_age);
      break;
    case PNUM:
      qsort(p->data, p->size, sizeof(Data), sort_by_pnum);
      break;
    case ADDR:
      qsort(p->data, p->size, sizeof(Data), sort_by_addr);
      break;
    default:
      printf("输入有误,请检查输入!\n");
  }
}
//打印帮助信息
void ContactHelp(Contact *p)
{
  printf("*******************************************\n");
  printf("******   add ---- 添加联系人信息  ******\n");
  printf("******   del ---- 删除联系人信息  ******\n");
  printf("******  search ---- 查找联系人信息  ******\n");
  printf("******  modify ---- 修改联系人信息  ******\n");
  printf("******  show ---- 展示联系人信息  ******\n");
  printf("******  help ---- 帮助信息      ******\n");
  printf("******  sort ---- 排序联系人信息  ******\n");
  printf("******  exit ---- 退出通讯录    ******\n");
  printf("*******************************************\n");
}
//退出通讯录
void ContactExit(Contact *p)
{
  printf("exit !\n");
}
Contact.c
#include "Contact.h"
void menu()
{
  //打印菜单
  printf("******************************************\n");
  printf("******    1.add     2.del     ******\n");
  printf("******    3.search  4.modify  ******\n");
  printf("******    5.show    6.sort    ******\n");
  printf("******    7.help    0.exit    ******\n");
  printf("******************************************\n");
}
void test()
{
  Contact list;//定义一个通讯录
  Contact *p = &list;//赋址
  //初始化
  ContactInit(p);
  int input = 0;//存放用户选择的信息
  do
  {
    menu();
    printf("请输入你的选择:>");
    scanf("%d", &input);
    switch (input)
    {
      case ADD:
        ContactAdd(p);
        break;
      case DEL:
        ContactDel(p);
        break;
      case SEARCH:
        ContactSearch(p);
        break;
      case MODIFY:
        ContactModify(p);
        break;
      case SHOW:
        ContactShow(p);
        break;
      case SORT:
        ContactSort(p);
        break;
      case HELP:
        ContactHelp(p);
        break;
      case EXIT:
        ContactExit(p);
        break;
      default:
        printf("输入非法!\n");
    }
  } while (input);
}
void test2()
{
  Contact list;//定义一个通讯录
  Contact *p = &list;//赋址
  //初始化
  ContactInit(p);
  //用一个函数指针数组来存放函数指针
  void (*fun[])(Contact *) ={ContactExit,
                 ContactAdd,
                 ContactDel,
                 ContactSearch,
                 ContactModify,
                 ContactShow,
                 ContactSort,
                 ContactHelp};
  int input = 0;//存放用户选择的信息
  do{
    menu();
    printf("请输入你的选择:>");
    scanf("%d", &input);
    system("cls");
    if(input>=0&&input<=sizeof(fun))
    {
      fun[input](p);
      system("cls");
    }
    else
    {
      system("cls");
      printf("输入非法,请检查输入!\n");
    }
  }while(input);
}
int main()
{
  //test();
  test2();
  return 0;
}
main.c

二.动态通讯录
动态实现的问题主要在于它的容量不再是一变不变的,而是可随着我们的数据量来变化的,所以在我们原来定义的Contact结构体就要微微改变一下了:
typedef struct Contact
{
  Data* data;//存放数据
  int size;//有效数据的个数
  int capacity;//容量的大小
} Contact;
初始化函数也要改改:
//初始化 --- 动态
void ContactInit(Contact *p)
{
  assert(p);
  p->data=NULL;
  p->size=0;
  p->capacity=1;
}
那么这样,添加函数也有一定的变化:
//检查容量函数
void CheckCapacity(Contact *p)
{
  assert(p);
  //如果联系人个数为0或与容量相同,就需要扩容
  if (p->size == 0 || p->size == p->capacity)
  {
    //动态内存开辟
    Data *ptr = (Data *) realloc(p->data, sizeof(Data) * p->capacity * 2);
    if (ptr == NULL)//开辟失败
    {
      //报错
      perror("CHECK CAPACITY ERROE !\n");
      exit(-1);
    }
    //开辟成功,重新赋值
    p->data = ptr;
    //扩容之后,容量也相应扩大
    p->capacity *= 2;
  }
  //反之什么都不需要干
}
//添加联系人 --- 动态
void ContactAdd(Contact *p)
{
  //断言保证p不为NULL
  assert(p);
  //如果联系人个数等于容量,或联系人个数等于0,这时我们就需要扩容了,我们来使用一个函数来干这事
  CheckCapacity(p);
  Data person;//记录联系人信息
  printf("请输入联系人的姓名:>");
  scanf("%s", person.name);
  printf("请输入联系人的年龄:>");
  scanf("%d", &person.age);
  printf("请输入联系人的性别:>");
  scanf("%s", person.sex);
  printf("请输入联系人的电话:>");
  scanf("%s", person.pnum);
  printf("请输入联系人的住址:>");
  scanf("%s", person.addr);
  //将联系人信息存到通讯录中
  p->data[p->size] = person;
  p->size++;
}
最后我们还要记得释放我们开辟的内存 --- 退出
//退出通讯录 --- 动态
void ContactExit(Contact *p)
{
  //释放我们开辟的内存
  free(p->data);
  printf("exit !\n");
}
动态通讯录的修改就只有这些:
完整代码展示:
//确保文件只包含一次
#ifndef CONTACT_CONTACT_H
#define CONTACT_CONTACT_H
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <assert.h>
//采用宏的目的是方便日后修改
#define NAME_MAX 20
#define SEX_MAX 8
#define PNUM_MAX 13
#define ADDR_MAX 20
#define MAX 10
//存放个人信息的结构体
typedef struct Data
{
  char name[NAME_MAX];//姓名
  int age;//年龄
  char sex[SEX_MAX];//性别
  char pnum[PNUM_MAX];//电话
  char addr[ADDR_MAX];//地址
} Data;
/*
//存放MAX个个人信息的通讯录 --- 静态
typedef struct Contact
{
  Data data[MAX];
  int size;
} Contact;
*/
//存放MAX个个人信息的通讯录 --- 动态
typedef struct Contact
{
  Data* data;//存放数据
  int size;//有效数据的个数
  int capacity;//容量的大小
} Contact;
//枚举来作为常量使得在看代码时比较清晰
enum choice
{
  EXIT,
  ADD,
  DEL,
  SEARCH,
  MODIFY,
  SHOW,
  SORT,
  HELP
};
enum sort_by
{
  NAME=1,
  SEX,
  AGE,
  PNUM,
  ADDR
};

//初始化通讯录
void ContactInit(Contact *p);
//添加联系人
void ContactAdd(Contact* p);
//删除联系人
void ContactDel(Contact* p);
//查找联系人
void ContactSearch(Contact* p);
//修改联系人信息
void ContactModify(Contact* p);
//展示联系人信息
void ContactShow(Contact* p);
//排序联系人
void ContactSort(Contact* p);
//打印帮助
void ContactHelp(Contact* p);
//退出通讯录
void ContactExit(Contact* p);


#endif //CONTACT_CONTACT_H
Contact.h
#include "Contact.h"
// 强调!!!
//调试请加setbuf(stdout,NULL)!!!

//查找模块
int ContactFind(Contact *p, char *FindData)
{
  assert(p);
  int i = 0;
  for (i = 0; i < p->size; i++)
  {
    if (strcmp(p->data[i].name, FindData) == 0)
    {
      return i;//找到就返回下标
    }
  }
  return -1;//找不到就返回-1
}
/*
//初始化 --- 静态
void ContactInit(Contact *p)
{
  //保证p不为NULL
  assert(p);
  //置零
  memset(p->data, 0, sizeof(p->data));
  p->size = 0;
}
*/
//初始化 --- 动态
void ContactInit(Contact *p)
{
  assert(p);
  p->data = NULL;
  p->size = 0;
  p->capacity = 1;
}
/*//添加联系人 --- 静态
void ContactAdd(Contact *p)
{
  //断言保证p不为NULL
  assert(p);
  //如果联系人容量已经等于最大容量了
  if (p->size == MAX)
  {
    printf("通讯录已满,请删除一些后继续添加!\n");
    return;
  }
  Data person;//记录联系人信息
  printf("请输入联系人的姓名:>");
  scanf("%s", person.name);
  printf("请输入联系人的年龄:>");
  scanf("%d", &person.age);
  printf("请输入联系人的性别:>");
  scanf("%s", person.sex);
  printf("请输入联系人的电话:>");
  scanf("%s", person.pnum);
  printf("请输入联系人的住址:>");
  scanf("%s", person.addr);
  //将联系人信息存到通讯录中
  p->data[p->size] = person;
  p->size++;
}*/
//检查容量函数
void CheckCapacity(Contact *p)
{
  assert(p);
  //如果联系人个数为0或与容量相同,就需要扩容
  if (p->size == 0 || p->size == p->capacity)
  {
    //动态内存开辟
    Data *ptr = (Data *) realloc(p->data, sizeof(Data) * p->capacity * 2);
    if (ptr == NULL)//开辟失败
    {
      //报错
      perror("CHECK CAPACITY ERROE !\n");
      exit(-1);
    }
    //开辟成功,重新赋值
    p->data = ptr;
    //扩容之后,容量也相应扩大
    p->capacity *= 2;
  }
  //反之什么都不需要干
}
//添加联系人 --- 动态
void ContactAdd(Contact *p)
{
  //断言保证p不为NULL
  assert(p);
  //如果联系人个数等于容量,或联系人个数等于0,这时我们就需要扩容了,我们来使用一个函数来干这事
  CheckCapacity(p);
  Data person;//记录联系人信息
  printf("请输入联系人的姓名:>");
  scanf("%s", person.name);
  printf("请输入联系人的年龄:>");
  scanf("%d", &person.age);
  printf("请输入联系人的性别:>");
  scanf("%s", person.sex);
  printf("请输入联系人的电话:>");
  scanf("%s", person.pnum);
  printf("请输入联系人的住址:>");
  scanf("%s", person.addr);
  //将联系人信息存到通讯录中
  p->data[p->size] = person;
  p->size++;
}
//删除联系人
void ContactDel(Contact *p)
{
  assert(p);
  char DelName[NAME_MAX] = {0};
  printf("请输入你要删除的联系人姓名:>");
  scanf("%s", DelName);
  int ret = ContactFind(p, DelName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    int j = 0;
    for (j = ret; j < p->size; j++)
    {
      //从前往后依次挪动覆盖
      p->data[j] = p->data[j + 1];
    }
    //删除完成之后,联系人个数减一
    p->size--;
  }
}
//查找联系人
void ContactSearch(Contact *p)
{
  assert(p);
  char SearchName[NAME_MAX];
  printf("请输入你要查找的联系人姓名:>");
  scanf("%s", SearchName);
  //查找有无此人
  int ret = ContactFind(p, SearchName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    printf("你所查找的联系人信息为:\n");
    printf("  姓名\t性别\t  年龄\t   电话\t\t地址\n");
    printf("   %-5s\t%s\t%d\t%s\t%s\n", p->data[ret].name,
         p->data[ret].sex,
         p->data[ret].age,
         p->data[ret].pnum,
         p->data[ret].addr);
  }
}
//修改联系人信息
void ContactModify(Contact *p)
{
  assert(p);
  char ModifyName[NAME_MAX];
  printf("请输入你要修改的联系人姓名:>");
  scanf("%s", ModifyName);
  int ret = ContactFind(p, ModifyName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    Data person;//记录联系人信息
    printf("请输入联系人的姓名:>");
    scanf("%s", person.name);
    printf("请输入联系人的年龄:>");
    scanf("%d", &person.age);
    printf("请输入联系人的性别:>");
    scanf("%s", person.sex);
    printf("请输入联系人的电话:>");
    scanf("%s", person.pnum);
    printf("请输入联系人的住址:>");
    scanf("%s", person.addr);
    //将联系人信息存到通讯录中
    p->data[ret] = person;
  }
}
//展示联系人信息
void ContactShow(Contact *p)
{
  if (p->size == 0)
  {
    printf("通讯录中并无一人!\n");
    return;
  }
  int i = 0;
  printf("  姓名\t性别\t  年龄\t   电话\t\t地址\n");
  for (i = 0; i < p->size; i++)
  {
    printf("   %-5s\t%s\t%d\t%s\t%s\n", p->data[i].name,
         p->data[i].sex,
         p->data[i].age,
         p->data[i].pnum,
         p->data[i].addr);
  }
}
void sort_menu()
{
  printf("       SORT_MENU      \n");
  printf("******************************\n");
  printf("****    1.name    ****\n");
  printf("****    2.sex     ****\n");
  printf("****    3.age     ****\n");
  printf("****    4.pnum    ****\n");
  printf("****    5.addr    ****\n");
  printf("******************************\n");
}
int sort_by_name(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->name, ((Data *) s2)->name);
}
int sort_by_sex(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->sex, ((Data *) s2)->sex);
}
int sort_by_age(const void *s1, const void *s2)
{
  return ((Data *) s1)->age - ((Data *) s2)->age;
}
int sort_by_pnum(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->pnum, ((Data *) s2)->pnum);
}
int sort_by_addr(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->addr, ((Data *) s2)->addr);
}

//排序联系人
void ContactSort(Contact *p)
{
  assert(p);
  int choice;
  sort_menu();
  printf("请选择排序的参考量:>");
  scanf("%d", &choice);
  switch (choice)
  {
    case NAME:
      qsort(p->data, p->size, sizeof(Data), sort_by_name);
      break;
    case SEX:
      qsort(p->data, p->size, sizeof(Data), sort_by_sex);
      break;
    case AGE:
      qsort(p->data, p->size, sizeof(Data), sort_by_age);
      break;
    case PNUM:
      qsort(p->data, p->size, sizeof(Data), sort_by_pnum);
      break;
    case ADDR:
      qsort(p->data, p->size, sizeof(Data), sort_by_addr);
      break;
    default:
      printf("输入有误,请检查输入!\n");
  }
}
//打印帮助信息
void ContactHelp(Contact *p)
{
  printf("*******************************************\n");
  printf("******   add ---- 添加联系人信息  ******\n");
  printf("******   del ---- 删除联系人信息  ******\n");
  printf("******  search ---- 查找联系人信息  ******\n");
  printf("******  modify ---- 修改联系人信息  ******\n");
  printf("******  show ---- 展示联系人信息  ******\n");
  printf("******  help ---- 帮助信息      ******\n");
  printf("******  sort ---- 排序联系人信息  ******\n");
  printf("******  exit ---- 退出通讯录    ******\n");
  printf("*******************************************\n");
}
/*//退出通讯录
void ContactExit(Contact *p)
{
  printf("exit !\n");
}*/
//退出通讯录 --- 动态
void ContactExit(Contact *p)
{
  //释放我们开辟的内存
  free(p->data);
  printf("exit !\n");
}
Contact.c
#include "Contact.h"
void menu()
{
  //打印菜单
  printf("******************************************\n");
  printf("******    1.add     2.del     ******\n");
  printf("******    3.search  4.modify  ******\n");
  printf("******    5.show    6.sort    ******\n");
  printf("******    7.help    0.exit    ******\n");
  printf("******************************************\n");
}
void test()
{
  Contact list;//定义一个通讯录
  Contact *p = &list;//赋址
  //初始化
  ContactInit(p);
  int input = 0;//存放用户选择的信息
  do
  {
    menu();
    printf("请输入你的选择:>");
    scanf("%d", &input);
    switch (input)
    {
      case ADD:
        ContactAdd(p);
        break;
      case DEL:
        ContactDel(p);
        break;
      case SEARCH:
        ContactSearch(p);
        break;
      case MODIFY:
        ContactModify(p);
        break;
      case SHOW:
        ContactShow(p);
        break;
      case SORT:
        ContactSort(p);
        break;
      case HELP:
        ContactHelp(p);
        break;
      case EXIT:
        ContactExit(p);
        break;
      default:
        printf("输入非法!\n");
    }
  } while (input);
}
void test2()
{
  Contact list;//定义一个通讯录
  Contact *p = &list;//赋址
  //初始化
  ContactInit(p);
  //用一个函数指针数组来存放函数指针
  void (*fun[])(Contact *) ={ContactExit,
                 ContactAdd,
                 ContactDel,
                 ContactSearch,
                 ContactModify,
                 ContactShow,
                 ContactSort,
                 ContactHelp};
  int input = 0;//存放用户选择的信息
  do{
    menu();
    printf("请输入你的选择:>");
    scanf("%d", &input);
    if(input>=0&&input<=sizeof(fun))
    {
      //system("cls");
      fun[input](p);
    }
    else
    {
      system("cls");
      printf("输入非法,请检查输入!\n");
    }
  }while(input);
}
int main()
{
  //test();
  test2();
  return 0;
}
#include "Contact.h"
void menu()
{
  //打印菜单
  printf("******************************************\n");
  printf("******    1.add     2.del     ******\n");
  printf("******    3.search  4.modify  ******\n");
  printf("******    5.show    6.sort    ******\n");
  printf("******    7.help    0.exit    ******\n");
  printf("******************************************\n");
}
void test()
{
  Contact list;//定义一个通讯录
  Contact *p = &list;//赋址
  //初始化
  ContactInit(p);
  int input = 0;//存放用户选择的信息
  do
  {
    menu();
    printf("请输入你的选择:>");
    scanf("%d", &input);
    switch (input)
    {
      case ADD:
        ContactAdd(p);
        break;
      case DEL:
        ContactDel(p);
        break;
      case SEARCH:
        ContactSearch(p);
        break;
      case MODIFY:
        ContactModify(p);
        break;
      case SHOW:
        ContactShow(p);
        break;
      case SORT:
        ContactSort(p);
        break;
      case HELP:
        ContactHelp(p);
        break;
      case EXIT:
        ContactExit(p);
        break;
      default:
        printf("输入非法!\n");
    }
  } while (input);
}
void test2()
{
  Contact list;//定义一个通讯录
  Contact *p = &list;//赋址
  //初始化
  ContactInit(p);
  //用一个函数指针数组来存放函数指针
  void (*fun[])(Contact *) ={ContactExit,
                 ContactAdd,
                 ContactDel,
                 ContactSearch,
                 ContactModify,
                 ContactShow,
                 ContactSort,
                 ContactHelp};
  int input = 0;//存放用户选择的信息
  do{
    menu();
    printf("请输入你的选择:>");
    scanf("%d", &input);
    if(input>=0&&input<=sizeof(fun))
    {
      //system("cls");
      fun[input](p);
    }
    else
    {
      system("cls");
      printf("输入非法,请检查输入!\n");
    }
  }while(input);
}
int main()
{
  //test();
  test2();
  return 0;
}
main.c



三.带文件的动态通讯录
在这个里面,我们只需在初始化时进行文件的读取及关闭时文件的保存:
初始化:
//从文件载入信息
void Lodging(Contact *p)
{
  assert(p);
  //打开一文件
  FILE *fp = fopen("../Contact.dat", "ab");//如果不存在就创建,存在就追加
  if (fp == NULL)
  {
    perror("FILE: Ab");
    exit(-1);
  }
  fclose(fp);//关闭文件,我们这一步只是为了确保文件存在
  //打开一文件
  fp=fopen("../Contact.dat","rb");
  if (fp == NULL)
  {
    perror("FILE: Rb");
    exit(-1);
  }
  Data temp;//将读入的信息存入temp中
  while(fread(&temp, sizeof(Data),1,fp))
  {
    //检查容量
    CheckCapacity(p);
    //赋值
    p->data[p->size]=temp;
    p->size++;
  }
  fclose(fp);//关闭文件
}

//初始化 --- 带文件
void ContactInit(Contact *p)
{
  assert(p);
  p->data = NULL;
  p->size = 0;
  p->capacity = 1;
  Lodging(p);
}
结束时保存:
void Save(Contact* p)
{
  assert(p);
  FILE* fp =fopen("../Contact.dat","wb");
  int i =0;
  for(i=0;i<p->size;i++)
  {
    fwrite(p->data+i, sizeof(Data),1,fp);
  }
  fclose(fp);
}
//退出通讯录 --- 带文件
void ContactExit(Contact *p)
{
  //保存置文件
  Save(p);
  //释放我们开辟的内存
  free(p->data);
  printf("exit !\n");
}
除此之外,其他都与动态通讯录相同
完整代码:
//确保文件只包含一次
#ifndef CONTACT_CONTACT_H
#define CONTACT_CONTACT_H
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <assert.h>
//采用宏的目的是方便日后修改
#define NAME_MAX 20
#define SEX_MAX 8
#define PNUM_MAX 13
#define ADDR_MAX 20
#define MAX 10
//存放个人信息的结构体
typedef struct Data
{
  char name[NAME_MAX];//姓名
  int age;//年龄
  char sex[SEX_MAX];//性别
  char pnum[PNUM_MAX];//电话
  char addr[ADDR_MAX];//地址
} Data;
/*
//存放MAX个个人信息的通讯录 --- 静态
typedef struct Contact
{
  Data data[MAX];
  int size;
} Contact;
*/
//存放MAX个个人信息的通讯录 --- 动态
typedef struct Contact
{
  Data* data;//存放数据
  int size;//有效数据的个数
  int capacity;//容量的大小
} Contact;
//枚举来作为常量使得在看代码时比较清晰
enum choice
{
  EXIT,
  ADD,
  DEL,
  SEARCH,
  MODIFY,
  SHOW,
  SORT,
  HELP
};
enum sort_by
{
  NAME=1,
  SEX,
  AGE,
  PNUM,
  ADDR
};

//初始化通讯录
void ContactInit(Contact *p);
//添加联系人
void ContactAdd(Contact* p);
//删除联系人
void ContactDel(Contact* p);
//查找联系人
void ContactSearch(Contact* p);
//修改联系人信息
void ContactModify(Contact* p);
//展示联系人信息
void ContactShow(Contact* p);
//排序联系人
void ContactSort(Contact* p);
//打印帮助
void ContactHelp(Contact* p);
//退出通讯录
void ContactExit(Contact* p);
//检查容量函数
void CheckCapacity(Contact *p);

#endif //CONTACT_CONTACT_H
Contact.h
#include "Contact.h"
// 强调!!!
//调试请加setbuf(stdout,NULL)!!!

//查找模块
int ContactFind(Contact *p, char *FindData)
{
  assert(p);
  int i = 0;
  for (i = 0; i < p->size; i++)
  {
    if (strcmp(p->data[i].name, FindData) == 0)
    {
      return i;//找到就返回下标
    }
  }
  return -1;//找不到就返回-1
}
/*
//初始化 --- 静态
void ContactInit(Contact *p)
{
  //保证p不为NULL
  assert(p);
  //置零
  memset(p->data, 0, sizeof(p->data));
  p->size = 0;
}
*/
/*
//初始化 --- 动态
void ContactInit(Contact *p)
{
  assert(p);
  p->data = NULL;
  p->size = 0;
  p->capacity = 1;
}
*/
//从文件载入信息
void Lodging(Contact *p)
{
  assert(p);
  //打开一文件
  FILE *fp = fopen("../Contact.dat", "ab");//如果不存在就创建,存在就追加
  if (fp == NULL)
  {
    perror("FILE: Ab");
    exit(-1);
  }
  fclose(fp);//关闭文件,我们这一步只是为了确保文件存在
  //打开一文件
  fp=fopen("../Contact.dat","rb");
  if (fp == NULL)
  {
    perror("FILE: Rb");
    exit(-1);
  }
  Data temp;//将读入的信息存入temp中
  while(fread(&temp, sizeof(Data),1,fp))
  {
    //检查容量
    CheckCapacity(p);
    //赋值
    p->data[p->size]=temp;
    p->size++;
  }
  fclose(fp);//关闭文件
}

//初始化 --- 带文件
void ContactInit(Contact *p)
{
  assert(p);
  p->data = NULL;
  p->size = 0;
  p->capacity = 1;
  Lodging(p);
}

/*//添加联系人 --- 静态
void ContactAdd(Contact *p)
{
  //断言保证p不为NULL
  assert(p);
  //如果联系人容量已经等于最大容量了
  if (p->size == MAX)
  {
    printf("通讯录已满,请删除一些后继续添加!\n");
    return;
  }
  Data person;//记录联系人信息
  printf("请输入联系人的姓名:>");
  scanf("%s", person.name);
  printf("请输入联系人的年龄:>");
  scanf("%d", &person.age);
  printf("请输入联系人的性别:>");
  scanf("%s", person.sex);
  printf("请输入联系人的电话:>");
  scanf("%s", person.pnum);
  printf("请输入联系人的住址:>");
  scanf("%s", person.addr);
  //将联系人信息存到通讯录中
  p->data[p->size] = person;
  p->size++;
}*/
//检查容量函数
void CheckCapacity(Contact *p)
{
  assert(p);
  //如果联系人个数为0或与容量相同,就需要扩容
  if (p->size == 0 || p->size == p->capacity)
  {
    //动态内存开辟
    Data *ptr = (Data *) realloc(p->data, sizeof(Data) * p->capacity * 2);
    if (ptr == NULL)//开辟失败
    {
      //报错
      perror("CHECK CAPACITY ERROE !\n");
      exit(-1);
    }
    //开辟成功,重新赋值
    p->data = ptr;
    //扩容之后,容量也相应扩大
    p->capacity *= 2;
  }
  //反之什么都不需要干
}
//添加联系人 --- 动态
void ContactAdd(Contact *p)
{
  //断言保证p不为NULL
  assert(p);
  //如果联系人个数等于容量,或联系人个数等于0,这时我们就需要扩容了,我们来使用一个函数来干这事
  CheckCapacity(p);
  Data person;//记录联系人信息
  printf("请输入联系人的姓名:>");
  scanf("%s", person.name);
  printf("请输入联系人的年龄:>");
  scanf("%d", &person.age);
  printf("请输入联系人的性别:>");
  scanf("%s", person.sex);
  printf("请输入联系人的电话:>");
  scanf("%s", person.pnum);
  printf("请输入联系人的住址:>");
  scanf("%s", person.addr);
  //将联系人信息存到通讯录中
  p->data[p->size] = person;
  p->size++;
}
//删除联系人
void ContactDel(Contact *p)
{
  assert(p);
  char DelName[NAME_MAX] = {0};
  printf("请输入你要删除的联系人姓名:>");
  scanf("%s", DelName);
  int ret = ContactFind(p, DelName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    int j = 0;
    for (j = ret; j < p->size; j++)
    {
      //从前往后依次挪动覆盖
      p->data[j] = p->data[j + 1];
    }
    //删除完成之后,联系人个数减一
    p->size--;
  }
}
//查找联系人
void ContactSearch(Contact *p)
{
  assert(p);
  char SearchName[NAME_MAX];
  printf("请输入你要查找的联系人姓名:>");
  scanf("%s", SearchName);
  //查找有无此人
  int ret = ContactFind(p, SearchName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    printf("你所查找的联系人信息为:\n");
    printf("  姓名\t性别\t  年龄\t   电话\t\t地址\n");
    printf("   %-5s\t%s\t%d\t%s\t%s\n", p->data[ret].name,
         p->data[ret].sex,
         p->data[ret].age,
         p->data[ret].pnum,
         p->data[ret].addr);
  }
}
//修改联系人信息
void ContactModify(Contact *p)
{
  assert(p);
  char ModifyName[NAME_MAX];
  printf("请输入你要修改的联系人姓名:>");
  scanf("%s", ModifyName);
  int ret = ContactFind(p, ModifyName);
  if (ret == -1)
  {
    printf("通讯录中并无此人,请重新检查输入!\n");
  } else
  {
    Data person;//记录联系人信息
    printf("请输入联系人的姓名:>");
    scanf("%s", person.name);
    printf("请输入联系人的年龄:>");
    scanf("%d", &person.age);
    printf("请输入联系人的性别:>");
    scanf("%s", person.sex);
    printf("请输入联系人的电话:>");
    scanf("%s", person.pnum);
    printf("请输入联系人的住址:>");
    scanf("%s", person.addr);
    //将联系人信息存到通讯录中
    p->data[ret] = person;
  }
}
//展示联系人信息
void ContactShow(Contact *p)
{
  assert(p);
  if (p->size == 0)
  {
    printf("通讯录中并无一人!\n");
    return;
  }
  int i = 0;
  printf("  姓名\t性别\t  年龄\t   电话\t\t地址\n");
  for (i = 0; i < p->size; i++)
  {
    printf("   %-5s\t%s\t%d\t%s\t%s\n", p->data[i].name,
         p->data[i].sex,
         p->data[i].age,
         p->data[i].pnum,
         p->data[i].addr);
  }
}
void sort_menu()
{
  printf("       SORT_MENU      \n");
  printf("******************************\n");
  printf("****    1.name    ****\n");
  printf("****    2.sex     ****\n");
  printf("****    3.age     ****\n");
  printf("****    4.pnum    ****\n");
  printf("****    5.addr    ****\n");
  printf("******************************\n");
}
int sort_by_name(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->name, ((Data *) s2)->name);
}
int sort_by_sex(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->sex, ((Data *) s2)->sex);
}
int sort_by_age(const void *s1, const void *s2)
{
  return ((Data *) s1)->age - ((Data *) s2)->age;
}
int sort_by_pnum(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->pnum, ((Data *) s2)->pnum);
}
int sort_by_addr(const void *s1, const void *s2)
{
  return strcmp(((Data *) s1)->addr, ((Data *) s2)->addr);
}

//排序联系人
void ContactSort(Contact *p)
{
  assert(p);
  int choice;
  sort_menu();
  printf("请选择排序的参考量:>");
  scanf("%d", &choice);
  switch (choice)
  {
    case NAME:
      qsort(p->data, p->size, sizeof(Data), sort_by_name);
      break;
    case SEX:
      qsort(p->data, p->size, sizeof(Data), sort_by_sex);
      break;
    case AGE:
      qsort(p->data, p->size, sizeof(Data), sort_by_age);
      break;
    case PNUM:
      qsort(p->data, p->size, sizeof(Data), sort_by_pnum);
      break;
    case ADDR:
      qsort(p->data, p->size, sizeof(Data), sort_by_addr);
      break;
    default:
      printf("输入有误,请检查输入!\n");
  }
}
//打印帮助信息
void ContactHelp(Contact *p)
{
  printf("*******************************************\n");
  printf("******   add ---- 添加联系人信息  ******\n");
  printf("******   del ---- 删除联系人信息  ******\n");
  printf("******  search ---- 查找联系人信息  ******\n");
  printf("******  modify ---- 修改联系人信息  ******\n");
  printf("******  show ---- 展示联系人信息  ******\n");
  printf("******  help ---- 帮助信息      ******\n");
  printf("******  sort ---- 排序联系人信息  ******\n");
  printf("******  exit ---- 退出通讯录    ******\n");
  printf("*******************************************\n");
}
/*//退出通讯录
void ContactExit(Contact *p)
{
  printf("exit !\n");
}*/
/*
//退出通讯录 --- 动态
void ContactExit(Contact *p)
{
  //释放我们开辟的内存
  free(p->data);
  printf("exit !\n");
}*/
void Save(Contact* p)
{
  assert(p);
  FILE* fp =fopen("../Contact.dat","wb");
  int i =0;
  for(i=0;i<p->size;i++)
  {
    fwrite(p->data+i, sizeof(Data),1,fp);
  }
  fclose(fp);
}
//退出通讯录 --- 带文件
void ContactExit(Contact *p)
{
  //保存置文件
  Save(p);
  //释放我们开辟的内存
  free(p->data);
  printf("exit !\n");
}
Contact.c
#include "Contact.h"
void menu()
{
  //打印菜单
  printf("******************************************\n");
  printf("******    1.add     2.del     ******\n");
  printf("******    3.search  4.modify  ******\n");
  printf("******    5.show    6.sort    ******\n");
  printf("******    7.help    0.exit    ******\n");
  printf("******************************************\n");
}
void test()
{
  Contact list;//定义一个通讯录
  Contact *p = &list;//赋址
  //初始化
  ContactInit(p);
  int input = 0;//存放用户选择的信息
  do
  {
    menu();
    printf("请输入你的选择:>");
    scanf("%d", &input);
    switch (input)
    {
      case ADD:
        ContactAdd(p);
        break;
      case DEL:
        ContactDel(p);
        break;
      case SEARCH:
        ContactSearch(p);
        break;
      case MODIFY:
        ContactModify(p);
        break;
      case SHOW:
        ContactShow(p);
        break;
      case SORT:
        ContactSort(p);
        break;
      case HELP:
        ContactHelp(p);
        break;
      case EXIT:
        ContactExit(p);
        break;
      default:
        printf("输入非法!\n");
    }
  } while (input);
}
void test2()
{
  Contact list;//定义一个通讯录
  Contact *p = &list;//赋址
  //初始化
  ContactInit(p);
  //用一个函数指针数组来存放函数指针
  void (*fun[])(Contact *) ={ContactExit,
                 ContactAdd,
                 ContactDel,
                 ContactSearch,
                 ContactModify,
                 ContactShow,
                 ContactSort,
                 ContactHelp};
  int input = 0;//存放用户选择的信息
  do{
    menu();
    printf("请输入你的选择:>");
    scanf("%d", &input);
    if(input>=0&&input<=sizeof(fun))
    {
      //system("cls");
      fun[input](p);
    }
    else
    {
      system("cls");
      printf("输入非法,请检查输入!\n");
    }
  }while(input);
}
int main()
{
  //test();
  test2();
  return 0;
}
main.c
|---------------------------------------------------------------------------------------------------
到此,我们的C语言也就告一段落了!
以后的路我们依然任重而道远!

转载声明:
作者:HighLight_FanYa
由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。
本文版权归作者和博客共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。


关注下面的标签,发现更多相似文章