温馨提示:这篇文章已超过470天没有更新,请注意相关的内容是否还可用!
摘要:,,本文介绍了C语言中通讯录的实现,包括静态版、动态版和文件版三种方式。静态版实现简单,但功能受限;动态版则通过动态内存分配实现通讯录的灵活管理。文件版则实现了通讯录数据的持久化存储和读取,提高了程序的实用性和便捷性。本文详细阐述了各种实现方式的原理、代码实现及注意事项,为读者提供了通讯录程序开发的参考。
个人主页(找往期文章包括但不限于本期文章中不懂的知识点): 我要学编程(ಥ_ಥ)-CSDN博客
目录
静态通讯录的实现逻辑
test.c:通讯录的逻辑实现
Contact.h:函数的声明与头文件的包含
Contact.c:函数的实现
通讯录源码:
test.c:
Contact.c:
Contect.h:
动态版通讯录
test.c:
Contact.h:
Contact.c:
动态通讯录(文件版)
test.c:
Contact.h:
Contact.c:
静态通讯录的实现逻辑
test.c:通讯录的逻辑实现
我们今天就一起来用c语言写一个通讯录的小程序。
这个通讯录可以实现存储100个联系人。
首先,我们进去这个通讯录,肯定得有一些基本的功能。如下图:
这个就和我们在前面写游戏的时候是一样的。
void menu() { printf("******************************************\n"); printf("**** 1.增加联系人 2.删除联系人 ****\n"); printf("**** 3.查找联系人 4.修改联系人 ****\n"); printf("**** 5.显示联系人 6.排序联系人 ****\n"); printf("**** 0.退出通讯录 ****\n"); printf("******************************************\n"); }
打印出界面之后,我们就得根据需求来进行选择。
void test() { int input = 0; //下面是对通讯录进行的各种操作,所以我们得先有一个通讯录 //创建一个通讯录,包含一个人的各种信息,是一个复杂对象,用结构体来描述 Contact con; InitContact(&con);//初始化通讯录 do { menu();//打印基本功能 printf("请选择:"); scanf("%d", &input); switch (input) { case 1: AddContact(&con);//增加联系人的信息 break; case 2: DelContact(&con);//删除联系人的信息 break; case 3: SearchContact(&con);//查找联系人的信息 break; case 4: ModifyContact(&con);//修改联系人的信息 break; case 5: ShowContact(&con);//显示联系人的信息 break; case 6: SortContact(&con);//排序联系人 break; case 0: printf("退出通讯录\n"); break; default: printf("选择错误,请重新选择\n"); break; } } while (input); }
为了让别人能够更清楚我们代码的功能,我们最好能把那些case后面的数字,改成ADD这些能够让别人一下就能够看懂。我们就可以联想到联合体。自定义类型:联合和枚举-CSDN博客
上面这篇博客,有关于联合体的知识。
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 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); }
可以把test函数在main函数里调用。
#include "Contact.h" int main() { test(); return 0; }
写完这些基本的功能之后,就可以开始实现这些编辑通讯录的函数了。上面这些都是放在test.c函数(实现通讯录的基本逻辑)。
Contact.h:函数的声明与头文件的包含
这些函数的声明和头文件的声明,我们都可以放在一个Contact.h的头文件中。
头文件的声明:
//头文件的声明 #include #include #include #include
联合体的创建:
//把选项一 一列举出来 enum OPPION { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT };
通讯录准备:
//为后期增加联系人做准备 #define MAX 100 #define MAX_NAME 20 #define MAX_SEX 5 #define MAX_TELE 12 #define MAX_ADDR 30 //类型的声明 typedef struct people { char name[MAX_NAME];//姓名 int age;//年龄 char sex[MAX_SEX];//性别 //电话(我们正常的电话是11位,超过了int的范围,所以用字符串比较合适) char tele[MAX_TELE]; char addr[MAX_ADDR];//住址 }people; //通讯录的创建 typedef struct Contact { people data[MAX]; int sz;//记录当前通讯录的人数 }Contact;
函数的声明:
//初始化通讯录的函数的声明 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); //排序联系人 void SortContact(const Contact* pc);
Contact.c:函数的实现
初始化通讯录函数:
#include "Contact.h"//声明头文件 //初始化通讯录的函数 void InitContact(Contact* pc) { assert(pc); //把pc->data的空间全部初始化为0 memset(pc->data, 0, sizeof(pc->data));//循环也可以,但是太麻烦。 pc->sz = 0; }
增加联系人信息的函数:
//增加联系人信息的函数 void AddContact(Contact* pc) { assert(pc); //首先得判断这个通讯录是否已经满了 if (pc->sz == MAX) { printf("通讯录已满,无法增加\n"); //通讯录满了,就无需执行下面的语句了 return;//因为是void。所以无需返回任何值 } else { printf("请输入姓名:"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:"); scanf("%d", &(pc->data[pc->sz].age));//age是int类型 printf("请输入性别:"); scanf("%s", pc->data[pc->sz].sex); printf("请输入电话:"); scanf("%s", pc->data[pc->sz].tele); printf("请输入住址:"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("成功增加联系人\n"); } }
显示联系人的信息的函数:
//显示联系人的信息的函数 void ShowContact(const Contact* pc) { assert(pc); //要有一定的排版(采用左对齐) printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); for (int i = 0; i sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } }
删除联系人信息的函数的声明:
//删除联系人信息的函数的声明 void DelContact(Contact* pc) { assert(pc); //判断是否能删除 if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); return; } //创建一个name数组来存放我们要寻找的联系人 char name[MAX_NAME] = { 0 }; //知道要删除谁 printf("请输入要删除的人的名字:"); scanf("%s", name); //找到要删除的人(字符串) int del = 0; int flag = 0; //遍历数组,一个一个的比较字符串 for (int i = 0; i sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { del = i;//记录当前的位置 flag = 1; break; } } //开始删除(删除的方法就是把后面一个往前覆盖) if (flag == 0) { printf("要删除的联系人不存在\n"); return;//后面的代码无需执行 } else { for (int i = del; i sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } } //删除最后一个元素时,虽然不能在循环中删除,但是pc->sz--了,致使访问不到最后一个元素了 //因此,我们在打印时也不会打印出来 pc->sz--; printf("删除成功\n"); }
其实我们会发现在这里寻找名字的时候,在后面查找联系人也会用到,不如我们直接分装成一个寻找名字的函数。
//查找联系人名字的函数 //这个函数我们只想在内部使用,没必要暴露给别人 static int FindByName(const Contact* pc, char name[]) { assert(pc); for (int i = 0; i sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i; } } return -1; }
那么上面的删除函数就可以改造成:
//删除联系人信息的函数的声明 void DelContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); return; } char name[MAX_NAME] = { 0 }; //知道要删除谁 printf("请输入要删除的人的名字:"); scanf("%s", name); //找到要删除的人(字符串) int del = FindByName(pc, name); if (del == -1) { printf("要删除的人不存在\n"); return; } for (int i = del; i sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } //删除最后一个元素时,虽然不能在循环中删除,但是pc->sz--了,致使访问不到最后一个元素了 //因此,我们在打印时也不会打印出来 pc->sz--; printf("删除成功\n"); }
查找指定联系人信息的函数:
//查找指定联系人信息的函数 void SearchContact(const Contact* pc) { assert(pc); //存放名字的数组 char name[MAX_NAME]; printf("请输入要查找的联系人:"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); return; } printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); }
修改指定联系人的信息:
void menu1() { printf("*******************************\n"); printf("**** 1.姓名 2.年龄 ****\n"); printf("**** 3.性别 4.电话 ****\n"); printf("**** 5.住址 ****\n"); printf("*******************************\n"); } //修改指定联系人的信息 void ModifyContact(Contact* pc) { assert(pc); //存放名字的数组 char name[MAX_NAME]; printf("请输入要修改的联系人:"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要修改的联系人不存在\n"); return; } menu1(); printf("请选择要修改的选项:"); int n = 0; scanf("%d", &n); switch (n) { case 1:printf("请输入姓名:"); scanf("%s", pc->data[pos].name); break; case 2:printf("请输入年龄:"); scanf("%d", &(pc->data[pos].age)); break; case 3:printf("请输入性别:"); scanf("%s", pc->data[pos].sex); break; case 4:printf("请输入电话:"); scanf("%s", pc->data[pos].tele); break; case 5:printf("请输入住址:"); scanf("%s", pc->data[pos].addr); break; } printf("修改成功\n"); //看看是否修改成功 printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); }
int cmp_peo_by_name(const void* e1, const void* e2) { return strcmp(((people*)e1)->name, ((people*)e2)->name); } int cmp_peo_by_age(const void* e1, const void* e2) { return ((people*)e1)->age - ((people*)e2)->age; } //排序联系人 void SortContact(const Contact* pc) { printf("请选择想要排的序:\n"); printf("********************************\n"); printf("***** 1.按照名字排序 ******\n"); printf("***** 2.按照年龄排序 ******\n"); printf("********************************\n"); int n = 0; printf("请选择:"); scanf("%d", &n); qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_name); qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_age); //看看是否排序成功 for (int i = 0; i sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } printf("排序成功\n"); }
通讯录源码:
test.c:
#include "Contact.h" void menu() { printf("******************************************\n"); printf("**** 1.增加联系人 2.删除联系人 ****\n"); printf("**** 3.查找联系人 4.修改联系人 ****\n"); printf("**** 5.显示联系人 6.排序联系人 ****\n"); printf("**** 0.退出通讯录 ****\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 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); } int main() { test(); return 0; }
Contact.c:
#include "Contact.h" //初始化通讯录的函数 void InitContact(Contact* pc) { assert(pc); memset(pc->data, 0, sizeof(pc->data));//循环也可以 pc->sz = 0; } //增加联系人信息的函数 void AddContact(Contact* pc) { assert(pc); if (pc->sz == MAX) { printf("通讯录已满,无法增加\n"); //通讯录满了,就无需执行下面的语句了 return;//因为是void。所以无需返回任何值 } else { printf("请输入姓名:"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入性别:"); scanf("%s", pc->data[pc->sz].sex); printf("请输入电话:"); scanf("%s", pc->data[pc->sz].tele); printf("请输入住址:"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("成功增加联系人\n"); } } //显示联系人的信息的函数 void ShowContact(const Contact* pc) { assert(pc); printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); for (int i = 0; i sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } } //查找联系人名字的函数 static int FindByName(const Contact* pc, char name[]) { assert(pc); for (int i = 0; i sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i; } } return -1; } //删除联系人信息的函数的声明 void DelContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); return; } char name[MAX_NAME] = { 0 }; //知道要删除谁 printf("请输入要删除的人的名字:"); scanf("%s", name); //找到要删除的人(字符串) int del = FindByName(pc, name); if (del == -1) { printf("要删除的人不存在\n"); return; } for (int i = del; i sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } //删除最后一个元素时,虽然不能在循环中删除,但是pc->sz--了,致使访问不到最后一个元素了 //因此,我们在打印时也不会打印出来 pc->sz--; printf("删除成功\n"); } //查找指定联系人信息的函数 void SearchContact(const Contact* pc) { assert(pc); char name[MAX_NAME]; printf("请输入要查找的联系人:"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); return; } printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } void menu1() { printf("*******************************\n"); printf("**** 1.姓名 2.年龄 ****\n"); printf("**** 3.性别 4.电话 ****\n"); printf("**** 5.住址 ****\n"); printf("*******************************\n"); } //修改指定联系人的信息 void ModifyContact(Contact* pc) { assert(pc); char name[MAX_NAME]; printf("请输入要修改的联系人:"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要修改的联系人不存在\n"); return; } menu1(); printf("请选择要修改的选项:"); int n = 0; scanf("%d", &n); switch (n) { case 1:printf("请输入姓名:"); scanf("%s", pc->data[pos].name); break; case 2:printf("请输入年龄:"); scanf("%d", &(pc->data[pos].age)); break; case 3:printf("请输入性别:"); scanf("%s", pc->data[pos].sex); break; case 4:printf("请输入电话:"); scanf("%s", pc->data[pos].tele); break; case 5:printf("请输入住址:"); scanf("%s", pc->data[pos].addr); break; } printf("修改成功\n"); printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } int cmp_peo_by_name(const void* e1, const void* e2) { return strcmp(((people*)e1)->name, ((people*)e2)->name); } int cmp_peo_by_age(const void* e1, const void* e2) { return ((people*)e1)->age - ((people*)e2)->age; } void SortContact(const Contact* pc) { printf("请选择想要排的序:\n"); printf("********************************\n"); printf("***** 1.按照名字排序 ******\n"); printf("***** 2.按照年龄排序 ******\n"); printf("********************************\n"); int n = 0; printf("请选择:"); scanf("%d", &n); qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_name); qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_age); for (int i = 0; i sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } printf("排序成功\n"); }
Contect.h:
//头文件的声明 #include #include #include #include //为后期增加联系人做准备 #define MAX 100 #define MAX_NAME 20 #define MAX_SEX 5 #define MAX_TELE 12 #define MAX_ADDR 30 //把选项一 一列举出来 enum OPPION { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; //类型的声明 typedef struct people { char name[MAX_NAME];//姓名 int age;//年龄 char sex[MAX_SEX];//性别 //电话(我们正常的电话是11位,超过了int的长度,所以用字符串比较合适) char tele[MAX_TELE]; char addr[MAX_ADDR];//住址 }people; //通讯录 typedef struct Contact { people data[MAX]; int sz; }Contact; //初始化通讯录的函数的声明 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); //按名字排序联系人 void SortContact(const Contact* pc);
动态版通讯录
有关动态内存开辟的知识点:动态内存管理-CSDN博客
上述是静态版的通讯录。
下面我们来实现一下动态版的通讯录。
目标:1. 可以实现储存通讯录人数不限。2. 默认可以放3个人的信息,如果不够,就每次增加2个人的信息(这样方便我们测试,也可以默认别的数,但数据太大,不好测试)。
首先,存放人信息的空间大小是不需要改变的,但是我们用的那个联系人数组要变成一个由malloc函数开辟的空间。其次,我们想要知道这个空间当前用了几个,还剩几个。记录用了几个,就可以用sz来记录,而还剩几个空间,就可以用count来记录一下。
//通讯录 typedef struct Contact { people* data;//指向通讯录的那块空间 int sz;//记录当前的联系人个数 int count;//记录总共开辟了多少空间 }Contact;
既然通讯录里的数据变了,那么我们的初始化函数也得变化。
//初始化通讯录的函数 void InitContact(Contact* pc) { assert(pc); //开辟一块空间给通讯录 pc->data = (people*)malloc(3 * sizeof(people)); if (pc->data == NULL)//空间开辟失败 { perror("InitContact"); return; } pc->sz = 0; pc->count = DEFAULT_SZ;//在头文件中定义一个宏,默认数据表示初始数据 }
容量变了,那我们增加联系人的函数也得发生变化。
static int CheckCount(Contact* pc)//判断是否需要增加空间 { if (pc->sz == pc->count) { people *ptr = (people*)realloc(pc->data, (pc->count + INC_SZ) * sizeof(people)); if (ptr == NULL) { perror("CheckCount"); return 0; } pc->data = ptr; pc->count += INC_SZ; printf("增容成功\n"); return 1; } return 1; } //增加联系人信息的函数 void AddContact(Contact* pc) { assert(pc); if (CheckCount(&pc) == 0)//增加失败就不需要往下走了 { return; } else { printf("请输入姓名:"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入性别:"); scanf("%s", pc->data[pc->sz].sex); printf("请输入电话:"); scanf("%s", pc->data[pc->sz].tele); printf("请输入住址:"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("成功增加联系人\n"); } }
删除,查找,显示,修改,排序这些就不需要更改了。
但我们还得在退出通讯录的时候,把动态开辟的内存给释放掉。
void DestroyContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->count = 0; pc->sz = 0; }
test.c:
#include "Contact.h" void menu() { printf("******************************************\n"); printf("**** 1.增加联系人 2.删除联系人 ****\n"); printf("**** 3.查找联系人 4.修改联系人 ****\n"); printf("**** 5.显示联系人 6.排序联系人 ****\n"); printf("**** 0.退出通讯录 ****\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 SEARCH: SearchContact(&con);//查找联系人的信息 break; case MODIFY: ModifyContact(&con);//修改联系人的信息 break; case SHOW: ShowContact(&con);//显示联系人的信息 break; case SORT: SortContact(&con);//按名字排序联系人 break; case EXIT: DestroyContact(&con);//销毁通讯录 printf("退出通讯录\n"); break; default:printf("选择错误,请重新选择\n"); break; } } while (input); } int main() { test(); return 0; }
Contact.h:
//头文件的声明 #include #include #include #include //为后期增加联系人做准备 #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 //把选项一 一列举出来 enum OPPION { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; //类型的声明 typedef struct people { char name[MAX_NAME];//姓名 int age;//年龄 char sex[MAX_SEX];//性别 //电话(我们正常的电话是11位,超过了int的长度,所以用字符串比较合适) char tele[MAX_TELE]; char addr[MAX_ADDR];//住址 }people; //通讯录 typedef struct Contact { people* data; int sz; int count; }Contact; //初始化通讯录的函数的声明 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); //按名字排序联系人 void SortContact(const Contact* pc); //销毁通讯录的函数 void DestroyContact(Contact* pc);
Contact.c:
#include "Contact.h" //初始化通讯录的函数 void InitContact(Contact* pc) { assert(pc); //开辟一块空间给通讯录 pc->data = (people*)malloc(3 * sizeof(people)); if (pc->data == NULL)//空间开辟失败 { perror("InitContact"); return; } pc->sz = 0; pc->count = DEFAULT_SZ; } static int CheckCount(Contact* pc)//判断是否需要增加空间 { if (pc->sz == pc->count) { people *ptr = (people*)realloc(pc->data, (pc->count + INC_SZ) * sizeof(people)); if (ptr == NULL) { perror("CheckCount"); return 0; } pc->data = ptr; pc->count += INC_SZ; printf("增容成功\n"); return 1; } return 1; } //增加联系人信息的函数 void AddContact(Contact* pc) { assert(pc); if (CheckCount(pc) == 0)//增加失败就不需要往下走了 { return; } else { printf("请输入姓名:"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入性别:"); scanf("%s", pc->data[pc->sz].sex); printf("请输入电话:"); scanf("%s", pc->data[pc->sz].tele); printf("请输入住址:"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("成功增加联系人\n"); } } //显示联系人的信息的函数 void ShowContact(const Contact* pc) { assert(pc); printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); for (int i = 0; i sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } } //查找联系人名字的函数 static int FindByName(const Contact* pc, char name[]) { assert(pc); for (int i = 0; i sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i; } } return -1; } //删除联系人信息的函数的声明 void DelContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); return; } char name[MAX_NAME] = { 0 }; //知道要删除谁 printf("请输入要删除的人的名字:"); scanf("%s", name); //找到要删除的人(字符串) int del = FindByName(pc, name); if (del == -1) { printf("要删除的人不存在\n"); return; } for (int i = del; i sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } //删除最后一个元素时,虽然不能在循环中删除,但是pc->sz--了,致使访问不到最后一个元素了 //因此,我们在打印时也不会打印出来 pc->sz--; printf("删除成功\n"); } //查找指定联系人信息的函数 void SearchContact(const Contact* pc) { assert(pc); char name[MAX_NAME]; printf("请输入要查找的联系人:"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); return; } printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } void menu1() { printf("*******************************\n"); printf("**** 1.姓名 2.年龄 ****\n"); printf("**** 3.性别 4.电话 ****\n"); printf("**** 5.住址 ****\n"); printf("*******************************\n"); } //修改指定联系人的信息 void ModifyContact(Contact* pc) { assert(pc); char name[MAX_NAME]; printf("请输入要修改的联系人:"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要修改的联系人不存在\n"); return; } menu1(); printf("请选择要修改的选项:"); int n = 0; scanf("%d", &n); switch (n) { case 1:printf("请输入姓名:"); scanf("%s", pc->data[pos].name); break; case 2:printf("请输入年龄:"); scanf("%d", &(pc->data[pos].age)); break; case 3:printf("请输入性别:"); scanf("%s", pc->data[pos].sex); break; case 4:printf("请输入电话:"); scanf("%s", pc->data[pos].tele); break; case 5:printf("请输入住址:"); scanf("%s", pc->data[pos].addr); break; } printf("修改成功\n"); printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } int cmp_peo_by_name(const void* e1, const void* e2) { return strcmp(((people*)e1)->name, ((people*)e2)->name); } int cmp_peo_by_age(const void* e1, const void* e2) { return ((people*)e1)->age - ((people*)e2)->age; } void SortContact(const Contact* pc) { printf("请选择想要排的序:\n"); printf("********************************\n"); printf("***** 1.按照名字排序 ******\n"); printf("***** 2.按照年龄排序 ******\n"); printf("********************************\n"); int n = 0; printf("请选择:"); scanf("%d", &n); qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_name); qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_age); for (int i = 0; i sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } printf("排序成功\n"); } void DestroyContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->count = 0; pc->sz = 0; }
动态通讯录(文件版)
有关文件的读写的知识点:C语言之文件操作(万字详解)-CSDN博客
上面是动态版的通讯录,可以实现空间不受限制。但是如果我们想要知道我们上一次是存放什么呢?那就得用文件来保存上一次的信息。我们应该是在销毁前保存。
void SaveContact(Contact* pc) { //打开文件 FILE* pf = fopen("data.txt", "wb"); if (pf == NULL) { perror("SaveContact"); return; } //写数据 for (int i = 0; i sz; i++) { fwrite(pc->data + i, sizeof(people), 1, pf); } //关闭文件 fclose(pf); pf = NULL; }
我们保存的信息是为了下一次打开的时候,可以直接查看到这些数据。那么我们在初始化通讯录的时候,就应该把数据放到通讯录里,如果我们要查看的话,就可以选择显示通讯录的信息即可。
void LoadContact(Contact* pc) { //把文件中的信息加载到通讯录中 FILE* pf = fopen("data.txt", "rb"); if (pf == NULL) { perror("LoadContact"); return; } //读文件 people tmp = {0}; while (fread(&tmp, sizeof(people), 1, pf))//读一个判断一个,当返回为0时,就说明已经读完了 { if (CheckCount(pc) == 0)//存放的时候,判断是否需要增加空间 { return; } pc->data[pc->sz] = tmp; pc->sz++; } //关闭文件 fclose(pf); pf = NULL; } //初始化通讯录的函数 void InitContact(Contact* pc) { assert(pc); //开辟一块空间给通讯录 pc->data = (people*)malloc(3 * sizeof(people)); if (pc->data == NULL)//空间开辟失败 { perror("InitContact"); return; } pc->sz = 0; pc->count = DEFAULT_SZ; //把文件中的信息加载到通讯录中 LoadContact(pc); }
test.c:
#include "Contact.h" void menu() { printf("******************************************\n"); printf("**** 1.增加联系人 2.删除联系人 ****\n"); printf("**** 3.查找联系人 4.修改联系人 ****\n"); printf("**** 5.显示联系人 6.排序联系人 ****\n"); printf("**** 0.退出通讯录 ****\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 SEARCH: SearchContact(&con);//查找联系人的信息 break; case MODIFY: ModifyContact(&con);//修改联系人的信息 break; case SHOW: ShowContact(&con);//显示联系人的信息 break; case SORT: SortContact(&con);//按名字排序联系人 break; case EXIT: SaveContact(&con);//把信息保存在文件里 DestroyContact(&con);//销毁通讯录 printf("退出通讯录\n"); break; default:printf("选择错误,请重新选择\n"); break; } } while (input); } int main() { test(); return 0; }
Contact.h:
//头文件的声明 #include #include #include #include //为后期增加联系人做准备 #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 //把选项一 一列举出来 enum OPPION { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; //类型的声明 typedef struct people { char name[MAX_NAME];//姓名 int age;//年龄 char sex[MAX_SEX];//性别 //电话(我们正常的电话是11位,超过了int的长度,所以用字符串比较合适) char tele[MAX_TELE]; char addr[MAX_ADDR];//住址 }people; //通讯录 typedef struct Contact { people* data; int sz; int count; }Contact; //初始化通讯录的函数的声明 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); //按名字排序联系人 void SortContact(const Contact* pc); //销毁通讯录的函数 void DestroyContact(Contact* pc); //加载通讯录的函数 void SaveContact(Contact* pc);
Contact.c:
#include "Contact.h" int CheckCount(Contact* pc); void LoadContact(Contact* pc) { //把文件中的信息加载到通讯录中 FILE* pf = fopen("data.txt", "rb"); if (pf == NULL) { perror("LoadContact"); return; } //读文件 people tmp = {0}; while (fread(&tmp, sizeof(people), 1, pf)) { if (CheckCount(pc) == 0) { return; } pc->data[pc->sz] = tmp; pc->sz++; } //关闭文件 fclose(pf); pf = NULL; } //初始化通讯录的函数 void InitContact(Contact* pc) { assert(pc); //开辟一块空间给通讯录 pc->data = (people*)malloc(3 * sizeof(people)); if (pc->data == NULL)//空间开辟失败 { perror("InitContact"); return; } pc->sz = 0; pc->count = DEFAULT_SZ; //把文件中的信息加载到通讯录中 LoadContact(pc); } static int CheckCount(Contact* pc)//判断是否需要增加空间 { if (pc->sz == pc->count) { people *ptr = (people*)realloc(pc->data, (pc->count + INC_SZ) * sizeof(people)); if (ptr == NULL) { perror("CheckCount"); return 0; } pc->data = ptr; pc->count += INC_SZ; printf("增容成功\n"); return 1; } return 1; } //增加联系人信息的函数 void AddContact(Contact* pc) { assert(pc); if (CheckCount(pc) == 0)//增加失败就不需要往下走了 { return; } else { printf("请输入姓名:"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入性别:"); scanf("%s", pc->data[pc->sz].sex); printf("请输入电话:"); scanf("%s", pc->data[pc->sz].tele); printf("请输入住址:"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("成功增加联系人\n"); } } //显示联系人的信息的函数 void ShowContact(const Contact* pc) { assert(pc); printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); for (int i = 0; i sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } } //查找联系人名字的函数 static int FindByName(const Contact* pc, char name[]) { assert(pc); for (int i = 0; i sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i; } } return -1; } //删除联系人信息的函数的声明 void DelContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法删除\n"); return; } char name[MAX_NAME] = { 0 }; //知道要删除谁 printf("请输入要删除的人的名字:"); scanf("%s", name); //找到要删除的人(字符串) int del = FindByName(pc, name); if (del == -1) { printf("要删除的人不存在\n"); return; } for (int i = del; i sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } //删除最后一个元素时,虽然不能在循环中删除,但是pc->sz--了,致使访问不到最后一个元素了 //因此,我们在打印时也不会打印出来 pc->sz--; printf("删除成功\n"); } //查找指定联系人信息的函数 void SearchContact(const Contact* pc) { assert(pc); char name[MAX_NAME]; printf("请输入要查找的联系人:"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); return; } printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } void menu1() { printf("*******************************\n"); printf("**** 1.姓名 2.年龄 ****\n"); printf("**** 3.性别 4.电话 ****\n"); printf("**** 5.住址 ****\n"); printf("*******************************\n"); } //修改指定联系人的信息 void ModifyContact(Contact* pc) { assert(pc); char name[MAX_NAME]; printf("请输入要修改的联系人:"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要修改的联系人不存在\n"); return; } menu1(); printf("请选择要修改的选项:"); int n = 0; scanf("%d", &n); switch (n) { case 1:printf("请输入姓名:"); scanf("%s", pc->data[pos].name); break; case 2:printf("请输入年龄:"); scanf("%d", &(pc->data[pos].age)); break; case 3:printf("请输入性别:"); scanf("%s", pc->data[pos].sex); break; case 4:printf("请输入电话:"); scanf("%s", pc->data[pos].tele); break; case 5:printf("请输入住址:"); scanf("%s", pc->data[pos].addr); break; } printf("修改成功\n"); printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } int cmp_peo_by_name(const void* e1, const void* e2) { return strcmp(((people*)e1)->name, ((people*)e2)->name); } int cmp_peo_by_age(const void* e1, const void* e2) { return ((people*)e1)->age - ((people*)e2)->age; } void SortContact(const Contact* pc) { printf("请选择想要排的序:\n"); printf("********************************\n"); printf("***** 1.按照名字排序 ******\n"); printf("***** 2.按照年龄排序 ******\n"); printf("********************************\n"); int n = 0; printf("请选择:"); scanf("%d", &n); qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_name); qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_peo_by_age); for (int i = 0; i sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } printf("排序成功\n"); } void DestroyContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->count = 0; pc->sz = 0; } void SaveContact(Contact* pc) { //打开文件 FILE* pf = fopen("data.txt", "wb"); if (pf == NULL) { perror("SaveContact"); return; } //写数据 for (int i = 0; i sz; i++) { fwrite(pc->data + i, sizeof(people), 1, pf); } //关闭文件 fclose(pf); pf = NULL; }
好啦!本期的通讯录的实现就到此结束啦!下一期,我们再一起学习吧!
还没有评论,来说两句吧...