您的位置:首页 > 编程语言 > C语言/C++

通讯录管理系统(C语言实现) 动态扩容,文件读写

2020-01-14 10:29 169 查看

通讯录可以用来存储个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址。而一个通讯录的管理系统,应该至少具备增、删、查、改等几项功能,并要对其进行拓展。
所以我们要实现的功能如下:

  1. 添加联系人信息
  2. 删除指定联系人信息
  3. 查找指定联系人信息
  4. 修改指定联系人信息
  5. 显示所有联系人信息
  6. 清空所有联系人
  7. 对联系人进行排序
  8. 通讯录应该是可扩容而非定长的
  9. 通讯录的数据应该存储在文件当中,以便多次使用

明确了目标,下面开始实现。

首先我们要选择合适的数据结构,对于这种线性的通讯录,顺序表无疑是最好的选择,在设置结构体的同时,还需要考虑到内存对齐的因素,将占用空间较小的成员尽量集中到一起。
同时为了通讯录的长度合适,我们运用了动态内存管理,当通讯录不够时自动扩容

typedef struct info
{
char name[NAME_MAX_SIZE];
char tel[TEL_MAX_SIZE];
char addr[ADDR_MAX_SIZE];
char gender[GENDER_MAX_SIZE];
int age;
//先存放四个字符型再存放整形,利用内存对齐来达到空间利用最大化
}info;

typedef struct
{
info* data;
int capacity;
int size;
}contact, *pcontact;
//采用顺序表的数据类型来存放数据

首先我们要对通讯录进行初始化

void InitContact(pcontact p)
{
p->data = (info*)malloc(CONTACT_SIZE * sizeof(info));
if (NULL == p->data)
{
printf("初始化失败!!!\n");
exit(0);
}
p->capacity = CONTACT_SIZE;
p->size = 0;
}

通讯录扩容

int CheckCapacity(pcontact p)
{
assert(p);
if (p->size == p->capacity)
{
printf("通讯录已满,进行扩容\n");
;
info *temp = realloc(p->data, (p->capacity + CONTACT_SIZE) * sizeof(info));
if (NULL == temp)
{
printf("扩容失败\n");
return 0;
}
else
{
p->data = temp;
p->capacity += CONTACT_SIZE;
printf("扩容成功!!!\n");
}
}
return 1;
}

添加联系人信息

void AddContact(pcontact p)
{
assert(p); //防止传入空指针,后面会一直使用
system("cls");  //清空之前的屏幕,防止画面太过杂乱
if (0 == CheckCapacity(p))  //判断通讯录是否已满,如果通讯录满且扩容失败将返回
{
printf("通讯录已满,添加失败\n");
return;
}
printf("请输入姓名:\n");
scanf("%s", p->data[p->size].name);
printf("请输入电话:\n");
scanf("%s", p->data[p->size].tel);
printf("请输入性别:\n");
scanf("%s", p->data[p->size].gender);
printf("请输入地址:\n");
scanf("%s", p->data[p->size].addr);
printf("请输入年龄:\n");
scanf("%d", &(p->data[p->size].age));

printf("添加成功!!!\n");
p->size++;
}

添加联系人信息

void DelContact(pcontact p)
{
assert(p);
system("cls");
int pos, i;
char name[NAME_MAX_SIZE];
if (!p->size)
{
printf("通讯录为空\n");
return;
}

printf("请输入要删除的人的姓名:\n");
scanf("%s", name);
pos = GetPosition(name, p);

if (-1 == pos)
{
printf("此人不存在\n");
}
else
{
for (i = pos; pos < p->size - 1; i++)
{
p->data[i] = p->data[i + 1];
}
p->size--;
printf("删除成功!!!\n");
}
}

按照名字获取通讯录的位置
这一个是为了给后面的查找和删除模块获取位置

int GetPosition(char* name, pcontact p)
{
assert(p);
int pos;
for (pos = 0; pos < p->size; pos++)
{
if (0 == strcmp(name, p->data[pos].name))
{
return pos;
}
}
return -1;
}

查找联系人信息

void SearchContact(pcontact p)
{
assert(p);
system("cls");
char name[NAME_MAX_SIZE];
int pos;
printf("请输入要查找的人的姓名:\n");
scanf("%s", name);
pos = GetPosition(name, p);
if (-1 == pos)
{
printf("此人不存在:\n");
}
else
{
printf("*******************************************\n");
printf("姓名:%s \n", p->data[pos].name);
printf("性别:%s \n", p->data[pos].gender);
printf("年龄:%d \n", p->data[pos].age);
printf("地址:%s \n", p->data[pos].addr);
printf("电话:%s \n", p->data[pos].tel);
printf("*******************************************\n");
printf("查找成功!!!\n");
}
}

