文章目录
- 一、前言
- 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;
}