C语言之通讯录的模拟实现
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;//姓名
int age;//年龄
char sex;//性别
char pnum;//电话
char addr;//地址
} Data;
现在有了个人信息的结构体,我们需要再来一个结构体来存放它的数组及数组内有效信息的个数,即:
//存放MAX个个人信息的通讯录
typedef struct Contact
{
Data data;
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 = 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.name,
p->data.sex,
p->data.age,
p->data.pnum,
p->data.addr);
}
}测试结果:
接下来就是删除联系人了
3.删除联系人
首先删除联系人肯定需要查找信息,又因为后面的几个函数也要用到它,所以我们单独来写一个查找模块:
//查找模块
int ContactFind(Contact *p, char *FindData)
{
assert(p);
int i = 0;
for (i = 0; i < p->size; i++)
{
if (strcmp(p->data.name, FindData) == 0)
{
return i;//找到就返回下标
}
}
return -1;//找不到就返回-1
}删除:
//删除联系人
void ContactDel(Contact *p)
{
assert(p);
char DelName = {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 = p->data;
}
//删除完成之后,联系人个数减一
p->size--;
}
}
4.查找联系人信息
//查找联系人
void ContactSearch(Contact *p)
{
assert(p);
char SearchName;
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.name,
p->data.sex,
p->data.age,
p->data.pnum,
p->data.addr);
}
}
5.修改联系人信息
//修改联系人信息
void ContactModify(Contact *p)
{
assert(p);
char ModifyName;
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 = 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(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;//姓名
int age;//年龄
char sex;//性别
char pnum;//电话
char addr;//地址
} Data;
//存放MAX个个人信息的通讯录
typedef struct Contact
{
Data data;
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_HContact.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.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 = person;
p->size++;
}
//删除联系人
void ContactDel(Contact *p)
{
assert(p);
char DelName = {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 = p->data;
}
//删除完成之后,联系人个数减一
p->size--;
}
}
//查找联系人
void ContactSearch(Contact *p)
{
assert(p);
char SearchName;
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.name,
p->data.sex,
p->data.age,
p->data.pnum,
p->data.addr);
}
}
//修改联系人信息
void ContactModify(Contact *p)
{
assert(p);
char ModifyName;
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 = 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.name,
p->data.sex,
p->data.age,
p->data.pnum,
p->data.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(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 = 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;//姓名
int age;//年龄
char sex;//性别
char pnum;//电话
char addr;//地址
} Data;
/*
//存放MAX个个人信息的通讯录 --- 静态
typedef struct Contact
{
Data data;
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_HContact.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.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 = 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 = person;
p->size++;
}
//删除联系人
void ContactDel(Contact *p)
{
assert(p);
char DelName = {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 = p->data;
}
//删除完成之后,联系人个数减一
p->size--;
}
}
//查找联系人
void ContactSearch(Contact *p)
{
assert(p);
char SearchName;
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.name,
p->data.sex,
p->data.age,
p->data.pnum,
p->data.addr);
}
}
//修改联系人信息
void ContactModify(Contact *p)
{
assert(p);
char ModifyName;
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 = 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.name,
p->data.sex,
p->data.age,
p->data.pnum,
p->data.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(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(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=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;//姓名
int age;//年龄
char sex;//性别
char pnum;//电话
char addr;//地址
} Data;
/*
//存放MAX个个人信息的通讯录 --- 静态
typedef struct Contact
{
Data data;
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_HContact.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.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=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 = 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 = person;
p->size++;
}
//删除联系人
void ContactDel(Contact *p)
{
assert(p);
char DelName = {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 = p->data;
}
//删除完成之后,联系人个数减一
p->size--;
}
}
//查找联系人
void ContactSearch(Contact *p)
{
assert(p);
char SearchName;
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.name,
p->data.sex,
p->data.age,
p->data.pnum,
p->data.addr);
}
}
//修改联系人信息
void ContactModify(Contact *p)
{
assert(p);
char ModifyName;
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 = 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.name,
p->data.sex,
p->data.age,
p->data.pnum,
p->data.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(p);
}
else
{
system("cls");
printf("输入非法,请检查输入!\n");
}
}while(input);
}
int main()
{
//test();
test2();
return 0;
}main.c
|---------------------------------------------------------------------------------------------------
到此,我们的C语言也就告一段落了!
以后的路我们依然任重而道远!
转载声明:
作者:HighLight_FanYa
由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。
本文版权归作者和博客共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
文档来源:51CTO技术博客https://blog.51cto.com/guguguhuha/3335922
页:
[1]