目录
一、通讯录的实现(静态版)
test.c 测试通讯录
contcat.h 函数和类型的声明
contcat.c 函数的实现
头文件的作用
我们可以将函数、数据的声明,宏的定义,库函数所用到的头文件放在一起,在源文件中只要引用
#include “contact.h”就可以实现,这样可以减少代码的重复编写,提高效率。
1.实现思路
通讯录中保存人的信息:姓名、年龄、性别、电话、住址。
1.2通讯录要存放的信息
我们要是一个可以存放100个人信息的通讯录
创建一个结构体,结构体中放我们要存的信息,姓名、年龄、性别、电话号、住址。
1.3 通讯录的功能
1.增加联系人 2.删除指定联系人
3.查找指定人联系人 4.修改指定人联系人
5.显示所有联系人信息 6.对联系人排序
1.4通讯录的创建
PeoInfo date[100];
int sz = 0;
我们创建好可以存放100个人的通讯录后,还要创建一个变量sz来记录通讯录中存放的人数,所以这两个变量要绑定在一起。我们在创建一个结构体,这样在传参时会更方便。
typedef struct Contact
{
PeoInfo date[100];//date存放有效数据
int sz;//sz是存放个数
}Contact;
1.5菜单打印以及基本逻辑的实现
#include "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 \n");
printf("------------------------------------\n");
}
void test()
{
int input = 0;
Contact con; //通讯录
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
在case语句里,别人使用我们的代码并不知道1,2,3……代表的是什么功能,所以我们可以使用枚举,让使用者了解我们的功能,提高代码可读性
优化代码:
enum OPTION//选项
{
Exit,//0
Add,//1
Del,
Serach,
Modify,
Show,
Sort
};
case Add:
break;
case Del:
break;
case Serach:
break;
case Modify:
break;
case Show:
break;
case Sort:
break;
case Exit:
printf("退出通讯录\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
2.实现功能
2.1初始化通讯录
初始化通讯录,我们要改变里面的内容,所以我们要传指针过去。注意要在头文件中对函数声明。
void InitContact(Contact* pc)
{
memset(pc->date, 0, sizeof(pc->date));
pc->sz = 0;
}
函数和类型声明
#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];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
}PeoInfo;
函数实现
void InitContact(Contact* pc)
{
memset(pc->date, 0, sizeof(pc->date));
pc->sz = 0;
}
void AddContact(Contact* pc)//增加联系人信息,最先开始要判断一下满了没有
{
if (pc->sz == MAX)
{
printf("通讯录已满,无法添加\n");
return;
}
2.2 增加联系人
我们要考虑通讯录有没有满,如果没有满添加的联系人放到下标sz的地方。我们要使用pc指针,所以用assert断言指针是否有效。
void AddContact(Contact* pc)
{
assert(pc);
if (pc->sz == MAX)
{
printf("通讯录已满,无法添加\n");
return;
}
printf("请输入名字:>");
scanf("%s", pc->date[pc->sz].name);
printf("请输入年龄:>");
scanf("%d", &(pc->date[pc->sz].name));
printf("请输入性别:>");
scanf("%s", pc->date[pc->sz].sex);
printf("请输入电话:>");
scanf("%s", pc->date[pc->sz].tele);
printf("请输入地址:>");
scanf("%s", pc->date[pc->sz].addr);
pc->sz++;
printf("添加成功\n");
}
2.3 显示联系人
我们只是显示联系人的数据,不会修改通讯录中的内容,所以在声明时用const修饰:
void ShowContact(const Contact* pc);
void ShowContact(const Contact* pc)
{
assert(pc);
//打印标题
printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
int i = 0;
for (i = 0; i < pc->sz; i++)
{
printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[i].name,
pc->date[i].age,
pc->date[i].sex,
pc->date[i].tele,
pc->date[i].addr);
}
}
注意:有 ‘ - ’ 是左对齐,没有 ‘ - ’ 是右对齐。
2.4 删除联系人
我们要考虑通信录中是否存在要删除的联系人,所以我们定义一个flag标签。
void DelContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法删除\n");
}
char name[MAX_NAME] = { 0 };
//找到要删除的人
printf("要删除的联系人:>");
scanf("%s", name);
int i = 0;
int del = 0;
int flag = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->date[i].name, name) == 0)
{
del = i;
flag = 1;
break;
}
}
if (flag == 0)
{
printf("要删除的联系人不存在\n");
return;
}
//删除坐标del的联系人
for (i = del; i < pc->sz - 1; i++)
{
pc->date[i] = pc->date[i + 1];
}
pc->sz--;
printf("成功删除联系人\n");
}
在删除,查找,修改的功能中都有查找的程序,所以我们可以把查找的功能封装成一个函数,更加方便 。
优化代码:
static int FindByname(const Contact* pc, char name[])//通过名字来查找
//FinByname这个函数只在内部调用,所以外部不用声明
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->date[i].name, name) == 0)
{
return i;//找到了
}
}
return -1;//找不到
}
void DelContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法删除\n");
}
char name[MAX_NAME] = { 0 };
//删除
printf("要删除的联系人:>");
scanf("%s", name);
//找到要删除人的信息
int del = FindByname(pc, name);
if (del == -1)
{
printf("要删除的联系人不存在\n");
return;
}
int i = 0;
//删除坐标del的联系人
for (i = del; i < pc->sz - 1; i++)
{
pc->date[i] = pc->date[i + 1];
}
pc->sz--;
printf("成功删除联系人\n");
}
2.5 查找联系人
使用上面封装好的查找的函数,如果我们要查找的人存在,就把信息打印在屏幕上。
void SearchContact(const Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入要查找人的名字:>");
scanf("%s", name);
int pos = FindByname(pc, name);
if (pos == -1)
{
printf("要查找的人不存在\n");
}
else
{
printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
//打印数据
printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[pos].name,
pc->date[pos].age,
pc->date[pos].sex,
pc->date[pos].tele,
pc->date[pos].addr);
}
}
2.6 修改联系人
使用上面封装好的查找的函数,要修改的人存在就重新录入它的信息。
void ModifyContact(Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入要修改的人的名字:>");
scanf("%s", name);
int pos = FindByname(pc, name);//要找到再修改
if (pos == -1)
{
printf("要修改的人不存在\n");
}
else
{
printf("请输入名字:>");
scanf("%s", pc->date[pos].name);
printf("请输入年龄:>");
scanf("%d", &(pc->date[pos].age));
printf("请输入性别:>");
scanf("%s", pc->date[pos].sex);
printf("请输入电话:>");
scanf("%s", pc->date[pos].tele);
printf("请输入地址:>");
scanf("%s", pc->date[pos].addr);
}
printf("修改成功\n");
}
2.7 按名字排序
case Sort:
//按名字排序
qsort(con.date, con.sz, sizeof(PeoInfo), cmp_by_name);
break;
int cmp_by_name(const void* p1, const void* p2)
{
return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
3.完整代码
contact.h 函数的声明和类型声明
#pragma once
#include <stdio.h>
#include <string.h>
#include <assert.h>
#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];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
}PeoInfo;
typedef struct Contact
{
PeoInfo date[MAX];
int sz;
}Contact;
enum OPTION
{
Exit,//0
Add,//1
Del,//2
Serach,
Modify,
Show,
Sort
};
//函数声明
//初始化
void InitContact(Contact* pc);//地址传过来,指针接收
//增加联系人
void AddContact(Contact* pc);
//显示所有联系人信息
void ShowContact(const Contact* pc);//仅仅是显示不会修改 用const修饰
//删除指定人联系人
void DelContact(Contact* pc);
//查找联系人
void SearchContact(const Contact* pc);
//排序
int cmp_by_name(const void* p1, const void* p2);
test.c 测试通讯录
#include "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 \n");
printf("------------------------------------\n");
}
void test()
{
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 Serach:
SearchContact(&con);
break;
case Modify:
ModifyContact(&con);
break;
case Show:
ShowContact(&con);
break;
case Sort:
//按名字排序
qsort(con.date, con.sz, sizeof(PeoInfo), cmp_by_name);
break;
case Exit:
printf("退出通讯录\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
contact.c 函数的实现
#include "contact.h"
void InitContact(Contact* pc)
{
memset(pc->date, 0, sizeof(pc->date));
pc->sz = 0;
}
void AddContact(Contact* pc)
{
assert(pc);//断言
if (pc->sz == MAX)
{
printf("通讯录已满,无法添加\n");
return;
}
printf("请输入名字:>");
scanf("%s", pc->date[pc->sz].name);//结构体指针—>找到date数组
printf("请输入年龄:>");
scanf("%d", &(pc->date[pc->sz].age));
printf("请输入性别:>");
scanf("%s", pc->date[pc->sz].sex);
printf("请输入电话:>");
scanf("%s", pc->date[pc->sz].tele);
printf("请输入地址:>");
scanf("%s", pc->date[pc->sz].addr);
pc->sz++;
printf("成功增加联系人\n");
}
void ShowContact(const Contact* pc)
{
int i = 0;
assert(pc);
//打印列标题
printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
//打印数据
for (i = 0; i < pc->sz; i++)
{
printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[i].name,
pc->date[i].age,
pc->date[i].sex,
pc->date[i].tele,
pc->date[i].addr);
}
}
static int FindByname(const Contact* pc, char name[])//通过名字来查找
//FinByname这个函数只在内部调用,所以外部不用声明
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->date[i].name, name) == 0)
{
return i;//找到了
}
}
return -1;//找不到
}
void DelContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法删除\n");
}
char name[MAX_NAME] = { 0 };
//删除
printf("要删除的联系人:>");
scanf("%s", name);
//找到要删除人的信息
int del = FindByname(pc, name);
if (del == -1)
{
printf("要删除的联系人不存在\n");
return;
}
int i = 0;
//删除坐标del的联系人
for (i = del; i < pc->sz - 1; i++)
{
pc->date[i] = pc->date[i + 1];
}
pc->sz--;
printf("成功删除联系人\n");
}
void SearchContact(const Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入要查找人的名字:>");
scanf("%s", name);
int pos = FindByname(pc, name);
if (pos == -1)
{
printf("要查找的人不存在\n");
}
else
{
printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
//打印数据
printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[pos].name,
pc->date[pos].age,
pc->date[pos].sex,
pc->date[pos].tele,
pc->date[pos].addr);
}
}
void ModifyContact(Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入要修改的人的名字:>");
scanf("%s", name);
int pos = FindByname(pc, name);
if (pos == -1)
{
printf("要修改的人不存在\n");
}
else
{
printf("请输入名字:>");
scanf("%s", pc->date[pos].name);
printf("请输入年龄:>");
scanf("%d", &(pc->date[pos].age));
printf("请输入性别:>");
scanf("%s", pc->date[pos].sex);
printf("请输入电话:>");
scanf("%s", pc->date[pos].tele);
printf("请输入地址:>");
scanf("%s", pc->date[pos].addr);
}
printf("修改成功\n");
}
int cmp_by_name(const void* p1, const void* p2)
{
return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
二、通讯录的实现(动态版)
改造的目标:
1.通讯录的大小不是固定的,大小是可以调整的。
2.默认初始能放三个人的信息,如果不够,每次增加两个人的信息。
2.1通讯录的创建
动态版本就不用数组来创建,使用malloc函数创建空间。还需要一个变量来存储我们通讯录的最大容量,当存储的信息到达最大容量,我们可以增容。
typedef struct Contact
{
PeoInfo* date; //指向存放数据的空间
int sz; //当前通讯录存储的信息的个数
int cap; //通讯录当前最大容量
}Contact;
2.1初始化通讯录
使用动态内存函数要引用头文件
#include <stdlib.h>
我们初始为开始可以存放三个人的信息。
void InitContact(Contact* pc)
{
assert(pc);
pc->date = (PeoInfo*)malloc(3 * sizeof(PeoInfo));
if (pc->date == NULL)
{
perror("InitContact");
return;
}
pc->sz = 0;
pc->cap = DEFAULT_SZ;
}
2.2增加联系人
在动态版本中不存在填满的情况,我们要判断增容。在填满的情况下,每次增加两个。我们使用的初始容量和要增加的量可以使用define定义。
#define DEFAULT_SZ 3
#define INC_SZ 2
如果增容成功或不需要增容,返回1,增加联系人;如果增容失败,返回0
int CheckCapacity(Contact* pc)
{
if (pc->sz == pc->cap)
{
PeoInfo* ptr=(PeoInfo*)realloc(pc->date, (pc->cap + INC_SZ) * sizeof(PeoInfo));
if (ptr == NULL)
{
perror("CheckCapacity");
return 0;
}
else
{
pc->date = ptr;
pc->capatity += INC_SZ;
printf("增容成功\n");
return 1;
}
}
return 1;
}
void AddContact(Contact* pc)
{
assert(pc);
if (0 == CheckCapacity(pc))
{
return;
}
printf("请输入名字:>");
scanf("%s", pc->date[pc->sz].name);
printf("请输入年龄:>");
scanf("%d", &(pc->date[pc->sz].age));
printf("请输入性别:>");
scanf("%s", pc->date[pc->sz].sex);
printf("请输入电话:>");
scanf("%s", pc->date[pc->sz].tele);
printf("请输入地址:>");
scanf("%s", pc->date[pc->sz].addr);
pc->sz++;
printf("添加成功\n");
}
2.3完整代码
contact.h
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
#define DEFAULT_SZ 3
#define INC_SZ 2
typedef struct PeoInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
}PeoInfo;
typedef struct Contact
{
PeoInfo* date; //指向存放数据的空间
int sz; //当前通讯录存储的信息的个数
int cap; //通讯录当前最大容量
}Contact;
enum OPTION
{
Exit,
Add,
Del,
Serach,
Modify,
Show,
Sort
};
//函数声明
//初始化
void InitContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//显示联系人
void ShowContact(const Contact* pc);
//删除联系人
void DelContact(Contact* pc);
//查找联系人
void SearchContact(const Contact* pc);
//修改联系人
void ModifyContact(Contact* pc);
//排序
int cmp_by_name(const void* p1, const void* p2);
//释放
void DestoryContact(Contact* pc);
test.c
#include "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 \n");
printf("------------------------------------\n");
}
void test()
{
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 Serach:
SearchContact(&con);
break;
case Modify:
ModifyContact(&con);
break;
case Show:
ShowContact(&con);
break;
case Sort:
//按名字排序
qsort(con.date, con.sz, sizeof(PeoInfo), cmp_by_name);
break;
case Exit:
DestoryContact(&con);//释放通讯录
printf("退出通讯录\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
contact.c
#include "contact.h"
void InitContact(Contact* pc)
{
assert(pc);
pc->date = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
if (pc->date == NULL)
{
perror("InitContact");
return;
}
pc->sz = 0;
pc->cap = DEFAULT_SZ;
}
int CheckCapacity(Contact* pc)//检测容量
{
if (pc->sz == pc->cap)
{
PeoInfo* ptr=(PeoInfo*)realloc(pc->date, (pc->cap + INC_SZ) * sizeof(PeoInfo));
if (ptr == NULL)
{
perror("CheckCapacity");
return 0;
}
else
{
pc->date = ptr;
pc->capatity += INC_SZ;
printf("增容成功\n");
return 1;
}
}
return 1;
}
//动态版本
void AddContact(Contact* pc)
{
assert(pc);
if (0 == CheckCapacity(pc))
{
return;
}
printf("请输入名字:>");
scanf("%s", pc->date[pc->sz].name);
printf("请输入年龄:>");
scanf("%d", &(pc->date[pc->sz].age));
printf("请输入性别:>");
scanf("%s", pc->date[pc->sz].sex);
printf("请输入电话:>");
scanf("%s", pc->date[pc->sz].tele);
printf("请输入地址:>");
scanf("%s", pc->date[pc->sz].addr);
pc->sz++;
printf("添加成功\n");
}
void ShowContact(const Contact* pc)
{
int i = 0;
assert(pc);
//打印列标题
printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
//打印数据
for (i = 0; i < pc->sz; i++)
{
printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[i].name,
pc->date[i].age,
pc->date[i].sex,
pc->date[i].tele,
pc->date[i].addr);
}
}
static int FindByname(const Contact* pc, char name[])//通过名字来查找
//FinByname这个函数只在内部调用,所以外部不用声明
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->date[i].name, name) == 0)
{
return i;//找到了
}
}
return -1;//找不到
}
void DelContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,无法删除\n");
}
char name[MAX_NAME] = { 0 };
//删除
printf("要删除的联系人:>");
scanf("%s", name);
//找到要删除人的信息
int del = FindByname(pc, name);
if (del == -1)
{
printf("要删除的联系人不存在\n");
return;
}
int i = 0;
//删除坐标del的联系人
for (i = del; i < pc->sz - 1; i++)
{
pc->date[i] = pc->date[i + 1];
}
pc->sz--;
printf("成功删除联系人\n");
}
void SearchContact(const Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入要查找人的名字:>");
scanf("%s", name);
int pos = FindByname(pc, name);
if (pos == -1)
{
printf("要查找的人不存在\n");
}
else
{
printf("%-10s\t%-4s\t%-5s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
//打印数据
printf("%-10s\t%-4d\t%-5s\t%-12s\t%-10s\n", pc->date[pos].name,
pc->date[pos].age,
pc->date[pos].sex,
pc->date[pos].tele,
pc->date[pos].addr);
}
}
void ModifyContact(Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入要修改的人的名字:>");
scanf("%s", name);
int pos = FindByname(pc, name);
if (pos == -1)
{
printf("要修改的人不存在\n");
}
else
{
printf("请输入名字:>");
scanf("%s", pc->date[pos].name);
printf("请输入年龄:>");
scanf("%d", &(pc->date[pos].age));
printf("请输入性别:>");
scanf("%s", pc->date[pos].sex);
printf("请输入电话:>");
scanf("%s", pc->date[pos].tele);
printf("请输入地址:>");
scanf("%s", pc->date[pos].addr);
}
printf("修改成功\n");
}
int cmp_by_name(const void* p1, const void* p2)
{
return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
void DestoryContact(Contact* pc)
{
free(pc->date);
pc->date = NULL;
pc->cap = 0;
pc->sz = 0;
}