前言:
hello啊,两天未更是因为课实在太多。今晚腾出来时间写一篇如何使用结构体来实现静态通讯录的博客。让我们一边看,一边解析。Not much to say, show code.
C语言具体实现:
头文件:Contact.h
#define _CRT_SECURE_NO_WARNING 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#pragma warning(disable:6031)
#define MAX 100//表示通讯录存储联系人的最大上限
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
//表示一个联系人的信息
typedef struct PeoInfo
{
char name[MAX_NAME];
char sex[MAX_SEX];
int age;
char tele[MAX_TELE];
char addr[MAX_ADDR];
}PeoInfo;
typedef struct Contact
{
PeoInfo data[MAX];//联系人信息构成的结构体数组
int sz;//已记录的有效联系人个数
}Contact,*pContact;//将struct Contact类型重命名为Contact,将struct Contact*重命名为pContact
//初始化通讯录
void InitContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//删除指定联系人
void DelContact(Contact* pc);
//查找指定联系人
void SearchContact(const Contact* pc);
//修改联系人信息
void ModifyContact(Contact* pc);
//显示联系人信息
void ShowContact(const Contact* pc);
//排序联系人信息
void SortContact(Contact* pc);
源文件:Contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
//初始化通讯录
void InitContact(Contact* pc)
{
pc->sz = 0;
memset(pc->data, 0, sizeof(pc->data));//使用memset对结构体数组初始化为0
}
static int FindByName(const Contact* pc, char name[])
{
int i = 0;
for (int i = 0; i < pc->sz; i++)
{
if (0 == strcmp(pc->data[i].name, name))
{
return i;
}
}
return -1;
}
//增加联系人
void AddContact(Contact* pc)
{
if (pc->sz == MAX)
{
printf("通讯录已满,无法增加\n");
return;//在函数里面直接return会终止函数,因为是void返回类型所以只写return就行。
}
printf("请输入联系人姓名:>");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别:>");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入联系方式:>");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].addr);
(pc->sz)++;//不加括号也没问题,因为->优先级大于++
printf("添加成功\n");
}
//删除联系人
void DelContact(Contact* pc)
{
char name[MAX_NAME] = { 0 };
if (pc->sz == 0)
{
printf("通讯录为空,无法删除\n");
return;
}
//删除
//1.找到要删除的联系人->位置,下标
printf("输入要删除人的名字:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("要删除的人不存在\n");
return;
}
int i = 0;
//2.删除-删除pos位置上的数据,并让pos之后的数据前移
for (i = pos; i < (pc->sz)-1; i++)
{
pc->data[i] = pc->data[i + 1];
}
(pc->sz)--;
printf("删除成功\n");
}
//查找联系人信息
void SearchContact(const Contact* pc)
{
char name[MAX_NAME] = { 0 };
printf("请输入要查找的名字:>");
scanf("%s", name);
//查找
int pos = FindByName(pc, name);
//如果不存在
if (pos == -1)
{
printf("查找的联系人不存在\n");
return;
}
//如果存在
//打印标题
printf("%-10s %-5s %-4s %-12s %-30s\n",//加-号表示左对齐,加数字表示字符串长度
"姓名", "性别", "年龄", "电话", "地址");
//打印数据内容
printf("%-10s %-5s %-4d %-12s %-30s\n",
pc->data[pos].name, pc->data[pos].sex, pc->data[pos].age, pc->data[pos].tele,pc->data[pos].addr);
}
//修改联系人信息
void ModifyContact(Contact* pc)
{
char name[MAX_NAME] = { 0 };
printf("请输入要修改联系人的名字:>");
scanf("%s", name);
//查找
int pos = FindByName(pc, name);
//如果不存在
if (pos == -1)
{
printf("要修改的联系人不存在\n");
return;
}
//修改
printf("请输入联系人姓名:>");
scanf("%s", pc->data[pos].name);
printf("请输入性别:>");
scanf("%s", pc->data[pos].sex);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pos].age));
printf("请输入联系方式:>");
scanf("%s", pc->data[pos].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pos].addr);
printf("修改成功\n");
}
//显示联系人信息
void ShowContact(const Contact* pc)
{
int i = 0;
//打印标题
printf("%-10s %-5s %-4s %-12s %-30s\n",//加-号表示左对齐,加数字表示字符串长度
"姓名", "性别", "年龄", "电话", "地址");
for (i = 0; i < pc->sz; i++)
{
//打印数据内容
printf("%-10s %-5s %-4d %-12s %-30s\n",
pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
}
}
static int cmp_by_name(const void* e1, const void* e2)
{
return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_by_name);
printf("排序成功\n");
}
测试代码:
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*************\n");
printf("*******************************\n");
}
enum Options//使用枚举列举出所有选项
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT
};
int main()
{
int input = 0;
Contact con;//通讯录
InitContact(&con);//初始化通讯录
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&con);
break;
case DEL:
DelContact(&con);
break;
case SEARCH:
SearchContact(&con);
break;
case MODIFY:
ModifyContact(&con);
break;
case SHOW:
ShowContact(&con);
break;
case SORT:
SortContact(&con);
break;
case EXIT:
printf("退出通讯录\n");
break;
default:
printf("选择错误,请重试\n");
break;
}
} while (input);
return 0;
}
测试结果展示:
(王五的添加省略了,因为过程都一样,不过多展示)
这是简单的展示,仅仅展示了添加联系人和展示通讯录列表两个功能,感兴趣的小伙伴可以保存代码自己运行尝试其他的功能。
重点解析:
1.为什么要分.h,.c文件?
因为这个通讯录这个程序是一个简单的工程,在实际工作中,一个工程的不同板块是由不同的人来实现的。就比如此程序中写contact.c文件的就是来负责函数实现的。所以分别写成.h文件和.c文件,contact.c文件主要用来实现各种函数,contact.h文件主要用来声明这些函数并且定义一些通讯录中的最值成宏(方便修改,并且可读性强,可维护性高)以及创建结构体。
并且这样其他.c文件在使用时只需引用头文件#include"contact.h"即可调用通讯录。
2.为何在测试中要枚举出所有选项?
因为我们是按照菜单中的序号来进行枚举,保证枚举常量的值就等于其序号(第一个枚举常量默认值为0,后面的会依次加1)。这样在switch分支中就可用枚举常量代替数字1,2,3.....。这样代码的可读性就变强了,并且可维护性也变高了。
3.在contact.c文件中为什么有的函数,比如FindByName,需要加static呢?
因为我们知道在程序写好了之后,有些函数,代码属于机密或者隐私,不想让使用者调用或者查看,我们就可以使用static修饰函数使之失去外部连接属性,这样使用者就无法再通过头文件调用了。
4.代码中有些部分看不懂怎么办?
私信我,或者在评论区提出。我会迅速解答。放心提问,问到就是学到!
Disadvantage:
此通讯录的信息是短暂的,打开程序存储后。退出再进来信息就没了。因为信息并未真正存储在计算机(文件)中。所以我们称这个是静态通讯录。
后续我会抓紧更新动态通讯录,可以保证信息存储在电脑中,就跟手机上通讯录的一样,可以随时查看使用。
结语:
ok辣,本章到这里就结束了。每天学一点就是进步一点!蛰久者,飞必高!
祝愿我们大家都能保持空杯心态继续努力,厚积薄发!!!
最后还是老话:路漫漫其修远兮,吾将上下而求索!!!