引言:在之前的项目中,我们所用的通讯录是静态版本,也就是常规的固定数组大小,但仔细思考,在现实的复杂环境中,是很难做到这样死板,所以在学习过动态内存的章节后,我们将通讯录重新修改,在不断添加联系人的环节中,我们也不断通过realloc
的扩容动态空间。
修改的地方:
-
在之前的静态版本中,我们只需要记录当前存储的通讯录个数即可,那么我们现在即将要改进到动态版本,
将通讯录数组改变为指向一块空间
,我们还需要记录通讯录的容量,意思就是当然存储个数 == 通讯容量的时候
,对通讯录动态开辟的空间进行重新扩容,以及对通讯容量进行增加
。 -
在添加联系人环节中,我们不在需要判断有没有装满通讯录,而是判断通讯录有没有达到扩容的条件。
-
在我们退出项目的时候,需要对动态开辟的空间通进行释放,将指针置为NULL,将容量以及存储个数置为0。
-
在模拟快排的函数中,我们可以把元素个数改变为当前存储的通讯录个数。
以上就是静态通讯录转变到动态通讯录的大致改变方向,接下来就是我们需要实践的地方。
Contact.h
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>
#include <assert.h>
#include <stdlib.h>#define MAX 20
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
#define DEFAULT_SZ 1
#define INT_SZ 2enum OPTION
{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SORT
};typedef struct People_Info People_Info;
struct People_Info
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
};//动态版本
typedef struct Contact Contact;
struct Contact
{People_Info* data;//指向存放数据的空间int sz;//记录当前存储个数int capacity;//记录最大可存储容量
};//初始化通讯录
void InitContact(Contact* Con);//添加联系人
void AddContact(Contact* Con);//显示全部联系人
void ShowContact(const Contact* Con);//删除指定联系人
void DelContact(Contact* Con);//查找指定联系人
void SearchContact(const Contact* Con);//修改指定联系人信息
void ModifyContact(Contact* Con);//字符串比较函数
int my_strcmp(char* str1, char* str2);//手搓快排
void Bubble_sort(People_Info* stu, int num, int sz, int (*cmp_by_name)(void* pf1, void* pf2));//声明cmp_by_name -> 模拟快排所需要的函数
int cmp_by_name(void* pf1, void* pf2);//销毁动态开辟的空间
void DestroyContact(Contact* Con);
Contact.c
动态通讯录进行初始化
void InitContact(Contact* Con)
{assert(Con != NULL);People_Info* pc = (People_Info*)malloc(DEFAULT_SZ * sizeof(People_Info));if (pc == NULL){perror("InitContact:");return;}Con->data = pc;Con->sz = 0;Con->capacity = DEFAULT_SZ;
}
添加联系人
//检查容量
int CheckCapacity(Contact* Con)
{if (Con->sz == Con->capacity){People_Info* ptr = (People_Info*)realloc(Con->data, (Con->capacity + INT_SZ) * sizeof(People_Info));if (ptr == NULL){perror("CheckCapacity:");return 0;}else{Con->data = ptr;Con->capacity += INT_SZ;printf("增容成功!!!\n");return 1;}}return 1;
}//添加联系人
void AddContact(Contact* Con)
{assert(Con != NULL);if (0 == CheckCapacity(Con)){printf("增容失败,请检查!!!\n");return;}printf("请输入你的名字:");scanf("%s", Con->data[Con->sz].name);Clear();printf("请输入你的年龄:");scanf("%d", &(Con->data[Con->sz].age));printf("请输入你的性别:");scanf("%s", Con->data[Con->sz].sex);Clear();printf("请输入你的电话:");scanf("%s", Con->data[Con->sz].tele);Clear();printf("请输入你的地址:");scanf("%s", Con->data[Con->sz].addr);Clear();printf("添加成功!!!\n");Con->sz++;
}
显示全部联系人
// 显示全部联系人
void ShowContact(const Contact* Con)
{assert(Con != NULL);title();if (Con->sz == 0){printf("暂无联系人!!!\n");return;}int i = 0;for (i = 0; i < Con->sz; i++){printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n",Con->data[i].name,Con->data[i].age,Con->data[i].sex,Con->data[i].tele,Con->data[i].addr);}
}
删除指定联系人
//字符串比较
int my_strcmp(char* str1, char* str2)
{while (*str1 == *str2){if (*str1 == '\0'){return 0;}str1++;str2++;}if (*str1 > *str2){return 1;}else{return -1;}
}//找动态空间中是否存在对应的名字
int Find_Name(Contact* Con, char* name)
{int i = 0;for (i = 0; i < Con->sz; i++){if (my_strcmp(Con->data[i].name, name) == 0){return i;}}return -1;
}//删除指定联系人
void DelContact(Contact* Con)
{assert(Con != NULL);if (Con->sz == 0){printf("暂无联系人!!!\n");return;}char name[MAX_NAME] = { 0 };printf("请输入需要删除的名字:");scanf("%s", name);int pos = Find_Name(Con, name);if (pos == -1){printf("没有找到指定删除的联系人名字!!!\n");return;}int i = 0;for (i = pos; i < Con->sz - 1; i++){Con->data[i] = Con->data[i + 1];}printf("删除成功!!!\n");Con->sz--;
}
查找指定联系人
//字符串比较
int my_strcmp(char* str1, char* str2)
{while (*str1 == *str2){if (*str1 == '\0'){return 0;}str1++;str2++;}if (*str1 > *str2){return 1;}else{return -1;}
}//找动态空间中是否存在对应的名字
int Find_Name(Contact* Con, char* name)
{int i = 0;for (i = 0; i < Con->sz; i++){if (my_strcmp(Con->data[i].name, name) == 0){return i;}}return -1;
}//查找指定联系人
void SearchContact(const Contact* Con)
{assert(Con != NULL);if (Con->sz == 0){printf("暂无添加联系人!!!\n");return;}char name[MAX_NAME] = { 0 };printf("请输人查找指定联系人的名字:");scanf("%s", name);int pos = Find_Name(Con, name);if (pos == -1){printf("暂无查找到指定联系人!!!\n");return;}else{title();printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n",Con->data[pos].name,Con->data[pos].age,Con->data[pos].sex,Con->data[pos].tele,Con->data[pos].addr);}
}
修改指定联系人信息
//字符串比较
int my_strcmp(char* str1, char* str2)
{while (*str1 == *str2){if (*str1 == '\0'){return 0;}str1++;str2++;}if (*str1 > *str2){return 1;}else{return -1;}
}//找动态空间中是否存在对应的名字
int Find_Name(Contact* Con, char* name)
{int i = 0;for (i = 0; i < Con->sz; i++){if (my_strcmp(Con->data[i].name, name) == 0){return i;}}return -1;
}//修改指定联系人信息 - 菜单
void menu_modify()
{printf("*****************************\n");printf("***** 1.Name 2.Age *****\n");printf("***** 3.Sex 4.Tele *****\n");printf("***** 5.Addr 0.Exit *****\n");printf("*****************************\n");
}//修改指定联系人信息
void ModifyContact(Contact* Con)
{assert(Con != NULL);if (Con->sz == 0){printf("暂无添加联系人信息\n");return;}char name[MAX_NAME] = { 0 };printf("请输入联系人名字:");scanf("%s", name);int pos = Find_Name(Con, name);if (pos == -1){printf("没有找到指定联系人!!!\n");return;}else{int input = 0;do{menu_modify();printf("请选择:");scanf("%d", &input);switch (input){case 1:printf("请输入你的名字:");scanf("%s", Con->data[pos].name);break;case 2:printf("请输入你的年龄:");scanf("%d", &(Con->data[pos].age));break;case 3:printf("请输入你的性别:");scanf("%s", Con->data[pos].sex);break;case 4:printf("请输入你的电话:");scanf("%s", Con->data[pos].tele);break;case 5:printf("请输入你的地址:");scanf("%s", Con->data[pos].addr);break;case 0:printf("退出选项!!!\n");break;default:printf("输入有误,请重新选择!!!\n");break;}} while (input);}
}
模拟快排并排序动态空间中的通讯录信息
int cmp_by_name(void* pf1, void* pf2)
{return my_strcmp(((People_Info*)pf1)->name, ((People_Info*)pf2)->name);
}void Swap(char* buf1, char* buf2, int sz)
{int i = 0;for (i = 0; i < sz; i++){char tmp = *(buf1 + i);*(buf1 + i) = *(buf2 + i);*(buf2 + i) = tmp;}
}void Bubble_sort(void* stu, int num, int sz, int (*cmp_by_name)(void* pf1, void* pf2))
{int i = 0;for (i = 0; i < num; i++){int j = 0;for (j = 0; j < num - i - 1; j++){if (cmp_by_name((char*)stu + j * sz, (char*)stu + (j + 1) * sz) < 0){Swap((char*)stu + j * sz, (char*)stu + (j + 1) * sz, sz);}}}
}
注:这部分也是我个人认为比较难的一块,本身的模拟快排难度就不小了再加上排序通讯录信息,真的让人爆炸。
销毁动态空间
//销毁动态开辟的空间
void DestroyContact(Contact* Con)
{free(Con->data);Con->data = NULL;Con->capacity = 0;Con->sz = 0;
}
test.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("******************************\n");
}void test()
{int input = 0;Contact Con;InitContact(&Con);do{menu();printf("请选择:");scanf("%d", &input);switch (input){case ADD:AddContact(&Con);break;case DEL:DelContact(&Con);break;case SEARCH:SearchContact(&Con);break;case MODIFY:ModifyContact(&Con);break;case SHOW:ShowContact(&Con);break;case SORT:Bubble_sort(&(Con.data[0]), Con.sz, sizeof(People_Info), cmp_by_name);break;case EXIT:DestroyContact(&Con);break;default:printf("输入有误,请重新输入!!!\n");break;}} while (input);
}int main()
{test();return 0;
}
总结:以上代码中,能模拟实现的库函数我都尽量手搓了,在写项目的同时也不要忘记巩固之前所学的内容。本项目还是在于增删查改的操作,逻辑上并不难以理解,但是操作上还需要我们结合自身前面所学的基础,只有基础打牢以及扎实,才能在这个项目中显得游刃有余。
本章完~