在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); }
这样是不是代码就少了很多!
所以完整代码如下:
Contact.h
//确保文件只包含一次 #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.c
#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"); }
main.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; }
二.动态通讯录
动态实现的问题主要在于它的容量不再是一变不变的,而是可随着我们的数据量来变化的,所以在我们原来定义的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"); }
动态通讯录的修改就只有这些:
完整代码展示:
Contact.h
//确保文件只包含一次 #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.c
#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"); }
main.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; }
三.带文件的动态通讯录
在这个里面,我们只需在初始化时进行文件的读取及关闭时文件的保存:
初始化:
//从文件载入信息 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"); }
除此之外,其他都与动态通讯录相同
完整代码:
Contact.h
//确保文件只包含一次 #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.c
#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"); }
main.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; }
到此这篇关于C语言之通讯录的模拟实现代码的文章就介绍到这了,更多相关C语言通讯录内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!