修改联系人信息

void ModifyContact(pcontact p)
{
assert(p);
system("cls");
char name[NAME_MAX_SIZE];
int pos;
printf("请输入要修改的人的姓名:\n");
scanf("%s", name);
pos = GetPosition(name, p);

if (-1 == pos)
{
printf("此人不存在\n");
}
else
{
printf("请输入修改后的姓名:\n");
scanf("%s", p->data[pos].name);
printf("请输入修改后的电话:\n");
scanf("%s", p->data[pos].tel);
printf("请输入修改后的性别:\n");
scanf("%s", p->data[pos].gender);
printf("请输入修改后的年龄:\n");
scanf("%d", &(p->data[pos].age));
printf("请输入修改后的地址:\n");
scanf("%s", p->data[pos].addr);
printf("修改成功!!!\n");
}
}

显示所有联系人信息

void ShowContact(pcontact p)
{
assert(p);
system("cls");
int i;
if (!p->size)
{
printf("通讯录为空\n");
return;
}

for (i = 0; i < p->size; i++)
{
printf("*******************************************\n");
printf("**********    第 %d 位联系人     **********\n", i + 1);
printf("姓名:%s \n", p->data[i].name);
printf("性别:%s \n", p->data[i].gender);
printf("年龄:%d \n", p->data[i].age);
printf("地址:%s \n", p->data[i].addr);
printf("电话:%s \n", p->data[i].tel);
printf("*******************************************\n");

}
}

清空通讯录

void EmptyContact(pcontact p)
{
assert(p);
system("cls");
if (!p->size)
{
printf("通讯录为空\n");
return;
}
else
{
free(p->data);
p->data = NULL;
p->size = 0;
p->capacity = 0;
printf("通讯录清空成功!!!\n");
}
}

为了通讯录方便我们查看,我们还需要排序,因为数据量过少以及排序不是这里的主体,所以采用最简单的冒泡排序

void SortContact(pcontact p)
{
assert(p);
system("cls");
int i, j, flag = 1;
info temp = { 0 };
for (i = p->size; i > 0 && flag; i--)
{
flag = 0;
for (j = 1; j < p->size; j++)
{
if (strcmp(p->data[j].name, p->data[j - 1].name) < 0)
{
temp = p->data[j];
p->data[j] = p->data[j - 1];
p->data[j - 1] = temp;
flag = 1;
}
}
}
printf("排序成功!!!\n");
}

同时,一个通讯录不可能每次使用都要重新输入数据,并且数据在关闭的时候会清空,所以我们要将数据的内容进行保存,而保存的方式我选择用二进制的形式保存,因为二进制的存储方式比ascii的存储方式操作更加简单和安全。唯一的缺点就是不方便查看。
保存数据

void SaveContact(pcontact p)
{
assert(p);
system("cls");
FILE* pf = fopen("contact.dat", "wb");
int i;
if (NULL == pf)
{
printf("文件打开失败\n");
return;
}
for (i = 0; i < p->size; i++)
{
fwrite(&(p->data[i]), sizeof(info), 1, pf);
}
printf("通讯录保存成功\n");
fclose(pf);
pf = NULL;
}

读取数据

void LoadContact(pcontact p)
{
assert(p);
system("cls");
FILE* pf = fopen("contact.dat", "rb");
if (NULL == pf)
{
printf("文件打开失败\n");
return;
}
while (fread(&(p->data[p->size]), sizeof(info), 1, pf))
{
if (CheckCapacity(p))
{
p->size++;
}
}
printf("通讯录读取成功\n");
fclose(pf);
pf = NULL;
}

同时,在结束时还要进行内存的释放,防止内存溢出

void EndContact(pcontact p)
{
free(p->data);
p->data = NULL;
p->size = 0;
p->capacity = 0;
exit(0);
}

在主函数方面,为了简化代码和去掉重复代码,我选择用函数指针数组来实现菜单

void Test()
{
int input;
contact book;
void (*p[10])(pcontact p) =
{
EndContact,
AddContact,
DelContact,
ModifyContact,
SearchContact,
SortContact,
ShowContact,
EmptyContact,
SaveContact,
LoadContact,
};
//利用函数指针数组简化不必要的代码

InitContact(&book);
//初始化

do
{
Menu();
printf("请输入要进行的操作:");
scanf("%d", &input);
if ((input <= 9 && input >= 0))
{
(*p[input])(&book);
}
else
{
printf("输入错误:\n");
}
} while (input);
}

