第一次编辑这么长的文章,如果对你有帮助,可以点赞收藏一下一起学习!一起进步!
目录
一、项目介绍
二、代码介绍
三、小记
四、完整代码
五、输出结果展示
1、成功将终端输入的用户姓名和密码分别存入到.txt文件中
2、登陆成功 && 退出成功
3、创建/初始化管理表成功
4、录入人员信息成功
5、按位置插入人员信息成功,插入位置不对会报错
6、输出所有人员信息成功
7、通过姓名查找人员信息成功
8、通过姓名删除人员信息成功
9、导出所有人员信息到文件内成功
10、打印文件信息到终端上成功
11、按姓名将通讯录排序成功(实现的是升序排序)
12、获取链表长度成功
13、统计性别数量成功
14、返回上级菜单成功
15、销毁链表成功
16、退出成功
一、项目介绍
项目:基于链表的通信录管理
意义:对于一个通信录来说,要管理联系人的信息,包括编号,姓名,性别,电话。开发其系统主要为了帮助用户提高通讯录有管理效率,节约资源,提高信息的精确度
模块:
一级菜单内容
1> 注册模块:完成用户信息的注册用于登录管理系统,将注册信息存入文件
2> 登录模块:使用输入的登录账号和密码与文件存储信息对比
3> 退出系统
二级菜单内容:
3> 创建模块create:创建链表完成对通信录的存储
4> 添加数据add:添加通信录的信息放入链表中
5> 查找信息find:可以通过姓名进行查找
6> 修改信息update:可以修改联系人信息并保存,修改联系人信息有包括了对联系人编号,姓名,性别,电话号码的分别修改,也可以同时对编号,姓名,性别,电话号码修改;
7> 删除信息delete:可根据输入的姓名进行删除
8> 插入信息insert:将给定的信息以及插入位置信息完成插入
9> 展示信息show:将通讯录的所有信息进行展示
10> 导出信息export:将通讯录信息导出到文件中
11> 按照姓名将通讯录排序
12> 返回上一级
辅助功能:
13> 初始化链表init:将链表进行初始化
14> 获取链表长度getLength:
15> 统计性别;
二、代码介绍
- 采用分文件编译,link_list.h,link_list.c,main.c
- 在堆区申请了空间用于存放链表
- link_list.h中定义了两个结构体,一个是管理结构体,一个是人员信息结构体,同时包含了函数的声明
- link_list.c中完成了函数功能的封装
- mian.c主函数里,使用了两个while循环,进行菜单的循环展示,如果登录成功,则会进入下一级菜单,使用switch,进行功能的实现
- 在注册的时候,只保证了一个用户的创建,多个用户的创建还没实现
三、小记
项目不难,有耐心就能完成,其中也是遇到了很多的问题。例如在对链表进行操作的时候,没有对输入的内容进行逻辑判断是否合理,导致指针指向的位置发生偏移出现段错误。在进行赋值语句的时候,尝尝忘记数组不能作为常量直接进行赋值,如果需要赋值,需要借助strcmp等函数进行操作,否则会发生报错。
四、完整代码
//link_list.h
#ifndef LINK_LIST_H
#define LINK_LIST_H
#include <myhead.h>
#define MAX 100
//人员信息
typedef struct Person
{
char id[20];
char name[20];
char gender[20];
char telephone[20];
}Person,*PersonPtr;
//人e员管理
typedef struct Manage
{
Person person;
int len;
struct Manage *next;
}Manage,*ManagePtr;
//创建登录视图
void create_log_view();
//注册
int register_user();
//登录
int log_user();
//判空
int link_empty(ManagePtr person_ptr);
//创建管理视图
void create_view();
//创建班级链表
ManagePtr link_person_create();
//申请人员信息结点
ManagePtr link_apply_node(Person person);
//头删
int link_delete_head(ManagePtr person_ptr);
//头插插入人员信息
int link_insert_person(ManagePtr person_ptr,Person person);
//遍历人员信息
int link_printf_person(ManagePtr person_ptr);
//按位置查找人员结点
ManagePtr link_search_person_pos(ManagePtr person_ptr,int pos);
//按位置插入人员信息
int link_insert_person_pos(ManagePtr person_ptr,int pos,Person person);
//通过姓名查找人员信息
int link_search_name(ManagePtr person_ptr);
//通过人名删除信息
int link_delete_name(ManagePtr person_ptr);
//导出所有人员信息到文件内
void link_export_person(ManagePtr person_ptr);
//打印文件信息
void file_show();
//按照姓名将通讯录排序
void link_person_sort_name(ManagePtr person_ptr);
//统计人员总人数(链表长度)
int link_len(ManagePtr person_ptr);
//统计性别
void link_gender_statistics(ManagePtr person_ptr);
//销毁管理表
void link_destroy(ManagePtr person_ptr);
#endif
//link_list.c
#include "link_list.h"
// 创建登录视图
void create_log_view()
{
printf("\t\t======1.注册\n");
printf("\t\t======2.登录\n");
printf("\t\t======3.退出\n");
}
// 注册
int register_user()
{
// 存用户和密码
char user_name[30] = {0};
char password[30] = {0};
// 判断是否成功打开文件
FILE *fp_user = NULL, *fp_password = NULL;
if ((fp_user = fopen("./user.txt", "w+")) == NULL || (fp_password = fopen("./password.txt", "w+")) == NULL)
{
perror("fopen error");
return -1;
}
// 从终端输入用户姓名和密码
printf("请输入用户姓名:");
fgets(user_name, sizeof(user_name), stdin);
printf("请输入密码:");
fgets(password, sizeof(password), stdin);
// 使用fputs将用户名存入user_name.txt
fputs(user_name, fp_user);
user_name[strlen(user_name) - 1] = '\0'; // 将回车换成 '\0'
// 使用fputs将密码写入password.txt
fputs(password, fp_password);
password[strlen(user_name) - 1] = '\0';
// 关闭文件
fclose(fp_user);
fclose(fp_password);
printf("注册成功\n");
return 0;
}
// 登录
int log_user()
{
char buf_name[30] = {0};
char buf_password[30] = {0};
char input_name[30] = {0};
char input_password[30] = {0};
// 打开文件
FILE *fp_user = NULL, *fp_password = NULL;
if ((fp_user = fopen("./user.txt", "r")) == NULL || (fp_password = fopen("./password.txt", "r")) == NULL)
{
perror("fopen error");
return -1;
}
// 从文件里获取账号和密码
while (1)
{
// 如果是NULL,用户姓名读取结束
if ((fgets(buf_name, sizeof(buf_name), fp_user)) == NULL)
{
break;
}
// 如果是NULL,密码读取结束
if ((fgets(buf_password, sizeof(buf_password), fp_password)) == NULL)
{
break;
}
}
buf_name[strlen(buf_name) - 1] = '\0'; // 将回车换成 '\0
buf_password[strlen(buf_password) - 1] = '\0';
// 输入用户名和密码
printf("请输入用户名:");
scanf("%s", input_name);
getchar();
printf("请输入密码:");
scanf("%s", input_password);
getchar();
// 判断是否相等
if (strcmp(buf_name, input_name) == 0 && strcmp(buf_password, input_password) == 0)
{
printf("登录成功\n");
return 0;
}
printf("用户名或密码错误,请重新输入\n");
return -1;
}
// 判空
int link_empty(ManagePtr person_ptr)
{
return person_ptr->next == NULL; // 如果头指针为空,则表示该链表为空,返回1;
}
// 创建管理视图
void create_view()
{
printf("\t\t======1.创建/初始化管理表\n");
printf("\t\t======2.录入人员信息\n");
printf("\t\t======3.按位置插入人员信息\n");
printf("\t\t======4.输出所有人员信息\n");
printf("\t\t======5.通过姓名查找人员信息\n");
printf("\t\t======6.通过姓名删除人员信息\n");
printf("\t\t======7.导出所有人员信息到文件内\n");
printf("\t\t======8.打印文件信息\n");
printf("\t\t======9.按照姓名将通讯录排序\n");
printf("\t\t======10.获取链表长度\n");
printf("\t\t======11.统计性别\n");
printf("\t\t======12.返回上级菜单\n");
printf("\t\t======13.销毁管理表\n");
printf("\t\t======0.退出\n");
}
// 创建人员管理链表
ManagePtr link_person_create()
{
ManagePtr person_ptr = (ManagePtr)malloc(sizeof(Manage)); // 在堆区申请空间
// 判断逻辑
if (person_ptr == NULL)
{
printf("人员管理表创建失败\n");
return NULL;
}
// 链表初始化
person_ptr->len = 0;
person_ptr->next = NULL;
printf("人员管理表创建成功\n");
putchar(10);
return person_ptr;
}
// 申请人员信息结点
ManagePtr link_apply_node(Person person)
{
ManagePtr p = (ManagePtr)malloc(sizeof(Manage));
// 判断逻辑
if (p == NULL)
{
printf("结点创建失败\n");
return NULL;
}
p->person = person;
p->next = NULL;
return p;
}
// 头删
int link_delete_head(ManagePtr person_ptr)
{
// 判断逻辑
if (NULL == person_ptr || link_empty(person_ptr))
{
printf("头删失败\n");
return -1;
}
ManagePtr q = person_ptr->next; // 保存要删除的节点
// 执行头删逻辑
person_ptr->next = q->next;
free(q);
person_ptr->len--;
return 0;
}
// 头插插入人员信息
int link_insert_person(ManagePtr person_ptr, Person person)
{
// 判断逻辑
if (person_ptr == NULL)
{
printf("插入失败\n");
return -1;
}
// 申请一个新的结点
ManagePtr p = link_apply_node(person);
p->next = person_ptr->next;
person_ptr->next = p;
person_ptr->len++;
printf("插入成功\n");
return 0;
}
// 遍历人员信息
int link_printf_person(ManagePtr person_ptr)
{
// 判断逻辑
if (NULL == person_ptr)
{
printf("遍历失败,链表不存在或已被销毁,请检查!\n");
return -1;
}
ManagePtr q = person_ptr->next;
// 循环链表
while (q)
{
printf("%s\t%s\t%s\t%s\n", q->person.id, q->person.name, q->person.gender, q->person.telephone);
q = q->next;
}
putchar(10);
return 0;
}
// 按位置查找人员结点
ManagePtr link_search_person_pos(ManagePtr person_ptr, int pos)
{
// 判断逻辑
if (NULL == person_ptr || pos < 0 || pos > person_ptr->len)
{
printf("查找失败\n");
return NULL;
}
// 通过位置查找结点
ManagePtr q = person_ptr;
for (int i = 0; i < pos; i++)
{
q = q->next;
}
// 返回结点
return q;
}
// 按位置插入人员信息
int link_insert_person_pos(ManagePtr person_ptr, int pos, Person person)
{
if (NULL == person_ptr || pos < 0 || pos > person_ptr->len)
{
printf("插入失败,您输入的位置不对,或者链表不存在,请检查!\n");
printf("\n");
return -1;
}
// 申请一个新的结点
ManagePtr p = link_apply_node(person);
// 查找前驱结点
ManagePtr q = link_search_person_pos(person_ptr, pos - 1);
p->next = q->next;
q->next = p;
person_ptr->len++;
printf("插入成功\n");
return 0;
}
// 通过姓名查找人员信息
int link_search_name(ManagePtr person_ptr)
{
// 判断逻辑,链表是否存在
if (NULL == person_ptr)
{
printf("查找失败\n");
return -1;
}
// 输入人员姓名
char search_name[30] = {0};
printf("请输入你需要查找的人员信息的姓名:");
scanf("%s", search_name);
getchar();
ManagePtr q = person_ptr->next;
// 循环比较输入的内容与存储在链表里面的内容,是否相等
while (q)
{
if (strcmp(q->person.name, search_name) == 0)
{
// 如果相等,就输出这个人的姓名
printf("编号\t姓名\t性别\t电话\n");
printf("%s\t%s\t%s\t%s\n", q->person.id, q->person.name, q->person.gender, q->person.telephone);
printf("\n");
return 0;
}
q = q->next;
}
// 如果q为NULL,则表示表中没有这个人,返回查找失败信息
if (q == NULL)
{
printf("查无此人\n");
printf("\n");
return -1;
}
}
// 通过人名删除信息
int link_delete_name(ManagePtr person_ptr)
{
// 判断逻辑
if (NULL == person_ptr)
{
printf("删除失败\n");
return -1;
}
// 输入人员姓名
char delete_name[30] = {0};
printf("请输入你需要删除的人员信息的姓名:");
scanf("%s", delete_name);
getchar();
// 查找链表中是否有该人员,如果有,则删除
ManagePtr p = person_ptr; // 记录头指针
ManagePtr L = p->next;
ManagePtr temp = NULL; // 定义一个交换指针
while (L)
{
// 如果查找到了,就删除该结点
if (strcmp(L->person.name, delete_name) == 0)
{
temp = L; // 记录要删除的结点
p->next = L->next;
free(temp);
person_ptr->len--;
printf("删除成功\n");
return 0;
}
// 循环后移节点
p = p->next;
L = L->next;
}
// 程序执行至此,表示没有找到该人员姓名
printf("没有此人,无需删除\n");
printf("\n");
return -1;
}
// 导出所有人员信息到文件内
void link_export_person(ManagePtr person_ptr)
{
char huiche[10] = {'\n'};
char t[10] = {'\t'};
// 判断逻辑
if (NULL == person_ptr)
{
printf("导出失败\n");
return;
}
FILE *fp_person = NULL;
// 判断文件是否成功打开
if ((fp_person = fopen("./person_information.txt", "w+")) == NULL)
{
perror("fopen error");
return;
}
ManagePtr p = person_ptr->next; // 记录头指针
while (p)
{
// 把链表里面的内容依次输入到文件中
fputs(p->person.id, fp_person);
fputs(t, fp_person); // 自动格式化一下
fputs(p->person.name, fp_person);
fputs(t, fp_person);
fputs(p->person.gender, fp_person);
fputs(t, fp_person);
fputs(p->person.telephone, fp_person);
fputs(huiche, fp_person); // 自动换行
p = p->next;
}
// 关闭文件
fclose(fp_person);
printf("导出数据成功\n");
return;
}
// 打印文件信息
void file_show()
{
FILE *fp_person = NULL;
char buf[30] = {0}; // 定义一个容器用来接收读取到的内容
// 以只读的形式打开文件
if ((fp_person = fopen("./person_information.txt", "r")) == NULL)
{
perror("fopen error"); // 输出错误信息
return;
}
printf("文件中的数据如下所示:\n");
// 从文件中获取数据
while ((fgets(buf, sizeof(buf), fp_person)) != NULL)
{
printf("%s", buf);
}
printf("\n输出成功\n");
return;
}
// 按照姓名将通讯录排序
void link_person_sort_name(ManagePtr person_ptr)
{
// 判断逻辑
if (NULL == person_ptr || link_empty(person_ptr))
{
printf("排序失败\n");
return;
}
ManagePtr prev = person_ptr;
// 记录数据
ManagePtr p = person_ptr->next;
Person temp; //定义一个结构体,用来存储交换的数据
// 执行排序逻辑
for (int i = 1; i < person_ptr->len; i++)
{
for (int j = 0; j < person_ptr->len - i; j++)
{
if (strcmp(p->person.name, p->next->person.name) > 0)
{
// 交换三步曲
temp = p->person;
p->person = p->next->person;
p->next->person = temp;
}
p = p->next;
}
p = prev->next;
}
printf("升序排序成功\n");
return;
}
//统计人员总人数(链表长度)
int link_len(ManagePtr person_ptr)
{
return person_ptr->len;
}
//统计性别
void link_gender_statistics(ManagePtr person_ptr)
{
int man = 0; //男性计数器
int woman = 0; //女性计数器
//判断逻辑
if(NULL == person_ptr || link_empty(person_ptr))
{
printf("统计失败\n");
return ;
}
ManagePtr p = person_ptr->next;
while(p)
{
if(strcmp(p->person.gender,"男") == 0)
{
man++;
}
else if(strcmp(p->person.gender,"女") == 0)
{
woman++;
}
p = p->next;
}
printf("统计完毕\n");
printf("男生一共有%d个,女生一共有%d个\n",man,woman);
printf("\n");
return ;
}
// 销毁管理表
void link_destroy(ManagePtr person_ptr)
{
// 判断逻辑
if (NULL == person_ptr)
{
printf("无需销毁\n");
return;
}
// 执行头删
while (!link_empty(person_ptr))
{
link_delete_head(person_ptr);
}
// 释放结点
free(person_ptr);
person_ptr = NULL;
printf("释放链表成功\n");
return;
}
//main.c
#include "link_list.h"
int main(int argc, char const *argv[])
{
int n = 0, pos = 0, logsuccess = 1;
int retval;
int len = 0;
ManagePtr person_ptr;
Person person;
// 登录视图
while (logsuccess)
{
START:
create_log_view();
printf("请输入您的需求:");
scanf("%d", &n);
getchar();
switch (n)
{
case 1:
retval = register_user();
break;
case 2:
retval = log_user();
logsuccess = retval;
break;
case 3:
goto END;
break;
default:
break;
}
}
// 管理试图
while (1)
{
create_view();
printf("请输入您需要实现的功能:");
scanf("%d", &n);
getchar();
switch (n)
{
case 1:
person_ptr = link_person_create();
break;
case 2:
printf("请输入你需要插入的编号:");
scanf("%s", person.id);
getchar();
printf("请输入你需要插入的姓名:");
scanf("%s", person.name);
getchar();
printf("请输入你需要插入的性别:");
scanf("%s", person.gender);
getchar();
printf("请输入你需要插入的电话:");
scanf("%s", person.telephone);
getchar();
link_insert_person(person_ptr, person);
break;
case 3:
printf("请输入你需要插入的位置:");
scanf("%d",&pos);
getchar();
printf("请输入你需要插入的编号:");
scanf("%s", person.id);
getchar();
printf("请输入你需要插入的姓名:");
scanf("%s", person.name);
getchar();
printf("请输入你需要插入的性别:");
scanf("%s", person.gender);
getchar();
printf("请输入你需要插入的电话:");
scanf("%s", person.telephone);
getchar();
link_insert_person_pos(person_ptr, pos, person);
break;
case 4:
printf("编号\t姓名\t性别\t电话\n");
link_printf_person(person_ptr);
break;
case 5:
link_search_name(person_ptr);
break;
case 6:
link_delete_name(person_ptr);
break;
case 7:
link_export_person(person_ptr);
break;
case 8:
file_show();
break;
case 9:
link_person_sort_name(person_ptr);
break;
case 10:
len = link_len(person_ptr);
printf("表中一共有%d个人\n",len);
printf("\n");
break;
case 11:
link_gender_statistics(person_ptr);
break;
case 12:
printf("已返回上级菜单\n");
printf("\n");
goto START;
break;
case 13:
link_destroy(person_ptr);
person_ptr = NULL;
break;
case 0:
goto END;
break;
default:
break;
}
}
END:
printf("退出成功\n");
return 0;
}
五、输出结果展示
1、成功将终端输入的用户姓名和密码分别存入到.txt文件中
2、登陆成功 && 退出成功
如果用户名密码对不上,提示重新输入
直接退出
3、创建/初始化管理表成功
4、录入人员信息成功
5、按位置插入人员信息成功,插入位置不对会报错
6、输出所有人员信息成功
7、通过姓名查找人员信息成功
8、通过姓名删除人员信息成功
可以看出已经把张三从表里删除了
9、导出所有人员信息到文件内成功
成功输入进person_information.txt文件中
10、打印文件信息到终端上成功
11、按姓名将通讯录排序成功(实现的是升序排序)
可以看出已经成功根据姓名进行了升序排序