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;

  那么,准备工作做好之后,我们就开始正式实现了,首先我们肯定是要先创建一个通讯录,这时我们再来想一想,我们就这样创建之后,我们是否可以直接使用呢?

  对此我们来看一张图片:

 

 

   我们发现,现在它里面都放着一些随机值,所以我们需要将其初始化一下,来方便我们的使用:

void ContactInit(Contact *p)
{
    //保证p不为NULL
    assert(p);
    //置零
    memset(p->data, 0, sizeof(p->data));
    p->size = 0;

}

  我们再来看一下结果:

 

 

   我们发现,现在它内部已经被我们置为了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++;
}

  我们要是观察到我们输入的信息,最好就是把我们所输入的信息给打印出来:

  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); } }

 

  测试结果:

 

 

 

 

 

   接下来就是删除联系人了

  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--;
    }
}

 

 

 

 

 

 

 

 

 

  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);
    }
}

 

 

 

 

 

   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;
    }
}

 

 

 

 

 

   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");
    }
}

 

 

 

 

 

 

到这,我们的静态通讯录就完了,但是我们仍可对用户操作优化一下,如:及时的清屏等,以及暂停:

例:

    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);
}

  这样是不是代码就少了很多!

 

所以完整代码如下:

//确保文件只包含一次
#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语言也就告一段落了!

以后的路我们依然任重而道远!