待到秋来九月八,我花开后百花杀
项目简介
近代通信少不了电话号码,但是朋友或是要联络的人太多,就需要把电话号码记下来,然而书本纸面上的记载,查询都太过麻烦,因此我们可以利用计算机编程实现一个多功能全面的通讯录,帮助我们更加方便的处理这些电话号码。
目标功能涵盖:
- 添加联系人信息
- 删除指定联系人信息
- 查找指定联系人信息
- 显示所有联系人信息
- 清空所有联系人
- 以名字排序所有联系人
- 保存联系人到文件 (文件版)
- 从文件加载联系人(文件版)
共需完成三种版本:
- 结构体版本(基础版本)
- 动态内存版本
- 文件操作版本
项目思路
流程图
主要功能放在一个对应的函数里进行封装
项目用到的知识点
- 结构体的使用
- 动态内存malloc realloc calloc free 的使用
- 文件的操作
项目功能的实现
函数声明及抽象目标
1.抽象个人信息
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<string.h>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
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.add 2.show 3.delete 4.search ****\n");
printf("*** 5.empty 6.distory 7.save 8.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