在掌握了C语言的指针,函数,结构体,并对他们有着一些了解之后。
可以试着完成一个通讯录。
实现思路:
一、创建好结构体
要做一个通讯录,它保存的联系人信息肯定有很多种类,可以把他们封装成一个结构体。
其中联系人包含信息有:姓名,性别,年龄,电话,住址
//联系人信息:姓名,性别,年龄,电话,住址
typedef struct PeoInFo
{
char name[NAME_MAX];
char sex[SEX_MAX];
int age;
char tele[TELE_MAX];
char addr[ADDR_MAX];
}PeoInFo; //这里重命名结构体名字为PeoInFo(增加可读性)
那通讯录其实就算这么多个联系人信息的集合呀。
(结构体嵌套)
因此可以创建一个通讯录结构体类型,其中包含:
1.联系人信息
2.保存了多少个信息
就是这个样子:
二、整体框架
依然是熟悉的do while结构。
先打印菜单,再根据菜单中的提示完成相应的选择。
为显得简洁易读,这里创建三个工作单元。
test.c: 代码的逻辑思路。
contact.h: 所用到的头文件和函数的声明、全局变量的定义
contact.h: 实现的函数的具体代码
先将test.c的代码放出来:
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
printf("\n\n\n************************************\n");
printf("***** 1.Add 2.Del *****\n");
printf("***** 3.Search 4.Modify *****\n");
printf("***** 5.Sort 6.Print *****\n");
printf("***** 0.Exit *****\n");
printf("************************************\n");
}
void test()
{
int input = 0;
//创建通讯录
Contact con;
//初始化通讯录
InitContact(&con);
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input) //这里case部分用到了contact.h中的枚举类型。
增加程序可读性
{
case ADD:
AddContact(&con); //增
break;
case DEL:
DeleContact(&con); //删
break;
case SEARCH:
SearchContact(&con); //查
break;
case MODIFY:
ModifyContact(&con); //改
break;
case SORT:
SortContact(&con); //排序
break;
case PRINT:
PrintContact(&con); //打印信息
break;
case EXIT:
printf("退出成功\n");
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
然后是contact.h
其中是函数声明及头文件的引用。
要注意,这是静态版本的通讯录,大小提前定义好了。
(开辟的是固定大小的空间)
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#include
#define MAX 10
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 20
enum OPTION //这里用到了枚举类型,增加代码可读性
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SORT,
PRINT
};
//联系人信息:姓名,性别,年龄,电话,住址
typedef struct PeoInFo
{
char name[NAME_MAX];
char sex[SEX_MAX];
int age;
char tele[TELE_MAX];
char addr[ADDR_MAX];
}PeoInFo;
//创建一个名字为con的结构体类型
//其中包含一个记录联系人信息的数组(数组的类型为联系人结构体),
//一个记录大小的整型变量count
//
//创建通讯录结构体
typedef struct Contact
{
//联系人信息(结构体)
PeoInFo data[MAX];
//多少个
int count;
}Contact;
//初始化通讯录
void InitContact(Contact*pc);
//添加联系人信息
void AddContact(Contact* pc);
//打印联系人信息
void PrintContact(const Contact* pc); //这里加const比较安全
//删除联系人的信息
void DeleContact(Contact* pc);
//查找联系人信息
void SearchContact(const Contact* pc);
//修改联系人信息
void ModifyContact(Contact* pc);
//对联系人信息进行排序
void SortContact(Contact* pc);
接下来就算contact.c,就是各个功能的实现:
#define _CRT_SECURE_NO_WARNINGS 1
//联系人信息:姓名,性别,年龄,电话,住址
#include"contact.h"
//Contact*pc其实就是通讯录结构体的指针,它指向的结构体包含两个元素
//一个是联系人信息的结构体,一个是记录当前联系人信息个数的count
//初始化通讯录 可以用memset函数帮助初始化通讯录中的信息
void InitContact(Contact*pc)
{
assert(pc);
//把sz置为0,把开辟的空间,都置成0
pc->count = 0;
memset(pc->data,0,sizeof(pc->data)); //数组名代表首元素地址,但是sizeof是个例外
}
//添加联系人信息
void AddContact(Contact* pc)
{
assert(pc);
//判断满了没
if (pc->count == MAX)
{
printf("通讯录空间已满,无法添加\n");
return;
}
//没满,添加
printf("请输入联系人姓名:");
scanf("%s", pc->data[pc->count].name);
printf("请输入联系人性别:");
scanf("%s", pc->data[pc->count].sex);
printf("请输入联系人年龄:");
scanf("%d", &(pc->data[pc->count]).age); //年龄需要解引用,其他的都可以直接传地址
printf("请输入联系人电话:");
scanf("%s", pc->data[pc->count].tele);
printf("请输入联系人地址:");
scanf("%s", pc->data[pc->count].addr);
pc->count++;
printf("添加成功\n");
}
//打印联系人信息
//联系人信息:姓名,性别,年龄,电话,住址
void PrintContact(const Contact* pc)
{
assert(pc);
printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "性别", "年龄", "电话", "住址");
int i = 0;
for (i = 0; i < pc->count; i++)
{
printf("%-20s %-5s %-5d %-12s %-30s\n", //增加代码美观性
pc->data[i].name,
pc->data[i].sex,
pc->data[i].age,
pc->data[i].tele,
pc->data[i].addr);
}
}
//查找信息,有就返回下标,没有返回-1
int FindByName(const Contact* pc, char name[NAME_MAX]) //这里又忘记const
{
int i = 0;
for (i = 0; i < pc->count; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
//对于查找 *** 作来说,不会对通讯录内部的值进行更改,因此,加上const会使代码更加安全
//删除联系人的信息
void DeleContact(Contact* pc)
{
assert(pc);
//空了,无需删除
if (pc->count == 0)
{
printf("无联系人信息需删除!\n");
return;
}
//需要删除
char name[NAME_MAX] = { 0 };
printf("请输入您要删除的联系人的名字:");
scanf("%s", name);
//有 或者 没有
int ret = FindByName(pc, name); //因为还需要实现查找联系人信息的功能,所以在这路封装了一个函数
if (ret == -1)
{
printf("没有找到您要删除的联系人信息!\n");
}
else
{
//删除联系人信息
int i = 0;
for (i = ret; i < pc->count; i++)
{
pc->data[ret] = pc->data[ret + 1];
}
pc->count--;
printf("删除成功\n");
PrintContact(pc);
}
}
//查找联系人信息
void SearchContact(const Contact* pc)
{
assert(pc);
//空了,无法查找
if (pc->count == 0)
{
printf("无联系人信息!\n");
return;
}
char name[NAME_MAX] = { 0 };
printf("请输入您要查找的联系人的名字:");
scanf("%s", name);
//有 或者 没有
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("没有找到您要查找的联系人信息!\n");
}
else
{
printf("该联系人信息为:\n");
printf("\n\n%-20s %-5s %-5s %-12s %-30s\n", "姓名", "性别", "年龄", "电话", "住址");
//打印联系人信息
printf("%-20s %-5s %-5d %-12s %-30s\n",
pc->data[ret].name,
pc->data[ret].sex,
pc->data[ret].age,
pc->data[ret].tele,
pc->data[ret].addr);
}
}
//修改联系人信息
void ModifyContact(Contact* pc)
{
assert(pc);
//空了,无法修改
if (pc->count == 0)
{
printf("无联系人信息!\n");
return;
}
char name[NAME_MAX] = { 0 };
printf("请输入您要修改的联系人的名字:");
scanf("%s", name);
//有 或者 没有
int ret = FindByName(pc, name);
if (ret == -1) //这里返回-1的原因是0也有可能是数组下标
{
printf("没有找到您要修改的联系人信息!\n");
}
else //这里修改信息的代码其实就和刚开始录入信息的是差不多的
{
printf("请输入联系人姓名:");
scanf("%s", pc->data[ret].name);
printf("请输入联系人性别:");
scanf("%s", pc->data[ret].sex);
printf("请输入联系人年龄:");
scanf("%d", &(pc->data[ret]).age); //年龄需要解引用,其他的都可以直接传地址
printf("请输入联系人电话:");
scanf("%s", pc->data[ret].tele);
printf("请输入联系人地址:");
scanf("%s", pc->data[ret].addr);
}
printf("修改成功!\n");
}
//对联系人信息进行排序
//这里用到了C语言提供的qsort函数,可以实现复杂类型的排序
//如果关于qsort函数用法有不懂的可以看我之前的博客
//这里除了年龄的排序不用strcmp外,其他的都用strcmp
//因为字符串的比较不能直接相减,需要用到strcmp函数
int cmp_by_name(const void* e1, const void* e2)
{
return strcmp(((PeoInFo*)e1)->name , ((PeoInFo*)e2)->name);
}
int cmp_by_sex(const void* e1, const void* e2)
{
return strcmp(((PeoInFo*)e1)->sex, ((PeoInFo*)e2)->sex);
}
int cmp_by_age(const void* e1, const void* e2)
{
return ((PeoInFo*)e1)->age - ((PeoInFo*)e2)->age;
}
int cmp_by_tele(const void* e1, const void* e2)
{
return strcmp(((PeoInFo*)e1)->tele, ((PeoInFo*)e2)->tele);
}
int cmp_by_addr(const void* e1, const void* e2)
{
return strcmp(((PeoInFo*)e1)->addr, ((PeoInFo*)e2)->addr);
}
void SortContact(Contact* pc)
{
int input = 0;
printf("请输入您想要的排列方式:1.姓名 2.性别 3.年龄 4.电话 5. 住址");
scanf("%d", &input);
switch (input)
{
case 1:
qsort(pc->data, pc->count, sizeof(PeoInFo), cmp_by_name);
PrintContact(pc);
break;
case 2:
qsort(pc->data, pc->count, sizeof(PeoInFo), cmp_by_sex);
PrintContact(pc);
break;
case 3:
qsort(pc->data, pc->count, sizeof(PeoInFo), cmp_by_age);
PrintContact(pc);
break;
case 4:
qsort(pc->data, pc->count, sizeof(PeoInFo), cmp_by_tele);
PrintContact(pc);
break;
case 5:
qsort(pc->data, pc->count, sizeof(PeoInFo), cmp_by_addr);
PrintContact(pc);
break;
default:
printf("输入错误请重新输入:");
break;
}
}
以上就是对于一个通讯录的具体实现了。
总结:
需要注意的是:
1.明白这两个结构体在内存中是怎样存在的(可以复制代码自己进行调试)
2.在实现时要分清每个指针指向的内容,特别是进行删除联系人信息的时侯。
要明白后边的元素“前移”的过程
3.qsort函数的使用。
qsort真的是一个很好用的排序函数。
自己实现通讯录真的很有成就感!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)