就这样,一个简单的通讯录管理系统就完成了




简单演示一下,剩下的部分就不再演示了

完整代码如下:
头文件部分Contact book.h

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<Windows.h>
#define NAME_MAX_SIZE 20
#define TEL_MAX_SIZE 20
#define ADDR_MAX_SIZE 30
#define GENDER_MAX_SIZE 10
#define CONTACT_SIZE 10

typedef struct info
{
char name[NAME_MAX_SIZE];
char tel[TEL_MAX_SIZE];
char addr[ADDR_MAX_SIZE];
char gender[GENDER_MAX_SIZE];
int age;
//先存放四个字符型再存放整形,利用内存对齐来达到空间利用最大化
}info;

typedef struct
{
info* data;
int capacity;
int size;
}contact, *pcontact;
//采用顺序表的数据类型来存放数据
void InitContact(pcontact p);
void AddContact(pcontact p);
void DelContact(pcontact p);
void SearchContact(pcontact p);
void SortContact(pcontact p);
void ShowContact(pcontact p);
void ModifyContact(pcontact p);
void EmptyContact(pcontact p);
int CheckCapacity(pcontact p);
int GetPosition(char* name, pcontact p);
void SaveContact(pcontact p);
void LoadContact(pcontact p);
void EndContact(pcontact p);

函数实现部分Contact book.c:

#include "Contact Book.h"

void InitContact(pcontact p)
{
p->data = (info*)malloc(CONTACT_SIZE * sizeof(info));
if (NULL == p->data)
{
printf("初始化失败!!!\n");
exit(0);
}
p->capacity = CONTACT_SIZE;
p->size = 0;
}
void AddContact(pcontact p)
{
assert(p);
system("cls");
if (0 == CheckCapacity(p))
{
printf("通讯录已满,添加失败\n");
return;
}
printf("请输入姓名:\n");
scanf("%s", p->data[p->size].name);
printf("请输入电话:\n");
scanf("%s", p->data[p->size].tel);
printf("请输入性别:\n");
scanf("%s", p->data[p->size].gender);
printf("请输入地址:\n");
scanf("%s", p->data[p->size].addr);
printf("请输入年龄:\n");
scanf("%d", &(p->data[p->size].age));

printf("添加成功!!!\n");
p->size++;
}

