河北购物网站开发公司,网站建设信息公开和解读回应,重庆网站模板建站公司,做网站卖广告位赚钱吗文章目录 1 基础要求2 通讯录功能2.1 引入单链表的文件2.2 定义联系人数据结构2.3 打开通讯录2.4 保存数据后销毁通讯录2.5 添加联系人2.6 删除联系人2.7 修改联系人2.8 查找联系人2.9 查看通讯录 3 通讯录代码展示3.1 SeqList_copy.h3.2 SeqList_copy.c3.3 Contact.h3.4 Conta… 文章目录 1 基础要求2 通讯录功能2.1 引入单链表的文件2.2 定义联系人数据结构2.3 打开通讯录2.4 保存数据后销毁通讯录2.5 添加联系人2.6 删除联系人2.7 修改联系人2.8 查找联系人2.9 查看通讯录 3 通讯录代码展示3.1 SeqList_copy.h3.2 SeqList_copy.c3.3 Contact.h3.4 Contact.c3.5 test.c3.6 调试控制台截图 1 基础要求 单链表,文件操作,结构体,二级指针 思路:利用上一篇博客-单链表,对单链表简易修改,应用到通讯录. 2 通讯录功能 通讯录只能能存100个人 用户信息:名字,性别,年龄,电话,地址 通讯录的展示,增,删,改,查,找. 联系人信息存储 2.1 引入单链表的文件
为了显现区别,笔者备份单链表的文件并且更名为SeqList_copy.h和SeqList_copy.c 创建Contact.h和Contact.c以及测试代码功能的test.c test.c和Contact.c引用的头文件都是Contact.h和SeqList_copy.h
2.2 定义联系人数据结构
在Contact.h头文件中 定义名字最大长度性别最大长度电话最大长度地址最大长度
#define NAME_MAX 120
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 50//前置声明
typedef struct SListNode contact;
//定义结构体
typedef struct ContactInfo
{ char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}ConInfo;2.3 打开通讯录
void ContactInit(contact** pcon)
{FILE* pf fopen(Contact_Info.txt, rb); //二进制方式打开文件if (pf NULL){perror(fopen error.\n); //主动报错,打开失败return;}ConInfo info;//回顾一下fread //size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );//从流中读取一个由count元素组成的数组每个元素的大小为size字节并将它们存储在ptr指定的内存块中。//流的位置指示器按读取的总字节数前进。//如果成功读取的总字节数为(size * count)while (fread(info, sizeof(info), 1, pf)){SLPushBack(pcon, info);}printf(历史数据已导入通讯录\n);
}2.4 保存数据后销毁通讯录 销毁通讯录之前一定要保存数据,不然2.3打开有存储联系人的通讯录的作用就没有了 void ContactSave(contact* con)
{FILE* pf fopen(Contact_Info.txt, wb);if (pf NULL){perror(fopen error\n);return;}contact* cur con;while (cur){fwrite((cur-data), sizeof(cur-data), 1, pf);cur cur-next;}printf(成功保存通讯录数据\n);
}void ContactDestory(contact** pcon)
{ContactSave(*pcon);SLDestory(pcon);
}2.5 添加联系人 使用单链表一节中尾插法添加数据 void ContactAdd(contact** pcon)
{ConInfo 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);SLPushBack(pcon, info);printf(已添加联系人数据\n);
}2.6 删除联系人 借助FindByName()函数,找到索引.然而缺陷明显,找到的索引是第一次出现的输入的姓名,同样,只能通过姓名查找 //我们这里通过姓名删除联系人
contact* FindByName(contact* con, char name[])
{contact* cur con;while (cur){if (strcmp(cur-data.name,name) 0){return cur;}cur cur-next;}return NULL;
}void ContactDel(contact** pcon)
{char name[NAME_MAX];printf(请输入你要删除的联系人姓名:\n);scanf(%s, name);contact* pos FindByName(*pcon, name);if (pos NULL){printf(该联系人不存在\n);return;}SLErase(pcon, pos);printf(已删除该联系人\n);
}2.7 修改联系人 注意age年龄是int整型,其他四个数据结构都是数组,用scanf时,这里的数组相当于首元素地址,不用. void ContactModify(contact* con)
{char name[NAME_MAX];printf(请输入你要修改的联系人姓名:\n);scanf(%s, name);contact* pos FindByName(con, name);if (pos NULL){printf(该联系人不存在\n);return;}printf(该联系人姓名修改为:\n);scanf(%s, pos-data.name); printf(该联系人性别修改为:\n);scanf(%s, pos-data.sex); printf(该联系人年龄修改为:\n);scanf(%d, pos-data.age); printf(该联系人电话修改为:\n);scanf(%s, pos-data.tel);printf(该联系人地址修改为:\n);scanf(%s, pos-data.addr);printf(修改成功\n);
}2.8 查找联系人 同样根据姓名查看详细联系人的通讯录信息 void ContactFind(contact* con)
{char name[NAME_MAX];printf(请输入你要查找的联系人姓名:\n);scanf(%s, name);contact* pos FindByName(con, name);if (pos NULL){printf(该联系人不存在\n);return;}printf(找到了\n);printf(%s %s %d %s %s\n,pos-data.name,pos-data.sex,pos-data.age,pos-data.tel,pos-data.addr);
}2.9 查看通讯录 第一次自己写的时候,curcur-next放在while循环外面了.QAQ void ContactShow(contact* con)
{printf(%s %s %s %s %s\n, 姓名, 性别, 年龄, 电话, 地址);contact* cur con;while (cur){printf(%s %s %d %s %s\n, cur-data.name, cur-data.sex, cur-data.age, cur-data.tel, cur-data.addr);cur cur-next;}
}3 通讯录代码展示
3.1 SeqList_copy.h
#pragma once
#includestdio.h
#includestdlib.h
#includeassert.h
#includestring.h
#includeContact.h//定义链表的结构
//typedef int SLDataType
typedef struct ContactInfo SLDataType; //更改SLDataType的类型typedef struct SListNode
{SLDataType data; //保存的数据struct SListNode* next; //指针变量存放下一个节点的地址
}SLNode;//1 打印链表
void SLPrint(SLNode* phead);//2 尾插
void SLPushBack(SLNode** pphead, SLDataType x);
//3 头插
void SLPushFront(SLNode** pphead, SLDataType x);//4 尾删
void SLPopBack(SLNode** pphead);//5 头删
void SLPopFront(SLNode** pphead);//SLFind()找到要查找数据的下标
//找节点的函数这里传一级实际上就可以了因为不改变头结点
//但是这里要写二级指针因为要保持接口一致性
//缺点:这个函数有一定的局限性,他找到数据x的下标是第一次出现的x的下标后,不会找后续的x的下标
SLNode* SLFind(SLNode** pphead, SLDataType x);//6 定点前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x);//7 定点后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x);//8 删除pos节点
void SLErase(SLNode** pphead, SLNode* pos);//9 删除pos后的节点
void SLEraseAfter(SLNode* pos);//10 销毁链表
void SLDestory(SLNode** pphead);3.2 SeqList_copy.c
#includeSList_copy.h//1 创建新的节点的函数
SLNode* SLBuyNode(SLDataType x)
{SLNode* node (SLNode*)malloc(sizeof(SLNode));node-data x;node-next NULL;return node;
}//2 尾插
void SLPushBack(SLNode** pphead, SLDataType x) //保存第一个节点的指针的地址
{assert(pphead);//创建一个节点SLNode* node SLBuyNode(x);if (*pphead NULL){*pphead node;return;}//链表不为空,找尾SLNode* pcur *pphead;while (pcur-next)//相当于pcur-next!NULL{pcur pcur-next;}pcur-next node;
}//3 头插
void SLPushFront(SLNode** pphead, SLDataType x)
{assert(pphead);SLNode* node SLBuyNode(x);//新结点跟头结点连接起来node-next *pphead;//让新节点成为头结点*pphead node;
}//4 尾删
void SLPopBack(SLNode** pphead)
{assert(pphead);assert(*pphead); //第一个节点不能为空//判断只有一个结点的情况if ((*pphead)-next NULL){free(*pphead);*pphead NULL;return;}//找到尾节点和尾节点的前一个节点SLNode* pre NULL;SLNode* ptail *pphead;while (ptail-next){pre ptail;ptail ptail-next;}//pre的next指针不指向ptail,而是指向ptail的下一个节点//pre-next NULL;pre-next ptail-next;//因为在SLPrint(SLNode* phead)函数中有判断节点是否为空while (pcur),所以置空free(ptail);ptail NULL;}//5 头插
void SLPopFront(SLNode** pphead)
{assert(pphead);assert(*pphead); //第一个节点不能为空SLNode* del *pphead;*pphead (*pphead)-next;free(del);del NULL;
}//6 定点前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x)
{assert(pphead);assert(pos); //pos不能为空assert(*pphead); //NULL前插入数据是荒谬的,所以assert第一个节点SLNode* node SLBuyNode(x);//当只有一个结点(pos就是第一个节点)//if (((*pphead)-next) NULL||pos*pphead),可以简化成以下代码if (pos *pphead) {node-next *pphead;*pphead node;return;}//找到pos的前一个节点SLNode* pre *pphead;while (pre-next ! pos){pre pre-next;}//处理pre node pos的位置node-next pos;pre-next node;
}//7 定点后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x)
{assert(pos);SLNode* node SLBuyNode(x);node-next pos-next;pos-next node;
}//8 删除pos节点
void SLErase(SLNode** pphead, SLNode* pos)
{assert(*pphead);assert(pphead);assert(pos);//pos是头结点if (pos *pphead){*pphead (*pphead)-next;free(pos);return;}//pos不是头结点,找pos的前一个节点SLNode* pre *pphead;while (pre-next ! pos){pre pre-next;}pre-next pos-next;free(pos);pos NULL; //代码规范
}//9 删除pos后的节点
void SLEraseAfter(SLNode* pos)
{//删除pos之后的节点也不能空assert(pos pos-next);SLNode* del pos-next;pos-next del-next;free(del);
}void SLDestory(SLNode** pphead)
{assert(pphead);SLNode* pcur *pphead;while (pcur){SLNode* next pcur-next;free(pcur);pcur next;}//头结点记得置空*pphead NULL;
}
3.3 Contact.h
#pragma once
//创建保存联系人数据的结构
#define NAME_MAX 120
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 50typedef struct ContactInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}ConInfo;
//前置声明
typedef struct SListNode contact;//1.打开通讯录
void ContactInit(contact** pcon);//2.保存数据后销毁通讯录
void ContactDestory(contact** pcon);//3.添加联系人
void ContactAdd(contact** pcon);//4.删除联系人
void ContactDel(contact** pcon);//5.修改联系人
void ContactModify(contact* con);//6.查找联系人
void ContactFind(contact* pcon);//7.查看通讯录
void ContactShow(contact* pcon);
3.4 Contact.c
#define _CRT_SECURE_NO_WARNINGS
#includeContact.h
#includeSList_copy.h//1.打开通讯录
void ContactInit(contact** pcon)
{FILE* pf fopen(Contact_Info.txt, rb);if (pf NULL){perror(fopen error.\n); //主动报错,打开失败return;}ConInfo info;//回顾一下fread //size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );//从流中读取一个由count元素组成的数组每个元素的大小为size字节并将它们存储在ptr指定的内存块中。//流的位置指示器按读取的总字节数前进。//如果成功读取的总字节数为(size * count)while (fread(info, sizeof(info), 1, pf)){SLPushBack(pcon, info);}printf(历史数据已导入通讯录\n);
}void ContactSave(contact* con)
{FILE* pf fopen(Contact_Info.txt, wb);if (pf NULL){perror(fopen error\n);return;}contact* cur con;while (cur){fwrite((cur-data), sizeof(cur-data), 1, pf);cur cur-next;}printf(成功保存通讯录数据\n);
}void ContactDestory(contact** pcon)
{ContactSave(*pcon);SLDestory(pcon);
}void ContactAdd(contact** pcon)
{ConInfo 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);SLPushBack(pcon, info);printf(已添加联系人数据\n);
}//我们这里通过姓名删除联系人
contact* FindByName(contact* con, char name[])
{contact* cur con;while (cur){if (strcmp(cur-data.name,name) 0){return cur;}cur cur-next;}return NULL;
}void ContactDel(contact** pcon)
{char name[NAME_MAX];printf(请输入你要删除的联系人姓名:\n);scanf(%s, name);contact* pos FindByName(*pcon, name);if (pos NULL){printf(该联系人不存在\n);return;}SLErase(pcon, pos);printf(已删除该联系人\n);
}void ContactModify(contact* con)
{char name[NAME_MAX];printf(请输入你要修改的联系人姓名:\n);scanf(%s, name);contact* pos FindByName(con, name);if (pos NULL){printf(该联系人不存在\n);return 1;}printf(该联系人姓名修改为:\n);scanf(%s, pos-data.name); printf(该联系人性别修改为:\n);scanf(%s, pos-data.sex); printf(该联系人年龄修改为:\n);scanf(%d, pos-data.age); printf(该联系人电话修改为:\n);scanf(%s, pos-data.tel);printf(该联系人地址修改为:\n);scanf(%s, pos-data.addr);printf(修改成功\n);
}void ContactFind(contact* con)
{char name[NAME_MAX];printf(请输入你要查找的联系人姓名:\n);scanf(%s, name);contact* pos FindByName(con, name);if (pos NULL){printf(该联系人不存在\n);return;}printf(找到了\n);printf(%s %s %d %s %s\n,pos-data.name,pos-data.sex,pos-data.age,pos-data.tel,pos-data.addr);
}void ContactShow(contact* con)
{printf(%s %s %s %s %s\n, 姓名, 性别, 年龄, 电话, 地址);contact* cur con;while (cur){printf(%s %s %d %s %s\n, cur-data.name, cur-data.sex, cur-data.age, cur-data.tel, cur-data.addr);cur cur-next;}
}
3.5 test.c
test()我封装了五个函数,都是用来测试通讯录功能的,调试结束后,就将函数封装在一起,写一个菜单完成通讯录功能.
#define _CRT_SECURE_NO_WARNINGS
#includeContact.h
#includeSList_copy.hvoid test1()
{contact *pcontactNULL;ContactInit(pcontact);
}void test2()
{contact* pcontact NULL;ContactInit(pcontact);ContactAdd(pcontact);ContactDel(pcontact);ContactShow(pcontact);}void test3()
{contact* pcontact NULL;ContactInit(pcontact);ContactShow(pcontact);ContactAdd(pcontact);ContactShow(pcontact);ContactDel(pcontact);ContactShow(pcontact);
}
void test4()
{contact* pcontact NULL;ContactInit(pcontact);ContactAdd(pcontact);ContactAdd(pcontact);ContactShow(pcontact);ContactFind(pcontact);ContactShow(pcontact);}void test5()
{contact* pcontact NULL;ContactInit(pcontact);ContactAdd(pcontact);ContactShow(pcontact);ContactModify(pcontact);ContactShow(pcontact);ContactDestory(pcontact);
}void menu()
{printf(\n);printf(****************************\n);printf(****************************\n);printf(************通讯录***********\n);printf(*********1.添加联系人********\n);printf(*********2.删除联系人********\n);printf(*********3.修改联系人********\n);printf(*********4.查找联系人********\n);printf(*********5.查看通讯录********\n);printf(*********0.退 出************\n);printf(****************************\n);printf(****************************\n);
}int main()
{//test1();//test2();//test3();//test4();//test5();int op 0;contact* conNULL;ContactInit(con);do {menu();printf(请选择:\n);scanf(%d, op);switch (op){case 1:ContactAdd(con);break;case 2:ContactDel(con);break;case 3:ContactModify(con);break;case 4:ContactFind(con);break;case 5:ContactShow(con);break;case 0:printf(退出了哈\n);break;default:printf(输入错误\n);break;}} while (op!0);ContactDestory(con);return 0;
}3.6 调试控制台截图 这里忘记啥问题了,一转眼就忘了 在多次语法错误,死循环,输出乱码,代码崩溃后,终于简单完成通讯录的功能!