【进阶C语言】通讯录(完整版)-创新互联
- 一.基本框架与功能
- 二.头文件的详细内容
- 三.函数的实现
- 1.打印菜单
- 2.初始化通讯录
- 3.添加联系人信息
- 4.打印联系人信息
- 5.查找名字
- 6.删除联系人信息
- 7.查找联系人
- 8.修改联系人信息
- 9.排序联系人(按照名字)
- 四.总结
- 1.test.c
- 2.contact.c
- 3.contact.h
- 五.文件操作所需的函数
- 1.检查容量
- 2.添加联系人信息
- 3.保存联系人信息
二.头文件的详细内容准备工作:
一.分模块开发
1.test.c,实现模块的测试环节
2.contact.c,实现函数的功能
3.contact.h,实现函数的命名与结构体的使用
下面重点讲解函数实现的函数,在开始时会提供头文件,以便于提高本文的可读性。
#include//printf,scanf,perror
#include//system,malloc,realloc
#include//strcmp
//对开辟的大小,方便之后的统一修改。
enum SIZE
{NAME_SIZE=10,
SEX_SIZE=5,
TELE_SIZE=15,
ADDRE_SIZE=20,
DEFAULT_SIZE=2,
ADD_SIZE=2
};
//功能的选项数字赋予一定的意义
enum function
{ADD=1,
DEL,
FIND,
MODIFY,
PRINT,
SORT,
EXIT
};
//联系人信息
typedef struct people
{char name[NAME_SIZE];
int age;
char sex[SEX_SIZE];
char tele[TELE_SIZE];
char addre[ADD_SIZE];
}peo;
//通讯录信息
typedef struct Contact
{int count;//联系人个数
int capacity;//当前大容量
peo CON[];//柔性数组利用内存池的概念,使内存管理更加高效,并且free只要一次,更方便。
}contact;
//菜单
void menu();
//初始化通讯录
void Init_contact(contact** p);//要修改一级指针所以要传一级指针的地址用二级指针来接收
//添加联系人信息
void Add_Contact(contact** p);//同理
//打印通讯录
void Print_Contact(contact* p);
//删除联系人信息
void Del_Contact(contact* p);
//查找联系人信息
void Find_Contact(contact* p);
//修改联系人信息
void Modify_Contact(contact* p);
//释放已开辟的内存空间
void Distory_Contact(contact** p);//同理
//按照名字进行排序通讯录
void Sort_Contact(contact* p);
三.函数的实现
1.打印菜单void menu()
{printf("******************************************\n");
printf("******** 1.增加联系人 2.删除联系人 *******\n");
printf("******** 3.查找联系人 4.修改联系人 *******\n");
printf("******** 5.打印联系人 6.排序联系人 *******\n");
printf("******** 7.退出通讯录 *******\n");
printf("******************************************\n");
}
2.初始化通讯录参数无,返回类型无(可以写return;)
void Init_contact(contact** p)
{*p = (contact*)malloc(4*2 + sizeof(peo) * DEFAULT_SIZE);
if (*p != NULL)
{(*p)->count = 0;
(*p)->capacity = DEFAULT_SIZE;
}
else
{perror("Init_contact");
return;
}
}
3.添加联系人信息1.这里的开辟空间默认为两个整形+初始能存的联系人个数(2)
2.结构体指针访问成员只能是一级指针,要改变一级指针,就得给函数传二级指针
3.这里也可以用calloc,不过比较麻烦,并且效率比,malloc略低。
4.注意对开辟空间返回的地址进行检查
void Add_Contact(contact** p)
{int judge = 0;
//判断内存是否够
if ((*p)->count== (*p)->capacity)
{printf("通讯录已满,请确定是否要增容(1是0否):");
scanf("%d", &judge);
if (judge)
{ contact* ptr = (contact*)realloc(*p, 4 * 2 + sizeof(peo) * ((*p)->capacity+ ADD_SIZE));
if (ptr != NULL)
{ (*p) = ptr;
(*p)->capacity += ADD_SIZE;
printf("增容成功\n");
}
else
{ perror("Add_Contact");
printf("增容失败\n");
return;
}
}
else
{ return;
}
}
//输入信息部分
printf("请输入姓名:");
scanf("%s", (*p)->CON[(*p)->count].name);
printf("请输入年龄:");
scanf("%d", &(*p)->CON[(*p)->count].age);
printf("请输入性别:");
scanf("%s", (*p)->CON[(*p)->count].sex);
printf("请输入电话:");
scanf("%s", (*p)->CON[(*p)->count].tele);
printf("请输入住址:");
scanf("%s", (*p)->CON[(*p)->count].addre);
printf("增加成功!\n");
(*p)->count++;
}
4.打印联系人信息1.对realloc返回值进行检查,如果为空要及时的报错
2.在输入信息之后要对联系人个数进行加1
3.输入信息时要确定访问的成员的类型,以确定是否取地址
补充:取地址数组名与数组名在进行输入的时候,效果相同,因为它们的数值是相同的,但是意义不同。
void Print_Contact(contact* p)
{if (p->count == 0)
{printf("通讯录为空!\n");
return;
}
printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名",
"年龄",
"性别",
"电话",
"住址");
int i = 0;
for (i = 0; i< p->count; i++)
{printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[i].name,
p->CON[i].age,
p->CON[i].sex,
p->CON[i].tele,
p->CON[i].addre);
}
}
5.查找名字1.在通讯录无信息时,应该及时的提醒。
2.注意下标与联系人信息的个数的关系
3.如果打印的内容太长,建议要进行换行,提高代码的易读性。
4.打印的时候需要对齐,要设置好格式进行打印,这样打印的内容较为简洁美观。
const int Find_By_name(contact* p,char*arr)
{int i = 0;
for (i = 0; i< p->count; i++)
{if (strcmp(p->CON[i].name, arr) == 0)
{ return i;
}
}
return -1;
}
6.删除联系人信息1.由于这个函数只服务于实现函数的模块,所以加上const
2.strcmp比较两个字符串,如果相等返回0
3.如果没有字符串返回-1,如果找到则返回其下标
4.这个函数是服务于查找联系人,修改联系人,删除联系人的
void Del_Contact(contact* p)
{char name[20] = {0 };
printf("请输入要删除的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret!=-1)
{int i = 0;
for (i = ret; i< p->count-1; i++)
{ p->CON[ret] = p->CON[ret + 1];
}
p->count--;
printf("已删除\n");
}
else
{printf("查无此人\n");
}
}
7.查找联系人1.这里删除的思路是进行覆盖,至于最后一个元素的情况,在联系人个数减过之后再添加会进行覆盖。
2.注意这里的i的范围,结合下面的代码可知可能会发生数组越界的问题,所以要减去1
3.结构体数组的成员可以直接覆盖前一个成员,跟数组的特性一样
void Find_Contact(contact* p)
{char name[20] = {0 };
printf("请输入要查找的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret != -1)
{printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名",
"年龄",
"性别",
"电话",
"住址");
printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[ret].name,
p->CON[ret].age,
p->CON[ret].sex,
p->CON[ret].tele,
p->CON[ret].addre);
}
else
{printf("查无此人\n");
}
}
8.修改联系人信息void Modify_Contact(contact* p)
{char name[20] = {0 };
printf("请输入要修改的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret != -1)
{printf("请输入姓名:");
scanf("%s", p->CON[ret].name);
printf("请输入年龄:");
scanf("%d", &p->CON[ret].age);
printf("请输入性别:");
scanf("%s", p->CON[ret].sex);
printf("请输入电话:");
scanf("%s", p->CON[ret].tele);
printf("请输入住址:");
scanf("%s", p->CON[ret].addre);
printf("修改成功!\n");
}
else
{printf("查无此人\n");
}
}
9.排序联系人(按照名字)int my_cmp(const void* e1, const void* e2)
{return strcmp(((peo*)e1)->name, ((peo*)e2)->name);
}
void Sort_Contact(contact* p)
{qsort(p->CON, p->count, sizeof(peo), my_cmp);
printf("排序成功!\n");
}
四.总结 1.test.c1.快排要写一个比较函数,由于是字符串比较要用到字符串比较函数
2.要注意快排的参数——排序的数组,排序的个数,元素的大小,比较函数
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
int main()
{contact *con =NULL;
Init_contact(&con);
int input = 0;
do
{menu();
printf("请输入:");
scanf("%d", &input);
switch (input)
{case ADD:
system("cls");
Add_Contact(&con);
break;
case DEL:
system("cls");
Del_Contact(con);
break;
case FIND:
system("cls");
Find_Contact(con);
break;
case MODIFY:
system("cls");
Modify_Contact(con);
break;
case PRINT:
system("cls");
Print_Contact(con);
break;
case SORT:
system("cls");
Sort_Contact(con);
break;
case EXIT:
system("cls");
Distory_Contact(&con);
printf("退出成功\n");
break;
default:
printf("输入错误\n");
break;
}
} while (input!=EXIT);
return 0;
}
2.contact.c#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{printf("******************************************\n");
printf("******** 1.增加联系人 2.删除联系人 *******\n");
printf("******** 3.查找联系人 4.修改联系人 *******\n");
printf("******** 5.打印联系人 6.排序联系人 *******\n");
printf("******** 7.退出通讯录 *******\n");
printf("******************************************\n");
}
void Init_contact(contact** p)
{*p = malloc(4*2 + sizeof(peo) * DEFAULT_SIZE);
if (*p != NULL)
{(*p)->count = 0;
(*p)->capacity = DEFAULT_SIZE;
}
else
{perror("Init_contact");
return;
}
}
//const void Think_Capacity(contact** p)
//{//
// if ((*p)->count == (*p)->capacity)
// {// contact* ptr = (contact*)realloc(*p, 8 + sizeof(peo) * ((*p)->capacity + ADD_SIZE));
// if (ptr != NULL)
// {// (*p) = ptr;
// (*p)->capacity += ADD_SIZE;
// printf("增容成功\n");
// }
// else
// {// perror("Add_Contact");
// printf("增容失败\n");
// return;
// }
// }
//
//}
//void Load_Contact(contact** p)
//{// FILE* pf = fopen("contact.txt", "rb");
// if (NULL == pf)
// {// perror("Load_Contact");
// }
// else
// {// peo tmp = { 0 };
// while (fread(&tmp, sizeof(peo), 1, pf))
// {// Think_Capacity(p);
// (*p)->CON[(*p)->count] = tmp;
// (*p)->count++;
// }
// }
// fclose(pf);
// pf = NULL;
//}
void Add_Contact(contact** p)
{int judge = 0;
if ((*p)->count== (*p)->capacity)
{printf("通讯录已满,请确定是否要增容(1是0否):");
scanf("%d", &judge);
if (judge)
{ contact* ptr = (contact*)realloc(*p, 4 * 2 + sizeof(peo) * ((*p)->capacity + ADD_SIZE));
if (ptr != NULL)
{ (*p) = ptr;
(*p)->capacity += ADD_SIZE;
printf("增容成功\n");
}
else
{ perror("Add_Contact");
printf("增容失败\n");
return;
}
}
else
{ return;
}
}
printf("请输入姓名:");
scanf("%s", (*p)->CON[(*p)->count].name);
printf("请输入年龄:");
scanf("%d", &(*p)->CON[(*p)->count].age);
printf("请输入性别:");
scanf("%s", (*p)->CON[(*p)->count].sex);
printf("请输入电话:");
scanf("%s", (*p)->CON[(*p)->count].tele);
printf("请输入住址:");
scanf("%s", (*p)->CON[(*p)->count].addre);
printf("增加成功!\n");
(*p)->count++;
}
void Print_Contact(contact* p)
{if (p->count == 0)
{printf("通讯录为空!\n");
return;
}
printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", "年龄", "性别", "电话", "住址");
int i = 0;
for (i = 0; i< p->count; i++)
{printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[i].name,
p->CON[i].age,
p->CON[i].sex,
p->CON[i].tele,
p->CON[i].addre);
}
}
const int Find_By_name(contact* p,char*arr)
{int i = 0;
for (i = 0; i< p->count; i++)
{if (strcmp(p->CON[i].name, arr) == 0)
{ return i;
}
}
return -1;
}
void Del_Contact(contact* p)
{char name[20] = {0 };
printf("请输入要删除的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret!=-1)
{int i = 0;
for (i = ret; i< p->count-1; i++)
{ p->CON[ret] = p->CON[ret + 1];
}
p->count--;
printf("已删除\n");
}
else
{printf("查无此人\n");
}
}
void Find_Contact(contact* p)
{char name[20] = {0 };
printf("请输入要查找的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret != -1)
{printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", "年龄", "性别", "电话", "住址");
printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[ret].name, p->CON[ret].age,
p->CON[ret].sex, p->CON[ret].tele,
p->CON[ret].addre);
}
else
{printf("查无此人\n");
}
}
void Modify_Contact(contact* p)
{char name[20] = {0 };
printf("请输入要修改的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret != -1)
{printf("请输入姓名:");
scanf("%s", p->CON[ret].name);
printf("请输入年龄:");
scanf("%d", &p->CON[ret].age);
printf("请输入性别:");
scanf("%s", p->CON[ret].sex);
printf("请输入电话:");
scanf("%s", p->CON[ret].tele);
printf("请输入住址:");
scanf("%s", p->CON[ret].addre);
printf("修改成功!\n");
}
else
{printf("查无此人\n");
}
}
//void Save_Contact(contact* p)
//{// FILE* pf = fopen("contact.txt", "wb");
// if (NULL == pf)
// {// perror("Save_Contact:pf");
// }
// else
// {// int i = 0;
// for (i = 0; i< p->count; i++)
// {// fwrite(p->CON + i, sizeof(peo), 1, pf);
// }
// }
// printf("保存成功!\n");
// fclose(pf);
// pf = NULL;
//
//}
void Distory_Contact(contact** p)
{free(*p);
*p = NULL;
}
int my_cmp(const void* e1, const void* e2)
{return strcmp(((peo*)e1)->name, ((peo*)e2)->name);
}
void Sort_Contact(contact* p)
{qsort(p->CON, p->count, sizeof(peo), my_cmp);
printf("排序成功!\n");
}
3.contact.h#include//printf,scanf,perror
#include//system,malloc,realloc
#include//strcmp
//对开辟的大小,方便之后的统一修改。
enum SIZE
{NAME_SIZE=10,
SEX_SIZE=5,
TELE_SIZE=15,
ADDRE_SIZE=20,
DEFAULT_SIZE=2,
ADD_SIZE=2
};
//功能的选项数字赋予一定的意义
enum function
{ADD=1,
DEL,
FIND,
MODIFY,
PRINT,
SORT,
EXIT
};
//联系人信息
typedef struct people
{char name[NAME_SIZE];
int age;
char sex[SEX_SIZE];
char tele[TELE_SIZE];
char addre[ADD_SIZE];
}peo;
//通讯录信息
typedef struct Contact
{int count;//联系人个数
int capacity;//当前大容量
peo CON[];//柔性数组利用内存池的概念,使内存管理更加高效,并且free只要一次,更方便。
}contact;
//菜单
void menu();
//初始化通讯录
void Init_contact(contact** p);//要修改一级指针所以要传一级指针的地址用二级指针来接收
//添加联系人信息
void Add_Contact(contact** p);//同理
//打印通讯录
void Print_Contact(contact* p);
//删除联系人信息
void Del_Contact(contact* p);
//查找联系人信息
void Find_Contact(contact* p);
//修改联系人信息
void Modify_Contact(contact* p);
//释放已开辟的内存空间
void Distory_Contact(contact** p);//同理
//按照名字进行排序通讯录
void Sort_Contact(contact* p);
//保存通讯录信息
//void Save_Contact(contact* p);
//加载通讯录信息
//void Load_Contact(contact* p);
五.文件操作所需的函数
1.检查容量const void Think_Capacity(contact** p)
{if ((*p)->count == (*p)->capacity)
{contact* ptr = (contact*)realloc(*p, 8 + sizeof(peo) * ((*p)->capacity + ADD_SIZE));
if (ptr != NULL)
{ (*p) = ptr;
(*p)->capacity += ADD_SIZE;
printf("增容成功\n");
}
else
{ perror("Add_Contact");
printf("增容失败\n");
return;
}
}
}
2.添加联系人信息void Load_Contact(contact** p)
{FILE* pf = fopen("contact.txt", "rb");
if (NULL == pf)
{perror("Load_Contact");
}
else
{peo tmp = {0 };
while (fread(&tmp, sizeof(peo), 1, pf))
{ Think_Capacity(p);
(*p)->CON[(*p)->count] = tmp;
(*p)->count++;
}
}
fclose(pf);
pf = NULL;
}
3.保存联系人信息void Save_Contact(contact* p)
{FILE* pf = fopen("contact.txt", "wb");
if (NULL == pf)
{perror("Save_Contact:pf");
}
else
{int i = 0;
for (i = 0; i< p->count; i++)
{ fwrite(p->CON + i, sizeof(peo), 1, pf);
}
}
printf("保存成功!\n");
fclose(pf);
pf = NULL;
}
要在当前项目(与源文件同路径)里面创建一个:contact.txt
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
文章题目:【进阶C语言】通讯录(完整版)-创新互联
链接URL:http://hbruida.cn/article/dghgcg.html