待到秋来九月八,我花开后百花杀
- 项目简介
- 项目思路
-
- 流程图
- 项目用到的知识点
- 项目功能的实现
-
- 函数声明及抽象目标
- 主函数的架构与搭建
- 初始化通讯录
- 加载联系人
- 添加成员
- 打印通讯录
- 删除成员
- 查找成员
- 清空通讯录
- 摧毁通讯录(动态版本)
- 保存联系人到文件(文件版本)
- 所遇问题
-
- 解决办法
- 项目源码
项目简介 近代通信少不了电话号码,但是朋友或是要联络的人太多,就需要把电话号码记下来,然而书本纸面上的记载,查询都太过麻烦,因此我们可以利用计算机编程实现一个多功能全面的通讯录,帮助我们更加方便的处理这些电话号码。
目标功能涵盖:
- 添加联系人信息
- 删除指定联系人信息
- 查找指定联系人信息
- 显示所有联系人信息
- 清空所有联系人
- 以名字排序所有联系人
- 保存联系人到文件 (文件版)
- 从文件加载联系人(文件版)
- 结构体版本(基础版本)
- 动态内存版本
- 文件操作版本
文章图片
文章图片
项目用到的知识点
- 结构体的使用
- 动态内存malloc realloc calloc free 的使用
- 文件的操作
typedef struct PersonInfo
{
char name[MAX_NAME];
char sex[SEX_NAME];
short age;
char tele[TEL_NAME];
char addr[TEL_NAME];
}PersonInfo;
2.抽象通讯录
typedef struct Contact {
//PersonInfo per[MAX_PER_NUM] ;
静态版本
int usedsize;
//有效数据个数 动态版本
PersonInfo* per;
//动态版本
int capacity;
//初始容量
}Contact;
//通讯录
需要实现函数:
#ifndef __CONTACT_H__
#define __CONTACT_H__
#include
#include
#include
#include
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MONDIFY,
SHOW,
EMPTY,
SORT
};
#define MAX_NAME 20
#define SEX_NAME 5
#define TEL_NAME 12
#define ADDR_NAME 20 //通讯录最多为1000人
#define MAX_PER_NUM 1000 //动态扩容版本
#define DEFAULT_SIZE 2;
typedef struct PersonInfo
{
char name[MAX_NAME];
char sex[SEX_NAME];
short age;
char tele[TEL_NAME];
char addr[TEL_NAME];
}PersonInfo;
typedef struct Contact
{
//PersonInfo per[MAX_PER_NUM] ;
普通版本
PersonInfo* per;
int usedsize;
//有效数据个数
int capacity;
//初始容量
}Contact;
//通讯录
//初始化通讯录
void InitContact(Contact *con);
//添加成员
void AddContact(Contact *con);
//打印通讯录
void ShowContact(Contact *con);
//删除成员
void DelContact(Contact *con);
//查找成员
int SearchContact(Contact *con);
//清空通讯录
void EmptyContact(Contact *con);
//摧毁通讯录(动态版本)
void DestoryContact(Contact *con);
//文件版本 //保存联系人到文件
void SaveContact(Contact *con);
//加载联系人
void LoadContact(Contact *con);
#endif //__CONTACT_H__
主函数的架构与搭建
#include"contact.h"void menu() {
printf("******************通讯录********************\n");
printf("*** 1.add2.show3.delete 4.search ****\n");
printf("*** 5.empty 6.distory 7.save8.load****\n");
printf("***************** 0.quit *******************\n");
printf("********************************************\n");
}int main()
{
int select = 0;
Contact contact;
InitContact(&contact);
do{
menu();
printf("Pleas intput you changce:");
scanf("%d", &select);
switch (select)
{
case QUIT:
printf("Good bye!\n");
break;
case ADD:
AddContact(&contact);
break;
case SHOW:
ShowContact(&contact);
break;
case DEL:
DelContact(&contact);
break;
case SEARCH:
SearchContact(&contact);
break;
case EMPTY:
EmptyContact(&contact);
break;
case DESTORY:
DestoryContact(&contact);
break;
case SAVE:
SaveContact(&contact);
break;
case LOAD:
LoadContact(&contact);
break;
default:
break;
}
} while (select);
system("pause");
return 0;
}
初始化通讯录
void InitContact(Contact *pcon) {
//普通版本
//pcon->usedSize = 0;
//memset(pcon->per,0,sizeof(pcon->per));
pcon->usedsize = 0;
pcon->capacity = DEFAULT_SIZE;
pcon->per = (PersonInfo *)malloc(
sizeof(PersonInfo) * pcon->capacity);
assert(pcon->per != NULL);
LoadContact(pcon);
//有可能文件中也有存储的联系人
}
加载联系人
void LoadContact(Contact *pcon) {
FILE *pf = fopen("Contact.bat", "rb");
PersonInfo tmp = { 0 };
if (pf == NULL)
{
return;
}
//fread函数的返回值是:读取成功的字节数
while (fread(&tmp, sizeof(PersonInfo), 1, pf) > 0)
{
//必须判断是否为满,如果满了扩容
CheckFullAndRe(pcon);
pcon->per[pcon->usedsize++] = tmp;
}
fclose(pf);
pf = NULL;
}
添加成员
void AddContact(Contact *pcon) {
//普通版本,无扩容解决办法
//if(pcon->usedSize == MAX_NUMBER)
//{
// printf("this contact is full\n");
// return;
//} if (CheckFullAndRe(pcon) != 1)
{
printf("扩容失败\n");
return;
} printf("请输入姓名:");
scanf("%s", pcon->per[pcon->usedsize].name);
printf("请输入年龄:");
scanf("%d", &(pcon->per[pcon->usedsize].age));
printf("请输入性别:");
scanf("%s", pcon->per[pcon->usedsize].sex);
printf("请输入电话:");
scanf("%s", pcon->per[pcon->usedsize].tele);
printf("请输入住址:");
scanf("%s", pcon->per[pcon->usedsize].addr);
pcon->usedsize++;
printf("添加成功\n");
}
打印通讯录
void ShowContact(Contact *pcon) {
int i = 0;
printf("%-10s %-5s %-5s %-11s %-20s\n", "姓名", "年龄",
"性别", "电话", "住址");
for (i = 0;
i < pcon->usedsize;
i++)
{
printf("%-10s %-5d %-5s %-11s %-20s\n",
pcon->per[i].name, pcon->per[i].age,
pcon->per[i].sex, pcon->per[i].tele,
pcon->per[i].addr);
}
}
删除成员
void DelContact(Contact *pcon) {
int index = SearchContact(pcon);
int i = 0;
if (index == -1)
{
printf("删除失败,查无此人\n");
return;
}
for (i = index;
i < pcon->usedsize - 1;
i++)
{
pcon->per[i] = pcon->per[i + 1];
}
pcon->usedsize--;
printf("删除成功\n");
}
查找成员
int SearchContact(Contact *pcon) {
int i = 0;
char name[MAX_NAME] = { 0 };
if (pcon->usedsize == 0)
{
printf("通讯录为空\n");
return -1;
}
printf("请输入你要删除的姓名:");
scanf("%s", name);
for (i = 0;
i < pcon->usedsize;
i++)
{
if (strcmp(pcon->per[i].name, name) == 0)
{
return i;
}
}
return -1;
}
清空通讯录
void EmptyContact(Contact *pcon) {
pcon->usedsize = 0;
}
摧毁通讯录(动态版本)
void DestoryContact(Contact *pcon) {
SaveContact(pcon);
free(pcon->per);
pcon->per = NULL;
//预防野指针
pcon->capacity = 0;
pcon->usedsize = 0;
}
保存联系人到文件(文件版本)
void SaveContact(Contact *pcon) {
int i = 0;
FILE *pf = fopen("Contact.bat", "wb");
assert(pf != NULL);
for (i = 0;
i < pcon->usedsize;
i++)
{
fwrite(pcon->per + i, sizeof(PersonInfo), 1, pf);
}
fclose(pf);
pf = NULL;
}
所遇问题 通讯录无论是静态版本还是动态版本,储存人数都有上限。
动态内存虽然可以需要多少开辟多少内存,但仍需要在编程中定义。
解决办法 设计一个拓展函数,如果存储不足时,再开辟更多内存。
扩容通讯录
static int CheckFullAndRe(Contact *pcon) {
if (pcon->usedsize == pcon->capacity)
{
PersonInfo * ptr = NULL;
ptr = (PersonInfo *)realloc(pcon->per,
sizeof(PersonInfo) * pcon->capacity * 2);
if (ptr != NULL)
{
pcon->per = ptr;
pcon->capacity *= 2;
printf("扩容成功\n");
return 1;
}
else
{
return 0;
//扩容失败
}
} return 1;
}
项目源码 我的通讯录项目源码:https://github.com/GagaAutom/C-programming-language/blob/master/my_contact/contact
推荐阅读
- 数据结构|LeetCode(206. 反转链表)
- 小项目集合|基于C语言扫雷游戏的设计与实现
- 错题锦集|C语言错题锦集(持续更新)
- 云原生|什么是云原生(——软件开发的现代方法)
- 小项目集合|C语言小项目——通讯录(适合刚学完C语言的初学者)
- C语言|动态内存管理(C语言)
- 结构体内存对齐
- C语言|strlen()函数--使用及模拟实现
- C语言|字符函数、字符串函数、内存函数