void DelContact(pcontact p)
{
assert(p);
system("cls");
int pos, i;
char name[NAME_MAX_SIZE];
if (!p->size)
{
printf("通讯录为空\n");
return;
}

printf("请输入要删除的人的姓名:\n");
scanf("%s", name);
pos = GetPosition(name, p);

if (-1 == pos)
{
printf("此人不存在\n");
}
else
{
for (i = pos; pos < p->size - 1; i++)
{
p->data[i] = p->data[i + 1];
}
p->size--;
printf("删除成功!!!\n");
}
}
void ShowContact(pcontact p)
{
assert(p);
system("cls");
int i;
if (!p->size)
{
printf("通讯录为空\n");
return;
}

for (i = 0; i < p->size; i++)
{
printf("*******************************************\n");
printf("**********    第 %d 位联系人     **********\n", i + 1);
printf("姓名:%s \n", p->data[i].name);
printf("性别:%s \n", p->data[i].gender);
printf("年龄:%d \n", p->data[i].age);
printf("地址:%s \n", p->data[i].addr);
printf("电话:%s \n", p->data[i].tel);
printf("*******************************************\n");

}
}void ModifyContact(pcontact p)
{
assert(p);
system("cls");
char name[NAME_MAX_SIZE];
int pos;
printf("请输入要修改的人的姓名:\n");
scanf("%s", name);
pos = GetPosition(name, p);

if (-1 == pos)
{
printf("此人不存在\n");
}
else
{
printf("请输入修改后的姓名:\n");
scanf("%s", p->data[pos].name);
printf("请输入修改后的电话:\n");
scanf("%s", p->data[pos].tel);
printf("请输入修改后的性别:\n");
scanf("%s", p->data[pos].gender);
printf("请输入修改后的年龄:\n");
scanf("%d", &(p->data[pos].age));
printf("请输入修改后的地址:\n");
scanf("%s", p->data[pos].addr);
printf("修改成功!!!\n");
}
}
void SearchContact(pcontact p)
{
assert(p);
system("cls");
char name[NAME_MAX_SIZE];
int pos;
printf("请输入要查找的人的姓名:\n");
scanf("%s", name);
pos = GetPosition(name, p);
if (-1 == pos)
{
printf("此人不存在:\n");
}
else
{
printf("*******************************************\n");
printf("姓名:%s \n", p->data[pos].name);
printf("性别:%s \n", p->data[pos].gender);
printf("年龄:%d \n", p->data[pos].age);
printf("地址:%s \n", p->data[pos].addr);
printf("电话:%s \n", p->data[pos].tel);
printf("*******************************************\n");
printf("查找成功!!!\n");
}
}
int GetPosition(char* name, pcontact p)
{
assert(p);
int pos;
for (pos = 0; pos < p->size; pos++)
{
if (0 == strcmp(name, p->data[pos].name))
{
return pos;
}
}
return -1;
}
void EmptyContact(pcontact p)
{
assert(p);
system("cls");
if (!p->size)
{
printf("通讯录为空\n");
return;
}
else
{
free(p->data);
p->data = NULL;
p->size = 0;
p->capacity = 0;
printf("通讯录清空成功!!!\n");
}
}
int CheckCapacity(pcontact p)
{
assert(p);
if (p->size == p->capacity)
{
printf("通讯录已满,进行扩容\n");
;
info *temp = realloc(p->data, (p->capacity + CONTACT_SIZE) * sizeof(info));
if (NULL == temp)
{
printf("扩容失败\n");
return 0;
}
else
{
p->data = temp;
p->capacity += CONTACT_SIZE;
printf("扩容成功!!!\n");
}
}
return 1;
}
void SortContact(pcontact p)
{
assert(p);
system("cls");
int i, j, flag = 1;
info temp = { 0 };
for (i = p->size; i > 0 && flag; i--)
{
flag = 0;
for (j = 1; j < p->size; j++)
{
if (strcmp(p->data[j].name, p->data[j - 1].name) < 0)
{
temp = p->data[j];
p->data[j] = p->data[j - 1];
p->data[j - 1] = temp;
flag = 1;
}
}
}
printf("排序成功!!!\n");
}
void SaveContact(pcontact p)
{
assert(p);
system("cls");
FILE* pf = fopen("contact.dat", "wb");
int i;
if (NULL == pf)
{
printf("文件打开失败\n");
return;
}
for (i = 0; i < p->size; i++)
{
fwrite(&(p->data[i]), sizeof(info), 1, pf);
}
printf("通讯录保存成功\n");
fclose(pf);
pf = NULL;
}
void LoadContact(pcontact p)
{
assert(p);
system("cls");
FILE* pf = fopen("contact.dat", "rb");
if (NULL == pf)
{
printf("文件打开失败\n");
return;
}
while (fread(&(p->data[p->size]), sizeof(info), 1, pf))
{
if (CheckCapacity(p))
{
p->size++;
}
}
printf("通讯录读取成功\n");
fclose(pf);
pf = NULL;
}
void EndContact(pcontact p)
{
free(p->data);
p->data = NULL;
p->size = 0;
p->capacity = 0;
exit(0);
}

测试部分:
test.c

#include "Contact Book.h"

void Menu()
{
printf("************************************************\n");
printf("**    0.退出程序          1.添加联系人        **\n");
printf("**    2.删除联系人        3.修改联系人        **\n");
printf("**    4.查找联系人        5.通讯录排序        **\n");
printf("**    6.显示所有联系人    7.删除所有联系人    **\n");
printf("**    8.保存通讯录        9.读取通讯录        **\n");
printf("************************************************\n");
}

void Test()
{
int input;
contact book;
void (*p[10])(pcontact p) =
{
EndContact,
AddContact,
DelContact,
ModifyContact,
SearchContact,
SortContact,
ShowContact,
EmptyContact,
SaveContact,
LoadContact,
};
//利用函数指针数组简化不必要的代码

InitContact(&book);
//初始化

do
{
Menu();
printf("请输入要进行的操作:");
scanf("%d", &input);
if ((input <= 9 && input >= 0))
{
(*p[input])(&book);
}
else
{
printf("输入错误:\n");
}
} while (input);
}
int main()
{
Test();
return 0;
}

github链接:https://github.com/HONGYU-LEE/test/tree/master/project/Contact%20Book

  • 点赞 1
  • 收藏
  • 分享
  • 文章举报
凌桓丶 发布了29 篇原创文章 · 获赞 20 · 访问量 2022 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: