C语言实现动态通讯录
一.动态通讯录的要求
1.通讯录的内存可随联系人的增加而增加,不用一次性分配大量空间造成空间的浪费
2.存储联系人的信息包含:
名字
性别
年龄
电话
地址
3.通讯录包含以下功能
增加好友信息
删除指定名字的好友信息
查找好友信息
修改指定名字的好友信息
显示通讯录所有联系人的信息
通讯录按照年龄的大小排序(升序)
二.实现思路
将实现动态通讯录的代码分为三个代码块分别存放在test.c,Contact.c,Contach.h 三个文件,这样就不用把
代码全放在一个文件显得乱且冗余
test.c
1.实现打印通讯录的界面
2.测试通讯录各个功能(即调用对应的功能函数)
通过一个switch语句来选择测试哪个功能
Contact.c
1.初始化通讯录
2.将各个通讯录的功能封装成一个个函数,即用函数实现通讯录的各个功能
Contact.h
只要其他文件包含Contact.h 这个头文件 就可以调用该文件的内容
包括其他头文件,宏定义,结构体的声明,函数的声明
1.项目的头文件的引用
2.其他文件用到的宏定义,枚举,将多次用到的数字都定义成宏方便后期修改,也可以提高代码的可读性一举两得
3.通讯录功能函数的声明
直接上代码讲解
test.c
首先创建一个通讯录(结构体的变量)该变量包含
1.维护动态内存的指针data
2.记录当前已有联系人的个数整形变量size
3.记录通讯录当前容量的整形变量capacity
然后初始化通讯录
1.初始化给通讯录分配默认动态内存交给data指针来维护
2.初始化当前通讯录元素个数为0 size为0
3.初始默认容量capacity(开始的容量 可以随意调整)
#include "contact.h"
//打印菜单
void menu(void)
{
printf("\n");
printf("*******************************************************\n");
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");
printf("*******************************************************\n");
printf("\n");
}
int main()
{
int input;
//创建一个通讯录
struct Contact con;//con为一个通讯录结构体的变量,包含data指针和size, capacity
//初始化通讯录
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);
printf("退出\n");
break;
default:
printf("选择错误\n");
break;
}
}while(input);
return 0;
}
Contact.h
只要其他文件包含Contact.h 这个头文件 就可以调用该文件的内容
包括其他头文件,宏定义,结构体的声明,函数的声明
1.项目的头文件的引用
2.其他文件用到的宏定义,枚举,将多次用到的数字都定义成宏或用枚举列举方便后期修改也可以提高代码的可读性一举两得
3.声明通讯录功能函数 方便 test.c 调用功能函数
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define DEFAULT_CAPACITY 3
#define MAX_NAME 10
#define MAX_GENDER 5
#define MAX_TEL 30
#define MAX_ADDR 30
//枚举,列举功能
enum Option
{
EXIT, //默认从0开始
ADD,//1
DEL,//2
SEARCH,//3
MODIFY,//4
SHOW,//5
SORT//6
};
//联系人信息的类型
struct PeoInfo
{
int age;
char name[MAX_NAME];
char gender[MAX_GENDER];
char tel[MAX_TEL];
char addr[MAX_ADDR];
};
//通讯录类型
struct Contact
{
//嵌套一个联系人信息的一个结构体
struct PeoInfo *data;//维护动态内存的指针
int size;//记录当前已有联系人的个数
int capacity;//记录通讯录当前容量
};
//初始化通讯录
void InitContact(struct Contact *ps);
//添加一个联系人到通讯录
void AddContact(struct Contact *ps);
//显示整个通讯录
void ShowContact(const struct Contact *ps);
//从通讯录删除一个指定联系人
void DelContact(struct Contact *ps);
//从通讯录寻找一个指定联系人
void SearchContact(const struct Contact *ps);
//修改指定联系人的信息
void ModifyContact(struct Contact *ps);
//按年龄排序
void SortContact( struct Contact *ps);
//检测容量是否够用,不够扩容默认一次扩两个
int CheckCapacity( struct Contact *ps);
//销毁通讯录(释放分配的动态内存)
void DestroyContact(struct Contact *ps);
Contact.c
用函数实现动态通讯录的各个功能
各个函数都有详细的注释这里就不在重复讲解
这里挑几个要注意的地方
1.static int FindByName(const struct Contact *ps,char name[MAX_NAME])
封装这个函数是因为有多个函数需要用到查找联系人并返回联系人的在内存中的位置,为了避免代码冗余将该功能封装成一个函数,其他函数要用到此功能直接调用该函数即可
2.每次添加新的联系人要先检测通讯录的容量是否足够,即用
int CheckCapacity( struct Contact *ps) 函数检测当前通讯录的人数与通讯录的容量是否相等,若相等即通讯录已满需要进行扩容利用realloc进行扩容这里我默认每次扩充两个人的信息容量(两个结构体的大小,一个结构体相当于一条记录存储着联系人的名字,姓名,年龄,电话,地址)
3.从通讯录删除一个指定名字的联系人,先查找该联系人的下标(pos)然后看图
#include "contact.h"
//初始化通讯录
void InitContact(struct Contact *ps)
{
ps->data=(struct PeoInfo*)malloc( DEFAULT_CAPACITY *sizeof(struct PeoInfo));//初始化给通讯录分配默认动态内存
ps->size=0;//初始化当前通讯录元素个数为0
ps->capacity=DEFAULT_CAPACITY;//默认容量
}
//因很多功能函数需要用到查找联系人,所以封装成一个函数方便调用,以减少代码的冗余
//加上static本文件可以调用
static int FindByName(const struct Contact *ps,char name[MAX_NAME])
{
int i=0;
for(i=0; i<ps->size; i++)
{
if(0==strcmp(ps->data[i].name,name))
{
return i;//找到联系人,返回该联系人的位置
break;
}
}
return -1;//没找到,返回-1
}
int CheckCapacity( struct Contact *ps)
{
if (ps->size == ps->capacity)
{
//当通讯录当前人数等于容量时进行扩容一次默认扩充两个空间
//参数1.要调整的内存地址 2.调整之后的大小(单位字节)
struct PeoInfo*str=(struct PeoInfo*)realloc(ps->data, (ps->capacity+2)*sizeof(struct PeoInfo) );
if ( str !=NULL )
{
ps->data=str;//开辟成功把地址赋给原来的指针继续维护
ps->capacity+=2;//通讯录的容量加2
printf("增容成功\n");
return 1;
}
else
{
printf("阵容失败\n");
return -1;
}
}
}
//添加一个联系人到通讯录
void AddContact(struct Contact *ps)
{
int ret=0;
if (ret= CheckCapacity(ps)==-1 )
{
printf("添加失败\n");
}
else
{
printf("输入姓名:");
scanf("%s",ps->data[ps->size].name);
printf("输入性别:");
scanf("%s",ps->data[ps->size].gender);
printf("输入年龄:");
//因年龄的数据类型为整形 须取地址操作
//其余为数组名本就为地址 则无需取地址
scanf("%d",&(ps->data[ps->size].age));
printf("输入电话:");
scanf("%s",ps->data[ps->size].tel);
printf("输入住址:");
scanf("%s",ps->data[ps->size].addr);
printf("添加成功\n");
ps->size++;//每加一个联系人当前通讯录元素个数加1
}
}
//显示整个通讯录
void ShowContact(const struct Contact *ps)
{
int i=0;
if ( ps->size ==0 )
{
printf("通讯录为空\n");
}
else
{
printf("%-10s %-5s %-5s %-10s %-30s \n","姓名","性别","年龄","电话","地址");
//将通讯录里每个联系人的信息一一打印出来
//打印size(当前通讯录几个联系人)个信息
for(i=0; i<ps->size; i++)
{
// "-5"号表示左对齐,打印长度为5
printf("%-10s %-5s %-5d %-10s %-30s \n",
ps->data[i].name,
ps->data[i].gender,
ps->data[i].age,
ps->data[i].tel,
ps->data[i].addr);
}
}
}
//从通讯录删除一个指定联系人
void DelContact(struct Contact *ps)
{
int j=0;
int pos=0;//创建一个变量来接收要删除联系人的位置
char name[MAX_NAME];
printf("请输入要删除人的名字");
scanf("%s",name);
pos=FindByName(ps,name);
if (pos ==-1 )
{
printf("没有找到此人\n");
}
else
{
for(j=pos; j<ps->size-1; j++)
{
ps->data[j]=ps->data[j+1];//将要删除联系人的后面的联系人的位置都向前移动一个位置覆盖要删除的联系人
}
printf("删除成功\n");
ps->size--;
}
}
//从通讯录寻找一个指定联系人
void SearchContact(const struct Contact *ps)
{
int pos=0;
char name[MAX_NAME];
printf("请输入要寻找人的名字");
scanf("%s",name);
pos=FindByName(ps,name);
if ( pos==-1 )
{
printf("没有找到此人\n");
}
else
{
//找到了打印信息
printf("找到了\n");
printf("%-10s %-5s %-5s %-10s %-30s \n","姓名","性别","年龄","电话","地址");
printf("%-10s %-5s %-5d %-10s %-30s \n",
ps->data[pos].name,
ps->data[pos].gender,
ps->data[pos].age,
ps->data[pos].tel,
ps->data[pos].addr);
}
}
//修改指定联系人的信息
void ModifyContact(struct Contact *ps)
{
int pos=0;
char name[MAX_NAME];
printf("请输入要修改的人的名字");
scanf("%s",name);
pos=FindByName(ps,name);
if ( pos==-1 )
{
printf("没有找到此人\n");
}
else
{
//找到该联系人重新录一遍信息,完成修改
printf("输入姓名:");
scanf("%s",ps->data[pos].name);
printf("输入性别:");
scanf("%s",ps->data[pos].gender);
printf("输入年龄:");
scanf("%d",&(ps->data[pos].age));
printf("输入电话:");
scanf("%s",ps->data[pos].tel);
printf("输入住址:");
scanf("%s",ps->data[pos].addr);
printf("修改成功\n");
}
}
//按年龄排序
void SortContact( struct Contact *ps)
{
int i=0;
int j=0;
int flag=1;
struct PeoInfo tmp;
for(i=0; i<ps->size; i++)
{
for(j=0; j<ps->size-i-1;j++)
{
if(ps->data[j].age - ps->data[j+1].age)
{
tmp= ps->data[j] ;
ps->data[j] = ps->data[j+1];
ps->data[j+1] = tmp;
flag=0;
}
}
if ( flag==1 )
{
break;
}
}
ShowContact(ps);
}
//销毁通讯录(释放分配的动态内存)
void DestroyContact(struct Contact *ps)
{
free(ps->data);//释放分配的动态内存
ps->data=NULL;
}
最后退出通讯录要调用 函数 void DestroyContact(struct Contact *ps)
释放动态分配的内存
case EXIT:
DestroyContact(&con);
printf("退出\n");
break;
效果演示
这里只展示了部分功能有兴趣的朋友可以自己实践一下
若文章有错误的地方欢迎指正,虚心接受,谢谢!!