当前位置: 首页 > news >正文

C 语 言 - - - 简 易 通 讯 录

C 语 言 - - - 简 易 通 讯 录

  • 代 码 全 貌 与 功 能 介 绍
  • 通 讯 录 的 功 能 说 明
  • 通 讯 录 效 果 展 示
  • 代 码 详 解
    • contact.h
    • contact.c
    • test.c
  • 总 结

💻作 者 简 介:曾 与 你 一 样 迷 茫,现 以 经 验 助 你 入 门 C 语 言
💡个 人 主 页:@笑口常开xpr 的 个 人 主 页
📚系 列 专 栏:C 启新程
✨代 码 趣 语:糟 糕 的 程 序 员 关 注 代 码,优 秀 的 程 序 员 关 注 数 据 结 构 及 其 关 系。
💪代 码 千 行,始 于 坚 持,每 日 敲 码,进 阶 编 程 之 路。
📦gitee 链 接:gitee

在这里插入图片描述

         在 编 程 的 世 界 里,每 一 行 代 码 都 可 能 隐 藏 着 无 限 的 可 能 性 。你 是 否 想 过,一 个 小 小 的 程 序 究 竟 能 改 变 什 么?它 可 以 是 解 决 复 杂 问 题 的 工 具 ,也 可 以 是 实 现 梦 想 的 桥 梁。今 天,就 让 我 们 一 起 走 进 C 语 言 通 讯 录 的 世 界,探 索 它 的 无 限 潜 力。


代 码 全 貌 与 功 能 介 绍


         整 个 通 讯 录 项 目 由 三 个 主 要 文 件 构 成:contact.h、contact.c 和 test.c。这 种 多 文 件 的 架 构 设 计,有 助 于 将 不 同 功 能 模 块 分 离,提 高 代 码 的 可 读 性、可 维 护 性 与 可 扩 展 性。

contact.h

         contact.h 包 含 了 通 讯 录 所 需 的 头 文 件 引 用、常 量 定 义 以 及 函 数 声 明。

test.c

         test.c 是 通 讯 录 的 主 逻 辑 文 件,负 责 处 理 用 户 输 入 和 代 码 流 程 的 控 制。

contact.c

contact.c 则 实 现 了 通 讯 录 的 具 体 功 能 函 数。

下 面 展 示完 整 代 码

读 者 可 以 将 这 段 代 码 复 制 到 自 己 的 编 译 器 中 运 行:

contact.h

#pragma once
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>#define MAX 100
#define NAME_MAX 20    //姓名
#define SEX_MAX 5      //性别
#define ADDR_MAX 30    //地址
#define TELE_MAX 12    //电话
#define DEFAULT_SZ 3   //默认大小
#define INC_SZ 2       //增加大小
//人的信息
typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char addr[ADDR_MAX];char tele[TELE_MAX];
}PeoInfo;//动态版本
typedef struct contact
{PeoInfo* data;//指向存放当前人的信息的空间int sz;//当前已经放的信息的总人数int capacity;//当前通讯录的最大容量
}contact;//通讯录初始化
void Initcontact(contact* pc);//增加联系人
void Addcontact(contact* pc);//显示通讯录
void Showcontact(const contact* pc);//删除通讯录
void Delcontact(contact* pc);//查找联系人
int find_by_name(const contact* pc, char name[MAX]);//查找联系人
void SearchContact(const contact* pc);//修改联系人
void Modifycontact(contact* pc);//排序
void Sortcontact(contact* pc);//检查容量
void check_capacity(contact* pc);//销毁通讯录
void DestoryContact(contact* pc);//保存通讯录中的信息到文件中
void SaveContact(contact* pc);//加载文件信息到通讯录
void LoadContact(contact* pc);//姓名排序
int cmp_contact_by_name(const void* e1, const void* e2);//年龄排序
int cmp_contact_by_age(const void* e1, const void* e2);//电话排序
int cmp_contact_by_tele(const void* e1, const void* e2);

test.c

