动态通讯录(C语言版本)
之前的版本静态存储的通讯录(C语言实现)
如果不懂得同学可以回顾一下这个博客,里面的知识点讲的很详细,特别适合新手入门。
动态通讯录更改部分(在静态版本上进行更改)
结构体的变动:
//一个人的信息typedefstructPeoInfo{char name[20];char sex[5];char tele[12];int age;char addr[30];}PeoInfo;通讯录(静态版本)//typedef struct Contact//{// PeoInfo data[100];// int sz;//}Contact;//动态版本typedefstructContact{structPeoInfo* data;int sz;//已经放了几个int capacity;//现在的容量}Contact;
因为静态版本只能给出固定的容量,超出容量就不可以扩容,这就很不人性,如果给的空间太大就过于浪费,但是给的太少又不符合实际应用,因为随机性很多。
VS不支持给数组一个变量的下标比如 :arr[n],像这样使用只能在C99平台下运行,不过大多数OJ平台下都可以运行(面试或者考试可以放心)。
解释:
我们只给了一个struct PeoInfo* data 这是一个结构体指针的形式,之后可以用malloc进行扩容。
初始化通讯录
#defineDEFAULT3//应该在contact.h文件中,放到这里方便观看。//静态版本//void InitContact(Contact* pc)//{// pc->sz = 0;// memset(pc->data, 0, 100 * sizeof(PeoInfo));//}//动态版本voidInitContact(Contact* pc){assert(pc);
pc->data =(PeoInfo*)malloc(DEFAULT*sizeof(PeoInfo));if(pc->data ==NULL){perror("InitContact");return;}
pc->capacity = DEFAULT;
pc->sz =0;}
解释:
我们直接在pc->data指针所指的位置上开辟空间,记住不是在pc->data上开辟空间,因为pc->data只是一个结构体指针,开辟的大小是个人信息结构体大小的三倍(default=3),以后要开辟空间一定要检验是否开辟成功,没有成功要perror,给出标记,如果开辟成功就可以给容量赋值了,并且给sz初始化为0.
增加联系人信息
//增加联系人(静态)//void AddContact(Contact* pc)//{// if (pc->sz == MAX)// {// printf("已经满了\n");// return;// }// else// {// printf("请输入名字;》\n");// scanf("%s", pc->data[pc->sz].name);// printf("请输入性别:》\n");// scanf("%s", pc->data[pc->sz].sex);// printf("请输入年龄:》\n");// scanf("%d", &(pc->data[pc->sz].age));// printf("请输入电话:》\n");// scanf("%s", pc->data[pc->sz].tele);// printf("请输入地址:》\n");// scanf("%s", pc->data[pc->sz].addr);// pc->sz++;// printf("成功增加联系人\n");////// }//}//检查容量intCheckCapacity(Contact* pc){if(pc->sz == pc->capacity){printf("已经满了\n");
PeoInfo* ptr =(PeoInfo*)realloc(pc->data,2* pc->capacity *sizeof(PeoInfo));if(ptr !=NULL){
pc->data = ptr;
pc->capacity *=2;printf("增容成功\n");return1;}else{perror("ADDContact");return0;}}elsereturn1;}//动态增加voidAddContact(Contact* pc){assert(pc);if(CheckCapacity(pc)){printf("请输入名字;》\n");scanf("%s", pc->data[pc->sz].name);printf("请输入性别:》\n");scanf("%s", pc->data[pc->sz].sex);printf("请输入年龄:》\n");scanf("%d",&(pc->data[pc->sz].age));printf("请输入电话:》\n");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址:》\n");scanf("%s", pc->data[pc->sz].addr);
pc->sz++;printf("成功增加联系人\n");}else{return;}}
解释:
静态增加信息因为容量有限,容量满了之后无法增加所以只需要在函数最早加一个判断sz是否等于MAX,如果不等于便可以增加,等于的话就会提示。
动态版本增加信息的函数前面也要有一个检验容量的信息如果不满可以进行增加,满了呢当然也不会退出,会直接进行扩容。因为后面也会用到检查容量的函数所以我直接将其封装成一个小函数,随用随取很方便。其他的就和静态一样增加个人信息即可,但是再也不会因为容量满了而退出程序了。
销毁整个通讯录
//销毁整个顺序表voidDestroyContact(Contact* pc){free(pc->data);
pc->data =NULL;
pc->capacity =0;
pc->sz =0;}
解释:
因为是顺序表,而且动态开辟了空间,使用完之后一定要释放,不然会把内存空间浪费掉使电脑性能下降的。
在这里也要声明pc->data开辟的空间被free之后,也一定要pc->data = NULL,因为会有野指针的风险,甚至你下次调用pc->data打印信息还能有一定几率打印出之前存的消息这是因为栈帧的原因,千万不要有侥幸心理,使用完开辟分空间之后一定要free和NULL。
修改好的主函数
#define_CRT_SECURE_NO_WARNINGS1#include"contact.h"//一个汉字占两个字节voidmenu(){printf("***************************\n");printf(" 1.add 2.del \n");printf(" 3.search 4.modify \n");printf(" 5.show 6.sort \n");printf(" 0.exit \n");printf("***************************\n");}enumOption//枚举的作用{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT
};intmain(){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:SortContact(&con);break;case EXIT:DestroyContact(&con);break;default:break;}}while(input);return0;}
修改点:
在这里最重要的是在退出选项的下面增加了一个DestroyContact(&con);函数,这是因为使用完动态分配的空间一定要释放。
还增加了枚举,这是因为你给出菜单选项是,别人阅读你的代码一是难免会忘记所以总要翻看查询会有很多不便,但是这里增加了枚举可以直接通过枚举来调用。
枚举的解释:
枚举如果你没有给里面的量赋值的话,他会主动给你赋值,从0,1,2…一直往下,当然你也可以直接赋值,我在这里没有赋值所以是按照 菜单的复制情况给他们拍的顺序(EXIT放在了最开始的位置也就是0)。
预告
之后还会有文件的版本敬请期待!也希望同学们要复习好知识哦。
版权归原作者 王少climax 所有, 如有侵权,请联系我们删除。