3.Contact.h
#define _CRT_SECURE_NO_WARNINGS //Contact 实现通讯录 头文件 #include<stdio.h> #include<string.h> #include<assert.h> #include<malloc.h> #include<stdlib.h> #include<search.h> #define MAX 100 #define NAME_MAX 20 #define SEX_MAX 5 #define ADDR_MAX 20 #define TELE_MAX 12 //下面两个define是用于动态通讯录的 #define MAX1 3 //表示第一次容积是多少 #define MAX2 2 //表示一次扩容多少 //构建通讯录所需的结构体 typedef struct PeopleInfo { char name[NAME_MAX];//姓名 int age;//年龄 char sex[NAME_MAX];//性别 char addr[ADDR_MAX];//地址 char tele[TELE_MAX];//电话号码 }PeopleInfo; //这是静态通讯录 就是data这个数组是固定死的MAX typedef struct Contact { PeopleInfo data[MAX];//表示存储的通讯录最大人员数 int sz;//表示当前Contact通讯录人员个数 }Contact; //初始化通讯录 void InitContact(Contact* pc); //添加通讯录的信息 void addContact(Contact* pc); //删除通讯录中的信息 void delContact(Contact* pc); //查找通讯录成员信息 int searchContact(Contact* pc); //打印 void showContact(Contact* pc); //改变指定元素 void changeContact(Contact* pc); //排序,按照名字排序 void sortContact(Contact* pc);
2.动态通讯录
1.test.c
#define _CRT_SECURE_NO_WARNINGS #include"Contact.h" //这边进行主要的通讯录流程操作 void menu() { printf("***********************************************\n"); printf("****** 1.add 2.del ******\n"); printf("****** 3.search 4.change ******\n"); printf("****** 5.show 6.sort ******\n"); printf("****** 0.exit ******\n"); printf("***********************************************\n"); } void test() { //打印选择菜单 int input = 0; int pos = 0; Contact pc; //Contact pc={0}; //当然可以这样初始化,但是不一定后来初始化都这样,所以有InitContact() InitContact(&pc); do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: addContact(&pc); break; case 2: delContact(&pc); break; case 3: pos = searchContact(&pc); if (pos == -1) { printf("没有查找到该成员\n"); } else { printf("%-20s\t%-5d\t%-5s\t%-20s\t%-12s\n", pc.data[pos].name, pc.data[pos].age, pc.data[pos].sex, pc.data[pos].addr, pc.data[pos].tele); } break; case 4: changeContact(&pc); break; case 5: showContact(&pc); break; case 6: sort(&pc); break; case 0: printf("退出通讯录\n"); free(pc.data); break; default: break; } } while (input); } int main() { test(); return 0; }
2.Contact.c
#define _CRT_SECURE_NO_WARNINGS #include"Contact.h" //用来实现头文件的代码 // //这是动态通讯录的初始化 void InitContact(Contact* pc) { //进行初始化的时候,我们当然可以直接 assert(pc);//断言 pc->sz = 0; PeopleInfo *ptr=(PeopleInfo*)calloc(MAX1,sizeof(PeopleInfo)); if (ptr == NULL) { perror("malloc::data"); return; } pc->data = ptr; pc->capacity=MAX1; } //动态通讯录 void check_capacity(Contact* pc) { PeopleInfo* ptr = (PeopleInfo*)realloc(pc->data, sizeof(PeopleInfo)*(pc->capacity+MAX2)); if (ptr == NULL) { perror("check_capacity"); return; } pc->data = ptr; pc->capacity = pc->capacity + MAX2; } void addContact(Contact* pc) { assert(pc); if (pc->sz == pc->capacity) { //使用realloc函数 进行扩容 check_capacity(pc); printf("扩容完成\n"); } printf("请输入名字:>"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:>"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入性别:>"); scanf("%s", pc->data[pc->sz].sex); printf("请输入地址:>"); scanf("%s", pc->data[pc->sz].addr); printf("请输入电话:>"); scanf("%s", pc->data[pc->sz].tele); printf("添加完成,请继续操作\n"); pc->sz++; } void delContact(Contact* pc) { assert(pc); printf("请选择删除的目标:>"); if (pc->sz == 0) { return; } //删除的话只需要找到对应的要删除的数据,比如以名字为准,先找到,然后再讲其后面的元素覆盖前面的 int pos = searchContact(pc); //换位置 if (pos == -1) { printf("没有查找到该成员\n"); return; } for (int i = pos; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--;//直接--不用管换位置之后最后一个数字的问题 printf("删除完成\n"); } int searchContact(Contact* pc) { assert(pc); char name[20]; int pos = -1; scanf("%s", name); //查询 for (int i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { pos = i; } } return pos; } void showContact(Contact* pc) { assert(pc); if (pc->sz == 0) { return; }//可以有可无 printf("%-20s\t%-5s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话"); for (int i = 0; i < pc->sz; i++) { printf("%-20s\t%-5d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele); } printf("打印完成\n"); } void changeContact(Contact* pc) { assert(pc); //先找到 int pos = searchContact(pc); printf("请输入名字:>"); scanf("%s", pc->data[pos].name); printf("请输入年龄:>"); scanf("%d", &(pc->data[pos].age)); printf("请输入性别:>"); scanf("%s", pc->data[pos].sex); printf("请输入地址:>"); scanf("%s", pc->data[pos].addr); printf("请输入电话:>"); scanf("%s", pc->data[pos].tele); printf("更改完成, 请继续操作\n"); } void sortContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录中暂无元素\n"); return; } Contact s; InitContact(&s); for (int i = 0; i < pc->sz-1; i++) { for (int j = 0; j < pc->sz-1-i; j++) { if (strcmp(pc->data[j].name, pc->data[j + 1].name)==1) { s.data[j] = pc->data[j]; pc->data[j] = pc->data[j + 1]; pc->data[j + 1] = s.data[j]; } } } } int compare(const void* e1, const void* e2) { return *((int*)e1) - *((int*)e2); } void sort(Contact*pc) { qsort(pc->data, pc->sz, sizeof(pc->data[0]), compare); }
3.Contact.h
#define _CRT_SECURE_NO_WARNINGS //Contact 实现通讯录 头文件 #include<stdio.h> #include<string.h> #include<assert.h> #include<malloc.h> #include<stdlib.h> #include<search.h> #define MAX 100 #define NAME_MAX 20 #define SEX_MAX 5 #define ADDR_MAX 20 #define TELE_MAX 12 //下面两个define是用于动态通讯录的 #define MAX1 3 //表示第一次容积是多少 #define MAX2 2 //表示一次扩容多少 //构建通讯录所需的结构体 typedef struct PeopleInfo { char name[NAME_MAX];//姓名 int age;//年龄 char sex[NAME_MAX];//性别 char addr[ADDR_MAX];//地址 char tele[TELE_MAX];//电话号码 }PeopleInfo; //实现动态通讯录 typedef struct Contact { PeopleInfo *data;//表示存储的通讯录最大人员数 int sz;//表示当前Contact通讯录人员个数 int capacity; //表示当前容量 作为扩容的依据 }Contact; //初始化通讯录 void InitContact(Contact* pc); //添加通讯录的信息 void addContact(Contact* pc); //删除通讯录中的信息 void delContact(Contact* pc); //查找通讯录成员信息 int searchContact(Contact* pc); //打印 void showContact(Contact* pc); //改变指定元素 void changeContact(Contact* pc); //排序,按照名字排序 void sortContact(Contact* pc);
总结
静态通讯录和动态通讯录都是比较简单好实现的,静态通讯录是固定的数组的形式储存成员,不确定成员个数的情况下,可能会浪费空间,也可能不够用。但是动态通讯录通过不断扩容,更好的解决了这个空间的事情,不会造成太多浪费。
动态,是依靠malloc、free、calloc、realloc这些函数进行申请空间,进行维护不断扩容的,下一章节,我们来一起细致的去讲解一下这四种函数的使用和区别