#define _CRT_SECURE_NO_WARNINGS 0 #include "contact.h"
enum Option
{EXIT,//0ADD,//1DELETE,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};
void menu()
{printf("*******************************************\n");printf("********   1. add      2. delete   ********\n");printf("********   3. search   4. modify   ********\n");printf("********   5. show     6. sort     ********\n");printf("********   0. exit                 ********\n");printf("*******************************************\n");
}
void test()
{int input = 0;//创建通讯录contact con;//初始化通讯录Initcontact(&con);do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case EXIT://保存通讯录信息到文件中SaveContact(&con);DestoryContact(&con);//销毁通讯录printf("退出通讯录\n");break;case ADD:Addcontact(&con);break;case DELETE:Delcontact(&con);break;case SEARCH:SearchContact(&con);break;case MODIFY:Modifycontact(&con);break;case SHOW:Showcontact(&con);break;case SORT:Sortcontact(&con);break;default:printf("选择错误,请重新输入\n");break;}} while (input);
}
int main()
{test();return 0;
}

contact.c

#define _CRT_SECURE_NO_WARNINGS 0 #include "contact.h"
//初始化通讯录
void Initcontact(contact* pc)
{assert(pc);pc->sz = 0;PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));if (ptr == NULL){perror("Initcontact");return;}pc->data = ptr;pc->capacity = DEFAULT_SZ;//加载文件信息到通讯录LoadContact(pc);
}//动态添加人数
void Addcontact(contact* pc)
{assert(pc);check_capacity(pc);printf("请输入名字:>\n");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:>\n");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:>\n");scanf("%s", pc->data[pc->sz].sex);printf("请输入地址:>\n");scanf("%s", pc->data[pc->sz].addr);printf("请输入电话:>\n");scanf("%s", pc->data[pc->sz].tele);pc->sz++;
}//显示通讯录
//声明和定义保持一致
void Showcontact(const contact* pc)
{assert(pc);int i = 0;printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");for (i = 0;i < pc->sz;i++){printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name, pc->data[i].age,pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);}
}//删除指定联系人
void Delcontact(contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}char name[MAX] = { 0 };printf("请输入要删除人的名字:>\n");scanf("%s", name);int ret = find_by_name(pc, name);int i = 0;if (-1 == ret){printf("要删除的人不存在\n");return;}else{//删除for (i = ret;i < pc->sz - 1;i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");}
}//查找联系人
int find_by_name(const contact* pc, char name[MAX])
{assert(pc);int i = 0;for (i = 0;i < pc->sz;i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}void SearchContact(const contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要查找人的名字:>\n");scanf("%s", name);int pos = find_by_name(pc, name);if (-1 == pos){printf("要查找的人不存在\n");return;}else{printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[pos].name, pc->data[pos].age,pc->data[pos].sex, pc->data[pos].addr, pc->data[pos].tele);}
}//修改通讯录
void Modifycontact(contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要修改人的名字:>\n");scanf("%s", name);int pos = find_by_name(pc, name);if (-1 == pos){printf("要修改的人不存在\n");return;}printf("请输入名字:>\n");scanf("%s", pc->data[pos].name);printf("请输入年龄:>\n");scanf("%d", &(pc->data[pos].age));printf("请输入性别:>\n");scanf("%s", pc->data[pos].sex);printf("请输入地址:>\n");scanf("%s", pc->data[pos].addr);printf("请输入电话:>\n");scanf("%s", pc->data[pos].tele);printf("修改完成\n");
}//增加容量
void check_capacity(contact* pc)
{if (pc->sz == pc->capacity){//增加容量PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr == NULL){perror("check_capacity::realloc");return;}pc->data = ptr;pc->capacity += INC_SZ;}
}//销毁通讯录
void DestoryContact(contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;
}void SaveContact(contact* pc)
{//写数据//打开文件FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("SaveContact");}else{//写数据int i = 0;for (i = 0; i < pc -> sz; i++){fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);}fclose(pf);pf = NULL;}printf("保存数据成功\n");
}//加载文件信息到通讯录
void LoadContact(contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "rb");if (NULL == pf){perror("LoadContact");}else{//读数据PeoInfo tmp = { 0 };int i = 0;while (fread(&tmp, sizeof(PeoInfo), 1, pf)){check_capacity(pc);pc->data[i] = tmp;pc->sz++;i++;}fclose(pf);pf = NULL;}
}void Sortcontact(contact* pc)
{assert(pc);int input = 0;printf("请输入你想以0. 名字 1. 电话 2. 年龄 排序的数字:>\n");scanf("%d", &input);if (input == 0){qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_contact_by_name);Showcontact(pc);}else if (input == 1){qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_contact_by_tele);Showcontact(pc);}else if (input == 2){qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_contact_by_age);Showcontact(pc);}else{printf("无效输入\n");}
}
int cmp_contact_by_name(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}int cmp_contact_by_age(const void* e1, const void* e2)
{return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age;
}int cmp_contact_by_tele(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->tele, ((PeoInfo*)e2)->tele);
}

通 讯 录 的 功 能 说 明

初 始 化 功 能:通 过 Initcontact 函 数 为 通 讯 录 分 配 内 存 并 设 置 初 始 状 态,并 从 文 件 中 加 载 已 有 联 系 人 信 息。

添 加 联 系 人:Addcontact 函 数 用 于 向 通 讯 录 中 添 加 新 的 联 系 人。它 会 检 查 通 讯 录 的 容 量,若 已 满 则 进 行 扩 容,然 后 获 取 用 户 输 入 的 联 系 人 信 息,包 括 姓 名、年 龄、性 别、地 址 和 电 话,并 将 其 添 加 到 通 讯 录 中。

显 示 联 系 人:Showcontact 函 数 用 于 显 示 通 讯 录 中 所 有 联 系 人 的 信 息。它 会 遍 历 通 讯 录,以 格 式 化 的 方 式 输 出 每 个 联 系 人 的 姓 名、年 龄、性 别、地 址 和 电 话。

删 除 联 系 人:Delcontact 函 数 用 于 删 除 通 讯 录 中 指 定 的 联 系 人。

查 找 联 系 人:SearchContact 函 数 用 于 查 找 通 讯 录 中 指 定 的 联 系 人。

修 改 联 系 人:Modifycontact 函 数 用 于 修 改 通 讯 录 中 指 定 联 系 人 的 信 息。

排 序 功 能:Sortcontact 函 数 用 于 对 通 讯 录 中 的 联 系 人 进 行排 序。用 户 可 以 选 择 按 姓 名、年 龄 或 电 话 进 行 排 序,根 据 用 户 的 选 择 调 用 相 应 并 显 示 排 序 后 的 通 讯 录。

数 据 持 久 化:SaveContact 函 数 用 于 将 通 讯 录 中 的 联 系 人 信 息 保 存 到 文 件 中,LoadContact 函 数 用 于 从 文 件 中 加 载 联 系 人 信 息 到 通 讯 录,实 现 数 据 的 持 久 化 存 储。

错 误 处 理:在 内 存 分 配 和 文 件 操 作 中 使 用 了 perror 等 方 式 进 行 错 误 处 理,当 操 作 失 败 时 输 出 相 应 的 错 误 信 息。


通 讯 录 效 果 展 示

菜 单 展 示

         每 次 循 环 开 始 时 会 显 示 菜 单,内 容 包 括:
add:     添 加 联 系 人
delete: 删 除 联 系 人
search:查 找 联 系 人
modify:修 改 联 系 人
show:   显 示 所 有 联 系 人
sort:     对 联 系 人 进 行 排 序
exit:     退 出 通 讯 录

在这里插入图片描述

添 加 联 系 人(add)

         输 入 1 后,程 序 会 提 示 用 户 依 次 输 入 名 字、年 龄、性 别、地 址 和 电 话。输 入 完 成 后,联 系 人 信 息 被 添 加 到 通 讯 录 中。如 果 通 讯 录 已 满,会 自 动 增 加 容 量。

在这里插入图片描述

显 示 联 系 人(show)

         输 入 5 后,程 序 会 显 示 所 有 已 添 加 的 联 系 人 信 息。

在这里插入图片描述

删 除 联 系 人(delete)

         输 入 2 后,程 序 会 提 示 用 户 输 入 要 删 除 的 联 系 人 名 字。如 果 找 到 该 联 系 人,将 其 从 通 讯 录 中 移 除;如 果 未 找 到,提 示 联 系 人 不 存 在。

在这里插入图片描述

查 找 联 系 人(search)

         输 入 3 后,程 序 会 提 示 用 户 输 入 要 查 找 的 联 系 人 名 字。如 果 找 到 该 联 系 人,显 示 其 详 细 信 息;如 果 未 找 到,提 示 联 系 人 不 存 在。

在这里插入图片描述

修 改 联 系 人(modify)

         输 入 4 后,程 序 会 提 示 用 户 输 入 要 修 改 的 联 系 人 名 字。如 果 找 到 该 联 系 人,提 示 用 户 依 次 输 入 新 的 名 字、年 龄、性 别 、地 址 和 电 话,完 成 修 改;如 果 未 找 到,提 示 联 系 人 不 存 在。

在这里插入图片描述

排 序 联 系 人(sort)

         输 入 6 后,程 序 会 提 示 用 户 选 择 排 序 方 式:
0:按 名 字 排 序
1:按 电 话 排 序
2:按 年 龄 排 序
         根 据 用 户 选 择 的 排 序 方 式 对 通 讯 录 中 的 联 系 人 进 行 排 序 , 并 显 示 排 序 后 的 结 果。

在这里插入图片描述

退 出 通 讯 录(exit)

         输 入 0 后,程 序 会 将 通 讯 录 中 的 信 息 以 二 进 制 形 式 保 存 到 文 件 “contact.txt” 中。释 放 内 存 并 销 毁 通 讯 录, 然 后 退 出 程 序。

在这里插入图片描述
在这里插入图片描述


代 码 详 解

contact.h

#pragma once

         #pragma once 是 一 个 预 处 理 指 令,用 于 防 止 头 文 件 被 重 复 包 含。在 大 型 项 目 中,多 个 源 文 件 可 能 会 包 含 同 一 个 头 文 件,使 用 #pragma once 可 以 确 保 头 文 件 的 内 容 只 被 编 译 一 次,避 免 重 复 定 义 的 错 误。

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>

         #include 指 令 用 于 引 入 必 要 的 标 准 库 头 文 件:

stdio.h:提 供 标 准 输 入 输 出 函 数,如 printf、scanf 等。
string.h:提 供 字 符 串 处 理 函 数,如 strcmp、strcpy 等。
assert.h:提 供 assert 宏,用 于 在 运 行 时 检 查 程 序 的 断 言 条 件。
stdlib.h:提 供 内 存 管 理 函 数(如 malloc、realloc、free)和 其 他 标 准 库 函 数。

#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define TELE_MAX 12
#define DEFAULT_SZ 3   //默认大小
#define INC_SZ 2   //增加大小

         #define 指 令 用 于 定 义 一 些 常 量:

MAX:用 于 表 示 通 讯 录 可 容 纳 的 最 大 联 系 人 数 量。
NAME_MAX:定 义 联 系 人 姓 名 的 最 大 长 度 为 20 个 字 符。
SEX_MAX:定 义 联 系 人 性 别 信 息 的 最 大 长 度 为 5 个 字 符。
ADDR_MAX:定 义 联 系 人 地 址 的 最 大 长 度 为 30 个 字 符。
TELE_MAX:定 义 联 系 人 电 话 号 码 的 最 大 长 度 为 12 个 字 符。
DEFAULT_SZ:定 义 通 讯 录 的 初 始 容 量 为 3 个 联 系 人。
INC_SZ:定 义 每 次 扩 展 通 讯 录 容 量 时 增 加 的 数 量 为 2 个 联 系 人。

//人的信息
typedef struct PeoInfo
{char name[20];int age;char sex[5];char addr[30];char tele[12];
} PeoInfo;

         定 义 了 一 个 名 为 PeoInfo 的 结 构 体,用 于 存 储 单 个 联 系 人 的 信 息:

name:字 符 数 组,用 于 存 储 联 系 人 姓 名。
age:整 数,用 于 存 储 联 系 人 年 龄。
sex:字 符 数 组,用 于 存 储 联 系 人 性 别。
addr:字 符 数 组,用 于 存 储 联 系 人 地 址。
tele:字 符 数 组,用 于 存 储 联 系 人 电 话 号 码。

//动态版本
typedef struct contact
{PeoInfo* data;//指向存放当前人的信息的空间int sz;//当前已经放的信息的总人数int capacity;//当前通讯录的最大容量
}contact;

         定 义 了 一 个 名 为 contact 的 结 构 体,用 于 表 示 整 个 通 讯 录:

data:指 向 PeoInfo 结 构 体 的 指 针,用 于 动 态 分 配 内 存 来 存 储 联 系 人 信 息。
sz:整 数,记 录 当 前 通 讯 录 中 已 存 储 的 联 系 人 数 量。
capacity:整 数,记 录 当 前 通 讯 录 的 最 大 容 量。

//通讯录初始化
void Initcontact(contact* pc);//增加联系人
void Addcontact(contact* pc);//显示通讯录
void Showcontact(const contact* pc);//删除联系人
void Delcontact(contact* pc);//查找联系人
int find_by_name(const contact* pc, char name[MAX]);//查找联系人
void SearchContact(const contact* pc);//修改联系人
void Modifycontact(contact* pc);//排序
void Sortcontact(contact* pc);//检查容量
void check_capacity(contact* pc);//销毁通讯录
void DestoryContact(contact* pc);//保存通讯录中的信息到文件中
void SaveContact(contact* pc);//加载文件信息到通讯录
void LoadContact(contact* pc);//姓名排序
int cmp_contact_by_name(const void* e1, const void* e2);//年龄排序
int cmp_contact_by_age(const void* e1, const void* e2);//电话排序
int cmp_contact_by_tele(const void* e1, const void* e2);

         函 数 声 明,定 义 了 对 通 讯 录 进 行 操 作 的 各 个 功 能 函 数:

Initcontact:用 于 初 始 化 通 讯 录,分 配 内 存 并 设 置 初 始 状 态。
Addcontact:用 于 向 通 讯 录 中 添 加 新 的 联 系 人。
Showcontact:用 于 显 示 通 讯 录 中 已 有 的 联 系 人 信 息。
Delcontact:用 于 从 通 讯 录 中 删 除 指 定 的 联 系 人。
find_by_name:根 据 姓 名 查 找 联 系 人,返 回 联 系 人 在 通 讯 录 中 的 位 置,找 不 到 返 回 特 定 值。
SearchContact:根 据 姓 名 查 找 并 显 示 联 系 人 信 息。
Modifycontact:用 于 修 改 通 讯 录 中 指 定 联 系 人 的 信 息。
Sortcontact:用 于 对 通 讯 录 中 的 联 系 人 按 照 指 定 方 式( 如 姓 名、年 龄、电 话)进 行 排 序。
check_capacity:检 查 通 讯 录 的 容 量,必 要 时 进 行 扩 容。
DestoryContact:用 于 销 毁 通 讯 录,释 放 分 配 的 内 存。
SaveContact:将 通 讯 录 中 的 信 息 保 存 到 文 件 中。
LoadContact:从 文 件 中 加 载 联 系 人 信 息 到 通 讯 录。
cmp_contact_by_name:比 较 两 个 联 系 人 的 姓 名,用 于 排 序。
cmp_contact_by_age:比 较 两 个 联 系 人 的 年 龄,用 于 排 序。
cmp_contact_by_tele:比 较 两 个 联 系 人 的 电 话,用 于 排 序。

contact.c

内 存 管 理 机 制

//初始化
void Initcontact(contact* pc)
{assert(pc);pc->sz = 0;PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));if (ptr == NULL){perror("Initcontact");return;}pc->data = ptr;pc->capacity = DEFAULT_SZ;//加载文件信息到通讯录LoadContact(pc);
}
//扩容
void check_capacity(contact* pc)
{if (pc->sz == pc->capacity){//增加容量PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr == NULL){perror("check_capacity::realloc");return;}pc->data = ptr;pc->capacity += INC_SZ;}
}

初 始 化:使 用 calloc 分 配 初 始 空 间 并 清 零。
动 态 扩 容:每 次 容 量 不 足 时 增 加 INC_SZ(2) 个 空 间。
内 存 安 全:通 过 realloc 确 保 数 据 连 续 性,失 败 时 输 出 错 误 信 息。

联 系 人 核 心 操 作

添 加 联 系 人

void Addcontact(contact* pc)
{assert(pc);check_capacity(pc);printf("请输入名字:>\n");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:>\n");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:>\n");scanf("%s", pc->data[pc->sz].sex);printf("请输入地址:>\n");scanf("%s", pc->data[pc->sz].addr);printf("请输入电话:>\n");scanf("%s", pc->data[pc->sz].tele);pc->sz++;
}

自 动 扩 容:添 加 前 检 查 容 量,不 足 时 自 动 扩 展。

输 入 处 理:使 用 scanf 获 取 用 户 输 入,未 处 理 包 含 空 格 的 字 符 串。

删 除 联 系 人

void Delcontact(contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}char name[MAX] = { 0 };printf("请输入要删除人的名字:>\n");scanf("%s", name);int ret = find_by_name(pc, name);int i = 0;if (-1 == ret){printf("要删除的人不存在\n");return;}else{//删除for (i = ret;i < pc->sz - 1;i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");}
}

查 找 联 系 人:通 过 find_by_name 定 位 联 系 人。
数 据 迁 移:删 除 后 将 后 续 元 素 前 移 覆 盖。

数 据 持 久 化

void SaveContact(contact* pc)
{//写数据//打开文件FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("SaveContact");}else{//写数据int i = 0;for (i = 0; i < pc -> sz; i++){fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);}fclose(pf);pf = NULL;}printf("保存数据成功\n");
}//加载文件信息到通讯录
void LoadContact(contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "rb");if (NULL == pf){perror("LoadContact");}else{//读数据PeoInfo tmp = { 0 };int i = 0;while (fread(&tmp, sizeof(PeoInfo), 1, pf)){check_capacity(pc);pc->data[i] = tmp;pc->sz++;i++;}fclose(pf);pf = NULL;}
}

二 进 制 存 储:使 用 fwrite 和 fread 进 行 整 块 数 据 读 写。

自 动 加 载:初 始 化 时 自 动 从 文 件 恢 复 数 据。

容 量 管 理:加 载 时 动 态 扩 展 内 存 确 保 足 够 空 间。

排 序 功 能

void Sortcontact(contact* pc)
{assert(pc);int input = 0;printf("请输入你想以0. 名字 1. 电话 2. 年龄 排序的数字:>\n");scanf("%d", &input);if (input == 0){qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_contact_by_name);Showcontact(pc);}else if (input == 1){qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_contact_by_tele);Showcontact(pc);}else if (input == 2){qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_contact_by_age);Showcontact(pc);}else{printf("无效输入\n");}
}
int cmp_contact_by_name(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}int cmp_contact_by_age(const void* e1, const void* e2)
{return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age;
}int cmp_contact_by_tele(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->tele, ((PeoInfo*)e2)->tele);
}

标 准 库 排 序:利 用 qsort 实 现 通 用 排 序。
函 数 指 针:符 合 qsort 要 求 的 比 较 函 数 原 型。
字 符 串 比 较:使 用 strcmp 进 行 字 典 序 比 较。
数 值 比 较:直 接 相 减 获 取 大 小 关 系。

查 找 联 系 人

int find_by_name(const contact* pc, char name[MAX])
{assert(pc);int i = 0;for (i = 0;i < pc->sz;i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}

函 数 功 能:在 通 讯 录 中 查 找 指 定 姓 名 的 联 系 人,返 回 其 索 引(未 找 到 返 回 - 1)。

test.c

菜 单 界 面

void menu() {printf("*******************************************\n");printf("********   1. add      2. delete   ********\n");printf("********   3. search   4. modify   ********\n");printf("********   5. show     6. sort     ********\n");printf("********   0. exit                 ********\n");printf("*******************************************\n");
}

使 用 星 号 (*) 绘 制 边 框,提 供 清 晰 的 视 觉 界 面。
数 字 编 号 对 应 不 同 功 能,方 便 用 户 选 择。

枚 举 常 量

enum Option
{EXIT,//0ADD,//1DELETE,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};

         定 义 了 一 个 枚 举 类 型 Option,其 中 包 含 了 EXIT(退 出)、ADD(添 加 联 系 人)、DELETE(删 除 联 系 人)、SEARCH(查 找 联 系 人)、MODIFY(修 改 联 系 人)、SHOW(显 示 联 系 人 信 息)、SORT(对 联 系 人 进 行 排 序)等 枚 举 常 量,这 些 常 量 用 于 表 示 不 同 的 操 作 选 项,每 个 常 量 对 应 一 个 整 数 值。

主 循 环 逻 辑

void test()
{int input = 0;//创建通讯录contact con;//初始化通讯录Initcontact(&con);do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case EXIT://保存通讯录信息到文件中SaveContact(&con);DestoryContact(&con);//销毁通讯录printf("退出通讯录\n");break;case ADD:Addcontact(&con);break;case DELETE:Delcontact(&con);break;case SEARCH:SearchContact(&con);break;case MODIFY:Modifycontact(&con);break;case SHOW:Showcontact(&con);break;case SORT:Sortcontact(&con);break;default:printf("选择错误,请重新输入\n");break;}} while (input);
}

初 始 化:调 用 Initcontact 分 配 内 存 并 加 载 文 件 数 据。
循 环 控 制:使 用 do-while 确 保 至 少 执 行 一 次 菜 单 选 择。
选 项 处 理:通 过 switch 分 支 调 用 不 同 功 能 函 数。
安 全 退 出:退 出 前 保 存 数 据 并 释 放 内 存,防 止 资 源 泄 漏。

程 序 入 口

int main()
{test();return 0;
}

         main 函 数 是 程 序 的 入 口 点,调 用 test 函 数 启 动 通 讯 录 管 理 系 统,最 后 返 回 0 表 示 程 序 正 常 结 束。

在这里插入图片描述


总 结


         通 过 对 这 个 C 语 言 通 讯 录 管 理 系 统 代 码 的 分 析,我 们 深 入 了 解 了 如 何 运 用 C 语 言 的 各 种 特 性 实 现 一 个 实 用 的 小 型 项 目。在 实 际 开 发 中,不 断 优 化 和 扩展 这 样 的 项 目,有 助 于 我 们 提 升 编 程 技 能,积 累 项 目 经 验。希 望 这 篇 博 客 能 对 大 家 学 习 C 语 言 和 理 解 程 序 设 计 有 所 帮 助,也 欢 迎 大 家 在 评 论 区 分 享 自 己 的 见 解 和 改 进 思 路!

相关文章:

  • Python 字符串
  • 【Linux 系统调试】syslog:Linux 系统日志工具详解
  • c++STL-vector的模拟实现
  • 开关电源滤波器讲解
  • 鲁滨逊归结原理详解:期末考点+解题指南
  • c++刷题便捷函数(类似于stoi的小函数)
  • 解锁性能密码:Linux 环境下 Oracle 大页配置全攻略​
  • 基于大模型的甲状腺结节诊疗全流程预测与方案研究报告
  • 基于STM32、HAL库的RN7302电能计量芯片驱动程序设计
  • Docke容器下JAVA系统时间与Linux服务器时间不一致问题解决办法
  • latex控制表格宽度,不要超出页面
  • java 中 pojo 的详细讲解
  • 国外付费AI软件充值教程
  • 图中点的层次:BFS与邻接表的完美结合
  • Linux复习笔记(三) 网络服务配置(web)
  • python标准库--itertools - 迭代器工具在算法比赛的应用
  • DVWA靶场保姆级通关教程--08SQL盲注(上)
  • Linux常用命令(持续完善)
  • 深入解读tcpdump:原理、数据结构与操作手册
  • Ollama+OpenWebUI+docker完整版部署,附带软件下载链接,配置+中文汉化+docker源,适合内网部署,可以局域网使用
  • 一手实测深夜发布的世界首个设计Agent - Lovart。
  • 第四届长三角国际应急博览会开幕,超3000件前沿装备技术亮相
  • 左娅︱悼陈昊
  • A股三大股指集体高开
  • 基因编辑技术让蜘蛛吐彩丝
  • 江西省司法厅厅长张强已任江西省委政法委分管日常工作副书记