动态通讯录管理系统
前言
之前写过一个初级的通讯管理系统,里边对于通讯录的容量是提前设置好的,这有一个坏处就是当容量达到最大值时就无法再添加信息。所以为了解决这样的问题,可以选择动态内存函数进行动态管理,在必要时自主增添容量。
若对通讯录管理系统不了解和C语言动态内存管理不熟悉的友友可以先看一下这两篇文章:
一、系统框架搭建
1.成员信息创建
首先成员信息的整体框架不变,依旧选择选择一个通讯录结构体和一个成员信息结构体;其次依旧是通讯录结构体内部会嵌套一个成员信息结构体和一个表示成员数量的变量。而发生变化的点在于刚开始要对通讯录结构体增添一个最大容量值,当容量满的时候再进行动态内存开辟,也就是通讯录容量动态增加。
struct PeoInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
};
//通讯录类型
struct Contact
{
struct PeoInfo *data;//存放一个信息
int size;//记录当前已经有的元素个数
int capacity;//当前通讯录最大容量
};
2.菜单实现
void menu()
{
printf("\n\n\t\t-------------------------欢迎使用-------------------------\n");
printf("\t\t☆☆ 1. ADD ☆☆\n\n");
printf("\t\t☆☆ 2. DEL ☆☆\n\n");
printf("\t\t☆☆ 3. SEARCH ☆☆\n\n");
printf("\t\t☆☆ 4. MODIFY ☆☆\n\n");
printf("\t\t☆☆ 5. SHOW ☆☆\n\n");
printf("\t\t☆☆ 6. SORT ☆☆\n\n");
printf("\t\t☆☆ 0. EXIT ☆☆\n\n");
printf("\t\t----------------------------------------------------------\n");
}
3.系统功能声明
这里比之前多了一个 DestroyContact()函数,它的功能是将之前动态开辟的内存通过 free()函数释放空间(销毁)。
void InitContcat(struct Contact* ps);//初始化同学录
void AddContact(struct Contact* ps);//增加
void ShowContact(const struct Contact* ps);//展示
void DelContact(struct Contact* ps);//删除
void SearchContact(struct Contact* ps);//查找
void ModifyContact(struct Contact* ps);//修改
void SortContact(struct Contact* ps);//排序
void DestroyContact(struct Contact* ps);//销毁
二、系统功能实现
1.初始化通讯录
在初始化函数内,通过 malloc()函数动态开辟三个成员信息大小的地址容量,并给通讯录当前人数以及通讯录最大容量赋值。
void InitContcat(struct Contact* ps)
{
ps->data = (struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));
if (ps->data == NULL)
{
return;
}
ps->size = 0;
ps->capacity = 3;
}
2.容量检测
该函数的功能是将通讯录当前人数与最大容量作比较,若空间还未满时则不执行该函数,相反将使用realloc() 函数进行扩容,每次扩容都会增加两个容量。
void CheckCapacity(struct Contact* ps)
{
if (ps->size == ps->capacity)
{
struct PeoInfo* ptr = realloc(ps->data, (ps->capacity + 2)*sizeof(struct PeoInfo));
if (ptr != NULL)
{
ps->data = ptr;
ps->capacity += 2;
printf("\t\t增容成功\n");
}
}
}
3.添加信息
该函数首先检测当前通讯录的容量,若满了,则增加容量,若没满,则就直接增加信息。
void AddContact(struct Contact* ps)
{
system("cls");
printf("\t\t----------------------------------\n");
CheckCapacity(ps);//检测当前通讯录的容量,若满了,则增加容量,若没满,则就直接增加信息
//增加数据
printf("\t\t请输入名字:>");
scanf("%s", ps->data[ps->size].name);
printf("\t\t请输入年龄:>");
scanf("%d", &(ps->data[ps->size].age));
printf("\t\t请输入性别:>");
scanf("%s", ps->data[ps->size].sex);
printf("\t\t请输入电话:>");
scanf("%s", ps->data[ps->size].tele);
printf("\t\t请输入住址:>");
scanf("%s", ps->data[ps->size].addr);
ps->size++;
printf("\t\t添加成功\n");
printf("\t\t----------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
4.打印信息
该函数功能是将所保存的信息进行打印,首先是要对通讯录的人数进行检测,为什么呢?原因就在于你刚打开这个通讯录就直接选择该函数,有了这样的判断就可以让管理人员与通讯录有更好地交互。
void ShowContact(const struct Contact* ps)
{
system("cls");
printf("\t\t--------------------------------------------------------------\n");
if (ps->size == 0)
{
printf("\t\t通讯录为空\n");
}
else
{
int i = 0;
printf("\t\t%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字","年龄","性别","电话","住址");
for (i = 0; i < ps->size; i++)
{
printf("\t\t%-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].tele,
ps->data[i].addr);
}
}
printf("\t\t---------------------------------------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
4.根据姓名查找位置
int FindByName(struct Contact* ps, char name[MAX_NAME])
{
system("cls");
printf("\t\t----------------------------------\n");
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (strcmp(ps->data[i].name, name) == 0)
{
return i;
}
}
return -1;
printf("\t\t----------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
5.删除信息
void DelContact(struct Contact* ps)
{
system("cls");
printf("\t\t----------------------------------\n");
char name[MAX_NAME];
printf("\t\t请输入删除人的名字:>");
scanf("%s", name);
int pos = FindByName(ps, name);
if (pos==-1)
{
printf("\t\t您要删除的人不存在!\n");
}
else
{
int j = 0;
for (j = pos; j < ps->size - 1; j++)
{
ps->data[j] = ps->data[j + 1];
}
ps->size--;
printf("\t\t删除成功\n");
}
printf("\t\t----------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
6.查找信息
void SearchContact(struct Contact* ps)
{
system("cls");
printf("\t\t----------------------------------------------------------------------\n");
char name[MAX_NAME];
printf("\t\t请输入您要查找对象的名字:>");
scanf("%s", name);
int pos = FindByName(ps, name);
if (pos == -1)
{
printf("\t\t对不起,没有找到您要查找的人!\n");
}
else
{
printf("\t\t%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "住址");
printf("\t\t%-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].tele,
ps->data[pos].addr);
}
printf("\t\t-----------------------------------------------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
7.修改信息
void ModifyContact(struct Contact* ps)
{
system("cls");
printf("\t\t---------------------------------------------------------------------------\n");
char name[MAX_NAME];
printf("\t\t请输入您要修改对象的名字:>");
scanf("%s", name);
int pos = FindByName(ps, name);
if (pos == -1)
{
printf("\t\t对不起,没有找到您要查找的人!\n");
}
else
{
printf("\t\t请输入名字:>");
scanf("%s", ps->data[pos].name);
printf("\t\t请输入年龄:>");
scanf("%d", &(ps->data[pos].age));
printf("\t\t请输入性别:>");
scanf("%s", ps->data[pos].sex);
printf("\t\t请输入电话:>");
scanf("%s", ps->data[pos].tele);
printf("\t\t请输入住址:>");
scanf("%s", ps->data[pos].addr);
printf("\t\t修改成功\n");
}
printf("\t\t----------------------------------------------------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
8.排序信息
该函数所选择的排序对象是姓名,当然也可以根据自己的需要换成其他的排序对象。
void SortContact(struct Contact* ps)
{
system("cls");
printf("\t\t-----------------------------------------------------------------------\n");
int i = 0;
for (i = 0; i < ps->size; i++)
{
int j = 0;
for (j = 0; j < ps->size-i-1; j++)
{
if (strcmp(ps->data[j].name ,ps->data[j+1].name)>0)
{
struct PeoInfo ret ;
ret = ps->data[j];
ps->data[j] = ps->data[j+1];
ps->data[j+1] = ret;
}
}
}
printf("\t\t%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "住址");
for (i = 0; i < ps->size; i++)
{
printf("\t\t%-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].tele,
ps->data[i].addr);
}
printf("\t\t-----------------------------------------------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
8.销毁通讯录
因为动态内存开辟的地址空间为成员信息所占有,所以在释放内存时只需将通讯录结构体里的数据项释放掉就可以。
void DestroyContact(struct Contact* ps)
{
free(ps->data);
ps->data = NULL;
//错误案例
//free(ps);
//ps=NULL;
}
三、源代码展示
1.test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
int main()
{
int n = 0;
system("color 3E");
struct Contact con;//con就是同学录,里边包含data指针和size和capacity
//初始化同学录
InitContcat(&con);
do
{
printf("\n\n\t\t-------------------------欢迎使用-------------------------\n");
printf("\t\t☆☆ 1. ADD ☆☆\n\n");
printf("\t\t☆☆ 2. DEL ☆☆\n\n");
printf("\t\t☆☆ 3. SEARCH ☆☆\n\n");
printf("\t\t☆☆ 4. MODIFY ☆☆\n\n");
printf("\t\t☆☆ 5. SHOW ☆☆\n\n");
printf("\t\t☆☆ 6. SORT ☆☆\n\n");
printf("\t\t☆☆ 0. EXIT ☆☆\n\n");
printf("\t\t----------------------------------------------------------\n");
printf("\t\t★★★★★★★★★★★★★★★★\n");
printf("\t\t请选择您要运行的选项按(0-6):");
scanf("%d", &n);
printf("\t\t★★★★★★★★★★★★★★★★\n");
Sleep(1000);
switch (n)
{
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:
Sleep(1000);
//销毁同学录
DestroyContact(&con);
printf("退出同学录\n");
break;
default:
printf("选择错误\n");
break;
}
} while (n);
return 0;
}
2.contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void InitContcat(struct Contact* ps)
{
ps->data = (struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));
if (ps->data == NULL)
{
return;
}
ps->size = 0;
ps->capacity = 3;
}
void CheckCapacity(struct Contact* ps)
{
if (ps->size == ps->capacity)
{
struct PeoInfo* ptr = realloc(ps->data, (ps->capacity + 2)*sizeof(struct PeoInfo));
if (ptr != NULL)
{
ps->data = ptr;
ps->capacity += 2;
printf("\t\t增容成功\n");
}
}
}
void AddContact(struct Contact* ps)
{
system("cls");
printf("\t\t----------------------------------\n");
CheckCapacity(ps);//检测当前通讯录的容量,若满了,则增加容量,若没满,则就直接增加信息
//增加数据
printf("\t\t请输入名字:>");
scanf("%s", ps->data[ps->size].name);
printf("\t\t请输入年龄:>");
scanf("%d", &(ps->data[ps->size].age));
printf("\t\t请输入性别:>");
scanf("%s", ps->data[ps->size].sex);
printf("\t\t请输入电话:>");
scanf("%s", ps->data[ps->size].tele);
printf("\t\t请输入住址:>");
scanf("%s", ps->data[ps->size].addr);
ps->size++;
printf("\t\t添加成功\n");
printf("\t\t----------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
void ShowContact(const struct Contact* ps)
{
system("cls");
printf("\t\t--------------------------------------------------------------\n");
if (ps->size == 0)
{
printf("\t\t通讯录为空\n");
}
else
{
int i = 0;
printf("\t\t%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字","年龄","性别","电话","住址");
for (i = 0; i < ps->size; i++)
{
printf("\t\t%-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].tele,
ps->data[i].addr);
}
}
printf("\t\t---------------------------------------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
int FindByName(struct Contact* ps, char name[MAX_NAME])
{
system("cls");
printf("\t\t----------------------------------\n");
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (strcmp(ps->data[i].name, name) == 0)
{
return i;
}
}
return -1;
printf("\t\t----------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
void DelContact(struct Contact* ps)
{
system("cls");
printf("\t\t----------------------------------\n");
char name[MAX_NAME];
printf("\t\t请输入删除人的名字:>");
scanf("%s", name);
int pos = FindByName(ps, name);
if (pos==-1)
{
printf("\t\t您要删除的人不存在!\n");
}
else
{
int j = 0;
for (j = pos; j < ps->size - 1; j++)
{
ps->data[j] = ps->data[j + 1];
}
ps->size--;
printf("\t\t删除成功\n");
}
printf("\t\t----------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
void SearchContact(struct Contact* ps)
{
system("cls");
printf("\t\t----------------------------------------------------------------------\n");
char name[MAX_NAME];
printf("\t\t请输入您要查找对象的名字:>");
scanf("%s", name);
int pos = FindByName(ps, name);
if (pos == -1)
{
printf("\t\t对不起,没有找到您要查找的人!\n");
}
else
{
printf("\t\t%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "住址");
printf("\t\t%-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].tele,
ps->data[pos].addr);
}
printf("\t\t-----------------------------------------------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
void ModifyContact(struct Contact* ps)
{
system("cls");
printf("\t\t---------------------------------------------------------------------------\n");
char name[MAX_NAME];
printf("\t\t请输入您要修改对象的名字:>");
scanf("%s", name);
int pos = FindByName(ps, name);
if (pos == -1)
{
printf("\t\t对不起,没有找到您要查找的人!\n");
}
else
{
printf("\t\t请输入名字:>");
scanf("%s", ps->data[pos].name);
printf("\t\t请输入年龄:>");
scanf("%d", &(ps->data[pos].age));
printf("\t\t请输入性别:>");
scanf("%s", ps->data[pos].sex);
printf("\t\t请输入电话:>");
scanf("%s", ps->data[pos].tele);
printf("\t\t请输入住址:>");
scanf("%s", ps->data[pos].addr);
printf("\t\t修改成功\n");
}
printf("\t\t----------------------------------------------------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
void SortContact(struct Contact* ps)
{
system("cls");
printf("\t\t-----------------------------------------------------------------------\n");
int i = 0;
for (i = 0; i < ps->size; i++)
{
int j = 0;
for (j = 0; j < ps->size-i-1; j++)
{
if (strcmp(ps->data[j].name ,ps->data[j+1].name)>0)
{
struct PeoInfo ret ;
ret = ps->data[j];
ps->data[j] = ps->data[j+1];
ps->data[j+1] = ret;
}
}
}
printf("\t\t%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "住址");
for (i = 0; i < ps->size; i++)
{
printf("\t\t%-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].tele,
ps->data[i].addr);
}
printf("\t\t-----------------------------------------------------------------------\n");
printf("\t\t3秒后自动退出至主页面\n");
Sleep(3000);
system("cls");
}
void DestroyContact(struct Contact* ps)
{
free(ps->data);
ps->data = NULL;
}
3.contact.h
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<windows.h>
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT,
};
struct PeoInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
};
//通讯录类型
struct Contact
{
struct PeoInfo *data;//存放一个信息
int size;//记录当前已经有的元素个数
int capacity;//当前通讯录最大容量
};
//声明函数
void InitContcat(struct Contact* ps);//初始化同学录
void AddContact(struct Contact* ps);//增加
void ShowContact(const struct Contact* ps);//展示
void DelContact(struct Contact* ps);//删除
void SearchContact(struct Contact* ps);//查找
void ModifyContact(struct Contact* ps);//修改
void SortContact(struct Contact* ps);//排序
void DestroyContact(struct Contact* ps);//销毁
注:此文章是一篇进阶版的通讯录管理系统,后续还会推出文件保存的终极版本。