文章目录
- 一、前言
- SList.h
- SList.c
- 二、通讯录的实现
- 通讯录项目
- Contact.h
- 载入数据
- 初始化通讯录
- 添加通讯录数据
- 通过姓名查找联系人
- 删除通讯录数据
- 展示通讯录数据
- 查找通讯录数据
- 修改通讯录数据
- 保存通讯录
- 销毁通讯录数据
- 三、所有源代码
- Contact.h
- Contact.c
- SList.h
- SList.c
- test.c
一、前言
这个通讯录是基于单链表实现的,关于单链表,之前已经做过完整的实现方法——数据结构——单链表(C语言版)
用单链表实现的通讯录其实和用顺序表实现的通讯录类似,可以参考该文章——基于动态顺序表的应用——通讯录
完成该通讯录需要引进经过修改后的单链表的文件
SList.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "Contact.h"typedef PeoInfo SLTDateType;typedef struct SListNode
{SLTDateType date;struct SListNode* next;
}SLTNode;//尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x);//头插
void SLTPushFront(SLTNode** pphead, SLTDateType x);//尾删
void SLTPopBack(SLTNode** pphead);//头删
void SLTPopFront(SLTNode** pphead);//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDateType x);//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos);//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos);//销毁链表
void SListDesTroy(SLTNode** pphead);
SList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"//申请新的结点
SLTNode* SLTBuyNode(SLTDateType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){printf("malloc fail!");exit(1);}newnode->date = x;newnode->next = NULL;return newnode;
}//尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x)
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);//空链表 和 非空链表if (*pphead == NULL){*pphead = newnode;}else{SLTNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}ptail->next = newnode;}
}//头插
void SLTPushFront(SLTNode** pphead, SLTDateType x)
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);newnode->next = *pphead;*pphead = newnode;
}//尾删
void SLTPopBack(SLTNode** pphead)
{assert(pphead && *pphead);//只有一个结点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}//多个结点else{SLTNode* prev = *pphead;SLTNode* ptail = *pphead;while (ptail->next){prev = ptail;ptail = ptail->next;}free(ptail);ptail = NULL;prev->next = NULL;}
}//头删
void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{assert(pphead && *pphead);assert(pos);if (*pphead == pos){SLTPushFront(pphead, x);}else{SLTNode* newnode = SLTBuyNode(x);SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = newnode;newnode->next = pos;}}//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDateType x)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);newnode->next = pos->next;pos->next = newnode;
}//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);if (pos == *pphead){SLTPopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}}//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}//销毁链表
void SListDesTroy(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}
二、通讯录的实现
通讯录项目
创建一个通讯录项目,包含以下文件:
Contact.h 通讯录的头文件,包含通讯录的声明以及相关函数的声明
Contact.c 通讯录函数的具体实现方法
contact.txt 保存通讯录中的数据
SList.h 单链表的声明
SList.c 单链表函数的声明
test.c 测试代码,也可以当菜单
Contact.h
#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100//联系人的数据
//姓名 性别 年龄 电话 地址
typedef struct PersonInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}PeoInfo;//前置声明
typedef struct SListNode contact;//初始化通讯录
void InitContact(contact** con);//添加通讯录数据
void AddContact(contact** con);//删除通讯录数据
void DelContact(contact** con);//展示通讯录数据
void ShowContact(contact* con);//查找通讯录数据
void FindContact(contact* con);//修改通讯录数据
void ModifyContact(contact** con);//销毁通讯录数据
void DestroyContact(contact** con);
载入数据
//载入数据
void LoadContact(contact** con)
{FILE* pf = fopen("contact.txt", "r");//判断读取是否成功if (pf == NULL){perror("fopen fail!");return;}//循环读取数据PeoInfo info;while (fread(&info, sizeof(PeoInfo), 1, pf)){SLTPushBack(con, info);}printf("历史数据导入通讯录成功!\n");
}
初始化通讯录
//初始化通讯录
void InitContact(contact** con)
{LoadContact(con);
}
添加通讯录数据
// 添加通讯录数据
void AddContact(contact** con)
{PeoInfo info;printf("请输入联系人的姓名:\n");scanf("%s", info.name);printf("请输入联系人的性别:\n");scanf("%s", info.sex);printf("请输入联系人的年龄:\n");scanf("%d", &info.age);printf("请输入联系人的电话:\n");scanf("%s", info.tel);printf("请输入联系人的地址:\n");scanf("%s", info.addr);SLTPushBack(con, info);
}
通过姓名查找联系人
//通过姓名查找联系人
contact* FindByName(contact* con, char name[])
{contact* pcur = con;while (pcur){if (strcmp(pcur->date.name, name) == 0){return pcur;}pcur = pcur->next;}return NULL;
}
删除通讯录数据
//删除通讯录数据
void DelContact(contact** con)
{char name[NAME_MAX];printf("请输入要删除的联系人的姓名->");scanf("%s", name);contact* pos = FindByName(*con, name);if (pos != NULL){SLTErase(con, pos);printf("删除成功!\n");}else{printf("删除失败!没有该联系人!\n");}
}
展示通讯录数据
//展示通讯录数据
void ShowContact(contact* con)
{printf("%6s %6s %6s %6s %6s\n", "姓名", "性别", "年龄", "电话", "地址");contact* pcur = con;while (pcur){printf("%6s %6s %6d %6s %6s\n",pcur->date.name,pcur->date.sex,pcur->date.age,pcur->date.tel,pcur->date.addr);pcur = pcur->next;}
}
查找通讯录数据
//查找通讯录数据
void FindContact(contact* con)
{char name[NAME_MAX];printf("请输入要查找的联系人的姓名->");scanf("%s", name);contact* pos = FindByName(con, name);if (pos == NULL){printf("没有该联系人!\n");}else{printf("找到了!该联系人的信息如下:\n");printf("%6s %6s %6s %6s %6s\n", "姓名", "性别", "年龄", "电话", "地址");printf("%6s %6s %6d %6s %6s\n",pos->date.name,pos->date.sex,pos->date.age,pos->date.tel,pos->date.addr);}
}
修改通讯录数据
//修改通讯录数据
void ModifyContact(contact** con)
{char name[NAME_MAX];printf("请输入要修改的联系人的姓名->");scanf("%s", name);contact* pos = FindByName(*con, name);if (pos == NULL){printf("没有该联系人!\n");}else{printf("开始修改!\n");printf("联系人的新姓名为:\n");scanf("%s", pos->date.name);printf("联系人的新性别为:\n");scanf("%s", pos->date.sex);printf("联系人的新年龄为:\n");scanf("%d", &pos->date.age);printf("联系人的新电话为:\n");scanf("%s", pos->date.tel);printf("联系人的新地址为:\n");scanf("%s", pos->date.addr);printf("修改成功!\n");}
}
保存通讯录
//保存通讯录
void SaveContact(contact* con)
{FILE* pf = fopen("contact.txt", "w");if (pf == NULL){perror("fopen fail!");return;}//将通讯录数据写入文件contact* pcur = con;while (pcur){fwrite(&(pcur->date), sizeof(pcur->date), 1, pf);pcur = pcur->next;}printf("通讯录保存成功!\n");
}
销毁通讯录数据
//销毁通讯录数据
void DestroyContact(contact** con)
{//在销毁通讯录之前,保存数据SaveContact(*con);SListDesTroy(con);
}
三、所有源代码
Contact.h
#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100//联系人的数据
//姓名 性别 年龄 电话 地址
typedef struct PersonInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}PeoInfo;//前置声明
typedef struct SListNode contact;//初始化通讯录
void InitContact(contact** con);//添加通讯录数据
void AddContact(contact** con);//删除通讯录数据
void DelContact(contact** con);//展示通讯录数据
void ShowContact(contact* con);//查找通讯录数据
void FindContact(contact* con);//修改通讯录数据
void ModifyContact(contact** con);//销毁通讯录数据
void DestroyContact(contact** con);
Contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
#include "SList.h"//载入数据
void LoadContact(contact** con)
{FILE* pf = fopen("contact.txt", "r");//判断读取是否成功if (pf == NULL){perror("fopen fail!");return;}//循环读取数据PeoInfo info;while (fread(&info, sizeof(PeoInfo), 1, pf)){SLTPushBack(con, info);}printf("历史数据导入通讯录成功!\n");
}//初始化通讯录
void InitContact(contact** con)
{LoadContact(con);
}// 添加通讯录数据
void AddContact(contact** con)
{PeoInfo info;printf("请输入联系人的姓名:\n");scanf("%s", info.name);printf("请输入联系人的性别:\n");scanf("%s", info.sex);printf("请输入联系人的年龄:\n");scanf("%d", &info.age);printf("请输入联系人的电话:\n");scanf("%s", info.tel);printf("请输入联系人的地址:\n");scanf("%s", info.addr);SLTPushBack(con, info);
}//通过姓名查找联系人
contact* FindByName(contact* con, char name[])
{contact* pcur = con;while (pcur){if (strcmp(pcur->date.name, name) == 0){return pcur;}pcur = pcur->next;}return NULL;
}//删除通讯录数据
void DelContact(contact** con)
{char name[NAME_MAX];printf("请输入要删除的联系人的姓名->");scanf("%s", name);contact* pos = FindByName(*con, name);if (pos != NULL){SLTErase(con, pos);printf("删除成功!\n");}else{printf("删除失败!没有该联系人!\n");}
}//展示通讯录数据
void ShowContact(contact* con)
{printf("%6s %6s %6s %6s %6s\n", "姓名", "性别", "年龄", "电话", "地址");contact* pcur = con;while (pcur){printf("%6s %6s %6d %6s %6s\n",pcur->date.name,pcur->date.sex,pcur->date.age,pcur->date.tel,pcur->date.addr);pcur = pcur->next;}
}//查找通讯录数据
void FindContact(contact* con)
{char name[NAME_MAX];printf("请输入要查找的联系人的姓名->");scanf("%s", name);contact* pos = FindByName(con, name);if (pos == NULL){printf("没有该联系人!\n");}else{printf("找到了!该联系人的信息如下:\n");printf("%6s %6s %6s %6s %6s\n", "姓名", "性别", "年龄", "电话", "地址");printf("%6s %6s %6d %6s %6s\n",pos->date.name,pos->date.sex,pos->date.age,pos->date.tel,pos->date.addr);}
}//修改通讯录数据
void ModifyContact(contact** con)
{char name[NAME_MAX];printf("请输入要修改的联系人的姓名->");scanf("%s", name);contact* pos = FindByName(*con, name);if (pos == NULL){printf("没有该联系人!\n");}else{printf("开始修改!\n");printf("联系人的新姓名为:\n");scanf("%s", pos->date.name);printf("联系人的新性别为:\n");scanf("%s", pos->date.sex);printf("联系人的新年龄为:\n");scanf("%d", &pos->date.age);printf("联系人的新电话为:\n");scanf("%s", pos->date.tel);printf("联系人的新地址为:\n");scanf("%s", pos->date.addr);printf("修改成功!\n");}
}//保存通讯录
void SaveContact(contact* con)
{FILE* pf = fopen("contact.txt", "w");if (pf == NULL){perror("fopen fail!");return;}//将通讯录数据写入文件contact* pcur = con;while (pcur){fwrite(&(pcur->date), sizeof(pcur->date), 1, pf);pcur = pcur->next;}printf("通讯录保存成功!\n");
}//销毁通讯录数据
void DestroyContact(contact** con)
{//在销毁通讯录之前,保存数据SaveContact(*con);SListDesTroy(con);
}
SList.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "Contact.h"typedef PeoInfo SLTDateType;typedef struct SListNode
{SLTDateType date;struct SListNode* next;
}SLTNode;//尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x);//头插
void SLTPushFront(SLTNode** pphead, SLTDateType x);//尾删
void SLTPopBack(SLTNode** pphead);//头删
void SLTPopFront(SLTNode** pphead);//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDateType x);//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos);//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos);//销毁链表
void SListDesTroy(SLTNode** pphead);
SList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"//申请新的结点
SLTNode* SLTBuyNode(SLTDateType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){printf("malloc fail!");exit(1);}newnode->date = x;newnode->next = NULL;return newnode;
}//尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x)
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);//空链表 和 非空链表if (*pphead == NULL){*pphead = newnode;}else{SLTNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}ptail->next = newnode;}
}//头插
void SLTPushFront(SLTNode** pphead, SLTDateType x)
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);newnode->next = *pphead;*pphead = newnode;
}//尾删
void SLTPopBack(SLTNode** pphead)
{assert(pphead && *pphead);//只有一个结点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}//多个结点else{SLTNode* prev = *pphead;SLTNode* ptail = *pphead;while (ptail->next){prev = ptail;ptail = ptail->next;}free(ptail);ptail = NULL;prev->next = NULL;}
}//头删
void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{assert(pphead && *pphead);assert(pos);if (*pphead == pos){SLTPushFront(pphead, x);}else{SLTNode* newnode = SLTBuyNode(x);SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = newnode;newnode->next = pos;}}//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDateType x)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);newnode->next = pos->next;pos->next = newnode;
}//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);if (pos == *pphead){SLTPopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}}//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}//销毁链表
void SListDesTroy(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"
//测试代码——菜单
void menu()
{printf("****************通讯录*******************\n");printf("******1.添加联系人 2.删除联系人*******\n");printf("******3.修改联系人 4.查找联系人*******\n");printf("******5.展示联系人 0. 退出************\n");printf("*****************************************\n");
}int main()
{int input = 0;contact* con = NULL;//初始化InitContact(&con);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:FindContact(con);break;case 5:ShowContact(con);break;case 0:printf("退出通讯录...\n");break;default:printf("输入错误!请重新输入!\n");break;}} while (input != 0);//销毁通讯录;DestroyContact(&con);return 0;
}