静态通讯录的实现过程
前言
前面的一篇博客介绍了结构体如何使用(包括:定义、赋值、初始化等操作)、结构体在内存中所占用空间大小以及定义结构体时的小技巧、位段等内容。
本篇来练习使用结构体变量来实现静态通讯录的过程。
一、要实现的功能
编写一个通讯录程序,能够存储100个人信息(包括:名字、年龄、性别、电话、地址),并且这个通讯录能够进行增、删、查、改、显示、排序的功能。
本次练习使用的是多文件编程的方式(就是把多个头文件和源文件组合在一起使用构成一个程序),这是C语言学习过程中的重难点。
其中C语言头文件包含各个函数的声明,学会了多文件的编程方式,又在学习的道路上迈进了一步。
二、通讯录的实现过程
1.分文件的规划
- 创建一个头文件 contact.h ,头文件中包含结构体类型的声明定义和各个功能实现函数声明;
- 创建一个.c文件 contact.c ,其中包含各个函数的定义和实现;
- 创建一个.c文件 main.c ,主要功能是整个程序的实现逻辑和程序对各个函数的调用;
2.实现过程
- 在 mian.c 主函数中先搭建程序框架,对程序框架进行打桩
#include "contact.h"//为确保各个函数正常使用,先包含头文件 “contact.h”
void menu()
{ //选择菜单
printf("********************************\n");
printf("*****1、add 2、del *****\n");
printf("*****3、search 4、modify*****\n");
printf("*****5、show 6、sort *****\n");
printf("*****0、exit 7、save *****\n");
printf("********************************\n");
}
enum Option //使用枚举类型代替数字,使得后面的switch语句可读性更高,
{ EXIT ,ADD ,DEL ,SEARCH ,MODIFY ,SHOW ,SORT ,SAVE };
int main()
{
Contact con;
InitContact(&con);//对通讯录进行初始化
int input;
do
{
menu();
printf("input your choice:");
scanf("%d",&input);
switch (input)
{
case ADD:
AddContact(&con);
break;
case DEL:
DelConct(&con);
break;
case SEARCH:
SearchContact(&con);
break;
case MODIFY:
ModContact(&con);
break;
case SHOW:
ShowContact(&con);
break;
case SORT:
SortContact(&con);
break;
case SAVE:
break;
case EXIT:
DestroyContact(&con);
printf("退出通讯录!\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
- 在 contact.h 头文件中包含结构体类型的定义和各个函数的声明,在其他.c文件中只需引用该头文件即可;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
#define MAX 1000
//每个人的信息
typedef struct PeoIfo //定义结构体类型struct PeoIfo,
{ //使用typedef函数将struct PeoIfo重命名为 PeoIfo,后面使用PeoIfo代表struct PeoIfo
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char tele[TELE_MAX];
char addr[ADDR_MAX];
}PeoIfo;
typedef struct Contact //定义通讯录结构体类型 struct Contact
{
PeoIfo date[100];
int sz;//表示通讯录中当前存放的人的信息个数
}Contact;
//增加一个人的信息
void AddContact(Contact * pc);
//显示信息
void ShowContact(Contact * pc);
//删除信息
void DelConct(Contact * pc);
//查找信息
void SearchContact(const Contact * pc);
//修改信息
void ModContact(Contact * pc);
//排序信息
void SortContact(Contact *pc);
- 在 main.c 中定义了一个 名为con 的变量,表示通讯录存储的信息
Contact con;
InitContact(&con);//对通讯录进行初始化
在程序开始先将con初始化,将所有数据初始化为0;
void InitContact(Contact * pc)
{
pc->sz = 0;
memset(pc->data,0,sizeof(pc->data));
printf("通讯录初始化完成!\n");
}
- 将con初始化完成之后,在contact.c 中编写AddContact( )函数,实现通讯录人数的增加
#include "contact.h"//在文件开头先引用contact.h头文件,确保各个函数可正常使用
void AddContact(struct Contact* pc) //增加通讯录信息
{
if (pc->sz == MAX) //判断通讯录的存贮人数是否达到最大值
{ //人数达到最大值时,无法添加
printf("通讯录已满,无法添加!\n");
}
else
{
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].tel);
printf("请输入住址:>");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("添加成功!\n");
}
}
- 为了方便后面的调试,先编写 ShowContact( ),来显示通讯录存储的信息
/*************************contact.c*************************/
//显示信息
void ShowContact(Contact* pc)
{
if (0 == pc->sz)
{
printf("通讯录为空!\n无法打印!\n");
return;
}
printf("name age sex tele address\n");
int i = 0;
for (i = 0; i < pc->sz; i++)
{
printf("%s %d %s %s %s\n",
pc->date[i].name,
pc->date[i].age,
pc->date[i].sex,
pc->date[i].tele,
pc->date[i].addr);
}
printf("show finish!\n");
}
- 编写 DelConct( ),来删除通讯录存储的信息
/*************************contact.c*************************/
static int FindByName(Contact* pc, char* name)
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (!strcmp(pc->date[i].name, name))
return i;//找到时返回下标的位置
}
return -1;//没找到时返回-1
}
在删除通讯录时,首先要对通讯录人员的名字进行查找.
当返回值为 -1 时,则说明通讯录中查不到此人
当返回值不为 -1 时,则说明通讯录中存在此人,返回的数值是联系人在通讯录中的位置
由于在后面的查找和修改功能功能中也需要用到该函数,为了避免代码的冗余,将此函数独立出来,方便代码的使用,代码更加简洁;
/*************************contact.c*************************/
//删除信息
void DelConct(Contact* pc)
{
if (0 == pc->sz)
{
printf("通讯录为空!\n无删除信息!\n");
return;
}
char name[NAME_MAX];
printf("input your delete name:");
scanf("%s",name);
int pos =FindByName(pc, name);
if (-1 == pos)
{
printf("你要删除的人不存在!\n");
}
else
{
int i = 0;
for (i = pos; i < pc->sz - 1; i++)
pc->date[pos] = pc->date[pos + 1];
pc->sz--;
printf("delete success!\n");
}
}
- 编写 SearchContact( ),查找通讯录人员信息
/*************************contact.c*************************/
//查找信息
void SearchContact(const Contact* pc)
{
char name[NAME_MAX];
printf("input your srarch name:");
scanf("%s",name);
int pos = FindByName(pc,name);
if (-1 == pos)
{
printf("no person!");
return;
}
else
{
printf("%s %d %s %s %s\n",
pc->date[pos].name,
pc->date[pos].age,
pc->date[pos].sex,
pc->date[pos].tele,
pc->date[pos].addr);
printf("search message finish!\n");
}
}
- 编写 ModContact( ),修改通讯录人员信息
/*************************contact.c*************************/
//修改信息
void ModContact(Contact* pc)
{
char name[NAME_MAX];
printf("input your modify name:");
scanf("%s",name);
int pos = FindByName(pc,name);
if (-1 == pos)
{
printf("not find!\n ");
return;
}
else
{
printf("input name:");
scanf("%s", pc->date[pos].name);
printf("input age:");
scanf("%d", &pc->date[pos].age);
printf("input sex:");
scanf("%s", pc->date[pos].sex);
printf("input tele:");
scanf("%s", pc->date[pos].tele);
printf("input address:");
scanf("%s", pc->date[pos].addr);
printf("modify sucess!\n");
}
}
- 编写 SortContact( ),排序通讯录人员信息
为了方便理解,使用冒泡排序的方法对通讯录进行排序,也可使用qsort函数来排序
/*************************contact.c*************************/
//排序信息
void SortContact(Contact* pc)
{
if (0 == pc->sz)
{
printf("通讯录为空!\n无法排序!\n");
return;
}
else
{
PeoIfo tmp;
int i = 0;
for ( i = 0; i < pc->sz; i++)
{
int j = 0;
for (j = 0; j < pc->sz-i-1; j++)
{
if (strcmp(pc->date[j].name, pc->date[j + 1].name) > 0)
{
tmp = pc->date[j];
pc->date[j] = pc->date[j + 1];
pc->date[j + 1] = tmp;
}
}
}
printf("end of the sort!\nsucess\n");
}
}
运行结果如下:
总结
以上就是静态结构体实现通讯录增、删、查、改等功能的方法,这种方法开辟的空间大小是固定的,无法调整,人数少时,浪费空间,人数多时,又无法再次开辟空间,所以后面会有动态开辟空间的版本。如果有表述不清或错误的地方,请大家多多指教^ _ ^!