资讯专栏INFORMATION COLUMN

【C语言进阶】C语言实现通讯录 升级版 { 含动态扩容/销毁/信息保存功能 }(强烈建议收藏食用)

gxyz / 2449人阅读

摘要:之前的通讯录在程序退出后内部的数据就会消失,再次打开程序后只能重新输入数据,为此我们增加了一个保存功能来保存信息。

前言:

  • 由于之前实现的通讯录在存储方面只能支持静态的1000人的存储量,但是如果联系人较少,则会造成较大的内存浪费。
  • 而当联系人一旦超过1000时,就不能再继续存储信息了。因此我将通讯录改成动态扩容版本,就不会减少内存的浪费,同时也可以无限增加通讯录的内部信息。
  • 之前的通讯录在程序退出后内部的数据就会消失,再次打开程序后只能重新输入数据,为此我们增加了一个保存功能来保存信息。

此版本将实现的功能:

  1. 新增联系人
  2. 查找联系人
  3. 删除联系人
  4. 修改联系人
  5. 查看所有联系人
  6. 清空所有联系人(新增)

  7. 按姓名排序联系人
  8. 保存联系人信息(新增)

注:之前版本写过的代码就不多做赘述了

如果有代码上的疑惑可以移步去 手把手教你用C语言实现通讯录(简易版  查看

本次仅对新增的内容进行解释和说明

通讯录(C语言升级版)

目录

一、通讯录菜单

二、通讯录主函数

三、枚举主函数内部选项

四、定义通讯录内容

五、全局变量声明

六、初始化通讯录

七、读取通讯录函数

八、通讯录扩充函数

九、头文件

十、实现通讯录新增功能

(一)清空所有联系人

(二)保存联系人信息

十一、完整代码


一、通讯录菜单

新增:

清空所有联系人选项(7)

保存联系人信息选项(8)

 代码如下: 

void menu(){	printf("*********************************/n");	printf("**      1. 添加联系人          **/n");	printf("**      2. 删除联系人          **/n");	printf("**      3. 查找联系人          **/n");	printf("**      4. 修改联系人          **/n");	printf("**      5. 显示所有联系人      **/n");    printf("**      6. 按姓名排序联系人    **/n");    printf("**      7. 清空所有联系人      **/n");    printf("**      8. 保存联系人信息      **/n");	printf("**      0. exit                **/n");	printf("*********************************/n");}

 执行结果:


二、通讯录主函数

 新增:

case 分支中 清空通讯录选项 & 清空实现函数

case 分支中 保存通讯录选项 & 保存实现函数

case 分支中 退出时自动保存实现函数

 代码如下: 

int main(){    int input = 0;    //创建通讯录    struct 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:            MoidfyContact(&con);            break;        case SHOW:            ShowContact(&con);            break;        case DESTROY:            DestroyContact(&con);            break;        case SORT:            SortContact(&con);            break;        case SAVE:            SaveContact(&con);            break;        case EXIT:            SaveContact(&con);            printf("退出通讯录/n");            break;        default:            printf("选择错误/n");            break;        }    } while (input);    return 0;}


三、枚举主函数内部选项

新增:

enum枚举 选择中新增 DESTROY  &  SAVE   的选项,通过枚举的方法对应 main 函数中的 case 分支。

 代码如下: 

//枚举:选择功能enum Choose{    EXIT,    //0    ADD,     //1    DEL,     //2    SEARCH,  //3    MODIFY,  //4    SHOW,    //5    SORT,    //6    DESTROY, //7    SAVE     //8};


四、定义通讯录内容

新增:

typedef 定义 Contact 函数,使其能直接使用不需要 struct 修饰

整型 capacity 变量来表示当前通讯录的最大容量

 代码如下:

//结构体:通讯录类型typedef struct Contact{    struct PeoInform *data;//存放信息    int size;//记录当前结构体内已经有的元素个数    int capacity;//当前通讯录的最大容量}Contact;


五、全局变量声明

新增:

为了实现动态,我们将初始空间 Org_SPACE (orignial space 初始空间) 设置为5个


修改:

删去了最大空间为1000个的静态内存空间

 代码如下: 

//初始空间为5个#define ORG_SPACE 5#define MAX_NAME 20#define MAX_SEX 5#define MAX_PHONE 12#define MAX_ADDRESS 30


六、初始化通讯录

新增:

通过 malloc 函数动态开辟一块地址,初始容量 ORG_SPACE 可以存放 5 个联系人信息,同时初始化最大容量 ORG_SPACE  

下方的 LoadContact 函数是为了读取信息来存放到通讯录中,来实现文件保存功能

 代码如下: 

//初始化通讯录的函数void InitContact(struct Contact *ps){	ps->data = (struct PeoInform*)malloc(ORG_SPACE*sizeof(struct PeoInform));	if(ps->data == NULL)	{		return;	}	ps->size = 0;	ps->capacity = ORG_SPACE;	//把文件中已经存放的通讯录中的信息加载到通讯录中	LoadContact(ps);}

七、读取通讯录函数

那么既然上方的初始化通讯录中已经出现了这个读取函数,那么我们就来设计一下:

这里的 FR 来临时读取 contact.txt 保存文件中的信息,一旦FR内部为空,就代表文件内没有保存任何信息。

而后面是读取文件中的信息,存放到通讯录中的临时变量 tmp 中去,此时我们要考虑读取到通讯录的数据是否会溢出,所以我们要进行判断,一旦超过了5个的初始空间,就进行扩充。

最后关闭文件时,将 FR 内部的数据清空

//读取通讯录信息void LoadContact(Contact *ps){	PeoInform tmp = {0};//临时变量tmp	FILE *FR = fopen("contact.txt", "rb");	if(FR == NULL)	{		printf("LoadContact::%s/n", strerror(errno));		return;	}		//读取文件,存放到通讯录中	while(fread(&tmp, sizeof(PeoInform), 1, FR))	{		ExpandCapacity(ps);		ps->data[ps->size] = tmp;		ps->size++;	}	fclose(FR);	FR = NULL;}

八、通讯录扩充函数

我们此时来设计一下通讯录扩充函数,同时使其能够实现检测当前通讯录的容量:

1. 如果满了,就增加空间

2. 如果不满,啥事都不干

3. 一旦存储达到5个以后就再使用realloc函数扩充5个动态空间

代码如下:

void ExpandCapacity(struct Contact *ps){    if(ps->size == ps->capacity)    {        struct PeoInform *ptr = realloc(ps->data, (ps->capacity+2)*sizeof(PeoInform));		if(ptr != NULL)		{			ps->data = ptr;			ps->capacity += 5; //自动开辟五个动态空间			printf("扩充成功/n");		}		else		{			printf("扩充失败/n");		}	}}


九、头文件

新增:

errno 函数 需要引用的 头文件

malloc 函数 需要引用的 头文件

   代码如下:

#include #include #include #include #include 


十、实现通讯录新增功能

(一)清空所有联系人

   代码如下:

//销毁通讯录中的所有信息void DestroyContact(Contact* ps){       printf("您确定要清空所有联系人吗? y/n/n");	char choice[2];	scanf("%s", &choice);	if (strcmp(choice, "y") == 0)	{        ps->size = 0;		printf("已清空所有联系人!/n");	}	if (strcmp(choice, "n") == 0)	{		printf("指令已取消/n");	}    //同时释放之前所开辟的动态空间	free(ps->data);	ps->data = NULL;}

   执行效果:


(二)保存联系人信息

   代码如下:

//保存联系人到文件void SaveContact(Contact* ps){	FILE* fp = fopen("contact.txt", "wb");	if (fp == NULL)	{		printf("SaveContact::%s/n", strerror(errno));		return;	}	//写通讯录中数据到为文件中	int i = 0;	for (i = 0; i < ps->size; i++)	{		fwrite(&(ps->data[i]), sizeof(PeoInform), 1, fp);        printf("已保存联系人!/n");	}}   

 执行效果:

 

 关闭程序后再次打开:


十一、完整代码

#include #include #include #include #include  //初始空间为5个#define ORG_SPACE 5#define MAX_NAME 20#define MAX_SEX 5#define MAX_PHONE 12#define MAX_ADDRESS 30//枚举:选择功能enum Choose{    EXIT,    //0    ADD,     //1    DEL,     //2    SEARCH,  //3    MODIFY,  //4    SHOW,    //5    SORT,    //6    DESTROY, //7    SAVE     //8}; //结构体:通讯录中每个成员的信息typedef struct PeoInform//将结构体指针类型命名为PeoInform{    char name[MAX_NAME];    int age;    char sex[MAX_SEX];    char phone[MAX_PHONE];    char address[MAX_ADDRESS];}PeoInform; //结构体:通讯录类型typedef struct Contact{    struct PeoInform *data;//存放信息    int size;//记录当前结构体内已经有的元素个数    int capacity;//当前通讯录的最大容量}Contact;//通讯录扩充void ExpandCapacity(struct Contact *ps){    if(ps->size == ps->capacity)    {        struct PeoInform *ptr = realloc(ps->data, (ps->capacity+2)*sizeof(PeoInform));		if(ptr != NULL)		{			ps->data = ptr;			ps->capacity += 5; //自动开辟五个动态空间			printf("扩充成功/n");		}		else		{			printf("扩充失败/n");		}	}}//读取通讯录信息void LoadContact(Contact *ps){	PeoInform tmp = {0};//临时变量tmp	FILE *FR = fopen("contact.txt", "rb");	if(FR == NULL)	{		printf("LoadContact::%s/n", strerror(errno));		return;	}		//读取文件,存放到通讯录中	while(fread(&tmp, sizeof(PeoInform), 1, FR))	{		ExpandCapacity(ps);		ps->data[ps->size] = tmp;		ps->size++;	}	fclose(FR);	FR = NULL;}//初始化通讯录的函数void InitContact(struct Contact *ps){	ps->data = (struct PeoInform*)malloc(ORG_SPACE*sizeof(struct PeoInform));	if(ps->data == NULL)	{		return;	}	ps->size = 0;	ps->capacity = ORG_SPACE;	//把文件中已经存放的通讯录中的信息加载到通讯录中	LoadContact(ps);}//按姓名查找联系人是否存在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;        }    }    return -1;//找不到的情况}//增加一个信息到通讯录void AddContact(struct Contact *ps){    ExpandCapacity(ps);    //增加数据    printf("请输入名字:>");    scanf("%s", ps->data[ps->size].name);    printf("请输入年龄:>");    scanf("%d", &(ps->data[ps->size].age));    printf("请输入性别:>");    scanf("%s", ps->data[ps->size].sex);    printf("请输入电话:>");    scanf("%s", ps->data[ps->size].phone);    printf("请输入家庭地址:>");    scanf("%s", ps->data[ps->size].address);     ps->size++;    printf("添加成功/n");} //删除指定的联系人void DelContact(struct Contact *ps){    int pos = 0;    char name[MAX_NAME];    printf("请输入要删除人的名字:>");    scanf("%s", name);    //1.查找要删除的人在什么位置    //找到了返回名字所在元素的下标    //找不到返回 -1    pos = FindByName(ps, name);    //2.删除    //查询不到联系人    if (pos == -1)    {        printf("查询不到要删除的联系人,请重试/n");    }    else    {        //删除数据        int j = 0;        for(j = pos; j < ps->size-1; j++)        {            ps->data[j] = ps->data[j + 1];            //由于删除了这个数据,所以后面的数据会顶替上来        }        ps->size--;        printf("删除成功/n");    }} //查找指定的人的信息void SearchContact(const struct Contact *ps){    char name[MAX_NAME];    printf("请输入要查找人的名字:>");    scanf("%s", name);    int pos = 0;    //查找联系人的位置    pos = FindByName(ps, name);    //2.删除    if (pos == -1)    {        printf("要查找的人不存在,请重试/n");    }    else    {        printf("%-20s/t%-4s/t%-5s/t%-12s/t%-20s/n", "名字", "年龄", "性别", "电话", "地址");        printf("%-20s/t%-4d/t%-5s/t%-12s/t%-20s/n",            ps->data[pos].name,            ps->data[pos].age,            ps->data[pos].sex,            ps->data[pos].phone,            ps->data[pos].address);    }} //修改指定联系人的信息void MoidfyContact(struct Contact *ps){    char name[MAX_NAME];    printf("请输入要修改联系人的名字:>");    scanf("%s", name);    int pos = 0;    pos = FindByName(ps, name);    if (pos == -1)    {        printf("要修改联系人的信息不存在,请重试/n");    }    else    {        printf("请输入名字:>");        scanf("%s", ps->data[pos].name);        printf("请输入年龄:>");        scanf("%d", &(ps->data[pos].age));        printf("请输入性别:>");        scanf("%s", ps->data[pos].sex);        printf("请输入电话:>");        scanf("%s", ps->data[pos].phone);        printf("请输入家庭地址:>");        scanf("%s", ps->data[pos].address);         printf("修改完成/n");    }}  //展示通讯录中的信息void ShowContact(const struct Contact *ps){    if(ps->size == 0)    {        printf("通讯录为空/n");    }    else    {        int i = 0;        //标题        printf("%-20s/t%-4s/t%-5s/t%-12s/t%-20s/n", "名字", "年龄", "性别", "电话", "地址");        //数据        for(i = 0; i < ps->size; i++)        {            printf("%-20s/t%-4d/t%-5s/t%-12s/t%-20s/n",            ps->data[i].name,            ps->data[i].age,            ps->data[i].sex,            ps->data[i].phone,            ps->data[i].address);        }    }}//销毁通讯录中的所有信息void DestroyContact(Contact* ps){       printf("您确定要清空所有联系人吗? y/n/n");	char choice[2];	scanf("%s", &choice);	if (strcmp(choice, "y") == 0)	{        ps->size = 0;		printf("已清空所有联系人!/n");	}	if (strcmp(choice, "n") == 0)	{		printf("指令已取消/n");	}    //同时释放之前所开辟的动态空间	free(ps->data);	ps->data = NULL;}//按姓名排序通讯录内容void SortContact(struct Contact *ps){    if (ps->size <= 0){		printf("通讯录中没有联系人,请添加!/n");	}	int i = 0;	int j = 0;	for (i = 0; i< ps->size - 1; i++)	{		for (j = 0; j< ps->size - i - 1; j++)		{			if (strcmp( ps->data[j].name, ( ps->data[j + 1]).name) > 0)			{                PeoInform tmp;				tmp = ps->data[j];				ps->data[j] = ps->data[j + 1];				ps->data[j + 1] = tmp;			}		}		printf("排序成功!/n");	}} //保存联系人到文件void SaveContact(Contact* ps){	FILE* fp = fopen("contact.txt", "wb");	if (fp == NULL)	{		printf("SaveContact::%s/n", strerror(errno));		return;	}	//写通讯录中数据到为文件中	int i = 0;	for (i = 0; i < ps->size; i++)	{		fwrite(&(ps->data[i]), sizeof(PeoInform), 1, fp);        printf("已保存联系人!/n");	}}   void menu(){	printf("*********************************/n");	printf("**      1. 添加联系人          **/n");	printf("**      2. 删除联系人          **/n");	printf("**      3. 查找联系人          **/n");	printf("**      4. 修改联系人          **/n");	printf("**      5. 显示所有联系人      **/n");    printf("**      6. 按姓名排序联系人    **/n");    printf("**      7. 清空所有联系人      **/n");    printf("**      8. 保存联系人信息      **/n");	printf("**      0. exit                **/n");	printf("*********************************/n");} int main(){    int input = 0;    //创建通讯录    struct Contact con;//con就是通讯录,里面包含:1000个元素的数和size    //初始化通讯录    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:            MoidfyContact(&con);            break;        case SHOW:            ShowContact(&con);            break;        case SORT:            SortContact(&con);            break;        case DESTROY:            DestroyContact(&con);            break;        case SAVE:            SaveContact(&con);            break;        case EXIT:            SaveContact(&con);            printf("退出通讯录/n");            break;        default:            printf("选择错误/n");            break;        }    } while (input);    return 0;}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/119672.html

相关文章

发表评论

0条评论

最新活动
阅读需要支付1元查看
<