C语言实战:简单易懂通讯录
前言:
以下是一个基于 C 语言的实战,基于数据结构中的顺序表实现通讯录程序设计,包含完整的功能实现和代码注释,适合初学者学习和实践,这个程序实现了联系人的添加、显示、查找、修改、删除以及数据持久化等核心功能,以下是实现通讯录所需的五个文件。
文件一 | Contact.h | 通讯录的头文件,定义了联系人信息结构体,同时声明了通讯录的业务接口。 |
文件二 | Contact.c | 通讯录功能的实现文件,基于顺序表操作封装了通讯录的业务逻辑,实现了Contact.h 中声明的函数 |
文件三 | SeqList.h | 顺序表的头文件,定义了顺序表的核心数据结构SL, 为底层存储提供接口规范。 |
文件四 | SeqList.c | 顺序表功能的实现文件,实现了SeqList.h 中声明的所有函数 |
文件五 | Test.c | 程序入口文件,仅包含main 函数,通过调用menu() 函数启动通讯录的交互界面,是程序运行的起点。 |
一、通讯录项目的准备知识
①本项目基于数据结构中的顺序表,熟练掌握顺序表中的各种函数接口。
②动态内存管理,熟悉掌握动态内存开辟的知识,正确使用malloc 、calloc、realloc等函数。
③为了方便代码的管理和保证通讯录实现逻辑的清晰性,我们将采用多文件管理的模式。
④熟练使用文件操作函数,能够正确读写文件。
⑤了解前置声明的知识。
如果有上面的一定基础就可以开始通讯录项目了~。
1.1SeqList头文件的内容:
1.2Contact.h的头文件的内容:
二、通讯录的功能概要
对于一个基本的通讯录至少需要包含以下功能:
①⾄少能够存储100个⼈的通讯信息
②能够保存⽤⼾信息:名字、性别、年龄、电话、地址等
③增加联系⼈信息
④删除指定联系⼈
⑤查找制定联系⼈
⑥修改指定联系⼈
⑦显⽰联系⼈信息
⑧保存联系人数据不丢失
三、通讯录的实现
3.1回顾顺序表的有关结构
基于上篇顺序表博客,我们通过以整形数组为主要结构,通过动态开辟的方法,实现了顺序表的各种方法,那么顺序表只能存储整形数据吗?
显然不是,我们可以将int类型的数据变换为char、结构体类型、自定义类型等,那么通讯录项目就是基于结构体类型的数据,顺序表中的每个元素均为结构体类型,如下图所示两者的对比与联系。
①以整形为数据类型实现的顺序表,如下图所示:
②基于结构体实现的顺序表,我们也将该顺序表称作通讯录,其中顺序表每个元素都为结构体类型。
3.2SeqList.h 和 SeqList.c 简介
这里我们不过多讲述SeqList.h 和 SeqList.c实现,详情可以看顺序表博客,我们这里直接献上源码,想必帅观众看了顺序表博客后一定能够理解。
3.3Contact.h 和 Contact.c 简介
①这里我们重点讲解Contact.c文件的实现
②如何处理多文件循环包含导致的问题
③调用底层顺序表以及写好的函数,实现代码的复用
四、Contact.h和Contact.c 实现
4.1定义联系人结构体
#pragma once
//定义联系人数据
//包含: 姓名 性别 年龄 电话 地址#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100typedef struct PersonInfo
{char name[NAME_MAX];char gender[GENDER_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];int id;
}PeoInfo;
①这里我们通过定义宏变量,以便后续空间的合理修改。
②定义联系人数据的结构体,包含:姓名、性别、年龄、电话、地址、编号
③将结构体struct PersonInfo进行重命名为PeoInfo。
4.2顺序表重命名为通讯录(核心)
//因为在Contact.h中未包含SeqList.h的头文件,所以这里编译器不认识SL导致报错
//但能否添加SeqList的头文件呢?显然是不行的,这样会导致循环包含,无限展开而出现错误//我们可以通过对SL进行前置声明,使编译器认识这个结构体,也就是顺序表typedef struct SeqList Contact;//在 C 语言中,typedef struct SeqList Contact;
//这句话包含了前置声明的效果,但不等同于单纯的前置声明
//它在完成前置声明的同时,还为结构体定义了一个别名。
①对于这里我们要思考这么一个问题:在底层的SeqList.h头文件已经包含了Contact.h头文件,我们能否在Contact.h头文件再次包含SeqList头文件呢?
这不同于头文件多次包含,可以使用#pragma once进行规避,这里是A文件包含B文件,同时B文件又包含A文件,导致文件的循环包含,在B文件打开A文件时,A文件又会打开B文件,导致循环展开,以至于无限循环。
②如果没有包含SeqList.h的头文件,我们又想使用去使用这个结构体变量,那又该如何做呢?
通过前置声明就可以做到这一点,在 C 语言中,typedef struct SeqList Contact; 它在完成前置声明的同时,还为结构体定义了一个别名,如果帅观众想要了解更多,可以去看一下前置声明的有关知识点,会对你加深这一块的理解。
③通过这段代码,我们将顺序表SeqList结构体重命名为Contact结构体,所以Contact结构体就相当于SeqList结构体,相当于土豆和马铃薯的区别,Contact结构体指针也可进行访问SeqList中的函数,这样就实现了调用底层顺序表SeqList封装的函数,以达到代码的复用,减少了代码的重复性。
4.3通讯录初始化
Contact.h头文件声明:
//对通讯录进行初始化
void ContactInit (Contact* con );
Contact.c文件实现:
//对通讯录进行初始化的实现
void ContactInit(Contact* con)
{//直接调用顺序表中的初始化操作SLInit(con);
}
直接调用顺序表中的初始化操作
4.4通讯录的销毁
Contact.h头文件声明:
void ContactDesTroy(Contact* con);
Contact.c文件实现:
//对通讯录的销毁
void ContactDesTroy(Contact* con)
{SLDestroy(con);
}
直接调用顺序表中的销毁操作
4.5通讯录添加数据
Contact.h头文件声明:
void ContactDel(Contact* con);
Contact.c文件实现:
//对通讯录添加数据
void ContactAdd(Contact* con)
{//先让用户输入数据//1.姓名 2.性别 3.年龄 4.电话 5.地址 //定义一个联系人结构体PeoInfo p = {0};//提示输入联系人的姓名printf("请输入联系人的姓名:\n");scanf("%s", p.name);printf("请输入联系人的性别:\n");scanf("%s", p.gender);printf("请输入联系人的年龄:\n");scanf("%d", &p.age);printf("请输入联系人的电话:\n");scanf("%s", &p.tel);printf("请输入联系人的地址:\n");scanf("%s", &p.addr);//通过尾插的方式,存入到通讯录中 SLPushBack(con, p); //添加编号con->arr[con->size-1].id = con->size;//存入到文件中SaveContact(con);printf("存入成功!\n");
}
这里我们通过第一个联系人数据的结构体,通过用户输入,将信息存入到该结构体中,然后通过顺序表尾插函数,将整个结构体的信息存入到通讯录中,并进行添加编号和存入文件操作。
4.6通讯录进行删除数据
Contact.h头文件声明:
void ContactDel(Contact* con);
Contact.c文件实现:
int FindbyName(Contact* con , const char name[])
{//遍历整个顺序表for (int i = 0; i < con->size; i++){//与名字进行匹配if (strcmp(con->arr[i].name, name) == 0){//匹配成功返回其在顺序表中的位置return i;}}//未找到返回-1return -1;
}void ContactDel(Contact* con)
{char name[NAME_MAX];printf("请输入你要删除的联系人姓名:\n");scanf("%s", name);int pos = FindbyName(con, name);if (pos == -1){//未找到姓名,进行输出提示printf("未查找到该联系人!\n"); } else{//找到了进行删除//通过调用顺序表中的指定位置删除函数SLErase(con, pos);printf("已删除该联系人\n");for (int i = pos; i < con->size; i++){con->arr[i].id--;}//存入到文件中SaveContact(con);}}
①通过定义了一个根据姓名查找的函数,如果能够查找到该联系人的姓名,则返回其对应在顺序表中的下标,如果查找不到该联系人的姓名则返回-1。
②根据查找到的联系人下标,通过调用顺序表中的指定位置删除函数,将联系人进行删除,并更新文件中存储的信息。
4.7通讯录查找数据
Contact.h头文件声明:
void ContactFind(Contact* con);
Contact.c文件实现:
void ContactFind(Contact* con)
{//提示输入要查找的联系人姓名printf("请输入要查找的联系人姓名:\n");char name[NAME_MAX] = {0};scanf("%s", name);int pos = FindbyName(con, name);if (pos == -1){//提示为查找到联系人printf("查找失败,未查找到该联系人\n");//退出函数return;}//查找到联系人打印改联系人的信息printf("查找成功!\n");printf("%-6s %-10s %-10s %-10s %-10s %-10s \n", "编号", "姓名", "性别", "年龄", "电话", "地址");printf("%-6d %-10s %-10s %-10d %-10s %-10s\n",con->arr[pos].id,con->arr[pos].name,con->arr[pos].gender,con->arr[pos].age,con->arr[pos].tel,con->arr[pos].addr);}
通过用户输入姓名进行查找,如果查找到了该联系人,进行展示该联系人的信息,如果未查找到联系人,直接退出函数,不进行返回操作。
4.8通讯录进行修改数据
Contact.h头文件声明:
void ContactModify(Contact* con);
Contact.c文件实现:
void ContactModify(Contact* con)
{printf("请输入要修改的联系人姓名:\n");char name[NAME_MAX];scanf("%s", name);int pos = FindbyName(con, name);if (pos == -1){//提示未找到联系人printf("修改失败,未找到该联系人!\n");return;}//找到联系人进行修改//提示输入联系人的姓名printf("请输入修改后联系人的姓名:\n");scanf("%s", con->arr[pos].name);printf("请输入修改后联系人的性别:\n");scanf("%s", con->arr[pos].gender);printf("请输入修改后联系人的年龄:\n");scanf("%d", &con->arr[pos].age);printf("请输入修改后联系人的电话:\n");scanf("%s", con->arr[pos].tel);printf("请输入修改后联系人的地址:\n");scanf("%s", con->arr[pos].addr);printf("成功修改!\n");//存入到文件中SaveContact(con);
}
①根据姓名进行查找通讯人,如果查找到该联系人,进行修改联系人的各种信息,如果未查找到该联系人,直接退出函数。
②直接将顺序表中指定位置的联系人数据进行覆盖
4.9展示通讯录的数据
Contact.h头文件声明:
void ContactShow(Contact* con);
Contact.c文件实现:
void ContactShow(Contact* con)
{printf("%-6s %-10s %-10s %-10s %-10s %-10s \n", "编号", "姓名", "性别", "年龄", "电话", "地址");for (int i = 0; i < con->size; i++){printf("%-6d %-10s %-10s %-10d %-10s %-10s\n",con->arr[i].id,con->arr[i].name,con->arr[i].gender, con->arr[i].age, con->arr[i].tel,con->arr[i].addr);}}
展示通讯录中的所有联系人信息。
4.10存入通讯录数据到文件中
Contact.h头文件声明:
void SaveContact(Contact* con);
Contact.c文件实现:
void SaveContact(Contact* con)
{FILE* pf = fopen("home.txt", "w");if (pf == NULL){perror("fopen\n");return;}//输出到文件中for (int i = 0; i < con->size; i++){fprintf(pf,"%-6s %-10s %-10s %-10s %-10s %-10s \n", "编号", "姓名", "性别", "年龄", "电话", "地址");fprintf(pf,"%-7d %-12s %-10s %-10d %-10s %-10s\n",con->arr[i].id,con->arr[i].name,con->arr[i].gender,con->arr[i].age,con->arr[i].tel,con->arr[i].addr);}fclose(pf);pf = NULL;}
通过文件操作函数fprintf将结构体按照指定格式化进行输出到文件中,保存联系人信息,防止数据丢失。
4.11打印菜单
Contact.h头文件声明:
void menu();
Contact.c文件实现:
enum
{exit,Add,Del,Find,Modify,Show,
};void menu()
{int op = -1;Contact con;ContactInit(&con);do{ printf("********************************\n");printf("****1、添加用户 2、删除用户****\n");printf("****3、查找用户 4、修改用户****\n");printf("****5、展示用户 0、退出 ****\n");printf("********************************\n");printf("请输入您的操作:\n");//提示用户,请输入您的操作scanf("%d", &op);switch (op){case Add:ContactAdd(&con);break;case Del:ContactDel(&con);break;case Find:ContactFind(&con);break;case Modify:ContactModify(&con);break;case Show:ContactShow(&con);break;case exit:printf("成功退出!\n");break;default:printf("输入有误,请重新输入\n");}} while (op != 0);}
①通过枚举定义各个常量,将数字进行替换,增强代码的可读性
②通过用户输入操作数,进行循环执行通讯录的增、删、改、查功能。
五、项目演示
5.1添加和展示功能:
5.2查找功能:
5.3修改联系人:
5.4删除联系人:
5.5退出程序:
六、项目源码
SeqList.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"Contact.h"
#pragma once
//动态顺序表的实现typedef struct PersonInfo SLDataType;
//通过将 struct PersonInfo 命名为SLDataType 以便后续更改类型 //定义顺序表的结构
typedef struct SeqList
{SLDataType* arr; //动态开辟顺序表int size; //有效元素个数int capacity; //顺序表的容量
}SL;//顺序表初始化
void SLInit(SL* ps);//顺序表销毁
void SLDestroy(SL* ps);//顺序表扩容
void SLCheckCapacity(SL* ps);//顺序表尾插
void SLPushBack(SL* ps, SLDataType x);//顺序表头插
void SLPushFront(SL* ps, SLDataType x);//顺序表尾删
void SLPopBack(SL* ps);//顺序表头删
void SLPopFront(SL* ps);//顺序表指定位置插入
void SLInsert(SL* ps, int pos, SLDataType x);//顺序表指定位置删除
void SLErase(SL* ps, int pos);
SeqList.c
#include"SeqList.h"//顺序表的初始化//这里不用SL ps作为参数,因为形参是实参的临时拷贝,改变形参不影响实参
void SLInit(SL* ps)
{assert(ps);ps->arr = NULL; ps->size = 0; //默认顺序表有效个数为0ps->capacity = 0; //默认顺序表空间为0
}//顺序表的销毁
void SLDestroy(SL* ps)
{//由于是动态开辟的,所以要进行free//判断是否为空,如果不为空将其free,并置为空assert(ps);if (ps->arr){//不为空free(ps->arr);//此时ps->arr仍然保存着arr的地址//但我们不能够访问这片空间,此时改指针为野指针,我们需要将其置空处理ps->arr = NULL;}//有效个数清空ps->size = 0;//开辟的空间清0ps->capacity = 0;
}//顺序表的扩容
void SLCheckCapacity(SL* ps)
{assert(ps);//什么时候应该扩容?空间不够用的时候。//什么时候空间不够用?当有效个数等于空间容量的时候。if (ps->size == ps->capacity){//使用什么进行扩容? realloc调整动态开辟的空间//每次扩多大?根据数学推导,成倍数增加容量是最好的,一般为2~3倍最佳。//realloc(ps->arr,ps->capacity * 2 *sizeof(SLDataType) );//直接传入ps->capacity这样是正确的吗?//因为我们初始化为0,所以我们需要进行额外处理。int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; //若刚开始为0,则开辟4个空间SLDataType* tmp=(SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType)); //防止空间开辟失败if (tmp == NULL){perror("error");exit(1);}//开辟成功,用ps->arr进行维护ps->arr = tmp;//对临时变量进行置空tmp=NULL;//更新当前空间ps->capacity = newCapacity;}
}//顺序表的尾插
void SLPushBack(SL* ps, SLDataType x)
{assert(ps);//判断是否空间足够SLCheckCapacity(ps);ps->arr[ps->size++] = x;}//顺序表的头插
void SLPushFront(SL* ps, SLDataType x)
{assert(ps);//判断空间是否足够SLCheckCapacity(ps);for (int i = ps->size; i>0; i--){ps->arr[i] = ps->arr[i - 1]; //根据最后一个元素移动,确定判断条件 arr[1]=arr[0]}//移动结束后,将元素插入第一个位置,即下标为0处。ps->arr[0] = x;ps->size++;
}//顺序表的尾删
void SLPopBack(SL* ps)
{assert(ps);//判断是否可以进行删除assert(ps->size > 0);//将size个数减少一个即可,删除的元素可以被覆盖ps->size--;
}void SLPopFront(SL* ps)
{assert(ps);//判断是否可以进行删除assert(ps->size > 0);for (int i = 0; i<ps->size-1; i++){ps->arr[i] = ps->arr[i + 1]; //根据最后一个元素移动,确定判断条件 arr[ps->size-2]=arr[ps->size-1]}//删除一个元素,ps->size的有效个数要减少ps->size--;
}void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);//判断pos是否在有效的位置(size下标可以插入一个元素)assert(pos >= 0 && pos <= ps->size);//判断空间是否足够SLCheckCapacity(ps);for (int i = ps->size; i>pos; i--){ps->arr[i] = ps->arr[i - 1]; //根据最后一个元素移动,确定判断条件 arr[pos+1]=arr[pos];}ps->arr[pos] = x;//增添一个元素,有效个数要增加1ps->size++;
}void SLErase(SL* ps, int pos)
{assert(ps);//判断pos是否在有效的位置 (size下标没有元素可删除)assert(pos >= 0 && pos < ps->size);assert(ps->size > 0);for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1]; //根据最后一个元素移动,确定判断条件 arr[size-2]=arr[size-1]}//删除一个元素,有效个数要减少一个ps->size--;
}
Contact.h
#pragma once
//定义联系人数据
//包含: 姓名 性别 年龄 电话 地址#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100typedef struct PersonInfo
{char name[NAME_MAX];char gender[GENDER_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];int id;
}PeoInfo;//因为在Contact.h中未包含SeqList.h的头文件,所以这里编译器不认识SL导致报错
//但能否添加SeqList的头文件呢?显然是不行的,这样会导致循环包含,无限展开而出现错误//我们可以通过对SL进行前置声明,使编译器认识这个结构体,也就是顺序表struct SeqList;
typedef struct SeqList Contact;//在 C 语言中,typedef struct SeqList Contact; 这句话包含了前置声明的效果,但不等同于单纯的前置声明
// —— 它在完成前置声明的同时,还为结构体定义了一个别名。//对通讯录进行初始化
void ContactInit (Contact* con );//对通讯录的销毁
void ContactDesTroy(Contact* con);//对通讯录添加数据
void ContactAdd(Contact* con);//对通讯录进行删除数据
void ContactDel(Contact* con);//对通讯录进行查找数据
void ContactFind(Contact* con);//对通讯录进行修改数据
void ContactModify(Contact* con);//展示通讯录的数据
void ContactShow(Contact* con);//存入通讯录数据到文件中
void SaveContact(Contact* con);void menu();
Contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h" //---包含了"Contact.h"的头文件
#include<string.h>
//对通讯录进行初始化的实现
void ContactInit(Contact* con)
{//直接调用顺序表中的初始化操作SLInit(con);
}//对通讯录的销毁
void ContactDesTroy(Contact* con)
{SLDestroy(con);
}//对通讯录添加数据
void ContactAdd(Contact* con)
{//先让用户输入数据//1.姓名 2.性别 3.年龄 4.电话 5.地址 //定义一个联系人结构体PeoInfo p = {0};//提示输入联系人的姓名printf("请输入联系人的姓名:\n");scanf("%s", p.name);printf("请输入联系人的性别:\n");scanf("%s", p.gender);printf("请输入联系人的年龄:\n");scanf("%d", &p.age);printf("请输入联系人的电话:\n");scanf("%s", &p.tel);printf("请输入联系人的地址:\n");scanf("%s", &p.addr);//通过尾插的方式,存入到通讯录中 SLPushBack(con, p); //添加编号con->arr[con->size-1].id = con->size;//存入到文件中SaveContact(con);printf("存入成功!\n");
}//删除通讯录的联系人//方法一:根据姓名查找 int FindbyName(Contact* con , const char name[])
{//遍历整个顺序表for (int i = 0; i < con->size; i++){//与名字进行匹配if (strcmp(con->arr[i].name, name) == 0){//匹配成功返回其在顺序表中的位置return i;}}//未找到返回-1return -1;
}void ContactDel(Contact* con)
{char name[NAME_MAX];printf("请输入你要删除的联系人姓名:\n");scanf("%s", name);int pos = FindbyName(con, name);if (pos == -1){//未找到姓名,进行输出提示printf("未查找到该联系人!\n"); } else{//找到了进行删除//通过调用顺序表中的指定位置删除函数SLErase(con, pos);printf("已删除该联系人\n");for (int i = pos; i < con->size; i++){con->arr[i].id--;}//存入到文件中SaveContact(con);}}////方法二:根据编号查找
//int FindbyId(Contact* con, int id)
//{
// //遍历整个顺序表
// for (int i = 0; i < con->size; i++)
// {
// //根据id进行匹配
// if (con->arr[i].id == id)
// {
// //匹配成功返回其在顺序表中的位置
// return i;
// }
// }
// //未找到返回-1
// return -1;
//}
//
//void ContactDel(Contact* con)
//{
// int id = -1;
// printf("请输入你要删除的联系人的编号:\n");
// scanf("%d", &id);
// int pos = FindbyId(con, id);
// if (pos == -1)
// {
// //未找到姓名,进行输出提示
// printf("未查找到该联系人!");
// }
// else
// {
// //找到了进行删除
// //通过调用顺序表中的指定位置删除函数
// SLErase(con, pos);
// printf("已删除该联系人");
// }
//
//}void ContactShow(Contact* con)
{printf("%-6s %-10s %-10s %-10s %-10s %-10s \n", "编号", "姓名", "性别", "年龄", "电话", "地址");for (int i = 0; i < con->size; i++){printf("%-6d %-10s %-10s %-10d %-10s %-10s\n",con->arr[i].id,con->arr[i].name,con->arr[i].gender, con->arr[i].age, con->arr[i].tel,con->arr[i].addr);}}void ContactFind(Contact* con)
{//提示输入要查找的联系人姓名printf("请输入要查找的联系人姓名:\n");char name[NAME_MAX] = {0};scanf("%s", name);int pos = FindbyName(con, name);if (pos == -1){//提示为查找到联系人printf("查找失败,未查找到该联系人\n");//退出函数return;}//查找到联系人打印改联系人的信息printf("查找成功!\n");printf("%-6s %-10s %-10s %-10s %-10s %-10s \n", "编号", "姓名", "性别", "年龄", "电话", "地址");printf("%-6d %-10s %-10s %-10d %-10s %-10s\n",con->arr[pos].id,con->arr[pos].name,con->arr[pos].gender,con->arr[pos].age,con->arr[pos].tel,con->arr[pos].addr);}//根据姓名修改通讯录中的数据
//对通讯录进行修改数据
void ContactModify(Contact* con)
{printf("请输入要修改的联系人姓名:\n");char name[NAME_MAX];scanf("%s", name);int pos = FindbyName(con, name);if (pos == -1){//提示未找到联系人printf("修改失败,未找到该联系人!\n");return;}//找到联系人进行修改//提示输入联系人的姓名printf("请输入修改后联系人的姓名:\n");scanf("%s", con->arr[pos].name);printf("请输入修改后联系人的性别:\n");scanf("%s", con->arr[pos].gender);printf("请输入修改后联系人的年龄:\n");scanf("%d", &con->arr[pos].age);printf("请输入修改后联系人的电话:\n");scanf("%s", con->arr[pos].tel);printf("请输入修改后联系人的地址:\n");scanf("%s", con->arr[pos].addr);printf("成功修改!\n");//存入到文件中SaveContact(con);
}void SaveContact(Contact* con)
{FILE* pf = fopen("home.txt", "w");if (pf == NULL){perror("fopen\n");return;}//输出到文件中for (int i = 0; i < con->size; i++){fprintf(pf,"%-6s %-10s %-10s %-10s %-10s %-10s \n", "编号", "姓名", "性别", "年龄", "电话", "地址");fprintf(pf,"%-7d %-12s %-10s %-10d %-10s %-10s\n",con->arr[i].id,con->arr[i].name,con->arr[i].gender,con->arr[i].age,con->arr[i].tel,con->arr[i].addr);}fclose(pf);pf = NULL;}enum
{quit,Add,Del,Find,Modify,Show,
};void menu()
{int op = -1;Contact con;ContactInit(&con);do{ printf("********************************\n");printf("****1、添加用户 2、删除用户****\n");printf("****3、查找用户 4、修改用户****\n");printf("****5、展示用户 0、退出 ****\n");printf("********************************\n");printf("请输入您的操作:\n");//提示用户,请输入您的操作scanf("%d", &op);switch (op){case Add:ContactAdd(&con);break;case Del:ContactDel(&con);break;case Find:ContactFind(&con);break;case Modify:ContactModify(&con);break;case Show:ContactShow(&con);break;case quit:printf("成功退出!\n");break;default:printf("输入有误,请重新输入\n");}} while (op != 0);}
Test.c
#include"SeqList.h"int main()
{menu();return 0;
}
七、总结
通过改通讯录项目,我们能够更好的了解动态内存管理、多文件编程、模块化编程、调试、前置声明、函数复用等技能。
既然看到这里了,不妨点赞+收藏,感谢大家,若有问题请指正。