首先如何实现一个通讯录呢?
a.根据日常生活我们知道一个通讯录包括:
1.可以保存多少个联系人的信息
2.增加联系人
3.删除指定联系人
4.查找指定联系人的信息
5.修改指定联系人的信息
6.显示所有联系人的信息
b.而每一个联系人,我们也需要填写相关信息:
1.名字 2.年龄 3.性别 4.电话 5.住址
根据以上需求,我们可以有目的的开始编写代码。
c.为了增加代码的可读性我们将代码分为三个部分:
1.test.c -测试代码
2.contact.h -函数声明
3.contact.c -函数实现
a.首先,我们先写主函数及通讯录菜单---test.c中内容
void menu()
{
printf("**********************************\n");
printf("***** 1. add 2. show *****\n");
printf("***** 3. del 4. search *****\n");
printf("***** 5. modify *****\n");
printf("***** 0. exit *****\n");
printf("**********************************\n");
}
enum Option
{
EXIT,
ADD,
SHOW,
DEL,
SEARCH,
MODIFY,
SORT//按照什么排序
};//这里用到了枚举常量,为了增加代码的可读性,在switch中体现,在菜单中方便选择读者想用的选项
int main()
{
Contact con;//定义一个通讯录变量
int input = 0;//接收选择数字
InitContact(&con);
do
{
menu();
printf("请输入你的选择->");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&con);
break;
case SHOW:
ShowContact(&con);
break;
case DEL:
DelContact(&con);
break;
case SEARCH:
SearchContact(&con);
break;
case MODIFY:
ModifyContact(&con);
break;
case EXIT:
SaveContact(&con);
DestroyContact(&con);
printf("退出通讯录");
break;
default:
printf("选择错误,请重新选择");
break;
}
} while (input);
return 0;
}
这里可以观察到因为我们使用了枚举常量,代码的观赏性提高。
b.接着我们可以在contact.h中声明我们所创立的函数
#pragma once
#include
#include
#include
#include
#define NAME_MAX 10
#define SEX_MAX 10
#define TELE_MAX 20
#define ADDR_MAX 40
#define MAX 100
#define SZ 3
#define INCREACE 2
typedef struct PeoInfo
{
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char tele_num[TELE_MAX];
char addr[ADDR_MAX];
}PeoInfo;
typedef struct Contact
{
PeoInfo* data;//用来指向任务信息的指针 媒介
int sz;//用来记录通讯录人数
int capacity;//用来记录通讯录容量
}Contact;
void InitContact(Contact* pc);//初始化通讯录
void AddContact(Contact* pc);//添加联系人
void ShowContact(Contact* pc);//显示所有联系人
void DelContact(Contact* pc);//删除所指定的联系人
void SearchContact(Contact* pc);//查找指定的联系人
void ModifyContact(Contact* pc);//修改指定联系人
void DestroyContact(Contact* pc);//销毁通讯录
void SaveContact(Contact* pc);//保存通讯录到文件
void LoadContact(Contact* pc);//从文件中导出通讯录
现在我们将开始分析以上代码:
typedef struct PeoInfo
{
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char tele_num[TELE_MAX];
char addr[ADDR_MAX];
}PeoInfo;
这里创建了一个结构体用于建立人物信息,并且设立了结构体变量PeoInfo,便于灵活处理任务信息。
typedef struct Contact
{
PeoInfo* data;//用来指向任务信息的指针 媒介
int sz;//用来记录通讯录人数
int capacity;//用来记录通讯录容量
}Contact;
这里便用结构体来建立通讯录信息,且设立了结构体变量Contact,便于通讯录中人数的记录,扩容等等。
void InitContact(Contact* pc);//初始化通讯录
void AddContact(Contact* pc);//添加联系人
void ShowContact(Contact* pc);//显示所有联系人
void DelContact(Contact* pc);//删除所指定的联系人
void SearchContact(Contact* pc);//查找指定的联系人
void ModifyContact(Contact* pc);//修改指定联系人
void DestroyContact(Contact* pc);//销毁通讯录
void SaveContact(Contact* pc);//保存通讯录到文件
void LoadContact(Contact* pc);//从文件中导出通讯录
以上代码就是我们所需要用到的主要函数的声明,我们在传入参数时传入的是通讯录变量的指针,方便更改与查找。
c.最后我们在contact.c中进行函数具体实现,(注意:每编写完一个函数,一定要运行一次程序,方便进行调试找到我们的错误)
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void CheckCapacity(Contact* pc);
void LoadContact(Contact* pc)
{
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL)
{
perror("LoadContact");
return;
}
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, pf))//只要不为0就能一直运行
{
CheckCapacity(pc);
pc->data[pc->sz] = tmp;
pc->sz++;
}
fclose(pf);
pf = NULL;
}
void InitContact(Contact* pc)
{
assert(pc);
pc->sz = 0;
pc->capacity = SZ;
pc->data = calloc(pc->capacity, sizeof(PeoInfo));
if (pc->data == NULL)
{
perror("InitContact->calloc");
return;
}
LoadContact(pc);
}
void CheckCapacity(Contact* pc)
{
if (pc->sz == pc->capacity)
{
PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INCREACE) * sizeof(PeoInfo));
if (ptr != NULL)
{
pc->data = ptr;
pc->capacity += INCREACE;
printf("增容成功!\n");
}
else
{
perror(" AddContact->realloc");
return;
}
}
}
void AddContact(Contact* pc)
{
assert(pc);
CheckCapacity(pc);//检查容量是否充足,不足则增加
printf("请输入姓名:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄:");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入手机号码:");
scanf("%s", pc->data[pc->sz].tele_num);
printf("请输入住址:");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("添加成功\n");
}
void ShowContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法打印");
return;
}
int i = 0;
printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
for (i = 0; i < pc->sz; i++)
{
printf("%-20s%-5d%-5s%-12s%-30s\n", pc->data[i].name,
pc->data[i].age, pc->data[i].sex, pc->data[i].tele_num,
pc->data[i].addr);
}
}
static int FindByName(Contact* pc,char name[] )
{
assert(pc);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(name, pc->data[i].name) == 0)
{
return i;
}
else
{
return -1;
}
}
}
void DelContact(Contact* pc)
{
char name[NAME_MAX];
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法删除\n");
return;
}
printf("请输入要删除的人的名字:");
scanf("%s", name);
int i = 0;
int inc = FindByName(pc,name);
if (inc != -1)
{
int i = inc;
for (i = inc; i < pc->sz-1; i++)
{
pc->data[i] = pc->data[i + 1];//最后一个pc->data[sz-2]==pc->data[sz-1]
}
pc->sz--;
printf("删除成功\n");
}
else
{
printf("所要删除的人不存在\n");
return;
}
}
void SearchContact(Contact* pc)
{
char name[NAME_MAX];
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法查找\n");
return;
}
printf("请输入查找的人的名字:");
scanf("%s", name);
int inc = FindByName(name, pc);
if (inc == -1)
{
printf("查找失败,没有这个人\n");
return;
}
printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
int i = inc;
printf("%-20s%-5d%-5s%-12s%-30s\n", pc->data[i].name,
pc->data[i].age, pc->data[i].sex, pc->data[i].tele_num,
pc->data[i].addr);
}
void ModifyContact(Contact* pc)
{
assert(pc);
char name[NAME_MAX];
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法查找\n");
return;
}
printf("请输入修改的人的名字:");
scanf("%s", name);
int inc = FindByName(pc,name);
if (inc == -1)
{
printf("查找失败,没有这个人\n");
return;
}
printf("请输入姓名:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄:");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入手机号码:");
scanf("%s", pc->data[pc->sz].tele_num);
printf("请输入住址:");
scanf("%s", pc->data[pc->sz].addr);
printf("修改成功!");
}
void DestroyContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->sz = 0;
pc->capacity = 0;
}
void SaveContact(Contact* pc)
{
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL)
{
perror("SaveContact");
return;
}
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
}
fclose(pf);
pf = NULL;
}
以上就是文件版本contact.c中所有的代码,接下来我们开始进行简略分析:
文件版本:void InitContact(Contact* pc)
void InitContact(Contact* pc)//初始化通讯录
{
assert(pc);//断言
pc->sz = 0;//相当于来记录人数
pc->capacity = SZ;//一个初始通讯录,人物最大容量,
//在添加联系人的时候与sz进行比较,用于判断是否需要扩容
pc->data = calloc(pc->capacity, sizeof(PeoInfo));//动态内存分配为存放数据开辟空间
if (pc->data == NULL)
{
perror("InitContact->calloc");//利用perror来进行报错
return;
}
LoadContact(pc);
}
assert用法:
#include
void assert (int expression)
作用是实现计算表达式expression ,若其值为0,打印错误信息,调用abort来终止程序。
在此的作用是检查传入参数pc的合法性
动态版本:(区别就是,在初始化时不将信息录入文件)
void InitContact(Contact* pc)
{
assert(pc);
pc->sz = 0;
pc->capacity = SZ;
pc->data = calloc(pc->capacity, sizeof(PeoInfo));
if (pc->data == NULL)
{
perror("InitContact->calloc");
return;
}
}
普通版本:(省略)
文件版本(同动态):void CheckCapacity(Contact* pc)
在添加,录入通讯录信息时,需要检查通讯录是否有足够空间,有人物信息。
void CheckCapacity(Contact* pc)
{
if (pc->sz == pc->capacity)
{
PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INCREACE) * sizeof(PeoInfo));
if (ptr != NULL)
{
pc->data = ptr;
pc->capacity += INCREACE;
printf("增容成功!\n");
}
else
{
perror(" AddContact->realloc");
return;
}
}
}
文件版本(同动态):void AddContact(Contact* pc)
void AddContact(Contact* pc)
{
assert(pc);
CheckCapacity(pc);//检查容量是否充足,不足则增加
printf("请输入姓名:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄:");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入手机号码:");
scanf("%s", pc->data[pc->sz].tele_num);
printf("请输入住址:");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("添加成功\n");
}
使用:void realloc(void* ptr,size_t size);
据实际情况,size是调整后的新大小,返回值为调整后内存起始地址。
文件版本(同动态):void ShowContact(Contact* pc)
void ShowContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法打印");
return;
}
int i = 0;
printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
for (i = 0; i < pc->sz; i++)
{
printf("%-20s%-5d%-5s%-12s%-30s\n", pc->data[i].name,
pc->data[i].age, pc->data[i].sex, pc->data[i].tele_num,
pc->data[i].addr);
}
}
文件版本(同动态):static int FindByName(Contact* pc,char name[] )
在查找,修改,删除人物信息的时候需要先判断该人物是否存在
static int FindByName(Contact* pc,char name[] )
{
assert(pc);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(name, pc->data[i].name) == 0)
{
return i;
}
else
{
return -1;
}
}
}
文件版本(同动态版本):void DelContact(Contact* pc)
void DelContact(Contact* pc)
{
char name[NAME_MAX];
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法删除\n");
return;
}
printf("请输入要删除的人的名字:");
scanf("%s", name);
int i = 0;
int inc = FindByName(pc,name);
if (inc != -1)
{
int i = inc;
for (i = inc; i < pc->sz-1; i++)
{
pc->data[i] = pc->data[i + 1];//最后一个pc->data[sz-2]==pc->data[sz-1]
}
pc->sz--;
printf("删除成功\n");
}
else
{
printf("所要删除的人不存在\n");
return;
}
}
文件版本(同动态):void SearchContact(Contact* pc)
void SearchContact(Contact* pc)
{
char name[NAME_MAX];
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法查找\n");
return;
}
printf("请输入查找的人的名字:");
scanf("%s", name);
int inc = FindByName(name, pc);
if (inc == -1)
{
printf("查找失败,没有这个人\n");
return;
}
printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
int i = inc;
printf("%-20s%-5d%-5s%-12s%-30s\n", pc->data[i].name,
pc->data[i].age, pc->data[i].sex, pc->data[i].tele_num,
pc->data[i].addr);
}
文件版本(同动态):void ModifyContact(Contact* pc)
void ModifyContact(Contact* pc)
{
assert(pc);
char name[NAME_MAX];
if (pc->sz == 0)
{
printf("通讯录为空,无法查找\n");
return;
}
printf("请输入修改的人的名字:");
scanf("%s", name);
int inc = FindByName(pc, name);
if (inc == -1)
{
printf("查找失败,没有这个人\n");
return;
}
printf("请输入姓名:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄:");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入手机号码:");
scanf("%s", pc->data[pc->sz].tele_num);
printf("请输入住址:");
scanf("%s", pc->data[pc->sz].addr);
printf("修改成功!");
}
文件版本(同动态):void DestroyContact(Contact* pc)
void DestroyContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->sz = 0;
pc->capacity = 0;
}
文件版本(动态版本无):void SaveContact(Contact* pc)
void SaveContact(Contact* pc)
{
FILE* pf = fopen("contact.txt", "wb");//“wb”为了输出数据,打开一个二进制文件
if (pf == NULL)
{
perror("SaveContact");
return;
}
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
//将人物数据pc->data + 1大小为1个sizeof(PeoInfo)写入pf中
}
fclose(pf);//记得关闭
pf = NULL;//防止pf成为野指针
}
文件版本(动态版本无):void LoadContact(Contact* pc)
void LoadContact(Contact* pc)
{
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL)
{
perror("LoadContact");
return;
}
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, pf))//只要不为0就能一直运行
{
CheckCapacity(pc);
pc->data[pc->sz] = tmp;
pc->sz++;
}
fclose(pf);
pf = NULL;
}
以上就是我们动态/文件版本通讯录的程序。
感谢观看,第一次写博客,若有不足请多多指教,我会努力改进的!