主要是为了让我们将结构体的知识,了解的更加深刻,将结构体应用一下,我们先将静态的通讯录实现,在进行改良,用动态内存的知识再将通讯录改造一边,将动态内容的知识也运用一下,最后再用文件操作的方式在改造一下通讯录。
所以我们会写三个通讯录,同时他是循序渐进的,一步一步的,如果不动前面的知识,可以去看看前面的知识点。
主要运用结构体的知识,不会的同学可以看看《自定义类型保姆级教学(结构体,位段,枚举,联合)》
首先先介绍一下代码的主题框架有三个部分
test.c
,contact.c
,contact.h
。
test.c
的作用:测试通讯录的实现,也就是主函数,整个代码的操作逻辑
🐖contact.c
的作用:写通讯录的实现(通讯录代码函数实现)
🐖contact.h
的作用:写通讯录的声明(通讯录代码函数声明)
contact.h
中放通讯录的声明,在test.c
和contact.c
的文件都要应用该声明,所以为什们我们不把#include
这些头文件也放到声明里,我们就不需要在test.c
和contact.c
的文件重复定义了,那么怎么在在test.c
和contact.c
的文件中引用contact.h
文件呢,include"contact.h"
,这样在contact.h
中存放的声明都可以使用。对于通讯录需要存放100个人的信息,每个人的信息包括(姓名,性别,电话,年龄,住址)
而且通讯录还要有以下功能,
🐶 (1)增加联系人
🐶 (2)删除指定联系人
🐶 (3)修改指定联系人
🐶 (4)查找指定联系人
🐶 (5)排序
🐶 (6)显示通讯录的信息
对于通讯录不可能看完做完一个操作就不做了,所以应该写一个循环,能够选择要进行的操作,等操作做完,想要退出循环也是可以的,我们又知道,这个操作至少要进行一次,所以我们学过的循环发现只有
do-while()
循环可以用了,但对于通讯录来说他有很多操作,所以要用switch,case
语句选择操作,但是又发现case
后面只能跟整型表达式;所以要用一个菜单函数将这些操作与整型数字联系起来,比如在菜单函数中规定1-就是增加联系人,当switch
选择1时就是增加联系人,
还需要注意一个点,也是在设计最巧妙的一个点,设置0
的时候退出程序,在case
后整型是0的时候break
,然后到while()
循环用0
,就可以跳出循环,因为0
为假。
在test.c 文件中写这个主函数
#include
void menu()
{printf("***********************************\n");printf("****1-增加联系人 2-删除联系人****\n");printf("****3-修改联系人 4-查找联系人****\n");printf("****5-排序 6-显示通讯录****\n");printf("**** 0-退出程序 ****\n");printf("***********************************\n");
}
int main()
{int input = 0;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);return 0;
}
contact.h
文件。//创建一个结构体,表示一个人的信息
struct PeoInf
{char name[20];char sex[20];char tele[12];int age;char addr[30];
};
struct PeoInf data[100];
这样就创建了可以存放100个人信息的通讯录。int sz;
来表示通讯录中有几个人的信息,所以将这两个内容再封装成一个结构体。代码如下,因为这是封装一个通讯录结构体,所以也放在contact.h
文件中。有了通讯录的结构体,我们就可以在主函数中创建一个通讯录。
对于创建好了通讯录,对于通讯录的内容,应该先初始化,之后才可以进行修改。下面就要进行通讯录的初始化,注意他是传的是地址,不可以传值,如果传值,他是形参的一份临时拷贝,不会改变原本的参数,也就不能初始化。
void InitContact(struct Contact* pc)
{//防止是空指针,用断言函数assert(pc);pc->sz = 0;memset(pc->data, 0, 100 * sizeof(struct PeoInf));
}
代码实现,在代码中用注释解释,看完代码相信你就能理解了
//增加通讯录
void AddContact(struct Contact* pc)
{//防止是空指针,用断言函数assert(pc);//判断通讯录的信息满了没有,就是看sz的大小//if (pc->sz == 100)//我们发现这个100,我们一直再用,可以直接用define定义MAX=100//这时我们可以把通讯录中人的信息也用define定义if(pc -> sz == MAX){printf("通讯录已满,无法增加数据\n"); return;//因为通讯录已经放不下了,应该退出函数,对于这//个函数的返回值是void,所以不需要返回任何东西}else{printf("请输入名字:>");scanf("%s", pc->data[pc->sz].name);printf("请输入性别:>");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话:>");scanf("%s", pc->data[pc->sz].tele); printf("请输入年龄:>");scanf("%s", &(pc->data[pc->sz].age));printf("请输入地址:>");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("成功增加联系人\n");}
}
跟增加通讯录一样,在注释中解释为什们要这么写
//显示通讯录的信息
void ShowContact(const struct Contact* pc)
{int i = 0;for (i = 0; i < pc->sz; i++){printf("%s %s %s %d %s\n", pc->data[i].name,pc->data[i].sex,pc->data[i].tele,pc->data[i].age,pc->data[i].addr);}
}
上图,是我用上面的代码增加了三个人的信息然后查看,发现他们乱七八糟,每一个都没有一一对齐,连一个表头都没有,所以我们就要将这些代码对齐然后,在创建一个表头,请看下面代码。
//显示通讯录的信息
void ShowContact(const struct Contact* pc)
{int i = 0;printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");for (i = 0; i < pc->sz; i++){printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,pc->data[i].sex,pc->data[i].tele,pc->data[i].age,pc->data[i].addr);}
}
跟增加通讯录一样,在注释中解释为什们要这么写
}
//查找函数,通过名字找到这个人
int Findname(const struct Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (0 == strcmp(pc->data[i].name, name)){return i;}}return -1;}
//删除通讯录
void DelContact(struct Contact* pc)
{char name[NAME];printf("请输入删除人的名字:>");scanf("%s", name);//查找一下指定的人是否存在//就构造一个函数int ret = Findname(pc, name);if (ret == -1){printf("要删除的人不存在\n");}else{//删除int j = 0;for (j = ret; j < pc->sz - 1 ; j++){pc->data[j] = pc->data[j + 1];}pc->sz--;printf("成功删除联系人\n");}
}
跟增加通讯录一样,在注释中解释为什们要这么写
//查找指定联系人
void SerchContact(const struct Contact* pc)
{//跟上面删除操作一样,只不过将删除变为查找char name[NAME];printf("请输入查找联系人的名字:>");scanf("%s", name);//查找一下查找的人是否存在//就会用上面的函数int ret = Findname(pc, name);if (ret == -1){printf("要查找的人不存在\n");}else{//查找联系人,找到就打印出来printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,pc->data[ret].sex,pc->data[ret].tele,pc->data[ret].age,pc->data[ret].addr);}
修改通讯录,就是先找到要修改的信息位置,然后再像增加通讯录一样重新录入一遍信息。
//修改指定联系人
void ModifyContact(struct Contact* pc)
{printf("请输入修改人的信息:>");char name[NAME];scanf("%s", name);int ret = Findname(pc, name);if (ret == -1){printf("要查找的人不存在\n");}else{//修改//就相当于重新录入信息printf("请输入名字:>");scanf("%s", pc->data[ret].name);printf("请输入性别:>");scanf("%s", pc->data[ret].sex);printf("请输入电话:>");scanf("%s", pc->data[ret].tele);printf("请输入年龄:>");scanf("%d", &(pc->data[ret].age));printf("请输入地址:>");scanf("%s", pc->data[ret].addr);printf("修改成功\n");}
}
要排序通讯录,就要学会使用qsort(可以在这个地方查找信息),我也写过一遍文章介绍这么用去sort函数《用冒泡排序模拟qsort库函数》,可以参考一下
下面代码是按年龄排序的,只要你将排序函数改一下内容就行了
//比较
int CmpByAge(const void* e1, const void* e2)
{return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//按照年龄来排序
void SortContact(struct Contact* pc)
{//用qsort排序qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
}
我们将每个函数都写完了,但是运行起来需要在主函数中将这些函数串联起来,因此可以看下面的主函数的代码。
int main()
{//创建一个通讯录struct Contact con;//初始化通讯录InitContact(&con);int input = 0;do{menu();printf("请选择操作->");scanf("%d", &input);switch(input){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:ModifyContact(&con);break;case 4:SerchContact(&con);break;case 5:SortContact(&con);break;case 6:ShowContact(&con);break;case 0:printf("退出程序\n");break;default:printf("输入错误,请重新输入\n");break;}} while (input);return 0;
}
这样通讯录就写完了,看一看各各文件的代码吧
test.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("**** 0-退出程序 ****\n");printf("***********************************\n");
}
int main()
{//创建一个通讯录struct Contact con;//初始化通讯录InitContact(&con);int input = 0;do{menu();printf("请选择操作->");scanf("%d", &input);switch(input){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:ModifyContact(&con);break;case 4:SerchContact(&con);break;case 5:SortContact(&con);break;case 6:ShowContact(&con);break;case 0:printf("退出程序\n");break;default:printf("输入错误,请重新输入\n");break;}} while (input);return 0;
}
contact.h
#pragma once
#include
#include
#define MAX 100
#define NAME 20
#define SEX 20
#define TELE 12
#define ADDR 30
#include
#include
struct PeoInfo
{char name[NAME];char sex[SEX];char tele[TELE];int age;char addr[ADDR];
};
//通讯录
struct Contact
{struct PeoInfo data[MAX];int sz ;
};
//初始化通讯录
void InitContact(struct Contact* pc);
//增加通讯录的信息
void AddContact(struct Contact* pc);
//显示通讯录的信息
void ShowContact(const struct Contact* pc);
//删除通讯录的信息
void DelContact(struct Contact *pc);
//查找指定联系人
void SerchContact(const struct Contact* pc);
//修改指定联系人
void ModifyContact(struct Contact* pc);
//排序通讯录-按照年龄
void SortContact(struct Constact* pc);
contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"void InitContact(struct Contact* pc)
{//防止是空指针,用断言函数assert(pc);pc->sz = 0;memset(pc->data, 0, 100 * sizeof(struct PeoInfo));
}
//增加通讯录
void AddContact(struct Contact* pc)
{//防止是空指针,用断言函数assert(pc);//判断通讯录的信息满了没有,就是看sz的大小//if (pc->sz == 100)//我们发现这个100,我们一直再用,可以直接用define定义MAX=100//这时我们可以把通讯录中人的信息也用define定义if(pc -> sz == MAX){printf("通讯录已满,无法增加数据\n"); return;//因为通讯录已经放不下了,应该退出函数,对于这//个函数的返回值是void,所以不需要返回任何东西}else{printf("请输入名字:>");scanf("%s", pc->data[pc->sz].name);printf("请输入性别:>");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话:>");scanf("%s", pc->data[pc->sz].tele); printf("请输入年龄:>");scanf("%d", &(pc->data[pc->sz].age));printf("请输入地址:>");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("成功增加联系人\n");}
}
//显示通讯录的信息
void ShowContact(const struct Contact* pc)
{int i = 0;printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");for (i = 0; i < pc->sz; i++){printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,pc->data[i].sex,pc->data[i].tele,pc->data[i].age,pc->data[i].addr);}
}
//查找函数,通过名字找到这个人
static int Findname(const struct Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (0 == strcmp(pc->data[i].name, name)){return i;}}return -1;}
//删除通讯录
void DelContact(struct Contact* pc)
{char name[NAME];printf("请输入删除人的名字:>");scanf("%s", name);//查找一下指定的人是否存在//就构造一个函数int ret = Findname(pc, name);if (ret == -1){printf("要删除的人不存在\n");}else{//删除int j = 0;for (j = ret; j < pc->sz - 1 ; j++){pc->data[j] = pc->data[j + 1];}pc->sz--;printf("成功删除联系人\n");}
}
//查找指定联系人
void SerchContact(const struct Contact* pc)
{//跟上面删除操作一样,只不过将删除变为查找char name[NAME];printf("请输入查找联系人的名字:>");scanf("%s", name);//查找一下查找的人是否存在//就会用上面的函数int ret = Findname(pc, name);if (ret == -1){printf("要查找的人不存在\n");}else{//查找联系人,找到就打印出来printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,pc->data[ret].sex,pc->data[ret].tele,pc->data[ret].age,pc->data[ret].addr);}
}
//修改指定联系人
void ModifyContact(struct Contact* pc)
{printf("请输入修改人的信息:>");char name[NAME];scanf("%s", name);int ret = Findname(pc, name);if (ret == -1){printf("要查找的人不存在\n");}else{//修改//就相当于重新录入信息printf("请输入名字:>");scanf("%s", pc->data[ret].name);printf("请输入性别:>");scanf("%s", pc->data[ret].sex);printf("请输入电话:>");scanf("%s", pc->data[ret].tele);printf("请输入年龄:>");scanf("%d", &(pc->data[ret].age));printf("请输入地址:>");scanf("%s", pc->data[ret].addr);printf("修改成功\n");}
}
//比较
int CmpByAge(const void* e1, const void* e2)
{return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//按照年龄来排序
void SortContact(struct Contact* pc)
{//用qsort排序qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
}
主要运用动态内存开辟的知识,不会的同学可以看看《动态内存管理(malloc free calloc realloc)》
malloc
存放3个人空间,存放满了后,在用realloc
增加两个人的空间,这样就更加灵活,并且不会浪费空间。malloc
创建的空间用void*
指针来接收,所以将data[]
变为指针,并且在多增加一个参数,容量参数capacity
,当sz
和capacity
相同时,增加2个空间。所以🐖
//通讯录
struct Contact
{struct PeoInfo *data ;int sz;int capacity;
};
初始化通讯录,用
malloc
申请3个结构体的空间
void InitContact(struct Contact* pc)
{//防止是空指针,用断言函数assert(pc);pc->data = (struct PeoInfo*)malloc(sizeof(struct PeoInfo) * 3);if (pc == NULL){peeor("InitContact");return;}else{pc -> sz = 0;//pc->capacity = 3;//我们发现这个3,我们一直再用,可以直接用define定义Capacity = 3//这时我们可以把通讯录中人的信息也用define定义pc->capacity = CAPATICY;}
}
对于增加那用不用改呢,答案是用的,因为当空间不够的时候就需要增加空间。
int check_capacity(struct Contact* pc)
{if (pc->sz == pc->capacity){//当前容量满了,现在用realloc增加容量struct PeoInfo* str = (struct PeoInfo*)relloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));if (str == NULL){printf("空间申请失败\n");return 0;}else{pc->data = str;//将申请的空间传给pc->data pc->capacity = pc->capacity + 2;//将容量变大2.printf("增容成功\n");return 1;}}return 1;
}//增加通讯录
void AddContact(struct Contact* pc)
{//防止是空指针,用断言函数assert(pc);//判断通讯录的信息满了没有,就是看sz的大小//if (pc->sz == 100)//我们发现这个100,我们一直再用,可以直接用define定义MAX=100//这时我们可以把通讯录中人的信息也用define定义//我们可以封装一个函数来判断他是否需要增容int ret = check_capacity(pc);if (ret == 1){printf("请输入名字:>");scanf("%s", pc->data[pc->sz].name);printf("请输入性别:>");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话:>");scanf("%s", pc->data[pc->sz].tele);printf("请输入年龄:>");scanf("%d", &(pc->data[pc->sz].age));printf("请输入地址:>");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("成功增加联系人\n");}else{return;}
}
我们知道
calloc
和free
是同时出现的,申请了空间,就肯定要销毁空间,所以在退出函数就可以添加一个函数,销毁函数。
void DistoryContact(struct Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;
}
动态开辟内存还是相对与来说比较简单的,希望大家先将动态内存的知识看懂,再将动态通讯录来练习学会。
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#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("**** 0-退出程序 ****\n");printf("***********************************\n");
}
int main()
{//创建一个通讯录struct Contact con;//初始化通讯录InitContact(&con);int input = 0;do{menu();printf("请选择操作->");scanf("%d", &input);switch (input){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:ModifyContact(&con);break;case 4:SerchContact(&con);break;case 5:SortContact(&con);break;case 6:ShowContact(&con);break;case 0:DistoryContact(&con);printf("退出程序\n");break;default:printf("输入错误,请重新输入\n");break;}} while (input);return 0;
}
contact.h
#pragma once
#pragma once
#include
#include
#define MAX 100
#define NAME 20
#define SEX 20
#define TELE 12
#define ADDR 30
#include
#include
#define CAPATICY 3
struct PeoInfo
{char name[NAME];char sex[SEX];char tele[TELE];int age;char addr[ADDR];
};
//通讯录
struct Contact
{struct PeoInfo *data ;int sz;int capacity;
};
//初始化通讯录
void InitContact(struct Contact* pc);
//增加通讯录的信息
void AddContact(struct Contact* pc);
//显示通讯录的信息
void ShowContact(const struct Contact* pc);
//删除通讯录的信息
void DelContact(struct Contact* pc);
//查找指定联系人
void SerchContact(const struct Contact* pc);
//修改指定联系人
void ModifyContact(struct Contact* pc);
//排序通讯录-按照年龄
void SortContact(struct Contact* pc);
//销毁通讯录
void DistoryContact(struct Contact*pc);
contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"void InitContact(struct Contact* pc)
{//防止是空指针,用断言函数assert(pc);pc->data = (struct PeoInfo*)malloc(sizeof(struct PeoInfo) * 3);if (pc == NULL){perror("InitContact");return;}else{pc -> sz = 0;//pc->capacity = 3;//我们发现这个3,我们一直再用,可以直接用define定义Capacity = 3//这时我们可以把通讯录中人的信息也用define定义pc->capacity = CAPATICY;}
}
int check_capacity(struct Contact* pc)
{if (pc->sz == pc->capacity){//当前容量满了,现在用realloc增加容量struct PeoInfo* str = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));if (str == NULL){printf("空间申请失败\n");return 0;}else{pc->data = str;//将申请的空间传给pc->data pc->capacity = pc->capacity + 2;//将容量变大2.printf("增容成功\n");return 1;}}return 1;
}//增加通讯录
void AddContact(struct Contact* pc)
{//防止是空指针,用断言函数assert(pc);//判断通讯录的信息满了没有,就是看sz的大小//if (pc->sz == 100)//我们发现这个100,我们一直再用,可以直接用define定义MAX=100//这时我们可以把通讯录中人的信息也用define定义//我们可以封装一个函数来判断他是否需要增容int ret = check_capacity(pc);if (ret == 1){printf("请输入名字:>");scanf("%s", pc->data[pc->sz].name);printf("请输入性别:>");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话:>");scanf("%s", pc->data[pc->sz].tele);printf("请输入年龄:>");scanf("%d", &(pc->data[pc->sz].age));printf("请输入地址:>");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("成功增加联系人\n");}else{return;}
}
//显示通讯录的信息
void ShowContact(const struct Contact* pc)
{int i = 0;printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");for (i = 0; i < pc->sz; i++){printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,pc->data[i].sex,pc->data[i].tele,pc->data[i].age,pc->data[i].addr);}
}
//查找函数,通过名字找到这个人
static int Findname(const struct Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (0 == strcmp(pc->data[i].name, name)){return i;}}return -1;}
//删除通讯录
void DelContact(struct Contact* pc)
{char name[NAME];printf("请输入删除人的名字:>");scanf("%s", name);//查找一下指定的人是否存在//就构造一个函数int ret = Findname(pc, name);if (ret == -1){printf("要删除的人不存在\n");}else{//删除int j = 0;for (j = ret; j < pc->sz - 1; j++){pc->data[j] = pc->data[j + 1];}pc->sz--;printf("成功删除联系人\n");}
}
//查找指定联系人
void SerchContact(const struct Contact* pc)
{//跟上面删除操作一样,只不过将删除变为查找char name[NAME];printf("请输入查找联系人的名字:>");scanf("%s", name);//查找一下查找的人是否存在//就会用上面的函数int ret = Findname(pc, name);if (ret == -1){printf("要查找的人不存在\n");}else{//查找联系人,找到就打印出来printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,pc->data[ret].sex,pc->data[ret].tele,pc->data[ret].age,pc->data[ret].addr);}
}
//修改指定联系人
void ModifyContact(struct Contact* pc)
{printf("请输入修改人的信息:>");char name[NAME];scanf("%s", name);int ret = Findname(pc, name);if (ret == -1){printf("要查找的人不存在\n");}else{//修改//就相当于重新录入信息printf("请输入名字:>");scanf("%s", pc->data[ret].name);printf("请输入性别:>");scanf("%s", pc->data[ret].sex);printf("请输入电话:>");scanf("%s", pc->data[ret].tele);printf("请输入年龄:>");scanf("%d", &(pc->data[ret].age));printf("请输入地址:>");scanf("%s", pc->data[ret].addr);printf("修改成功\n");}
}
//比较
int CmpByAge(const void* e1, const void* e2)
{return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//按照年龄来排序
void SortContact(struct Contact* pc)
{//用qsort排序qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
}
void DistoryContact(struct Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;
}
主要运用文件操作的知识,不会的同学可以看看《C的文件操作》
首先我们要实现这个需求,在退出之前,保存通讯录。
//保存通讯录
void SaveContact(struct Contact* pc)
{//打开文件,用二进制的方式写FILE* tt = fopen("Contact.txt", "wb");//判断是否为空指针if (tt == NULL){perror("SaveContact:fopen");return;}//可以写了for (int i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(struct PeoInfo), 1, tt);}//关闭文件fclose(tt);tt = NULL;return 0;
}
⭐将通讯录保存了,但是在打开通讯录的时候,需要能够读取文件的信息,但是这个操作在哪进行呀,我们可以在初始化通讯录的时候进行读取文件的信息操作。
static int check_capacity(struct Contact* pc);void loadContact(struct Contact* pc)
{//打开文件FILE* tt = fopen("Contact.txt", "rb");if (tt == NULL){perror("loadContact:fopen");return;}//读文件//创建一个临时结构体,当中介struct PeoInfo tmp = { 0 };//因为这是动态版本,可能涉及到增容问题//用他的返回值看,读取失败返回0;while (fread(&tmp, sizeof(struct PeoInfo), 1, tt)){//考虑增容问题check_capacity(pc);pc->data[pc->sz] = tmp;pc->sz++;}//关闭文件
}
test.c
文件的代码其实大致无差,就是多了这个功能,为了以防万一还是放在这里了。欢迎大家食用。
#define _CRT_SECURE_NO_WARNINGS 1
#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("**** 0-退出程序 ****\n");printf("***********************************\n");
}
int main()
{//创建一个通讯录struct Contact con;//初始化通讯录InitContact(&con);int input = 0;do{menu();printf("请选择操作->");scanf("%d", &input);switch (input){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:ModifyContact(&con);break;case 4:SerchContact(&con);break;case 5:SortContact(&con);break;case 6:ShowContact(&con);break;case 0:SaveContact(&con);DistoryContact(&con);printf("退出程序\n");break;default:printf("输入错误,请重新输入\n");break;}} while (input);return 0;
}
contact.h
#pragma once
#pragma once
#include
#include
#define MAX 100
#define NAME 20
#define SEX 20
#define TELE 12
#define ADDR 30
#include
#include
#define CAPATICY 3
struct PeoInfo
{char name[NAME];char sex[SEX];char tele[TELE];int age;char addr[ADDR];
};
//通讯录
struct Contact
{struct PeoInfo *data ;int sz;int capacity;
};
//初始化通讯录
void InitContact(struct Contact* pc);
//增加通讯录的信息
void AddContact(struct Contact* pc);
//显示通讯录的信息
void ShowContact(const struct Contact* pc);
//删除通讯录的信息
void DelContact(struct Contact* pc);
//查找指定联系人
void SerchContact(const struct Contact* pc);
//修改指定联系人
void ModifyContact(struct Contact* pc);
//排序通讯录-按照年龄
void SortContact(struct Contact* pc);
//销毁通讯录
void DistoryContact(struct Contact*pc);
//保存通讯录
void SaveContact(struct Contact* pc);
contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
static int check_capacity(struct Contact* pc);void loadContact(struct Contact* pc)
{//打开文件FILE* tt = fopen("Contact.txt", "rb");if (tt == NULL){perror("loadContact:fopen");return;}//读文件//创建一个临时结构体,当中介struct PeoInfo tmp = { 0 };//因为这是动态版本,可能涉及到增容问题//用他的返回值看,读取失败返回0;while (fread(&tmp, sizeof(struct PeoInfo), 1, tt)){//考虑增容问题check_capacity(pc);pc->data[pc->sz] = tmp;pc->sz++;}//关闭文件
}
void InitContact(struct Contact* pc)
{//防止是空指针,用断言函数assert(pc);pc->data = (struct PeoInfo*)malloc(sizeof(struct PeoInfo) * 3);if (pc == NULL){perror("InitContact");return;}else{pc -> sz = 0;//pc->capacity = 3;//我们发现这个3,我们一直再用,可以直接用define定义Capacity = 3//这时我们可以把通讯录中人的信息也用define定义pc->capacity = CAPATICY;}//加载通讯录,让文件的信息加载到通讯录loadContact(pc);
}
static int check_capacity(struct Contact* pc)
{if (pc->sz == pc->capacity){//当前容量满了,现在用realloc增加容量struct PeoInfo* str = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));if (str == NULL){printf("空间申请失败\n");return 0;}else{pc->data = str;//将申请的空间传给pc->data pc->capacity = pc->capacity + 2;//将容量变大2.printf("增容成功\n");return 1;}}return 1;
}//增加通讯录
void AddContact(struct Contact* pc)
{//防止是空指针,用断言函数assert(pc);//判断通讯录的信息满了没有,就是看sz的大小//if (pc->sz == 100)//我们发现这个100,我们一直再用,可以直接用define定义MAX=100//这时我们可以把通讯录中人的信息也用define定义//我们可以封装一个函数来判断他是否需要增容int ret = check_capacity(pc);if (ret == 1){printf("请输入名字:>");scanf("%s", pc->data[pc->sz].name);printf("请输入性别:>");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话:>");scanf("%s", pc->data[pc->sz].tele);printf("请输入年龄:>");scanf("%d", &(pc->data[pc->sz].age));printf("请输入地址:>");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("成功增加联系人\n");}else{return;}
}
//显示通讯录的信息
void ShowContact(const struct Contact* pc)
{int i = 0;printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");for (i = 0; i < pc->sz; i++){printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,pc->data[i].sex,pc->data[i].tele,pc->data[i].age,pc->data[i].addr);}
}
//查找函数,通过名字找到这个人
static int Findname(const struct Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (0 == strcmp(pc->data[i].name, name)){return i;}}return -1;}
//删除通讯录
void DelContact(struct Contact* pc)
{char name[NAME];printf("请输入删除人的名字:>");scanf("%s", name);//查找一下指定的人是否存在//就构造一个函数int ret = Findname(pc, name);if (ret == -1){printf("要删除的人不存在\n");}else{//删除int j = 0;for (j = ret; j < pc->sz - 1; j++){pc->data[j] = pc->data[j + 1];}pc->sz--;printf("成功删除联系人\n");}
}
//查找指定联系人
void SerchContact(const struct Contact* pc)
{//跟上面删除操作一样,只不过将删除变为查找char name[NAME];printf("请输入查找联系人的名字:>");scanf("%s", name);//查找一下查找的人是否存在//就会用上面的函数int ret = Findname(pc, name);if (ret == -1){printf("要查找的人不存在\n");}else{//查找联系人,找到就打印出来printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,pc->data[ret].sex,pc->data[ret].tele,pc->data[ret].age,pc->data[ret].addr);}
}
//修改指定联系人
void ModifyContact(struct Contact* pc)
{printf("请输入修改人的信息:>");char name[NAME];scanf("%s", name);int ret = Findname(pc, name);if (ret == -1){printf("要查找的人不存在\n");}else{//修改//就相当于重新录入信息printf("请输入名字:>");scanf("%s", pc->data[ret].name);printf("请输入性别:>");scanf("%s", pc->data[ret].sex);printf("请输入电话:>");scanf("%s", pc->data[ret].tele);printf("请输入年龄:>");scanf("%d", &(pc->data[ret].age));printf("请输入地址:>");scanf("%s", pc->data[ret].addr);printf("修改成功\n");}
}
//比较
int CmpByAge(const void* e1, const void* e2)
{return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//按照年龄来排序
void SortContact(struct Contact* pc)
{//用qsort排序qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
}
void DistoryContact(struct Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;
}//保存通讯录
void SaveContact(struct Contact* pc)
{//打开文件,用二进制的方式写FILE* tt = fopen("Contact.txt", "wb");//判断是否为空指针if (tt == NULL){perror("SaveContact:fopen");return;}//可以写了for (int i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(struct PeoInfo), 1, tt);}//关闭文件fclose(tt);tt = NULL;return 0;
}
⭐我们现在就将三种形式的通讯录写完了,相信大家肯定或多多少都有点收获,如果大家不太理解,可以私信我,看到必会,如果对大家有点帮助,希望大家一键三联,这将是我的动力。欢迎大家食用。😊😊
下一篇:【Linux练习生】线程池