前沿:
~~在一个周前,我用c语言实现了一个银行账号的功能,在总结当中我说了要实现一个通讯录,来实现人员的增删插改功能,而现在就是我实现它的时候!!,本文呢小马将通过三种形式来实现用户的增删插改,其实也就是一点点的优化版本,从静态的实现,到动态的实现,最后以文件的形式来完成,请大家和我一起往下看吧!➡︎
思维导图:↘️ ⤵️
↘️
目录
一、基础版本:
1.1 通讯录的个人信息(结构体来实现):
1..2通讯录名单:
1.3人员初始化:
1.4菜单:
1.5主函数:
二、功能的实现:
2.1、增加人数:
2.2、删除人数:
2.3、查找:
2.4、展示:
2.5、排序(这里我是通过名字):
三、通讯录进阶(设置动态存储):
3.1通讯录从静态改为动态:
3.2通讯录的初始化:
3.3通讯录的增加需要判断是否满了:
四、文件的形式存储通讯录:
4.1人员信息的保存:
4.2人员信息的流入:
总结:
前提准备:
1、通讯录里面的人的个人信息(姓名、性别、年龄、手机号、地址)。
2、通讯录名单(来实现人员的增删插改)。
3、人员的初始化。
4、菜单。
typedef struct peoInfo //重定义
{
char name[20]; //姓名
int age ; //年龄
char sex[10]; //性别
char tele[12]; //手机号
char addr[30]; //地址
}peoInfo;
typedef struct Contact
{
peoInfo data[100]; //人员名单 结构体数组
int count; //人员数量
}Contact;
void InitContact(Contact* con)
{
assert(con);
con->count=0; //初始人数为0
memset(con->data,0,sizeof(con->data)); //这是一个c语言的库函数把数组里面的数全部初始化为0
}
void menu(void)
{
printf("===============================\n");
printf("====1.add 2. del 3.serch=====\n");
printf("=====4.modify 5.show======\n");
printf("=====6.sort 0.exit======\n");
printf("===============================\n");
printf("===============================\n");
}
enum a
{
ext, //这里用了简单的枚举的方法 枚举的初始值为0
add,
del,
serch,
modify,
show,
sort
};
int main()
{
int choice;
Contact con; //通讯录
do
{
menu();
printf("请选择功能\n");
scanf("%d",&choice);
switch(choice)
{
case add:
AddContact(&con); //实现增加功能的函数
break ;
case del:
DelContanct(&con); //实现删除功能的函数
break ;
case serch:
SerContact(&con); //实现查找功能的函数
break ;
case modify:
ModContact(& con); //实现修改功能的函数
break ;
case show:
ShowContact(&con); //实现展示功能的函数
break ;
case sort:
SorContact(&con); //实现排序功能的函数
break ;
case ext :
printf("程序结束\n");
break;
default :
printf("输入有误请重新输入\n");
}
}while(choice);
return 0;
}
void AddContact(Contact* con)
{
assert(con); //指针不能为空
if(con->count==Max)
{
printf("存放已满\n");
return ;
}
printf("请输入名字");
scanf("%s",con->data[con->count].name);
printf("请输入年龄");
scanf("%d",&(con->data[con->count].age));
printf("请输入性别");
scanf("%s",con->data[con->count].sex);
printf("请输入电话");
scanf("%s",con->data[con->count].tele);
printf("请输入地址");
scanf("%s",con->data[con->count].addr);
con->count++;
printf("增加成功\n");
}
static int xiaomafind(Contact* con,char name[])
{
assert(con);
int i=0;
for(i=0;icount;i++)
{
if(0==strcmp(con->data[i].name,name)) //通过名字来查找看是否存在 ,如果有返回下标。
{
return i;
}
else
{
return -1;
}
}
void DelContanct(Contact* con)
{
char name[20]={0};
printf("请输入你想删除的名字\n");
assert(con);
int i;
scanf("%s",name);
int pos=xiaomafind(con,name);
if(pos==-1)
{
printf("没有你要删除的人\n");
}
else
{
for(i=pos;icount;i++)
{
con->data[i]=con->data[i+1]; //通过数组后一个覆盖前一个来完成删除功能
}
con->count--; //删除完成后人员减一
printf("删除成功\n");
}
}
static int xiaomafind(Contact* con,char name[])
{
assert(con);
int i=0;
for(i=0;icount;i++)
{
if(0==strcmp(con->data[i].name,name))
{
return i;
}
}
return -1;
}
void SerContact(Contact *con)
{
char name[20]={0};
printf("请输入你想查找的名字\n");
assert(con);
scanf("%s",name);
int find =xiaomafind(con,name);
if(find==-1)
{
printf("没有你要查找的用户\n");
}
else{
printf("查找成功\n");
}
}
void ShowContact( const Contact* con)
{
assert(con);
int i;
for(i=0;icount;i++)
{
printf("%2s\t%3d\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); //这里是为了打印好看
}
}
^ _ ^用qsort 函数发现很很容的都能进行排序,我们只需要告诉他我们的排序方法是什么就可以很容易的进行一下排序
int cmp_stu_by_name(const void*e1,const void*e2)
{
return strcmp(((peoInfo*)e1)->name,((peoInfo*)e2)->name);
} //如不不理解的看我指针讲解中回调函数
void SorContact(Contact* con)
{
assert(con);
qsort(con->data, con->count, sizeof(peoInfo), cmp_stu_by_name); //这里运用了一个c语言的库函数qsort函数,在指针进阶中我也讲述了如何使用,如果不会的可以看一下指针的进阶。
}
动态版本只需要改三个位置就行啦
静态版本
//typedef struct Contact
//{
// peoInfo data[100]; //人员名单 结构体数组
// int count; //人员数量
//}Contact;
动态版本
typedef struct Contact
{
peoInfo *data; //人员名单 结构体指针
int count; //人员数量
int capicity; //通讯录容量
}Contact;
//静态版本
//void InitContact(Contact* con)
//{
// assert(con);
// con->count=0; //初始人数为0
// memset(con->data,0,sizeof(con->data)); //这是一个c语言的库函数把数组里面的数全部初始化为0
//}
//动态版本
void InitContact(Contact* con)
{
assert(con);
con->count=0;
con->data=(PeoInf0*)calloc(3,sizeof(peoInfo*));
if(con->data=NULL)
{
perrror("con->data"); //如果空指针打印错误原因
}
con->capicity=3; //这里我们设置的初始容量为3
}
void AddContact(Contact* con)
{
assert(con); //指针不能为空
if(con->count==con->capicity)
{
(peoInfo*)ptr=(PeoInfo*)realloc(con->data,(con->capicity)*2*sizeof(peoInfo)). //增加人数前先进行判断是否满了,如果满了扩大2倍。
if(ptr==NULL)
{
perror("peoInof");
return ;
}
else{
con->data=ptr;
}
}
printf("请输入名字");
scanf("%s",con->data[con->count].name);
printf("请输入年龄");
scanf("%d",&(con->data[con->count].age));
printf("请输入性别");
scanf("%s",con->data[con->count].sex);
printf("请输入电话");
scanf("%s",con->data[con->count].tele);
printf("请输入地址");
scanf("%s",con->data[con->count].addr);
con->count++;
printf("增加成功\n");
}
^ - ^这样我们就实现通讯录的动态化,就不怕通讯录人数会存满了。
前面的通讯录在程序结束后发现人员没有办法进行一个保存,而通过文件的形式我们可以很好的做到这一点,在结束之前进行对文件的保存,在再一次执行程序是输入保存的文件,但是文件操作也有自己的不足之处,后面用数据库来实现更好,当前我们先用文件的形式来进行实现数据的保存,而实现这个只需要在结束时对文件保存,在初始化的时候时文件信息流入。
void SaveContact(Contact*con)
{
assert(con);
//通过二进制写的形式把人员数据写入当中
FILE* pfWrite=fopen("Contact.txt","wb");
if(pfWrite==NULL)
{
perror("SaveContact");
return ;
}
int i=0;
for(i=0;icount;i++)
{
fwrite(con->data+i,sizeof(peoInfo),1,pfWrite); //一次写一个人员
}
fclose(pfWrite);
pfWrite=NULL;
}
void LoadContact(Contact* con)
{
assert(con);
FILE*pfread =fopen("/Users/mamenghao/Desktop/Contact.txt","rb"); //二进制来读取文件信息
if(pfread==NULL)
{
perror("LoadContact");
return ;
}
peoInfo tmp={0}; //创建一个人员结构体变量先做临时的保存
while( fread(&tmp,sizeof(peoInfo),1,pfread)==1)
{
if(con->count==con->capicity)
{
peoInfo* ptr=(peoInfo*)realloc(con->data,((con->capicity)*2*sizeof(peoInfo)));
if(ptr==NULL)
{
perror("peoInof");
return ;
}
else{
con->data=ptr;
}
} //在增加前先判断是否容量已经满了
con->data[con->count]=tmp;
con->count++;
}
fclose(pfread);
pfread=NULL;
}
总结:
通讯录本身实现它并不是特别的难,运用的知识就是顺序表的增删插改功能,而进一步的优化只需要大家熟练掌握文件的操作和动态内存存储就能很好的实现啦!!
最后小马码文不易,觉得有帮助的话请多多支持哈^ _ ^