三.Linux开发:通讯录(结构体实现)
本项目基于C 语言 单向链表实现通讯录管理系统采用分层架构设计支持人员信息增删改查、文件持久化存储配套完整的调试与 BUG 排查方案是 Linux C 开发入门的经典工程实践项目。完整代码在最下面。一、项目总览与架构设计1.1 核心需求分析通讯录系统的核心功能围绕联系人信息管理展开基础需求如下增添加新联系人支持姓名、手机号、性别、年龄等信息录入删按指定条件姓名 / 手机号删除联系人改修改已有联系人的信息查按姓名 / 手机号查询并展示联系人详情遍历格式化展示所有联系人列表持久化程序退出时保存数据到文件启动时自动加载数据交互控制台菜单支持用户选择操作1.2 分层架构设计项目采用经典的三层架构实现数据、逻辑、接口解耦提升代码可维护性与可调试性。层级职责特点数据层链表层定义数据结构实现链表基础操作增删节点、遍历、销毁只负责数据存储与组织不包含任何业务规则接口层API 层封装链表底层操作向上提供统一的函数接口屏蔽指针细节业务层无需直接操作链表节点业务逻辑层处理业务规则如数据合法性校验、重复判断、异常分支处理核心业务规则都在这一层实现交互层UI 层菜单打印、用户输入接收、结果展示只负责交互不包含核心逻辑架构设计的核心优势分层解耦修改链表实现不影响业务逻辑修改业务规则不改动底层数据结构便于调试问题可快速定位到对应层级可扩展性强后续新增功能只需在对应层级补充代码二、底层链表实现2.1 核心结构体定义1联系人信息结构体存储单个联系人的所有属性作为链表节点的数据域。typedef struct Contact { char name[32]; // 姓名 char phone[20]; // 手机号 char gender[8]; // 性别 int age; // 年龄 }Contact;2链表节点结构体单向链表节点包含数据域和指针域。// 链表节点结构体 typedef struct Node { Contact data; // 数据域联系人信息 struct Node* next; // 指针域指向后继节点 } Node;3链表管理结构体封装链表头指针与节点数量简化操作。// 通讯录链表管理结构体 typedef struct AddressBook { Node* head; int count; } AddressBook;2.2 链表基础操作函数数据层仅实现最基础的链表原子操作不包含业务判断init_book()初始化通讯录创建空链表头指针置 NULL计数清 0create_node(Contact data)申请内存创建新节点返回节点指针insert_head(Node **head, Node *new_node)头插法插入节点insert_tail(Node **head, Node *new_node)尾插法插入节点通讯录推荐使用保持添加顺序free_node(Node *node)释放单个节点内存destroy_book(Node **head)销毁整个链表释放所有节点内存防止内存泄漏关键注意点每次malloc后必须判断返回值是否为 NULL处理内存分配失败的情况尾节点的next必须初始化为NULL避免遍历出现野指针程序退出前必须遍历释放所有节点杜绝内存泄漏三、接口层设计与实现3.1 接口层的作用与设计原则接口层是业务逻辑与底层链表之间的桥梁核心作用是封装底层细节提供标准化调用入口。设计原则入参校验所有接口先判断参数合法性如指针非空、字符串长度合法状态返回函数返回状态码0 成功-1 失败-2 不存在等便于上层处理屏蔽指针业务层无需操作Node*只通过接口函数传递数据3.2 核心接口函数定义// 添加联系人传入联系人数据返回状态码 int api_add_contact(AddressBook *book, Contact *data); ​ // 删除联系人按姓名删除返回状态码 int api_delete_contact(AddressBook *book, const char *name); ​ // 查询联系人按姓名查找返回找到的节点数据通过出参带回 int api_search_contact(AddressBook *book, const char *name, Contact *result); ​ // 修改联系人按姓名查找并更新信息 int api_modify_contact(AddressBook *book, const char *name, Contact *new_data); ​ // 遍历所有联系人回调函数方式/直接打印 int api_list_all(AddressBook *book); ​ // 获取联系人总数 int api_get_count(AddressBook *book);四、业务逻辑层分析与实现4.1 业务层职责业务层是系统的核心负责所有业务规则判断调用接口层完成数据操作。数据合法性校验业务规则判断如姓名是否重复异常场景处理多步操作封装4.2 核心业务逻辑实现1添加联系人业务逻辑校验输入数据姓名不能为空、手机号长度合法、年龄在合理范围0~150查重判断调用查询接口检查姓名 / 手机号是否已存在调用接口层api_add_contact完成插入返回执行结果给交互层2删除联系人业务逻辑校验删除条件姓名非空判断链表是否为空空链表直接返回 “无数据”调用接口层执行删除根据返回值反馈 “删除成功 / 联系人不存在”3修改联系人业务逻辑先查询目标联系人是否存在校验新数据的合法性调用接口层执行修改4查询与遍历业务逻辑查询支持精确查询也可扩展模糊查询遍历格式化输出对齐列宽提升可读性五、人员操作功能调试与运行5.1 编译与调试环境编译命令gcc -g contact.c main.c -o contact_book-g参数生成调试信息支持 gdb 调试调试工具Linux 下使用gdbWindows 下可使用 VS、Dev-C 等 IDE 调试5.2 增改查功能调试要点添加功能调试断点位置create_node、insert_tail函数入口检查项节点内存是否分配成功、数据是否正确拷贝、next 指针是否置 NULL、头指针是否正确更新常见问题字符串赋值用了导致地址赋值错误必须用strcpy/strncpy查询功能调试断点位置遍历循环处、字符串比较处检查项循环是否遍历所有节点、字符串比较是否使用strcmp不能用常见问题遍历提前终止、未处理空链表情况修改功能调试检查项找到节点后数据是否正确覆盖、未找到节点是否返回对应错误码5.3 基础功能测试用例测试场景预期结果正常添加 1 条联系人添加成功总数 1添加姓名重复的联系人提示已存在添加失败空链表查询 / 删除提示无数据不崩溃修改不存在的联系人提示联系人不存在输入非法数据空姓名、负数年龄校验不通过提示重新输入六、删除功能调试与 BUG 解决方案链表删除是最高频出 BUG 的环节必须分场景处理。6.1 链表删除的三种场景删除头节点特殊处理将链表头指针指向第二个节点删除中间节点找到前驱节点prev执行prev-next cur-next删除尾节点前驱节点的next置为NULL6.2 常见 BUG 与排查方法写完代码可以查一下自己出现了哪些错误。常见 BUG现象原因解决方案段错误Segmentation Fault删除操作时程序崩溃空链表直接操作、访问 NULL 指针的 next函数入口先判空所有指针访问前校验非空删除头节点后数据丢失删除第一个人后链表无法遍历未更新头指针头指针变成野指针删除头节点时执行*head cur-next删除后遍历死循环执行删除后遍历停不下来删除尾节点时前驱节点 next 未置 NULL尾节点删除后手动将prev-next NULL明明存在却删不掉输入正确姓名但提示不存在字符串比较用了比较的是地址而非内容使用strcmp(name, cur-data.name) 0判断相等内存泄漏多次增删后内存占用升高删除节点只改指针未 free 节点内存移除节点后必须执行free(cur)释放内存删错节点删除的不是目标联系人遍历查找逻辑错误、指针偏移出错gdb 逐步打印节点姓名跟踪指针走向BUG 排查通用思路分段打印在关键节点打印指针地址、节点数据缩小问题范围gdb 单步执行跟踪每一步指针变化定位出错的代码行边界优先优先测试空链表、单节点链表、尾节点等边界场景七、文件持久化保存与加载7.1 接口层文件读写接口1保存文件接口遍历链表将每个节点的数据写入文件推荐二进制存储读写效率高、结构体直接读写。// 接口层保存通讯录到文件 int api_save_to_file(AddressBook *book, const char *filename) { FILE *fp fopen(filename, wb); // 二进制写模式 if(fp NULL) return -1; Node* cur book-head; while(cur ! NULL) { fwrite(cur-data, sizeof(Contact), fp); // 写入单条联系人数据 cur cur-next; } fclose(fp); return 0; }2加载文件接口从文件循环读取数据创建节点插入链表重建内存中的数据结构。// 接口层从文件加载通讯录 int api_load_from_file(AddressBook *book, const char *filename) { FILE* fp fopen(filename, rb); // 二进制读模式 if(fp NULL) return -1; // 文件不存在时返回初始化空链表 Contact tmp; while(fread(tmp, sizeof(Contact), 1, fp) 1) { api_add_contact(book, tmp); // 调用已有添加接口插入链表 } fclose(fp); return 0; }7.2 业务层持久化逻辑封装启动自动加载程序初始化时自动调用加载函数读取本地文件退出自动保存用户选择 “退出” 选项时自动执行保存操作手动保存菜单提供 “保存” 选项支持随时手动存档7.3 边界与异常处理文件不存在首次运行无数据文件时正常初始化空通讯录不报错文件为空读取 0 条数据返回空链表读写权限不足fopen失败时给出明确提示数据损坏可扩展校验逻辑异常文件提示数据损坏八、项目整体联调与运行8.1 完整运行流程程序启动 ↓ 初始化通讯录结构体 ↓ 加载本地数据文件 → 无文件则创建空通讯录 ↓ 打印主菜单等待用户输入 ↓ 用户选择功能 → 执行业务逻辑 → 展示结果 ↓ 循环菜单直到用户选择退出 ↓ 自动保存数据到文件 ↓ 释放链表所有内存 → 程序退出8.2 全场景测试用例首次运行测试无数据文件程序正常启动添加数据后退出再打开数据不丢失边界数据测试0 个联系人、1 个联系人、大量联系人100 条异常输入测试菜单输入字母、超长字符串输入程序不崩溃异常退出测试强制关闭程序后下次启动保留最后一次保存的数据重复操作测试反复增删改查链表结构正常无内存泄漏8.3 内存与健壮性优化内存泄漏检测使用valgrind工具检测命令valgrind --leak-checkfull ./contact_book要求程序正常退出后所有堆内存都被释放输入健壮性限制输入字符串长度使用fgets替代scanf避免缓冲区溢出错误提示友好所有失败操作给出明确原因不输出无意义的报错完整代码address_book.c#include stdio.h #include stdlib.h #include string.h ​ /************************* 宏定义 *************************/ #define NAME_LEN 32 #define PHONE_LEN 20 #define GENDER_LEN 8 #define DATA_FILE contact.dat ​ /************************* 数据结构定义 *************************/ // 联系人信息结构体数据域 typedef struct { char name[NAME_LEN]; char phone[PHONE_LEN]; char gender[GENDER_LEN]; int age; } Contact; ​ // 链表节点结构体 typedef struct Node { Contact data; // 数据域 struct Node* next; // 指针域指向后继节点 } Node; ​ // 通讯录管理结构体封装头指针与数量 typedef struct { Node* head; // 链表头指针 int count; // 当前联系人总数 } AddressBook; ​ /************************* 数据层链表基础操作 *************************/ /** * brief 初始化空通讯录 */ void init_book(AddressBook *book) { book-head NULL; book-count 0; } ​ /** * brief 创建新的链表节点 * param data 联系人数据 * return 新节点指针失败返回NULL */ Node* create_node(Contact *data) { Node *new_node (Node*)malloc(sizeof(Node)); if(new_node NULL) { printf(内存分配失败\n); return NULL; } // 拷贝数据初始化指针 memcpy(new_node-data, data, sizeof(Contact)); new_node-next NULL; return new_node; } ​ /** * brief 头插法插入节点 * return 0成功 -1失败 */ int insert_head(AddressBook *book, Node *new_node) { if(book NULL || new_node NULL) return -1; // 空链表新节点直接作为头节点 if(book-head NULL) { book-head new_node; } else { new_node-next book-head-next; book-head-next new_node; } book-count ; return 0; } ​ /** * brief 销毁整个链表释放所有内存防止内存泄漏 */ void destroy_book(AddressBook *book) { if(book NULL) return ; Node *cur book-head; while(cur ! NULL) { Node *tmp cur-next; free(cur); cur tmp; } book-head NULL; book-count 0; } ​ /************************* 接口层功能封装 *************************/ /** * brief 添加联系人接口 * return 0成功 -1失败 */ int api_add_contact(AddressBook *book, Contact *data) { if(book NULL || data NULL) return -1; Node *new_node create_node(data); if(new_node NULL) return -1; return insert_head(book, new_node); } ​ /** * brief 按姓名删除联系人接口 * return 0成功 -1参数/空链表错误 -2联系人不存在 */ int api_delete_contact(AddressBook *book, const char *name) { if(book NULL || name NULL || book-head NULL) return -1; Node *prev NULL; Node *cur book-head; // 遍历查找目标联系人 while(cur ! NULL) { if (strcmp(cur-data.name, name) 0) { break; } prev cur; cur cur-next; } if(cur NULL) return -2; // 未找到 // 执行删除分场景处理 if(prev NULL) { // 场景1删除头节点 book-head cur-next; } else { // 场景2删除中间/尾节点 prev-next cur-next; } free(cur); book-count--; return 0; } ​ /** * brief 按姓名查询联系人 * param result 出参带回找到的联系人数据 * return 0成功 -1未找到 */ int api_search_contact(AddressBook *book, const char *name, Contact *result) { if(book NULL || name NULL || result NULL) return -1; Node *cur book-head; while(cur ! NULL) { if(strcmp(cur-data.name, name) 0) { memcpy(result, cur-data, sizeof(Contact)); return 0; } cur cur-next; } return -1; } ​ /** * brief 修改联系人信息 * return 0成功 -1失败 */ int api_modify_contact(AddressBook *book, const char *name, Contact *new_data) { if (book NULL || name NULL || new_data NULL) return -1; Node *cur book-head; while(cur ! NULL) { if(strcmp(cur-data.name, name) 0) { // 保留原姓名更新其他字段 strncpy(cur-data.phone, new_data-phone, PHONE_LEN - 1); strncpy(cur-data.gender, new_data-gender, GENDER_LEN - 1); return 0; } cur cur-next; } return -1; } ​ /** * brief 遍历并打印所有联系人 */ void api_list_all(AddressBook *book) { if (book NULL || book-head NULL) { printf(通讯录为空暂无联系人\n); return ; } printf(\n 联系人列表共%d条\n, book-count); printf(%-12s %-15s %-6s %-4s\n, 姓名, 手机号, 性别, 年龄); printf(----------------------------------------\n); Node *cur book-head; while(cur ! NULL) { printf(%-12s %-15s %-6s %-4d\n, cur-data.name, cur-data.phone, cur-data.gender, cur-data.age); cur cur-next; } printf(\n); } ​ /** * brief 保存通讯录到文件 * return 0成功 -1失败 */ int api_save_to_file(AddressBook *book, const char *filename) { if (book NULL || filename NULL) return -1; FILE *fp fopen(filename, wb); // 二进制写模式 if(fp NULL) { perror(保存文件失败); return -1; } Node *cur book-head; while(cur ! NULL) { fwrite(cur-data, sizeof(Contact), 1, fp); cur cur-next; } fclose(fp); return 0; } ​ /** * brief 从文件加载通讯录 * return 0成功 -1文件不存在/读取失败 */ int api_load_from_file(AddressBook *book, const char *filename) { if (book NULL || filename NULL) return -1; FILE *fp fopen(filename, rb); if (fp NULL) { // 文件不存在属于正常情况首次运行不报错 return -1; } Contact temp; while(fread(temp, sizeof(Contact), 1, fp) 1) { api_add_contact(book, temp); } fclose(fp); return 0; } ​ /************************* 业务逻辑层 *************************/ /** * brief 校验联系人数据合法性 * return 1合法 0非法 */ int biz_validate_contact(Contact *data) { if (data NULL) return 0; if (strlen(data-name) 0) return 0; // 姓名不能为空 if (data-age 0 || data-age 150) return 0; // 年龄范围校验 if (strlen(data-phone) 0) return 0; // 手机号不能为空 return 1; } ​ /** * brief 添加联系人业务逻辑查重 校验 调用接口 * return 0成功 -1数据非法 -2姓名重复 */ int biz_add_contact(AddressBook *book, Contact *data) { // 1. 数据合法性校验 if (!biz_validate_contact(data)) { return -1; } // 2. 姓名查重 Contact tmp; if (api_search_contact(book, data-name, tmp) 0) { return -2; } // 3. 调用接口层执行添加 return api_add_contact(book, data); } ​ /************************* 交互层菜单与工具函数 *************************/ // 清空输入缓冲区避免scanf残留换行影响后续输入 void clear_input_buffer() { int c; while((c getchar())! \n c ! EOF); } ​ // 打印主菜单 void print_menu() { printf(\n 通讯录管理系统 \n); printf(1. 添加联系人\n); printf(2. 删除联系人\n); printf(3. 修改联系人\n); printf(4. 查询联系人\n); printf(5. 查看所有联系人\n); printf(6. 保存数据到文件\n); printf(0. 退出系统\n); printf(\n); printf(请输入选项); } ​ // 录入联系人信息 void input_contact(Contact *data) { printf(请输入姓名); scanf(%s, data-name); printf(请输入手机号); scanf(%s, data-phone); printf(请输入性别); scanf(%s, data-gender); printf(请输入年龄); scanf(%d, data-age); clear_input_buffer(); } ​ /************************* 主函数程序入口 *************************/ int main() { AddressBook book; init_book(book); // 启动自动加载本地数据 api_load_from_file(book, DATA_FILE); printf(系统启动完成已加载%d条联系人数据\n, book.count); int choice -1; char name_buf[NAME_LEN]; Contact tmp_data; while(1) { print_menu(); scanf(%d, choice); clear_input_buffer(); switch(choice) { case 1: // 添加联系人 printf(\n--- 添加联系人 ---\n); input_contact(tmp_data); int ret biz_add_contact(book, tmp_data); if (ret 0) { printf(添加成功\n); } else if (ret -1) { printf(添加失败数据不合法\n); } else if (ret -2) { printf(添加失败该姓名已存在\n); } break; case 2: // 删除联系人 printf(\n--- 删除联系人 ---\n); printf(请输入要删除的姓名); scanf(%s, name_buf); clear_input_buffer(); ret api_delete_contact(book, name_buf); if (ret 0) { printf(删除成功\n); } else if (ret -2) { printf(删除失败联系人不存在\n); } else { printf(删除失败\n); } break; case 3: // 修改联系人 printf(\n--- 修改联系人 ---\n); printf(请输入要修改的姓名); scanf(%s, name_buf); clear_input_buffer(); if (api_search_contact(book, name_buf, tmp_data) ! 0) { printf(联系人不存在\n); break; } printf(请输入新的信息姓名不可修改\n); printf(新手机号); scanf(%s, tmp_data.phone); printf(新性别); scanf(%s, tmp_data.gender); printf(新年龄); scanf(%d, tmp_data.age); clear_input_buffer(); ​ if (api_modify_contact(book, name_buf, tmp_data) 0) { printf(修改成功\n); } else { printf(修改失败\n); } break; case 4: // 查询联系人 printf(\n--- 查询联系人 ---\n); printf(请输入要查询的姓名); scanf(%s, name_buf); clear_input_buffer(); if (api_search_contact(book, name_buf, tmp_data) 0) { printf(\n查询结果\n); printf(姓名%s\n, tmp_data.name); printf(手机号%s\n, tmp_data.phone); printf(性别%s\n, tmp_data.gender); printf(年龄%d\n, tmp_data.age); } else { printf(未找到联系人\n); } break; case 5: // 查看所有 api_list_all(book); break; case 6: // 手动保存 if (api_save_to_file(book, DATA_FILE) 0) { printf(数据已保存到 %s\n, DATA_FILE); } break; case 0: // 退出 printf(\n正在保存数据...\n); api_save_to_file(book, DATA_FILE); destroy_book(book); // 释放内存 printf(系统已退出欢迎下次使用\n); return 0; default: printf(输入无效请输入0-6之间的数字\n); break; } } return 0; }

相关新闻

2026Python内存优化实战教程:布尔数组从1MB到100KB,从入门到精通

2026Python内存优化实战教程:布尔数组从1MB到100KB,从入门到精通

做Python开发,存大量布尔值的场景太常见了:线性筛素数、用户标签、特征工程标记、布隆过滤器、位图索引,数据量一上来内存直接爆,list占内存大,numpy不够灵活,自己写位数组又麻烦。这篇是2026年最新的Pytho…

2026/10/14 17:51:05 阅读更多 →
介观电子输运:从量子效应到纳米器件设计的核心原理

介观电子输运:从量子效应到纳米器件设计的核心原理

介观系统中的电子输运,这个看似专业的物理概念,实际上正在深刻改变我们对纳米尺度电子行为的理解。如果你正在研究纳米器件、量子计算或低维材料,却对传统宏观输运理论与实际观测结果之间的差距感到困惑,那么这篇文章将为你揭示其…

2026/10/10 15:12:39 阅读更多 →
短信炸弹与越权提权组合攻击:原理、渗透测试与纵深防御实战

短信炸弹与越权提权组合攻击:原理、渗透测试与纵深防御实战

1. 项目概述:当“短信炸弹”遇上“越权提权”最近在给一家金融科技公司做安全评估时,我们遇到了一个非常典型的组合攻击场景:攻击者利用一个看似无害的“短信验证码接口”,配合一个隐蔽的权限绕过漏洞,差点就拿到了核心…

2026/10/9 12:19:48 阅读更多 →

最新新闻

基于集群划分的分布式光伏配电网电压协调控制与Matlab实现

基于集群划分的分布式光伏配电网电压协调控制与Matlab实现

分布式光伏一多起来,配电网最先暴露问题的往往是电压。光照一强、负荷又轻的时候,馈线末端电压能一路冲到1.06甚至1.07标幺值,逆变器要么降出力、要么直接脱网保护,好好的发电量白白丢了。传统的变电站有载调压和固定电容器组又反…

2026/10/15 7:39:00 阅读更多 →
MEDS:基于Docker Compose的本地开发环境标准化方案

MEDS:基于Docker Compose的本地开发环境标准化方案

1. 项目概述:MEDS不是医疗系统,而是开发者私藏的“效率加速器”最近在几个技术社区里频繁刷到“MEDS”这个词,有人问“MEDS开源项目值不值得学”,也有人发帖说“搭完MEDS后本地开发流速翻倍”。但翻遍GitHub热门榜单和主流技术媒体…

2026/10/15 7:39:00 阅读更多 →
多Agent系统面试攻略:4种经典架构详解与避坑指南

多Agent系统面试攻略:4种经典架构详解与避坑指南

多 Agent 系统面试怎么答?我总结了 4 种经典架构这两年只要面试 AI 应用岗位,十个里面有八个会被问到“多 Agent 系统怎么设计”。我作为经常端坐在对面的人,说实话最怕听到的回答是:“这个简单,用 LangGraph 编排几个…

2026/10/15 7:39:00 阅读更多 →
MEDS:面向开发者的模块化本地工作台与服务编排工具

MEDS:面向开发者的模块化本地工作台与服务编排工具

1. 项目概述:MEDS不是医疗系统,而是开发者日常提效的“数字工作台”最近在几个技术社区和开源协作平台刷到一个叫MEDS的项目,标题里带“开源项目推荐”,但点进去发现它既不卖药也不做电子病历,和医院信息系统&#xff…

2026/10/15 7:39:00 阅读更多 →
Excel一键生成炫彩二维码:IMAGE函数与VBA实战教程

Excel一键生成炫彩二维码:IMAGE函数与VBA实战教程

上个月帮朋友准备展板物料,需求看着不复杂:几十个二维码,每个对应不同链接,但每个都得配合当天的主题色来展示,不能清一色黑乎乎。他那边既没有Python环境,也不方便一个个打开在线生成器,最后发…

2026/10/15 7:39:00 阅读更多 →
CentOS 7.6搭建DNS正向解析服务:BIND配置实战

CentOS 7.6搭建DNS正向解析服务:BIND配置实战

平时做运维的朋友肯定都有过这种经历:公司内部新起了一套系统,IP地址越来越多,今天要连这个、明天要连那个,总不能天天翻Excel表格。更尴尬的是,内网服务想用一个好记的域名访问,结果发现公共DNS根本不认识…

2026/10/15 7:37:59 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →