[{"content":"欢迎来到我的个人博客！这是我的第一篇文章。\n这个博客是做什么的？ 这个博客主要分享以下几类内容：\n技术文章：编程学习、开发工具、架构设计 学习笔记：读书笔记、课程笔记 生活随笔：记录生活的点滴 关于本博客 本博客基于 Hugo 静态站点生成器构建，使用 hugo-theme-stack 主题，部署在云服务器上，具有以下特点：\n极速访问：纯静态页面，无需数据库 支持暗色模式：自动跟随系统或手动切换 全文搜索：内置搜索功能 移动端友好：响应式设计 接下来 我会持续更新博客内容，敬请期待！\n如果你有任何问题或建议，欢迎在文章下方留言，或通过关于页面中的联系方式与我交流。\n感谢你的访问！\n","date":"2026-08-18T00:00:00Z","permalink":"/p/welcome/","title":"欢迎来到我的博客"},{"content":" 在清理硬盘的时候，遇到大文件夹删除卡顿、卡死、删不掉问题，有感而发，作为一个笔记，希望能够对你有所帮助。\n一、你为什么删超大文件夹一直卡死？ 日常使用Windows时，相信大家都遇到过这种崩溃场景：\n面对 几十万小文件、多层嵌套目录、几十GB甚至上百GB 的超大文件夹，右键删除/Shift+Delete之后：\n进度条一动不动，预估时间无限递增 文件资源管理器未响应、系统严重卡顿 删到一半弹窗报错：文件正在使用、权限不足、路径过长 强行终止后，文件残留、磁盘空间不释放 二、底层原理：图形化删除为什么巨慢？ Windows文件资源管理器的图形删除模式，存在大量冗余操作，这是卡顿的核心根源。\n2.1 普通删除（Delete） 执行流程：遍历所有文件统计大小数量 → 写入回收站日志 → 迁移文件至回收站 → 实时校验文件状态 → 更新系统索引。\n海量小文件场景下，统计和日志耗时远大于删除本身，直接导致进程卡死。\n2.2 强制删除（Shift+Delete） 虽然跳过回收站，但依然保留 前置全量遍历、实时权限校验、文件占用检测 逻辑，遇到深层目录、破损文件依旧会卡顿中断。\n2.3 命令行删除 命令行/批处理删除：跳过所有冗余统计与弹窗校验，直接调用系统底层删除接口，静默递归删除，极大降低CPU和磁盘I/O占用。\n三、四大落地删除方案 3.1 方案一：优化图形化删除 适合10万文件以内的中型文件夹。\n操作步骤： 选中目标文件夹，直接按下 Shift + Delete 永久删除，跳过回收站； 若提示权限不足：右键文件夹 → 属性 → 安全 → 编辑 → 添加Everyone用户，赋予完全控制权限； 若提示文件占用：Ctrl+Shift+Esc打开任务管理器，关闭关联后台进程后重试。 优缺点： ✅ 零学习成本、操作简单\n❌ 百万级海量文件仍会卡顿，无法处理超长路径目录\n3.2 方案二：CMD命令行极速删除（通用最优解） 这是个人电脑、临时清理场景的最优方案，实测50万文件仅需2分钟左右，无卡顿、无弹窗。\n操作步骤： Win+R 输入 cmd，右键以管理员身份运行（规避所有权限报错）； 依次输入以下两条核心指令，逐条回车执行。 \\# 强制、静默、递归删除文件夹内所有文件 del /f /s /q 你的文件夹完整路径 # 递归删除空目录+根文件夹 rd /s /q 你的文件夹完整路径 ","date":"2026-08-06T00:00:00Z","permalink":"/p/163525935/","title":"【Windows干货】解决超大文件夹删除卡顿、卡死、删不掉问题"},{"content":" 在安装openclaw的时候，发现一个网站，号称国内版openclaw，就去询问了AI它的官网，AI提供了PowerShell的安装方式，就想写篇文章记录一下这个工具，之前是知道它，但不求甚解，这次一起仔细了解一下它。\n一、什么是 PowerShell？ 在 Windows 系统中，很多用户都见过一个蓝色窗口——PowerShell。\n对于普通用户来说，它可能只是一个类似 CMD（命令提示符）的黑色命令窗口；但对于开发者、系统管理员以及 DevOps 工程师来说，PowerShell 是一个强大的自动化平台。\nPowerShell 适合需要高效管理 Windows 系统、自动化重复任务或与微软产品（如 Active Directory、Azure、Exchange 等）交互的技术人员，包括系统管理员、IT 运维、开发者和安全工程师。\n二、PowerShell核心定位与版本区别 2.1 核心定义 PowerShell是微软推出的开源、跨平台、面向对象的自动化运维框架，兼具命令行交互工具与脚本编程语言双重属性，依托.NET框架构建，支持完整的编程逻辑与系统底层调用，核心设计理念是一切皆为对象，彻底区别于传统Shell的文本处理模式。\n2.2 两大核心版本（新手必懂） 目前主流存在两个版本，功能与定位差异极大，也是技术圈最容易混淆的知识点：\nWindows PowerShell 5.1：Windows10/11、Windows Server系统预装内置版本，基于.NET Framework，仅支持Windows平台，目前微软仅做安全维护，不再新增功能，适合传统单机运维场景。 PowerShell 7+（新版）：开源跨平台版本，基于全新.NET跨平台框架，兼容Windows、Linux、macOS系统，新增云原生适配、批量自动化、API对接等大量能力，是目前企业运维、DevOps的主力推荐版本。 三、PowerShell的核心作用 PowerShell的价值贯穿个人开发、企业运维、云端管控全场景，告别手动重复操作，实现全流程自动化，核心作用可分为五大模块。\n3.1 精细化Windows系统本地运维 相比于CMD只能实现简单的文件管理、网络查询，PowerShell可以深度控制系统底层资源，实现精细化运维。支持文件批量处理、进程精准管控、服务启停管理、注册表修改、系统权限配置、用户账号管理等全维度操作。\n日常场景中，批量重命名文件、批量清理垃圾、查杀指定进程、开机自启项配置、系统状态监控等繁琐操作，均可通过简短PowerShell命令或脚本一键完成，大幅降低手动操作失误率。\n3.2 企业服务器与集群远程管控 在企业IT架构中，服务器集群管理是核心痛点。PowerShell原生支持WS-Management远程管理协议，无需搭建复杂第三方工具，即可实现批量远程管理多台Windows服务器。\n运维人员可通过单条命令，批量查询多台服务器运行状态、重启服务、部署程序、更新配置、排查故障，彻底告别逐台服务器手动操作，是Windows Server、AD域、Exchange邮件服务运维的标配工具。\n3.3 脚本自动化，替代传统批处理 PowerShell拥有完整的编程语言能力，支持变量、循环、条件判断、函数、异常捕获、参数配置等高级特性，脚本文件以.ps1为后缀，可替代老旧低效的bat批处理脚本。\n无论是日常重复性运维操作、定时任务执行、日志自动采集，还是复杂的业务流程调度，均可编写PowerShell脚本实现无人值守自动化运行，是轻量化自动化落地的最优方案之一。\n3.4 云原生与微软生态专属管控 这是PowerShell不可替代的核心优势。微软全系云服务、企业服务均深度适配PowerShell，包括Azure云平台、Microsoft 365、SharePoint、Teams、云服务器资源等。\n相较于可视化后台繁琐的点击操作，通过PowerShell命令可快速批量创建云资源、配置云服务器、管理企业账号、统计办公数据，是微软云运维的官方标准工具，无任何第三方工具可替代。\n3.5 数据处理与API快速对接 PowerShell原生支持JSON、CSV、XML等主流数据格式，内置Invoke-RestMethod等专用命令，可轻松调用各类REST API接口，实现数据抓取、接口测试、数据批量导入导出。\n凭借极强的兼容性，PowerShell可作为“胶水工具”，串联系统运维、接口调用、数据处理全流程，无需依赖Python、Java等高级语言，即可完成轻量化数据自动化任务。\n四、PowerShell vs CMD 很多人无法理解PowerShell的强大，核心是没看懂它与CMD的底层本质区别，而非简单的功能多少差异：\n对比维度 CMD（命令提示符） PowerShell 数据传输模式 纯文本字符串传输，需手动截取解析，极易出错 对象传输，保留完整数据属性，直接筛选、排序、修改 语法规范 命令杂乱无章，无统一规范，学习成本高 统一动词-名词规范（Get/Set/New/Remove），可读性极强 脚本能力 仅支持简单批处理，无法实现复杂逻辑 完整编程语言特性，支持复杂自动化脚本开发 运维能力 仅基础文件、网络操作，无法控制系统底层 深度管控系统内核、服务、注册表、远程集群 生态适配 仅适配老旧Windows系统，无云生态支持 适配跨平台、微软全系云服务、DevOps体系 简单来说：CMD是兼容老旧系统的过渡工具，PowerShell是微软未来长期迭代的核心运维工具。\n五、当前情况 忽然想起来，之前有一大堆文件需要批量更改名称，最后就是使用了Powershell解决了这个问题。但属实用的不多，emmmm。\nPowershell就是一个工具，在有这个需求的时候，不要忘记它。PowerShell取代CMD，还是任重而道远。\n节选B站评论：\n微软一直想干掉CMD这个古老的窗口工具 但是现实是CMD和Powershell生态位和等级位已经完全不同了\nCMD是指向性的DOS指令底层的读取，呆板指令，但确实很好用，他的等级位是（大哥）；\nPowershell引入了变量的概念，有了一套丰富的变量指令集，丰富了调度层的命令架构，使得CMD做不到的Powershell能做到，提升了更强的兼容性。于是二哥位诞生了；\n两者之间的服务对象并不同，但是有效的提升了windows在兼容与命令层的丰富度；\n然后微软为了将windows的兼容性变得更强，意图将这个窗口工具替代cmd，甚至不惜一切代价独特的为Powershell设计了一套全新的语言逻辑对CMD做指令归递，虽然这对一些已经接触了新语言的系统管理用户来说是非常强的窗口工具。\n但实际的现实是老用户甚至新用户调度CMD的利用率远高于Powershell，为什么呢？为啥干不掉CMD呢？\n其根本在于——对于已经熟悉DOS架构的CMD的老用户而言，去学习Powershell的时间成本，习惯成本和认知成本太高了，所以当前很多用户宁愿CMD能做就CMD，也不愿意用Powershell，甚至有些掌握了新语言的开发者，宁愿CMD指令做归集也不愿意用Powershell去做，归根到底，Powershell的丰富度也带来了一定的复杂。\n既然复杂，那么不听话的开发者甚至一些不愿意学习的系统管理员，宁愿简单也不愿意复杂，从而导致时至今日CMD的利用率也高于Powershell。\n因为有大量祖传的批处理脚本还在运行，微软根本删不掉cmd，我们公司就有一套流程控制腳本，加起來80多M。删掉了谁去用powershell去重写呢。\n","date":"2026-07-31T00:00:00Z","permalink":"/p/163355582/","title":"搞懂PowerShell是什么"},{"content":" Node.js 是基于 Chrome V8 引擎构建的 JavaScript 运行环境，它突破了 JavaScript 仅能在浏览器中执行的限制，使 JS 可直接运行于操作系统之上；依托异步非阻塞的特性与庞大的 npm 开源生态，它常被用于搭建后端接口服务、实现前端项目工程化打包构建，也可开发实时通讯程序、Electron 桌面应用以及各类自动化脚本，实现前后端统一使用 JavaScript 开发，但不太适合重度 CPU 密集型运算场景。\n1. 下载 VMware Workstation 官网地址：https://nodejs.org/zh-cn/ ⚠️ 重要规范：安装路径不要包含中文、空格！\n2. 安装全流程 双击打开 node-v26.5.0-x64.msi。\n一直点击“next”即可。\n3. 验证安装 打开命令窗口，输入“node -v”查看安装状态。\n","date":"2026-07-29T00:00:00Z","permalink":"/p/163309827/","title":"Node.js安装全流程"},{"content":" VMware于1998年在美国成立，是全球虚拟化技术标杆，曾被EMC、戴尔掌控，2023年被博通以610亿美元收购。它主导全场景虚拟化，拥有庞大客户与合作伙伴生态，推动IT资源高效利用与数字化转型，虽收购后因许可政策调整引发监管关注，但仍是行业核心力量，深刻影响全球IT基础设施发展。\nVMware Workstation是VMware公司销售的商业软件产品之一。VMware Workstation允许一台真实的电脑在一个操作系统中同时开启并运行数个操作系统，其它VMware产品帮助在多个宿主电脑之间管理或移植VMware虚拟机。\n1. 下载 VMware Workstation 1. 1官网下载VMware Workstation 官网地址：VMware Workstation Pro 下载（需注册账号） 滚动找到“VMware Workstation Pro for PC”。\n1. 1.1注册博通账号 选择账号注册。\n输入邮箱与验证码。\n从输入的邮箱接收验证码并输入。\n填写注册信息。\n密码规则较多，需仔细校对。\n依次选择\u0026quot;Software\u0026quot;-\u0026gt;“VMware Cloud Foundation”-\u0026gt;“My Downloads”。\n1. 1.2登录博通账号 点击\u0026quot;VMware Workstation Pro\u0026quot;。\n选择虚拟机版本。\n1. 2 Linux 系统镜像下载 1. 2.1 阿里云开源镜像站 https://developer.aliyun.com/mirror/ 1. 2.2 清华大学开源软件镜像站 https://mirrors.tuna.tsinghua.edu.cn/ 2. 安装VMware Workstation 下载安装包后，双击 VMware-workstation-full-17.6.4-24832109.exe 运行安装包，点击 下一步：\n选择“我接收许可协议中的条款”。\n自定义安装，更改安装目录(不放C盘)，下一步：\n用户体验设置，点击下一步：\n快捷方式，全部勾选，然后下一步：\n已准备好安装VMware Workstation Pro ，点击 安装：\n软件安装完成。\n3. 创建一个空的虚拟机 按照提示的填写。\n点击“完成”。\n安装中…\n4. 安装完成 设置语言\n重启系统，完成安装。\n","date":"2026-04-21T00:00:00Z","permalink":"/p/160361241/","title":"【保姆级教程】VMware虚拟机安装全流程"},{"content":"在观看美剧时，忽然弹出\u0026quot;当前音频无法播放\u0026quot;,让人十分难受。\n手动下载OpenCodec安装包就解决了这个问题。\n通过网盘分享的文件：OpenCodec安装包 链接: https://pan.baidu.com/s/1K8EzBoNXYhodIWXp9KLTFA?pwd=U3DF 提取码: U3DF --来自百度网盘超级会员v4的分享 安装注意事项：\n1、关闭PotPlayer，双击OpenCodecSetup.exe安装。\n2、会自动定位到PotPlayer所在目录。\n3、打开PotPlayer“选项 - 滤镜 - 音频解码器 - 内置解码器（Pass Through输出）设置”（可以查看解码器可选择状态）。\n","date":"2026-03-08T00:00:00Z","permalink":"/p/158806198/","title":"PotPlayer音频故障:DirectX驱动程序未正确安装或音像设备被禁用"},{"content":" 在如今各类网站、APP 泛滥的时代，密码管理已经成为每个人的刚需。记不住、重复用、容易泄露，是大多数人的痛点。今天给大家带来一款开源、免费、跨平台的密码管理器——Bitwarden，本文将对Bitwarden进行详细讲解，适合新手直接照着操作。\n一、Bitwarden 是什么？ 在如今各类网站、APP 泛滥的时代，密码管理已经成为每个人的刚需。记不住、重复用、容易泄露，是大多数人的痛点。今天给大家带来一款开源、免费、跨平台的密码管理器——Bitwarden，Bitwarden 是一款开源、端到端加密的密码管理器，支持 Windows、macOS、Linux、Android、iOS 以及几乎所有主流浏览器。\n它可以帮你：\n安全存储密码、银行卡、笔记、密钥等敏感信息 全设备自动同步 一键自动填充账号密码 生成高强度随机密码 检测弱密码、重复密码、泄露密码 二、Bitwarden 安装全步骤 1. 注册账号（免费） 打开官网： https://bitwarden.com 点击 Get Started → Create Free Account\n填写：\n填写邮箱\n提示查看邮箱：\n完成注册并验证邮箱。\n⚠️ 重要：主密码是唯一钥匙，忘记后只能重置清空库！\n三、电脑端安装（Windows/macOS） 下载页面：\nhttps://bitwarden.com/download\n选择对应系统下载安装即可。 打开客户端，登录账号。 四、浏览器扩展安装（核心：自动填充必备） 以 Chrome / Edge 为例：\n应用商店搜索：Bitwarden 添加扩展，并固定到工具栏 登录同一账号 以后登录网站会自动提示保存密码，一键填充。\n五、手机端安装与自动填充设置 应用商店安装 Bitwarden 输入账号密码，登录即可同步所有密码。 六、安全增强设置（设置自动锁定时间） Settings → Security → Vault Timeout\n建议：5 分钟无操作自动锁定。\n七、从其他密码管理器迁移到 Bitwarden 从 Edge 导出 CSV Bitwarden →导入\n八、总结 Bitwarden 是目前性价比最高、最安全、最良心的免费密码管理器之一。\n开源 + 跨平台 + 全功能免费，足以吊打绝大多数同类工具。只要你愿意花 10 分钟配置，它能彻底解决你“记不住密码”的所有烦恼。\n推荐所有重视账号安全的朋友使用！\n","date":"2026-02-26T00:00:00Z","permalink":"/p/158402759/","title":"保姆级教程-Bitwarden密码管理器使用指南"},{"content":"题目一：生成斐波那契数列的前 n 项 斐波那契数列的起始两项为 1，从第三项开始，每一项都等于前两项之和。 #斐波那契数列 生成斐波那契数列的前 n 项 def fibonacci(n): if n \u0026lt;= 1: return n else: return fibonacci(n - 2) + fibonacci(n - 1) def main(): user\\_input = input(\u0026#34;请输入生成斐波那契数列第n项的值: \u0026#34;) try: print(fibonacci(int(user\\_input, base=10))) except ValueError: print(\u0026#34;输入无效，请输入一个有效的整数。\u0026#34;) main() if \\_\\_name\\_\\_ == \u0026#34;\\_\\_main\\_\\_\u0026#34;: main() AI写代码bash12345678910111213141516171819 题目二：冒泡排序 冒泡排序（Bubble Sort）是一种简单的排序算法。它通过重复地遍历待排序的元素，比较相邻的元素并交换它们的位置，直到整个序列有序。 def bubble\\_sort(arr): n = len(arr) for i in range(n): for j in range(0, n - i - 1): if arr\\[j\\] \u0026gt; arr\\[j + 1\\]: arr\\[j\\], arr\\[j + 1\\] = arr\\[j + 1\\], arr\\[j\\] return arr def main(): arr = \\[64, 34, 25, 12, 22, 11, 90\\] print(bubble\\_sort(arr)) if \\_\\_name\\_\\_ == \u0026#34;\\_\\_main\\_\\_\u0026#34;: main() AI写代码bash1234567891011121314 题目三：二分查找 二分查找（Binary Search）是一种高效的查找算法，适用于已经排序的数组或列表。它的基本思想是通过不断将查找范围分为两半，缩小查找的范围，从而快速找到目标元素。 def binary\\_search(arr, target): low = 0 high = len(arr) - 1 while low \u0026lt;= high: mid = (low + high) // 2 # 计算中间索引 if arr\\[mid\\] == target: return mid # 找到目标，返回索引 elif arr\\[mid\\] \u0026lt; target: low = mid + 1 # 目标在右半部分 else: high = mid - 1 # 目标在左半部分 return -1 # 没有找到目标，返回-1 def main(): arr = \\[1, 3, 5, 7, 9, 11, 13, 15, 17, 19\\] target = 7 result = binary\\_search(arr, target) if result != -1: print(f\u0026#34;目标元素 {target} 在索引 {result} 处\u0026#34;) else: print(f\u0026#34;目标元素 {target} 不在数组中\u0026#34;) if \\_\\_name\\_\\_ == \u0026#34;\\_\\_main\\_\\_\u0026#34;: main() AI写代码bash1234567891011121314151617181920212223242526 题目四：最大子数组和 （kadane算法） 给定一个整数数组，找出一个具有最大和的连续子数组，并返回其和。这个子数组至少包含一个元素。 def kadane(nums): # 如果数组为空，返回0 if not nums: return 0 # 初始化当前子数组和和最大子数组和 current\\_sum = max\\_sum = nums\\[0\\] for i in range(1, len(nums)): # 更新当前子数组和 #print(\u0026#34;init current\\_sum = :\u0026#34;, current\\_sum) current\\_sum = max(nums\\[i\\], current\\_sum + nums\\[i\\]) #print(\u0026#34;current\\_sum = :\u0026#34;, current\\_sum) # 更新最大子数组和 max\\_sum = max(max\\_sum, current\\_sum) # print(\u0026#34;max\\_sum = :\u0026#34;, max\\_sum) return max\\_sum def main(): nums = \\[-3, 1, -3, 4, -1, 2, 1, -5, 4\\] result = kadane(nums) print(\u0026#34;最大子数组和:\u0026#34;, result) if \\_\\_name\\_\\_ == \u0026#34;\\_\\_main\\_\\_\u0026#34;: main() AI写代码bash12345678910111213141516171819202122232425 题目五：水仙花数 水仙花数是指一个 n 位数，其各位数字的 n 次方之和等于该数本身。 \\# 判断是否为水仙花数 def is\\_armstrong\\_number(number): # 提取百位、十位和个位的数字 hundreds = number // 100 tens = (number // 10) % 10 ones = number % 10 # 判断水仙花数条件：各位数字的立方和等于原数 if (hundreds \\*\\* 3 + tens \\*\\* 3 + ones \\*\\* 3) == number: return True else: return False def main(): # 获取用户输入 num = int(input(\u0026#34;请输入一个三位数: \u0026#34;)) # 判断输入是否是有效的三位数 if 100 \u0026lt;= num \u0026lt;= 999: if is\\_armstrong\\_number(num): print(f\u0026#34;{num} 是一个水仙花数\u0026#34;) else: print(f\u0026#34;{num} 不是水仙花数\u0026#34;) else: print(\u0026#34;请输入一个有效的三位数\u0026#34;) if \\_\\_name\\_\\_ == \u0026#34;\\_\\_main\\_\\_\u0026#34;: main() AI写代码bash1234567891011121314151617181920212223242526272829 题目六：判断一个数是否为质数 质数（英文名：Prime number）又称素数，是指在大于1的自然数中，除了1和它本身以外不再有其他因数的自然数。 import math def is\\_prime(n): if n \u0026lt;= 1: return False if n == 2: return True if n % 2 == 0: return False for i in range(3, int(math.sqrt(n)) + 1, 2): if n % i == 0: return False return True def main(): # 输入一个数字并判断是否为质数 num = int(input(\u0026#34;请输入一个数：\u0026#34;)) if is\\_prime(num): print(f\u0026#34;{num} 是质数\u0026#34;) else: print(f\u0026#34;{num} 不是质数\u0026#34;) if \\_\\_name\\_\\_ == \u0026#34;\\_\\_main\\_\\_\u0026#34;: main() AI写代码bash123456789101112131415161718192021222324 ","date":"2025-03-24T00:00:00Z","permalink":"/p/146374394/","title":"【Python】6道Python入门算法练习题及源码"},{"content":"1.没有主函数的Python脚本会怎么样？ Python 中没有main函数也可以正常运行代码。Python 是一种脚本语言，它的代码是按照从上到下的顺序逐行执行的。当你运行一个 Python 脚本时，解释器会直接开始执行脚本中的代码，而不需要像一些编程语言（如 C、C++、Java 等）那样必须有一个特定的main函数作为程序的入口点。如下所示，没有main函数也可正常运行。\nn = 888 + 999 print(n) 2.主函数的使用场景在什么情况？ 主函数（也称为入口函数）是一个Python程序中的特殊函数，它标识着程序的开始执行的位置。在许多编程语言中，这个函数被称为main函数，但在Python中我们使用if name == \u0026ldquo;main\u0026ldquo;来实现主函数的功能。\n在较大型的 Python 项目中，为了使代码结构更清晰，逻辑更有条理，并且方便控制代码的执行流程，通常会使用if name == \u0026ldquo;main\u0026ldquo;这种形式来模拟一个main函数的作用，将程序的主要执行逻辑放在这个条件块内。\ndef add\\_numbers(a, b): return a + b if \\_\\_name\\_\\_ == \u0026#34;\\_\\_main\\_\\_\u0026#34;: result = add\\_numbers(5, 3) print(result) def sum(a, b): return a + b def main(): result = sum(5, 3) print(result) if \\_\\_name\\_\\_ == \u0026#34;\\_\\_main\\_\\_\u0026#34;: main() 3.错误示范 不恰当的缩进\n","date":"2025-03-24T00:00:00Z","permalink":"/p/146374684/","title":"【Python】主函数详解"},{"content":"1 初识Python 1.1 Python概述 Python是一种高级、解释型、通用的编程语言，由Guido van Rossum于20世纪90年代初创立。Python以其简洁易读的语法和强大的功能而闻名，使其成为新手和经验丰富的开发人员的首选语言之一。\nPython的设计初衷是为了强调代码的可读性和简洁性。Guido van Rossum在1989年的圣诞节期间开始编写Python，目的是为了创建一种既能处理系统管理任务又能进行大规模应用开发的语言。1991年，Python 0.9.0版本发布，自此Python逐步发展成为一门功能强大且灵活的编程语言。\nTIOBE排行榜是一个反映编程语言热度的指标，通过统计互联网上有经验的程序员、课程和第三方厂商的数量，以及使用搜索引擎、Wikipedia等平台的数据，来评估各种编程语言的流行程度。Python TIOBE排名如下图所示。\n1.2 Python应用 Python 是一种高级、通用、解释型的编程语言，凭借其简洁易读的语法、丰富的库和强大的生态系统，在众多领域都有广泛的应用。\n1.2.1 数据科学 数据分析：Python 拥有丰富的数据分析库，如 Pandas、NumPy 等。Pandas 提供了高效的数据结构（如 DataFrame）和数据操作方法，可用于数据清洗、转换和分析；NumPy 提供了高性能的多维数组对象和计算工具，能方便地进行数值计算和统计分析。 数据可视化：Matplotlib、Seaborn 和 Plotly 等库可用于创建各种可视化图表，如折线图、柱状图、散点图、热力图等，帮助用户更直观地理解数据。 机器学习：Scikit - learn 是一个简单易用的机器学习库，提供了各种机器学习算法，如分类、回归、聚类等；TensorFlow 和 PyTorch 则是深度学习领域的主流框架，可用于构建和训练神经网络模型，应用于图像识别、自然语言处理等领域。 1.2.2 人工智能 自然语言处理（NLP）：Python 中有许多用于 NLP 的库，如 NLTK、SpaCy 和 Transformers。NLTK 提供了丰富的语料库和工具，可用于文本处理、词性标注、命名实体识别等；Transformers 库则提供了预训练的语言模型，如 BERT、GPT 等，可用于文本生成、情感分析、问答系统等任务。 计算机视觉：OpenCV 是一个强大的计算机视觉库，可用于图像和视频处理，如图像滤波、特征提取、目标检测等；结合深度学习框架，还可以实现更复杂的计算机视觉任务，如人脸识别、图像分割等。 1.2.3 Web 开发 后端开发：Python 有多个流行的 Web 框架，如 Django、Flask 和 FastAPI。Django 是一个功能强大的全栈 Web 框架，提供了内置的数据库管理、用户认证、表单处理等功能，适合开发大型的 Web 应用；Flask 是一个轻量级的 Web 框架，灵活性高，易于上手，适合快速开发小型 Web 应用；FastAPI 则是一个基于 Python 的高性能 Web 框架，利用 Python 的类型提示功能，提供快速的开发体验和高效的性能。 爬虫开发：Python 的 Requests 库可用于发送 HTTP 请求，获取网页内容；BeautifulSoup 和 Scrapy 则是常用的网页解析和爬虫框架，可用于提取网页中的数据。 1.2.4 自动化运维 系统管理：Python 可以用于编写脚本，实现系统的自动化管理任务，如文件操作、进程管理、系统监控等。通过 Paramiko 库，还可以实现远程服务器的自动化操作。 配置管理：Ansible、SaltStack 等自动化配置管理工具使用 Python 编写，可用于自动化服务器的配置部署和管理，提高运维效率。 1.2.5.游戏开发 简单游戏开发：Pygame 是一个专门用于开发 2D 游戏的 Python 库，提供了图形、声音、输入等功能，可用于快速开发简单的游戏，如街机游戏、益智游戏等。 游戏脚本开发：在一些大型游戏开发中，Python 也可以作为脚本语言，用于实现游戏中的逻辑控制、AI 行为等。 1.2.6.金融领域 量化交易：Python 可用于开发量化交易策略，通过获取金融市场数据，进行数据分析和模型构建，实现自动化交易。常见的金融数据接口库有 Pandas - Datareader、Tushare 等，可用于获取股票、期货等市场数据。 风险评估：利用 Python 进行金融数据建模和分析，评估投资风险，如计算风险价值（VaR）、信用风险评估等。 1.3 Python开发环境 Python 有多个版本，目前较常用的是 Python 3.x。你可以从 Python官网下载适合你操作系统的安装包。\nWindows 系统\n下载安装包后，运行安装程序。在安装过程中，勾选 “Add Python to PATH” 选项，这样可以将 Python 添加到系统环境变量中，方便在命令行中直接使用。\n按照安装向导的提示完成安装。安装完成后，打开命令提示符（CMD），输入 python \u0026ndash;version 命令，如果能正确显示 Python 版本号，说明安装成功。 macOS 系统\nmacOS 系统通常自带 Python 2.x，但我们建议安装 Python 3.x。可以通过 Homebrew 包管理器进行安装，打开终端，输入以下命令： brew install python3 安装完成后，在终端输入 python3 \u0026ndash;version 命令，验证安装是否成功。\nLinux 系统\n不同的 Linux 发行版安装 Python 3 的方式略有不同。以 Ubuntu 为例，打开终端，输入以下命令进行安装： sudo apt update sudo apt install python3 安装完成后，输入 python3 \u0026ndash;version 验证安装结果。\n1.4 Python开发工具 除了Python自带的IDLE以外，还有很多能够进行Python编程的开发工具。下面对常用的第三方开发工具进行简要介绍。\nPyCharm：由 JetBrains 公司开发，有专业版和社区版。专业版功能丰富，适合企业级开发；社区版免费，适合个人开发者和初学者。它的智能代码提示、代码分析和调试功能都非常强大。 Visual Studio Code（VS Code）：微软开发的开源代码编辑器，通过安装 Python 扩展可以变成一个强大的 Python IDE。它具有轻量级、跨平台、丰富的扩展生态系统等特点，深受开发者喜爱。 2 Python语言基础 Python 是一种计算机编程语言。计算机编程语言和我们日常使用的自然语言有所不同，最大的区别就是，自然语言在不同的语境下有不同的理解，而计算机要根据编程语言执行任务，就必须保证编程语言写出的程序决不能有歧义，所以，任何一种编程语言都有自己的一套语法，编译器或者解释器就是负责把符合语法的程序代码转换成CPU能够执行的机器码，然后执行。\n2.1 数据类型和变量 计算机顾名思义就是可以做数学计算的机器，因此，计算机程序理所当然地可以处理各种数值。但是，计算机能处理的远不止数值，还可以处理文本、图形、音频、视频、网页等各种各样的数据，不同的数据，需要定义不同的数据类型。\n2.1.1 变量 变量是存储数据的容器，通过变量名可以引用存储在其中的数据。\n变量的命名规则：\n只能包含字母、数字和下划线：变量名可以以字母或下划线开头，但不能以数字开头。例如，my_variable 是合法的，而 123variable 是不合法的。 区分大小写：myVariable 和 myvariable 是两个不同的变量。 不能使用 Python 的关键字：如 if、else、for 等。 #定义一个整数类型的变量 age = 25 #定义一个字符串类型的变量 name = \u0026#34;Alice\u0026#34; 2.1.2 基本数据类型 整数（int）：表示整数，可正可负，没有小数部分。例如：\nnum1 = 10 num2 = -20 浮点数（float）：表示带有小数部分的数字。例如：\nheight = 1.75 weight = 65.2 布尔值（bool）：只有两个值，True 和 False，常用于条件判断。例如：\nis\\_student = True has\\_license = False 字符串（str）：表示文本数据，用单引号 ’ 或双引号 \u0026quot; 括起来。例如：\nmessage = \u0026#39;Hello, World!\u0026#39; greeting = \u0026#34;Welcome to Python\u0026#34; 2.1.3 复合数据类型 列表（list）：是一种有序的、可变的数据集合，可以包含不同类型的元素。用方括号 [] 表示，元素之间用逗号分隔。例如：\nfruits = \\[\u0026#39;apple\u0026#39;, \u0026#39;banana\u0026#39;, \u0026#39;cherry\u0026#39;\\] numbers = \\[1, 2, 3, 4, 5\\] mixed\\_list = \\[1, \u0026#39;hello\u0026#39;, True\\] 元组（tuple）：是一种有序的、不可变的数据集合，用圆括号 () 表示。一旦创建，元组的元素不能被修改。例如：\npoint = (3, 5) colors = (\u0026#39;red\u0026#39;, \u0026#39;green\u0026#39;, \u0026#39;blue\u0026#39;) 集合（set）：是一种无序的、唯一的数据集合，用花括号 {} 表示，或者使用 set() 函数创建。集合中的元素不能重复。例如：\nnumbers\\_set = {1, 2, 3, 4, 5} unique\\_fruits = set(\\[\u0026#39;apple\u0026#39;, \u0026#39;banana\u0026#39;, \u0026#39;apple\u0026#39;\\]) # 集合会自动去重 字典（dict）：是一种无序的键值对集合，用花括号 {} 表示，键和值之间用冒号 : 分隔，键必须是唯一的。(dict全称dictionary，在其他语言中也称为map，使用键-值（key-value）存储，具有极快的查找速度。) 例如：\nperson = {\u0026#39;name\u0026#39;: \u0026#39;Alice\u0026#39;, \u0026#39;age\u0026#39;: 25, \u0026#39;city\u0026#39;: \u0026#39;New York\u0026#39;} 2.1.4 数据类型的转换 在 Python 中，可以使用一些内置函数进行数据类型的转换。例如：\n\\# 将整数转换为字符串 num = 10 str\\_num = str(num) print(type(str\\_num)) # 输出: # 将字符串转换为整数 str\\_num = \u0026#34;20\u0026#34; num = int(str\\_num) print(type(num)) # 输出: 序号 函数 说明 1 int(x [,base]) 将x转换为一个整数 2 float(x) 将x转换到一个浮点数 3 complex(real [,imag]) 创建一个复数 4 str(x) 将对象 x 转换为字符串 5 repr(x) 将对象 x 转换为表达式字符串 6 eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象 7 tuple(s) 将序列 s 转换为一个元组 8 list(s) 将序列 s 转换为一个列表 9 set(s) 转换为可变集合 10 dict(d) 创建一个字典。d 必须是一个 (key, value)元组序列。 10 frozenset(s) 转换为不可变集合 11 chr(x) 将一个整数转换为一个字符 12 ord(x) 将一个字符转换为它的整数值 13 hex(x) 将一个整数转换为一个十六进制字符串 14 oct(x) 将一个整数转换为一个八进制字符串 2.2 流程控制语句 2.2.1 条件语句（分支结构） if-elif-else：实现多条件判断，elif可简化多重分支逻辑。 score = 85 if score \u0026gt;= 90: print(\u0026#34;优秀\u0026#34;) elif score \u0026gt;= 70: print(\u0026#34;良好\u0026#34;) else: print(\u0026#34;待提高\u0026#34;) 嵌套条件：允许在条件块内嵌套其他条件语句，处理复杂逻辑。 x = 10 if x \u0026gt; 0: if x % 2 == 0: print(\u0026#34;正偶数\u0026#34;) 三元运算符\n简化单行条件判断，语法：值1 if 条件 else 值2。 age = 18 status = \u0026#34;成年\u0026#34; if age \u0026gt;= 18 else \u0026#34;未成年\u0026#34; 2.2.2 循环语句 2.2.2.1 while循环 基本语法：重复执行直到条件为假。\ntotal = 0 i = 1 while i \u0026lt;= 100: total += i i += 1 2.2.2.2 for循环 遍历序列：处理列表、字符串等可迭代对象。 fruits = \\[\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;cherry\u0026#34;\\] for fruit in fruits: print(fruit) 复制 结合range()：生成数字序列，常用于固定次数循环。 for i in range(5): # 输出0-4 print(i) 2.2.3 跳转控制语句 break与continue break：立即终止当前循环，常用于满足条件时退出。\ncontinue：跳过当前迭代，进入下一次循环。\nfor num in \\[1, 2, 3, 4, 5\\]: if num == 3: break # 终止循环 print(num) # 输出1,2 pass语句\n空操作占位符，保持代码结构完整性9。 if x \u0026gt; 0: pass # 待后续补充逻辑 3 函数 3.1 函数定义与调用 3.1.1基本语法 使用def关键字定义函数，语法为： def 函数名(参数列表): 函数体 \\[return 返回值\\] #示例：计算两数之和7 def add(a, b): return a + b result = add(3, 5) # 输出8 3.1.2 参数类型 必选参数：调用时必须传入，如add(3,5) 默认参数：简化调用，如def power(x, n=2): return x**n 可变参数：*args接收任意数量参数，自动组装为元组 def avg(\\*nums): return sum(nums)/len(nums) if nums else 0 avg(1, 2, 3) # 输出2.0 关键字参数：**kwargs接收键值对，组装为字典34 3.2 函数返回值与作用域 3.2.1 返回值特性 可返回多个值（实质为元组），如： def get\\_coordinates(): return 40.7128, -74.0060 lat, lon = get\\_coordinates() 无return语句时默认返回None 3.2.2 作用域规则 局部变量：函数内定义的变量仅内部可见 全局变量：函数外定义，需用global声明修改6 count = 0 def increment(): global count count += 1 3.3 高级函数特性 3.3.1 嵌套函数与闭包 函数内部可定义其他函数，形成闭包（保留外部变量状态）： def multiplier(factor): def multiply(number): return number \\* factor # factor为外层自由变量 return multiply double = multiplier(2) print(double(5)) # 输出10 闭包常用于实现装饰器6 3.3.2 递归函数 函数调用自身，需设置终止条件： def factorial(n): return 1 if n \u0026lt;= 1 else n \\* factorial(n-1) print(factorial(5)) # 输出120 #注意栈溢出风险，复杂递归建议改用迭代 3.4 典型应用场景 3.4.1 数据处理 批量转换数据格式 def clean\\_data(dirty\\_list): return \\[x.strip() for x in dirty\\_list if x\\] 实现算法逻辑（如斐波那契数列） def fibonacci\\_recursive(n): if n == 0: return 0 elif n == 1: return 1 else: return fibonacci\\_recursive(n - 1) + fibonacci\\_recursive(n - 2) # 测试递归实现 n = 10 print(f\u0026#34;递归实现：斐波那契数列的第 {n} 项是 {fibonacci\\_recursive(n)}\u0026#34;) 3.4.2 模块化开发 将功能拆分为独立函数，提升可维护性 跨文件调用：通过import导入模块函数 3.4.3 回调机制 函数作为参数传递，实现灵活控制： def process\\_data(data, callback): processed = \\[x\\*2 for x in data\\] return callback(processed) 4 面向对象 面向对象编程（OOP）是一种编程范式，它使用 “对象” 来组织代码。对象是类的实例，类是对象的蓝图，它定义了对象的属性和方法。下面从几个方面详细介绍 Python 中的面向对象设计，并给出示例代码。\n4.1 类和对象的基本定义 类是创建对象的模板，而对象是类的具体实例。以下是一个简单的类和对象的示例：\nclass Person: # 类属性 species = \u0026#34;Homo sapiens\u0026#34; def \\_\\_init\\_\\_(self, name, age): # 实例属性 self.name = name self.age = age def introduce(self): # 实例方法 print(f\u0026#34;我叫 {self.name}，今年 {self.age} 岁。\u0026#34;) # 创建对象 person1 = Person(\u0026#34;Alice\u0026#34;, 25) person1.introduce() 在上述代码中：\nPerson 是一个类，它有一个类属性 species 和两个实例属性 name 和 age。 \\_\\_init\\_\\_ 是一个特殊的方法，称为构造函数，用于初始化对象的属性。 introduce 是一个实例方法，用于打印对象的信息。 4.2 继承 继承允许一个类（子类）继承另一个类（父类）的属性和方法。以下是一个继承的示例：\nclass Student(Person): def \\_\\_init\\_\\_(self, name, age, student\\_id): # 调用父类的构造函数 super().\\_\\_init\\_\\_(name, age) self.student\\_id = student\\_id def study(self): print(f\u0026#34;{self.name}（学号：{self.student\\_id}）正在学习。\u0026#34;) # 创建 Student 对象 student1 = Student(\u0026#34;Bob\u0026#34;, 20, \u0026#34;12345\u0026#34;) student1.introduce() student1.study() 在上述代码中：\nStudent 类继承自 Person 类，它可以使用 Person 类的属性和方法。 super().init(name, age) 调用了父类的构造函数，用于初始化从父类继承的属性。 study 是 Student 类自己的方法。 4.3 多态 多态是指不同类的对象可以对同一消息做出不同的响应。以下是一个多态的示例：\nclass Animal: def speak(self): pass class Dog(Animal): def speak(self): print(\u0026#34;汪汪汪！\u0026#34;) class Cat(Animal): def speak(self): print(\u0026#34;喵喵喵！\u0026#34;) def make\\_animal\\_speak(animal): animal.speak() # 创建不同的动物对象 dog = Dog() cat = Cat() # 调用多态函数 make\\_animal\\_speak(dog) make\\_animal\\_speak(cat) 在上述代码中：\nAnimal 是一个抽象基类，它定义了一个抽象方法 speak。 Dog 和 Cat 类继承自 Animal 类，并实现了 speak 方法。 make_animal_speak 函数接受一个 Animal 类型的对象，并调用其 speak 方法，不同的对象会有不同的响应。 4.4 封装 封装是指将数据和操作数据的方法绑定在一起，并隐藏对象的内部实现细节。以下是一个封装的示例：\nclass BankAccount: def \\_\\_init\\_\\_(self, account\\_number, balance): # 私有属性 self.\\_\\_account\\_number = account\\_number self.\\_\\_balance = balance def deposit(self, amount): if amount \u0026gt; 0: self.\\_\\_balance += amount print(f\u0026#34;成功存入 {amount} 元，当前余额为 {self.\\_\\_balance} 元。\u0026#34;) else: print(\u0026#34;存款金额必须大于 0。\u0026#34;) def withdraw(self, amount): if amount \u0026gt; 0 and amount \u0026lt;= self.\\_\\_balance: self.\\_\\_balance -= amount print(f\u0026#34;成功取出 {amount} 元，当前余额为 {self.\\_\\_balance} 元。\u0026#34;) else: print(\u0026#34;取款金额无效或余额不足。\u0026#34;) def get\\_balance(self): return self.\\_\\_balance # 创建银行账户对象 account = BankAccount(\u0026#34;123456789\u0026#34;, 1000) account.deposit(500) account.withdraw(200) print(f\u0026#34;当前余额：{account.get\\_balance()} 元\u0026#34;) 在上述代码中：\n__account_number 和 __balance 是私有属性，外部无法直接访问。 deposit 和 withdraw 方法用于对账户余额进行操作，封装了具体的业务逻辑。 get_balance 方法用于获取账户余额，提供了对私有属性的访问接口。 5 模块 在 Python 里，模块是一个包含 Python 定义和语句的文件，其文件名以 .py 结尾。模块能够让你把相关的代码组织在一起，实现代码的复用与管理，下面从模块的创建、导入、内置模块以及包的概念等方面详细介绍。\n5.1 创建模块 创建模块非常简单，只需把相关的代码写在一个 .py 文件中即可。以下是一个名为 math_operations.py 的模块示例，其中包含了一些数学运算的函数：\n\\# math\\_operations.py def add(a, b): return a + b def subtract(a, b): return a - b def multiply(a, b): return a \\* b def divide(a, b): if b == 0: raise ValueError(\u0026#34;除数不能为零\u0026#34;) return a / b 5.2. 导入模块 在 Python 中，有多种方式可以导入模块。\n5.2.1 import 语句 使用 import 语句可以导入整个模块，之后通过模块名来访问其中的函数或变量。\nimport math\\_operations result\\_add = math\\_operations.add(3, 5) print(result\\_add) result\\_multiply = math\\_operations.multiply(4, 6) print(result\\_multiply) 5.2.2 from…import 语句 使用 from…import 语句可以从模块中导入特定的函数或变量，这样在使用时就无需再加上模块名。\nfrom math\\_operations import add, multiply result\\_add = add(3, 5) print(result\\_add) result\\_multiply = multiply(4, 6) print(result\\_multiply) 5.2.3 from…import * 语句 使用 from…import * 语句可以导入模块中的所有函数和变量，但这种方式不建议大量使用，因为可能会导致命名冲突。\nfrom math\\_operations import \\* result\\_subtract = subtract(8, 3) print(result\\_subtract) result\\_divide = divide(10, 2) print(result\\_divide) 5.2.4 为模块或导入的对象指定别名 使用 as 关键字可以为模块或导入的对象指定别名，方便在代码中使用。\nimport math\\_operations as mo result = mo.add(2, 7) print(result) from math\\_operations import add as addition result = addition(4, 9) print(result) 5.3. 内置模块 Python 自带了许多内置模块，这些模块提供了丰富的功能，例如 math 模块用于数学运算，random 模块用于生成随机数等。\nimport math import random # 使用 math 模块 sqrt\\_result = math.sqrt(25) print(sqrt\\_result) # 使用 random 模块 random\\_num = random.randint(1, 10) print(random\\_num) 4. \\_\\_name\\_\\_ 属性 在 Python 模块中，\\_\\_name\\_\\_ 是一个特殊的内置变量。当模块作为脚本直接运行时，\\_\\_name\\_\\_ 的值为 \u0026#39;\\_\\_main\\_\\_\u0026#39;；当模块被导入时，\\_\\_name\\_\\_ 的值为模块名。可以利用这个特性来编写测试代码。 python # math\\_operations.py def add(a, b): return a + b if \\_\\_name\\_\\_ == \u0026#39;\\_\\_main\\_\\_\u0026#39;: result = add(2, 3) print(f\u0026#34;测试加法：{result}\u0026#34;) 在上述代码中，if name == ‘main’: 块中的代码只有在该模块作为脚本直接运行时才会执行，当该模块被其他模块导入时，这部分代码不会执行。\n5.5 包 包是一种管理 Python 模块命名空间的方式，它是一个包含多个模块的目录，并且该目录下必须有一个 init.py 文件（在 Python 3.3 及以后的版本中，init.py 文件不是必需的，但为了兼容性，通常还是会保留）。\n假设我们有一个名为 my_package 的包，其目录结构如下：\nplaintext my\\_package/ \\_\\_init\\_\\_.py module1.py module2.py module1.py 和 module2.py 是包中的模块，我们可以这样导入和使用它们：\nfrom my\\_package import module1, module2 result1 = module1.some\\_function() result2 = module2.another\\_function() 参考文献 [ 1 ] 《python学习手册》 第5版\n","date":"2025-03-19T00:00:00Z","permalink":"/p/146137523/","title":"【Python】基础语法总结"},{"content":"1、项目简介 在教育教学过程中，高效、精准地管理学生信息对于学校、教师以及学生自身都至关重要。传统的人工记录与管理学生信息的方式，不仅耗时费力，而且容易出现数据错误、信息更新不及时等问题。随着信息技术的飞速发展，开发一套功能完备、操作便捷的学生信息管理系统成为提升教育管理效率和质量的迫切需求。该系统旨在为教育工作者提供一个集成化的平台，实现学生信息的全面、规范化管理，助力教育教学工作的顺利开展。\n2、项目简介 信息整合与集中管理：将学生的基本信息（如姓名、ID、联系方式等）、学业成绩（英语、Python、C 语言等课程成绩）等各 类 数据进行整合，存储于一个统一的数据库中，实现信息的集中管理，方便随时查询与调用。\n便捷的信息操作功能：为用户提供录入、查找、删除、修改学生信息等一系列便捷操作功能，简化管理流程，提高工作效率。同时，支持对学生信息按照不同维度进行排序，如按成绩高低排序，以便快速了解学生的学业表现分布。\n数据统计与分析支持：具备 统计学 生总人数等基础统计功能，为教育决策提供数据支持。通过对学生成绩等信息的分析，能够辅助教师发现教学过程中的问题，为教学方法的改进和个性化教学的实施提供依据。\n系统易用性与稳定性：设计简洁明了的用户界面，确保操作流程直观易懂，降低用户的学习成本。同时，保证系统的稳定性，在高并发或长时间运行的情况下，也能可靠地处理和存储学生信息，避免数据丢失或系统崩溃。\n3、功能概述 录入功能：支持批量录入学生信息，包括学生的 ID、姓名、各学科成绩等。在录入过程中，对输入数据进行格式校验和合理性检查，如成绩必须为整数且在合理范围内，确保录入数据的准确性。 查找功能：提供灵活的查找方式，用户既可以通过学生 ID 精准查找特定学生的信息，也可以通过学生姓名进行模糊查询。查询结果以清晰的表格形式展示，方便用户查看。 删除功能：根据用户输入的学生 ID，在系统中准确删除对应的学生信息，并提供二次确认机制，防止误删重要数据。删除成功后，及时更新系统数据显示，反映最新的学生信息状态。 修改功能：用户能够根据实际需求修改学生的各项信息。在修改前，系统先展示学生的原始信息供用户参考，修改过程中对新输入的数据进行严格验证，确保修改后的数据质量。 排序功能：可按照英语、Python、C 语言单科成绩以及总成绩对学生信息进行升序或降序排序。排序结果实时呈现，帮助用户快速了解学生在不同学科的成绩排名情况。 统计功能：自动统计系统中存储的学生总人数，并在界面上直观显示，为学校的招生规划、教学资源分配等工作提供基础数据。 显示功能：以表格形式完整展示所有学生的详细信息，包括 ID、姓名、各科成绩及总成绩，方便用户全面浏览学生信息，掌握学生整体情况。 4、效果展示 5、 项目源码 import re # 导入正则表达式模块 import os # 导入操作系统模块 filename = \u0026#34;students.txt\u0026#34; # 定义保存学生信息的文件名 def menu(): # 输出菜单 print(\u0026#39;\u0026#39;\u0026#39; ╔———————学生信息管理系统————————╗ │ │ │ =============== 功能菜单 =============== │ │ │ │ 1 录入学生信息 │ │ 2 查找学生信息 │ │ 3 删除学生信息 │ │ 4 修改学生信息 │ │ 5 排序 │ │ 6 统计学生总人数 │ │ 7 显示所有学生信息 │ │ 0 退出系统 │ │ ========================================== │ │ 说明：通过数字或↑↓方向键选择菜单 │ ╚———————————————————————╝ \u0026#39;\u0026#39;\u0026#39;) def main(): ctrl = True # 标记是否退出系统 while (ctrl): menu() # 显示菜单 option = input(\u0026#34;请选择：\u0026#34;) # 选择菜单项 option\\_str = re.sub(\u0026#34;\\\\D\u0026#34;, \u0026#34;\u0026#34;, option) # 提取数字 if option\\_str in \\[\u0026#39;0\u0026#39;, \u0026#39;1\u0026#39;, \u0026#39;2\u0026#39;, \u0026#39;3\u0026#39;, \u0026#39;4\u0026#39;, \u0026#39;5\u0026#39;, \u0026#39;6\u0026#39;, \u0026#39;7\u0026#39;\\]: option\\_int = int(option\\_str) if option\\_int == 0: # 退出系统 print(\u0026#39;您已退出学生成绩管理系统！\u0026#39;) ctrl = False elif option\\_int == 1: # 录入学生成绩信息 insert() elif option\\_int == 2: # 查找学生成绩信息 search() elif option\\_int == 3: # 删除学生成绩信息 delete() elif option\\_int == 4: # 修改学生成绩信息 modify() elif option\\_int == 5: # 排序 sort() elif option\\_int == 6: # 统计学生总数 total() elif option\\_int == 7: # 显示所有学生信息 show() \u0026#39;\u0026#39;\u0026#39;1 录入学生信息\u0026#39;\u0026#39;\u0026#39; def insert(): stdentList = \\[\\] # 保存学生信息的列表 mark = True # 是否继续添加 while mark: id = input(\u0026#34;请输入ID（如 1001）：\u0026#34;) if not id: # ID为空，跳出循环 break name = input(\u0026#34;请输入名字：\u0026#34;) if not name: # 名字为空，跳出循环 break try: english = int(input(\u0026#34;请输入英语成绩：\u0026#34;)) python = int(input(\u0026#34;请输入Python成绩：\u0026#34;)) c = int(input(\u0026#34;请输入C语言成绩：\u0026#34;)) except: print(\u0026#34;输入无效，不是整型数值．．．．重新录入信息\u0026#34;) continue stdent = {\u0026#34;id\u0026#34;: id, \u0026#34;name\u0026#34;: name, \u0026#34;english\u0026#34;: english, \u0026#34;python\u0026#34;: python, \u0026#34;c\u0026#34;: c} # 将输入的学生信息保存到字典 stdentList.append(stdent) # 将学生字典添加到列表中 inputMark = input(\u0026#34;是否继续添加？（y/n）:\u0026#34;) if inputMark == \u0026#34;y\u0026#34;: # 继续添加 mark = True else: # 不继续添加 mark = False save(stdentList) # 将学生信息保存到文件 print(\u0026#34;学生信息录入完毕！！！\u0026#34;) # 将学生信息保存到文件 def save(student): try: students\\_txt = open(filename, \u0026#34;a\u0026#34;) # 以追加模式打开 except Exception as e: students\\_txt = open(filename, \u0026#34;w\u0026#34;) # 文件不存在，创建文件并打开 for info in student: students\\_txt.write(str(info) + \u0026#34;\\\\n\u0026#34;) # 按行存储，添加换行符 students\\_txt.close() # 关闭文件 \u0026#39;\u0026#39;\u0026#39;2 查找学生成绩信息\u0026#39;\u0026#39;\u0026#39; def search(): mark = True student\\_query = \\[\\] # 保存查询结果的学生列表 while mark: id = \u0026#34;\u0026#34; name = \u0026#34;\u0026#34; if os.path.exists(filename): # 判断文件是否存在 mode = input(\u0026#34;按ID查输入1；按姓名查输入2：\u0026#34;) if mode == \u0026#34;1\u0026#34;: id = input(\u0026#34;请输入学生ID：\u0026#34;) elif mode == \u0026#34;2\u0026#34;: name = input(\u0026#34;请输入学生姓名：\u0026#34;) else: print(\u0026#34;您的输入有误，请重新输入！\u0026#34;) search() # 重新查询 with open(filename, \u0026#39;r\u0026#39;) as file: # 打开文件 student = file.readlines() # 读取全部内容 for list in student: d = dict(eval(list)) # 字符串转字典 if id is not \u0026#34;\u0026#34;: # 判断是否按ID查 if d\\[\u0026#39;id\u0026#39;\\] == id: student\\_query.append(d) # 将找到的学生信息保存到列表中 elif name is not \u0026#34;\u0026#34;: # 判断是否按姓名查 if d\\[\u0026#39;name\u0026#39;\\] == name: student\\_query.append(d) # 将找到的学生信息保存到列表中 show\\_student(student\\_query) # 显示查询结果 student\\_query.clear() # 清空列表 inputMark = input(\u0026#34;是否继续查询？（y/n）:\u0026#34;) if inputMark == \u0026#34;y\u0026#34;: mark = True else: mark = False else: print(\u0026#34;暂未保存数据信息...\u0026#34;) return \u0026#39;\u0026#39;\u0026#39;3 删除学生成绩信息\u0026#39;\u0026#39;\u0026#39; def delete(): mark = True # 标记是否循环 while mark: studentId = input(\u0026#34;请输入要删除的学生ID：\u0026#34;) if studentId is not \u0026#34;\u0026#34;: # 判断要删除的学生是否存在 if os.path.exists(filename): # 判断文件是否存在 with open(filename, \u0026#39;r\u0026#39;) as rfile: # 打开文件 student\\_old = rfile.readlines() # 读取全部内容 else: student\\_old = \\[\\] ifdel = False # 标记是否删除 if student\\_old: # 如果存在学生信息 with open(filename, \u0026#39;w\u0026#39;) as wfile: # 以写方式打开文件 d = {} # 定义空字典 for list in student\\_old: d = dict(eval(list)) # 字符串转字典 if d\\[\u0026#39;id\u0026#39;\\] != studentId: wfile.write(str(d) + \u0026#34;\\\\n\u0026#34;) # 将一条学生信息写入文件 else: ifdel = True # 标记已经删除 if ifdel: print(\u0026#34;ID为 %s 的学生信息已经被删除...\u0026#34; % studentId) else: print(\u0026#34;没有找到ID为 %s 的学生信息...\u0026#34; % studentId) else: # 不存在学生信息 print(\u0026#34;无学生信息...\u0026#34;) break # 退出循环 show() # 显示全部学生信息 inputMark = input(\u0026#34;是否继续删除？（y/n）:\u0026#34;) if inputMark == \u0026#34;y\u0026#34;: mark = True # 继续删除 else: mark = False # 退出删除学生信息功能 \u0026#39;\u0026#39;\u0026#39;4 修改学生成绩信息\u0026#39;\u0026#39;\u0026#39; def modify(): show() # 显示全部学生信息 if os.path.exists(filename): # 判断文件是否存在 with open(filename, \u0026#39;r\u0026#39;) as rfile: # 打开文件 student\\_old = rfile.readlines() # 读取全部内容 else: return studentid = input(\u0026#34;请输入要修改的学生ID：\u0026#34;) with open(filename, \u0026#34;w\u0026#34;) as wfile: # 以写模式打开文件 for student in student\\_old: d = dict(eval(student)) # 字符串转字典 if d\\[\u0026#34;id\u0026#34;\\] == studentid: # 是否为要修改的学生 print(\u0026#34;找到了这名学生，可以修改他的信息！\u0026#34;) while True: # 输入要修改的信息 try: d\\[\u0026#34;name\u0026#34;\\] = input(\u0026#34;请输入姓名：\u0026#34;) d\\[\u0026#34;english\u0026#34;\\] = int(input(\u0026#34;请输入英语成绩：\u0026#34;)) d\\[\u0026#34;python\u0026#34;\\] = int(input(\u0026#34;请输入Python成绩：\u0026#34;)) d\\[\u0026#34;c\u0026#34;\\] = int(input(\u0026#34;请输入C语言成绩：\u0026#34;)) except: print(\u0026#34;您的输入有误，请重新输入。\u0026#34;) else: break # 跳出循环 student = str(d) # 将字典转换为字符串 wfile.write(student + \u0026#34;\\\\n\u0026#34;) # 将修改的信息写入到文件 print(\u0026#34;修改成功！\u0026#34;) else: wfile.write(student) # 将未修改的信息写入到文件 mark = input(\u0026#34;是否继续修改其他学生信息？（y/n）：\u0026#34;) if mark == \u0026#34;y\u0026#34;: modify() # 重新执行修改操作 \u0026#39;\u0026#39;\u0026#39;5 排序\u0026#39;\u0026#39;\u0026#39; def sort(): show() # 显示全部学生信息 if os.path.exists(filename): # 判断文件是否存在 with open(filename, \u0026#39;r\u0026#39;) as file: # 打开文件 student\\_old = file.readlines() # 读取全部内容 student\\_new = \\[\\] for list in student\\_old: d = dict(eval(list)) # 字符串转字典 student\\_new.append(d) # 将转换后的字典添加到列表中 else: return ascORdesc = input(\u0026#34;请选择（0升序；1降序）：\u0026#34;) if ascORdesc == \u0026#34;0\u0026#34;: # 按升序排序 ascORdescBool = False # 标记变量，为False表示升序排序 elif ascORdesc == \u0026#34;1\u0026#34;: # 按降序排序 ascORdescBool = True # 标记变量，为True表示降序排序 else: print(\u0026#34;您的输入有误，请重新输入！\u0026#34;) sort() mode = input(\u0026#34;请选择排序方式（1按英语成绩排序；2按Python成绩排序；3按C语言成绩排序；0按总成绩排序）：\u0026#34;) if mode == \u0026#34;1\u0026#34;: # 按英语成绩排序 student\\_new.sort(key=lambda x: x\\[\u0026#34;english\u0026#34;\\], reverse=ascORdescBool) elif mode == \u0026#34;2\u0026#34;: # 按Python成绩排序 student\\_new.sort(key=lambda x: x\\[\u0026#34;python\u0026#34;\\], reverse=ascORdescBool) elif mode == \u0026#34;3\u0026#34;: # 按C语言成绩排序 student\\_new.sort(key=lambda x: x\\[\u0026#34;c\u0026#34;\\], reverse=ascORdescBool) elif mode == \u0026#34;0\u0026#34;: # 按总成绩排序 student\\_new.sort(key=lambda x: x\\[\u0026#34;english\u0026#34;\\] + x\\[\u0026#34;python\u0026#34;\\] + x\\[\u0026#34;c\u0026#34;\\], reverse=ascORdescBool) else: print(\u0026#34;您的输入有误，请重新输入！\u0026#34;) sort() show\\_student(student\\_new) # 显示排序结果 \u0026#39;\u0026#39;\u0026#39; 6 统计学生总数\u0026#39;\u0026#39;\u0026#39; def total(): if os.path.exists(filename): # 判断文件是否存在 with open(filename, \u0026#39;r\u0026#39;) as rfile: # 打开文件 student\\_old = rfile.readlines() # 读取全部内容 if student\\_old: print(\u0026#34;一共有 %d 名学生！\u0026#34; % len(student\\_old)) else: print(\u0026#34;还没有录入学生信息！\u0026#34;) else: print(\u0026#34;暂未保存数据信息...\u0026#34;) \u0026#39;\u0026#39;\u0026#39; 7 显示所有学生信息 \u0026#39;\u0026#39;\u0026#39; def show(): student\\_new = \\[\\] if os.path.exists(filename): # 判断文件是否存在 with open(filename, \u0026#39;r\u0026#39;) as rfile: # 打开文件 student\\_old = rfile.readlines() # 读取全部内容 for list in student\\_old: student\\_new.append(eval(list)) # 将找到的学生信息保存到列表中 if student\\_new: show\\_student(student\\_new) else: print(\u0026#34;暂未保存数据信息...\u0026#34;) # 将保存在列表中的学生信息显示出来 def show\\_student(studentList): if not studentList: print(\u0026#34;(o@.@o) 无数据信息 (o@.@o) \\\\n\u0026#34;) return format\\_title = \u0026#34;{:^6}{:^12}\\\\t{:^8}\\\\t{:^10}\\\\t{:^10}\\\\t{:^10}\u0026#34; print(format\\_title.format(\u0026#34;ID\u0026#34;, \u0026#34;名字\u0026#34;, \u0026#34;英语成绩\u0026#34;, \u0026#34;Python成绩\u0026#34;, \u0026#34;C语言成绩\u0026#34;, \u0026#34;总成绩\u0026#34;)) format\\_data = \u0026#34;{:^6}{:^12}\\\\t{:^12}\\\\t{:^12}\\\\t{:^12}\\\\t{:^12}\u0026#34; for info in studentList: print(format\\_data.format(info.get(\u0026#34;id\u0026#34;), info.get(\u0026#34;name\u0026#34;), str(info.get(\u0026#34;english\u0026#34;)), str(info.get(\u0026#34;python\u0026#34;)), str(info.get(\u0026#34;c\u0026#34;)), str(info.get(\u0026#34;english\u0026#34;) + info.get(\u0026#34;python\u0026#34;) + info.get(\u0026#34;c\u0026#34;)).center(12))) if \\_\\_name\\_\\_ == \u0026#34;\\_\\_main\\_\\_\u0026#34;: main() AI写代码bash123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 ","date":"2025-03-19T00:00:00Z","permalink":"/p/146353855/","title":"【Python项目】学生信息管理系统"},{"content":" 前言随笔：很多东西经常不用，慢慢的就忘记了，刚好对之前的c++笔记做个整理，就当作复习了。\n一、C++语言的历史 C++是一种计算机高级程序设计语言，由C语言扩展升级而产生 ，最早于1979年由Bjarne Stroustrup（见下图）在AT\u0026amp;T贝尔工作室研发。\nC++既可以进行C语言的过程化程序设计，又可以进行以抽象数据类型为特点的基于对象的程序设计，还可以进行以继承和多态为特点的面向对象的程序设计。C++擅长面向对象程序设计的同时，还可以进行基于过程的程序设计。C++几乎可以创建任何类型的程序：游戏、设备驱动程序、HPC、云、桌面、嵌入式和移动应用等。 甚至用于其他编程语言的库和编译器也使用C++编写。\n时间轴 发展 1979年 贝尔实验室的 Bjarne Stroustmp 开始对C语言进行改进，为其加入面向对象的特性。最初，这种新语言被称为“带类的C（C with Classes）” 。 1983年 带类的C”加入虚函数、函数和运算符重载、引用等概念后，正式定名为“C++（C plus plus）”。 1985年 1985 年，C++ 最权威的著作、由 Bjarne Stroustmp 撰写的《C++程序设计语言》（The C++ Programming Language）第一版发布。 1989年 1989 年，C++ 2.0 版发布，加入了多重继承、抽象类、静态成员、常量成员函数等概念。 1990年 加入了模板、异常处理、名字空间等机制。 1994年 ANSI C++ 标准发布。 1998年 NSI（美国国家标准协会）和 ISO（国际标准化组织）联合发布了至今使用最为广泛的 C++ 标准，称为 C++ 98。C++ 98 最为重大的改进就是加入了 “标准模板库”（Standard Template Library, STL），使得“泛型程序设计”成为 C++ 除“面向对象”外的另一主要特点。 2003年 ISO 的 C++ 标准委员会又对 C++ 略做了一些修订，发布了 C++ 03 标准。C++ 03 和 C++ 98 的区别对大多数程序员来说可以不必关心。 2005年 一份名为 Library Technical Report 1（简称 TR1）的技术报告发布，为 C++ 加入了正则表达式、哈希表等重要类模板。虽然 TR1 当时没有正式成为 C++ 标准，但如今的许多 C++ 编译器都已经支持 TR1 中的特性。 2011年 ISO 通过了新的 C+ + 标准，这就是 C++11。C++11 在酝酿的过程中被称为 C++ 0x，因为 Bjame Stroustmp 原本预计它应该在 2008 年或 2009 年发布。 C++11是 C++ 语言的一个重要版本，它大幅度改进了 C++，引入了许多新的特性和库，提升了语言的现代性，增强了开发效率 2014年 C++14作为C++11的修正版，主要对C++11中的一些特性进行了修正和小范围的增强。 2017年 C++17引入了许多新的功能和库，改进了 C++ 语言的现代性和效率。 2020年 C++20是 C++ 语言的一个重要版本，加入了许多现代化的特性，进一步提升了语言的表达能力和性能。 2023年 C++23标准于2023年末正式通过，并已进入广泛采用阶段。C++23在C++20的基础上，进一步增强了语言功能和标准库的便利性。 2024年 C++24仍处于制定标准和提案讨论阶段。 二、C++语言基础** 1、“Hello World” 每个初学者都是从\u0026quot;Hello World\u0026quot;打开了新世界的大门，上来给你一串代码，但很多时候不知道为什么，先进行“模仿”，在进行练习，很多东西都是在使用过程中学会了，才有了自己的思考。哈哈，扯远了，见下图。\ninclude：包含；把……列为一部分，把……算入； stdio：标准输入输出； void：空的； main：主要的； printf：写格式化输出；打印函数； return：回应； 2、数据类型 C++的基本数据类型大体上可分为布尔型、字符型、整数型、浮点型、双浮点型、空值型和宽字符型。\n注意：当一个变量被赋予一个超过其最大值的数值时，它会发生溢出。 3、转义字符 对于 ASCII 编码，0~31（十进制）范围内的字符为控制字符，它们都是看不见的，不能在显示器上显示，甚至无法从键盘输入，只能用转义字符的形式来表示。\n4、变量与常量 4.1、标识符与关键字 4.1.1 标识符 标识符由字母、数字、下划线“_”组成。 不能把C++关键字作为标识符。 标识符长度限制32字符。 标识符对大小写敏感。 首字符只能是字母或下划线，不能是数字。 4.1.2 关键字 关键字是编程语言中的预定义的保留字，具有特殊的语法意义。它们是语言的一部分，用于实现语言的控制结构、数据类型定义、函数行为等。程序员不能将这些关键字用作标识符（如变量名、函数名等）。关键字在程序执行过程中被编译器识别并处理，是构成程序语法和语义的基础。\n4.2、变量 在 C++ 中，变量的定义是指声明一个变量并为其指定类型，之后你可以给该变量赋值以存储数据。变量的定义包括以下几个基本要素：\n1. 数据类型：指定变量能够存储的数据类型（如 int、double、char 等）。\n2. 变量名：变量的标识符，用于在程序中引用该变量。\n3. 可选的初始值：在定义时，变量可以被赋一个初始值。\n4.3、常量 在 C++ 中，常量（const）是指在程序执行过程中，其值不可改变的变量。常量用于保护一些不应修改的数据，能够提高程序的可靠性和可读性。\n如果一个变量被const修饰，那么它的值就不能再被改变。\n指针常量：const修饰一个常量，且它为指针，被const修饰的值不能被修改，即这个指针不能被改变，而指针指向的地址可以被修改。 常量指针：指向常量的指针，指针本身可以改变，可以指向不同的内容，但是它所指向的内容是不可修改的。 #include int main() { int x = 123; int\ty = 456; // 指针常量 int\\* const ptr\\_x = \u0026amp;x; \\*ptr\\_x = 30; // 合法，可以修改指针指向的值 //ptr\\_x = \u0026amp;y; // 非法，不能修改指针本身的值（指向的地址） // 常量指针 const int\\* ptr\\_y = \u0026amp;x; ptr\\_y = \u0026amp;y; // 合法，可以修改指针指向的地址 // \\*ptr\\_y = 40; // 非法，不能通过指针修改指向的值 printf(\u0026#34;x = %d, y = %d\\\\n\u0026#34;, x, y); printf(\u0026#34;\\*ptr\\_x = %d, \\*ptr\\_y = %d\\\\n\u0026#34;, \\*ptr\\_x, \\*ptr\\_y); return 0; } 5、运算符 在 C++ 中，运算符是用于执行操作的符号或关键字，它们可以对数据进行计算、比较、赋值或修改等操作。\n6、控制结构 在程序设计语言中控制结构用于指明程序的执行流程。C++包括提供的基本控制结构分为三种：\n1. 顺序结构：按照先后顺序依次执行程序中的语句。\n2. 选择结构：按照给定条件有选择地执行程序中的语句。\n3. 循环结构：按照给定规则重复地执行程序中的语句。\n6.1、顺序结构 顺序结构是最简单的控制结构，指的是程序从上到下、按顺序逐行执行语句。\n6.2、选择结构 1. if 语句：根据条件是否为真，执行相应的代码。\n2. if-else 语句：如果条件为真执行一部分代码，条件为假执行另一部分代码。\n3. else-if 语句：多个条件依次判断，选择执行第一个满足条件的代码块。\n4. switch 语句：根据不同的值来选择执行不同的代码块，通常用于多重条件判断。\n#include using namespace std; int main() { int a = 5, b = 3; if (a \u0026gt; b) { cout \u0026lt;\u0026lt; \u0026#34;a is greater than b\u0026#34; \u0026lt;\u0026lt; endl; } else { cout \u0026lt;\u0026lt; \u0026#34;a is less than or equal to b\u0026#34; \u0026lt;\u0026lt; endl; } enum color { RED, GREEN, BLUE }; switch (RED) { case RED: std::cout \u0026lt;\u0026lt; \u0026#34;red\\\\n\u0026#34;; break; case GREEN: std::cout \u0026lt;\u0026lt; \u0026#34;green\\\\n\u0026#34;; break; case BLUE: std::cout \u0026lt;\u0026lt; \u0026#34;blue\\\\n\u0026#34;; break; } return 0; } 6.3、循环结构 循环结构允许程序在满足特定条件时重复执行某些代码。常见的循环结构包括 for 循环、while 循环和 do-while 循环。\n#include using namespace std; int main() { // for 循环示例 for (int i = 0; i \u0026lt; 5; i++) { cout \u0026lt;\u0026lt; i \u0026lt;\u0026lt; \u0026#34; \u0026#34;; } cout \u0026lt;\u0026lt; endl; // while 循环示例 int j = 0; while (j \u0026lt; 5) { cout \u0026lt;\u0026lt; j \u0026lt;\u0026lt; \u0026#34; \u0026#34;; j++; } cout \u0026lt;\u0026lt; endl; // do-while 循环示例 int k = 0; do { cout \u0026lt;\u0026lt; k \u0026lt;\u0026lt; \u0026#34; \u0026#34;; k++; } while (k \u0026lt; 5); cout \u0026lt;\u0026lt; endl; return 0; } 7、函数 函数（function）是把一个语句序列（函数体, function body）关联到一个名字和零或更多个函数形参（function parameter）的列表的 C++ 实体。每个函数都是一个独立的模块，绝不允许在一个函数体内定义另外一个函数。\n通俗的讲，就是把一段经常使用的代码封装起来，减少重复代码。\n#include // 用户自定义函数 doPrint() void doPrint() // doPrint() 是被调函数 { std::cout \u0026lt;\u0026lt; \u0026#34;In doPrint()\\\\n\u0026#34;; } // 定义函数 main() int main() { std::cout \u0026lt;\u0026lt; \u0026#34;Starting main()\\\\n\u0026#34;; doPrint(); // 去执行函数 doPrint(). main() 是调用者. std::cout \u0026lt;\u0026lt; \u0026#34;Ending main()\\\\n\u0026#34;; // doPrint() 执行结束后，返回这里继续执行 return 0; } 8、构造数据类型 8.1、枚举 如果一个变量只有集中可能的取值，可以使用枚举类型进行定义。枚举类型属于用户自定义的数据类型。枚举声明的一般类型如下。\nenum country\\_name { CHINA 1, USA 2, Korea } 注意：\n枚举类型名以及枚举常量为标识符，遵循标识符的取名规则。 在定义一个枚举类型时定义了多个常量，供枚举类型变量取值，我们称此常量为枚举常量。当没有给枚举常量指定值时，其值默认为0、1、2、…在定义枚举类型时，也可以使用赋值号另外指定枚举常量的值。 8.2、数组 在C++中，数组是一种数据结构，用于存储固定大小的相同类型元素的顺序集合。数组的每个元素可以通过索引访问，索引从0开始。数组在内存中占用连续的空间，最低地址对应第一个元素，最高地址对应最后一个元素。\n#include using namespace std; #include using std::setw; int main () { int n\\[ 10 \\]; // n 是一个包含 10 个整数的数组 // 初始化数组元素 for ( int i = 0; i \u0026lt; 10; i++ ) { n\\[ i \\] = i + 100; // 设置元素 i 为 i + 100 } cout \u0026lt;\u0026lt; \u0026#34;Element\u0026#34; \u0026lt;\u0026lt; setw( 13 ) \u0026lt;\u0026lt; \u0026#34;Value\u0026#34; \u0026lt;\u0026lt; endl; // 输出数组中每个元素的值 for ( int j = 0; j \u0026lt; 10; j++ ) { cout \u0026lt;\u0026lt; setw( 7 )\u0026lt;\u0026lt; j \u0026lt;\u0026lt; setw( 13 ) \u0026lt;\u0026lt; n\\[ j \\] \u0026lt;\u0026lt; endl; } return 0; } 8.3、指针 指针是一种特殊的变量，它存储的是另一个变量的内存地址，而不是实际的数据值。通过指针，你可以间接地访问和操作存储在该内存地址中的数据。\n在C++中，有几种特殊的指针类型，它们用于特定的用途。以下是常见的几种特殊指针类型及其解释：\n空指针 (Null Pointer)： 空指针是指向“无效”内存地址的指针。通常用于表示指针未初始化或不指向任何有效的对象。\nnullptr 是 C++11 引入的关键字，表示一个空指针。\nint\\* ptr = nullptr; 野指针 (Dangling Pointer)： 野指针是指向已经被释放或超出作用域的内存的指针。使用野指针会导致未定义行为。\nint\\* ptr = new int(10); // 动态分配内存 delete ptr; // 释放内存 // ptr 现在是一个野指针 常量指针 (Constant Pointer)： 常量指针是指针本身的值不能被改变，但它指向的内容是可以修改的。\nint x = 10; int\\* const ptr = \u0026amp;x; // ptr 是常量指针 \\*ptr = 20; // 可以修改 ptr 指向的值 // ptr = \u0026amp;y; // 错误：不能改变指针 ptr 的指向 指针常量 (Pointer to Constant)： 指针常量是指针可以改变，但它指向的数据内容是常量，不能修改。\nconst int\\* ptr = \u0026amp;x; // ptr 是指向常量的指针 \\*ptr = 20; // 错误：不能修改 \\*ptr 的值 ptr = \u0026amp;y; // 可以改变 ptr 指向的地址 常量指针常量 (Constant Pointer to Constant)： 常量指针常量是指既不能改变指针本身的值，也不能修改指针所指向的数据。\nconst int\\* const ptr = \u0026amp;x; // ptr 是常量指针常量 \\*ptr = 20; // 错误：不能修改 \\*ptr 的值 ptr = \u0026amp;y; // 错误：不能改变 ptr 的指向 函数指针 (Function Pointer)： 函数指针是指向函数的指针，可以用来调用函数。\nvoid (\\*funcPtr)(int); // 声明一个函数指针，指向接受一个 int 类型参数并返回 void 的函数 void myFunction(int x) { std::cout \u0026lt;\u0026lt; x \u0026lt;\u0026lt; std::endl; } funcPtr = myFunction; // 将函数指针指向 myFunction funcPtr(10); // 调用 myFunction，通过函数指针 指针数组 (Array of Pointers)： 指针数组是一个数组，其中的每个元素都是指针。常用于存储多个指针。\nint\\* arr\\[10\\]; // 一个包含 10 个整数指针的数组 指针指针 (Pointer to Pointer)：\n指针指针是指向指针的指针，用来间接访问指针所指向的内存。\nint x = 10; int\\* ptr = \u0026amp;x; int\\*\\* ptr2 = \u0026amp;ptr; // ptr2 是指向 ptr 的指针 智能指针 (Smart Pointer)： 智能指针是 C++11 引入的类，用来自动管理动态分配的内存，避免内存泄漏。\nstd::unique_ptr：表示唯一所有权，不能共享。\nstd::shared_ptr：表示共享所有权，多个指针可以共享同一个对象。\nstd::weak_ptr：用于解决 shared_ptr 的循环引用问题。\nstd::unique\\_ptr ptr = std::make\\_unique(10); std::shared\\_ptr sptr = std::make\\_shared(20); 8.4、引用 从逻辑上理解﹐引用(reference)是已存在变量的别名(alias)。通过引用﹐我们可以间接访问变量,指针也能间接访问变量,但引用在使用上比指针更安全。引用的主要用途是描述函数的参数和返回值,特别是传递较大的数据变量。\n8.3、结构与联合 数组是由类型相同的数据元素构成的,然而,在程序中往往需要处理一些由不同类型数据元素所构成的数据。例如,一个学生的基本情况由学号、姓名、性别、出生日期、成绩等数据元素构成,这些数据元素具有不同的数据类型,如果使用独立的不同数据类型的变量来描述这些信息,那么变量之间的关系不能体现出来。C++提供了描述不同数据类型的组合体的方法,即结构(struct)与联合(uion)。\n9、类与对象 9.1、类与对象的概念 类和对象是面向对象编程（OOP）中的两个核心概念。在C++以及其他OOP语言中，它们提供了一种结构化和组织化代码的方式，使得程序更加模块化、可维护和可扩展。\n9.1.1、类 类是一种自定义的数据类型，它是描述一组具有相同属性和行为的对象的模板。类定义了对象的属性（数据成员）和方法（成员函数），并且可以封装相关的功能。\n9.1.2、对象 对象是类的一个实例，是根据类的模板创建的实体。类定义了对象的属性和行为，而对象则是类的实际应用，每个对象可以拥有不同的属性值。\nint main() { // 创建对象 Car car1; // car1 是 Car 类的一个对象 Car car2; // car2 是另一个 Car 类的对象 // 给对象 car1 的成员赋值 car1.brand = \u0026#34;Toyota\u0026#34;; car1.year = 2020; // 给对象 car2 的成员赋值 car2.brand = \u0026#34;Honda\u0026#34;; car2.year = 2018; // 调用对象的成员函数 car1.displayInfo(); car2.displayInfo(); return 0; } 9.2、构造函数与析构函数 构造函数和析构函数是面向对象编程（OOP）中用于初始化和清理对象的特殊成员函数。它们通常在类中定义，用于对象的生命周期管理。\n9.2.1、构造函数（Constructor） 构造函数是当一个对象被创建时自动调用的特殊函数。它主要用于初始化对象的状态或进行资源的分配。\n特点：\n自动调用：当创建对象时，构造函数会被自动调用。 名称与类相同：构造函数的名称必须与类的名称相同。 没有返回值：构造函数没有返回值类型，甚至不可以指定 void。 可以有多个重载：一个类可以有多个构造函数，分别接收不同的参数（构造函数重载）。 9.2.2、析构函数（Destructor） 析构函数是当对象生命周期结束时自动调用的特殊函数。它主要用于释放构造函数中分配的资源，防止内存泄漏和其他资源浪费。\n特点：\n自动调用：当对象生命周期结束时，析构函数会被自动调用。 名称与类相同，但前面加上~ ：析构函数的名称必须与类名相同，但在函数名前加一个波浪号（~）。 没有返回值：析构函数没有返回值类型，也不能指定 void。 不能有参数：析构函数不能有参数，因此不能进行重载。 10、封装、继承和多态 封装、继承和多态是面向对象编程（OOP）的三大基本特性。\n封装：将客观事物封装成抽象的类，⽽而类可以把⾃自⼰己的数据和⽅方法暴暴露露给可信的类或者对象，对不不可信的类或\n对象则进⾏行行信息隐藏。 继承：可以使⽤用现有类的所有功能，并且⽆无需重新编写原来的类即可对功能进⾏行行拓拓展； 多态：⼀一个类实例例的相同⽅方法在不不同情形下有不不同的表现形式，使不不同内部结构的对象可以共享相同的外部接口。 10.1、封装 在C++中，封装通过类来实现。类内部的成员变量通常设为私有（private），并通过公共（public）方法来访问和修改它们。\n#include using namespace std; class Circle { private: double radius; // 私有成员变量 public: // 公共成员函数，提供对radius的访问接口 void setRadius(double r) { if (r \u0026gt; 0) { radius = r; } } double getRadius() const { return radius; } double getArea() const { return 3.14159 \\* radius \\* radius; } }; int main() { Circle c; c.setRadius(5); // 使用公共接口设置radius cout \u0026lt;\u0026lt; \u0026#34;Radius: \u0026#34; \u0026lt;\u0026lt; c.getRadius() \u0026lt;\u0026lt; endl; cout \u0026lt;\u0026lt; \u0026#34;Area: \u0026#34; \u0026lt;\u0026lt; c.getArea() \u0026lt;\u0026lt; endl; return 0; } 10.2、继承 继承是面向对象编程的另一大特性，它允许一个类从另一个类继承属性和行为。通过继承，可以实现代码复用和扩展，减少重复代码。\n代码重用：子类可以继承父类的成员变量和成员函数，避免重复编写相同的代码。 扩展功能：子类可以添加自己特有的成员，也可以重写父类的成员函数。 #include using namespace std; class Animal { public: void eat() { cout \u0026lt;\u0026lt; \u0026#34;Eating...\u0026#34; \u0026lt;\u0026lt; endl; } }; class Dog : public Animal { // Dog 类继承自 Animal 类 public: void bark() { cout \u0026lt;\u0026lt; \u0026#34;Barking...\u0026#34; \u0026lt;\u0026lt; endl; } }; int main() { Dog dog; dog.eat(); // Dog 类继承了 Animal 类的 eat() 方法 dog.bark(); // Dog 类自定义了 bark() 方法 return 0; } 10.3、多态 多态是指不同对象对相同消息（方法调用）做出不同响应的能力。多态通常通过“方法重载”和“方法重写”来实现。C++支持两种类型的多态：\n静态多态（编译时多态）：通过方法重载（函数名相同，参数不同）和运算符重载实现。 动态多态（运行时多态）：通过继承和虚函数（virtual）机制实现。 #include using namespace std; class Animal { public: virtual void sound() { // 声明为虚函数 cout \u0026lt;\u0026lt; \u0026#34;Animal sound\u0026#34; \u0026lt;\u0026lt; endl; } }; class Dog : public Animal { public: void sound() override { // 重写父类的虚函数 cout \u0026lt;\u0026lt; \u0026#34;Bark\u0026#34; \u0026lt;\u0026lt; endl; } }; class Cat : public Animal { public: void sound() override { // 重写父类的虚函数 cout \u0026lt;\u0026lt; \u0026#34;Meow\u0026#34; \u0026lt;\u0026lt; endl; } }; int main() { Animal\\* animal1 = new Dog(); // 父类指针指向子类对象 Animal\\* animal2 = new Cat(); // 父类指针指向子类对象 animal1-\u0026gt;sound(); // 调用 Dog 类的 sound() 方法 animal2-\u0026gt;sound(); // 调用 Cat 类的 sound() 方法 delete animal1; delete animal2; return 0; } 11、模板 模板元编程（Template Metaprogramming，简称TMP）是C++中一种强大的编程技术，它允许在编译期间进行计算和类型操作。通过模板元编程，开发者可以生成高效、可复用的代码，并在编译时进行优化，实现泛型编程。\n11.1、函数模板 函数模板通过建立一个通用函数，其函数返回值类型和形参类型可以不具体指定，用一个虚拟的类型来代表。\n#基本语法 template T add(T a, T b) { return a + b; } #-------------------------------------# # 样例 # #-------------------------------------# #include using namespace std; template T add(T a, T b) { return a + b; } int main() { int intResult = add(2, 3); // 传递int类型 cout \u0026lt;\u0026lt; \u0026#34;intResult: \u0026#34; \u0026lt;\u0026lt; intResult \u0026lt;\u0026lt; endl; double doubleResult = add(2.5, 3.7); // 传递double类型 cout \u0026lt;\u0026lt; \u0026#34;doubleResult: \u0026#34; \u0026lt;\u0026lt; doubleResult \u0026lt;\u0026lt; endl; return 0; } 11.2、类模板 类模板允许我们定义一个模板类，这个类可以在实例化时接受不同的类型参数。类模板的使用方式与函数模板类似。\n#基本语法 template class Box { private: T value; public: Box(T v) : value(v) {} T getValue() { return value; } }; #-------------------------------------# # 样例 # #-------------------------------------# #include using namespace std; template class Box { private: T value; public: Box(T v) : value(v) {} T getValue() { return value; } }; int main() { Box intBox(42); // 实例化一个Box cout \u0026lt;\u0026lt; \u0026#34;Box: \u0026#34; \u0026lt;\u0026lt; intBox.getValue() \u0026lt;\u0026lt; endl; Box doubleBox(3.14); // 实例化一个Box cout \u0026lt;\u0026lt; \u0026#34;Box: \u0026#34; \u0026lt;\u0026lt; doubleBox.getValue() \u0026lt;\u0026lt; endl; return 0; } 12、输入/输出流与文件系统 12.1、输入\\输出流 C++的标准库提供了输入流（istream）和输出流（ostream），以及它们的派生类来处理不同的输入和输出操作。\nC++ 的开发者认为数据输入和输出的过程也是数据传输的过程，数据像水一样从一个地方流动到另一个地方，所以 C++ 中将此过程称为“流”，实现此过程的类称为“流类”。\nistream：常用于接收从键盘输入的数据； ostream：常用于将数据输出到屏幕上； ifstream：用于读取文件中的数据； ofstream：用于向文件中写入数据； iostream：继承自 istream 和 ostream 类，因为该类的功能兼两者于一身，既能用于输入，也能用于输出； fstream：兼 ifstream 和 ofstream 类功能于一身，既能读取文件中的数据，又能向文件中写入数据。 12.2、文件管理 C++通过 fstream 库提供了对文件的输入输出操作。通过文件流，程序可以从文件中读取数据，或将数据写入文件。\nifstream：用于从文件中读取数据（输入文件流）。 ofstream：用于将数据写入文件（输出文件流）。 fstream：用于同时进行文件的读取和写入操作（输入输出文件流）。 12.2.1、 文件读取操作 (ifstream) #include #include #include using namespace std; int main() { ifstream infile(\u0026#34;example.txt\u0026#34;); // 打开文件进行读取 if (!infile) { // 检查文件是否成功打开 cerr \u0026lt;\u0026lt; \u0026#34;Failed to open the file!\u0026#34; \u0026lt;\u0026lt; endl; return 1; } string line; while (getline(infile, line)) { // 逐行读取文件内容 cout \u0026lt;\u0026lt; line \u0026lt;\u0026lt; endl; } infile.close(); // 关闭文件 return 0; } 12.2.2、 文件写入操作 (ofstream) #include #include using namespace std; int main() { ofstream outfile(\u0026#34;output.txt\u0026#34;); // 打开文件进行写入 if (!outfile) { cerr \u0026lt;\u0026lt; \u0026#34;Failed to open the file!\u0026#34; \u0026lt;\u0026lt; endl; return 1; } outfile \u0026lt;\u0026lt; \u0026#34;Hello, this is a test file!\u0026#34; \u0026lt;\u0026lt; endl; outfile \u0026lt;\u0026lt; \u0026#34;Writing to a file in C++.\u0026#34; \u0026lt;\u0026lt; endl; outfile.close(); // 关闭文件 return 0; } 12.2.3、 同时读写文件 (fstream) #include #include #include using namespace std; int main() { fstream file(\u0026#34;example.txt\u0026#34;, ios::in | ios::out); // 打开文件进行读写 if (!file) { cerr \u0026lt;\u0026lt; \u0026#34;Failed to open the file!\u0026#34; \u0026lt;\u0026lt; endl; return 1; } string line; while (getline(file, line)) { cout \u0026lt;\u0026lt; \u0026#34;Read: \u0026#34; \u0026lt;\u0026lt; line \u0026lt;\u0026lt; endl; } file.seekp(0, ios::end); // 将写入指针移动到文件末尾 file \u0026lt;\u0026lt; \u0026#34;Appending new content to the file.\u0026#34; \u0026lt;\u0026lt; endl; file.close(); return 0; } 13、异常处理 C++中的异常处理机制使用 try、throw 和 catch 来捕获和处理程序中的异常（错误）。通过这种机制，我们可以在程序运行时捕获错误并做出相应的处理，而不会导致程序直接崩溃。\ntry 块：用于包含可能抛出异常的代码。 throw 关键字：用于抛出异常，表示遇到错误时将异常传递出去。 catch 块：用于捕获抛出的异常并处理它。 try { // 可能会抛出异常的代码 } catch (类型1\u0026amp; 异常变量1) { // 处理异常类型1 } catch (类型2\u0026amp; 异常变量2) { // 处理异常类型2 } catch (...) { // 处理其他所有类型的异常 } 抛出异常\n#include using namespace std; void checkDivideByZero(int divisor) { if (divisor == 0) { throw \u0026#34;除数不能为零\u0026#34;; // 抛出异常 } cout \u0026lt;\u0026lt; \u0026#34;结果: \u0026#34; \u0026lt;\u0026lt; 10 / divisor \u0026lt;\u0026lt; endl; } int main() { try { checkDivideByZero(0); // 触发异常 } catch (const char\\* e) { cout \u0026lt;\u0026lt; \u0026#34;捕获到异常: \u0026#34; \u0026lt;\u0026lt; e \u0026lt;\u0026lt; endl; // 捕获并处理异常 } return 0; } 捕获不同类型的异常\n#include using namespace std; void testExceptions() { throw 404; // 抛出整数类型异常 } int main() { try { testExceptions(); // 调用可能抛出异常的函数 } catch (int e) { cout \u0026lt;\u0026lt; \u0026#34;捕获到整数异常: \u0026#34; \u0026lt;\u0026lt; e \u0026lt;\u0026lt; endl; } catch (const char\\* e) { cout \u0026lt;\u0026lt; \u0026#34;捕获到字符异常: \u0026#34; \u0026lt;\u0026lt; e \u0026lt;\u0026lt; endl; } catch (...) { cout \u0026lt;\u0026lt; \u0026#34;捕获到未知异常\u0026#34; \u0026lt;\u0026lt; endl; } return 0; } 异常的继承关系\n#C++的异常类可以继承自标准异常类 std::exception。 #这样，我们可以创建自定义异常类型，并通过继承标准异常类来获取标准异常的一些功能。 #include #include using namespace std; class MyException : public exception { public: const char\\* what() const noexcept override { return \u0026#34;自定义异常\u0026#34;; } }; void throwMyException() { throw MyException(); // 抛出自定义异常 } int main() { try { throwMyException(); } catch (const MyException\u0026amp; e) { cout \u0026lt;\u0026lt; \u0026#34;捕获到异常: \u0026#34; \u0026lt;\u0026lt; e.what() \u0026lt;\u0026lt; endl; } return 0; } 三、总结** 整理笔记是一个二次学习的过程，许多知识点在使用中，会较易发现其潜在的发现。之后会对各个模块进行详细补充。\n参考文献 [ 1 ] C语言中文网\n[ 2 ] 菜鸟教程-基本数据类型\n[ 3 ] C++参考手册\n","date":"2025-02-12T00:00:00Z","permalink":"/p/144201161/","title":"【C++】基础语法总结复习"},{"content":"消抖算法 消抖算法（Debouncing Algorithm）是一种常用于软件开发中的技术，用于处理频繁触发的事件或信号。其主要目的是防止因输入设备的机械开关引起的电气浮动或者软件中的逻辑波动导致的多次触发问题。\n在实际应用中，消抖算法通常用于处理按钮点击、键盘输入或者其他类似的事件。具体而言，消抖算法通过设定一个时间阈值，在该时间内如果事件再次发生，那么会被视为同一次事件的触发，而不是多次独立触发。\n#include #include #include enum class ButtonState { Idle, Pressed, Debouncing }; class Button { private: ButtonState state; std::chrono::steady\\_clock::time\\_point last\\_change\\_time; std::chrono::steady\\_clock::duration debounce\\_duration; public: Button(std::chrono::steady\\_clock::duration duration) : state(ButtonState::Idle), debounce\\_duration(duration) {} void press() { auto now = std::chrono::steady\\_clock::now(); switch (state) { case ButtonState::Idle: state = ButtonState::Pressed; last\\_change\\_time = now; break; case ButtonState::Pressed: if (now - last\\_change\\_time \u0026gt; debounce\\_duration) { state = ButtonState::Debouncing; last\\_change\\_time = now; } break; case ButtonState::Debouncing: // Do nothing while debouncing break; } } bool shouldTrigger() { auto now = std::chrono::steady\\_clock::now(); if (state == ButtonState::Debouncing \u0026amp;\u0026amp; now - last\\_change\\_time \u0026gt; debounce\\_duration) { state = ButtonState::Idle; return true; } return false; } }; int main() { Button button(std::chrono::milliseconds(500)); // 设置防抖时间为500ms // 模拟按钮按下事件 for (int i = 0; i \u0026lt; 10; ++i) { std::this\\_thread::sleep\\_for(std::chrono::milliseconds(200)); // 模拟200ms内可能的多次按下 button.press(); if (button.shouldTrigger()) { std::cout \u0026lt;\u0026lt; \u0026#34;Button pressed!\u0026#34; \u0026lt;\u0026lt; std::endl; // 在这里可以执行按钮触发后的逻辑 } } return 0; } ","date":"2025-02-12T00:00:00Z","permalink":"/p/145601612/","title":"消抖算法防止多次触发"},{"content":"一、前言 服务器厂商：华为云；\nLinux版本 ： CentOS 8.2 64bit ；\nSVN版本 ：1.10.2；\n闲谈：搭建的过程，主要是对端口的开发和配置文件的处理修改。看了很多篇文章，有头无尾，到后面就推不下去，连续的失败使我痛苦不已，基本流程如下图所示。\n二、安装svnserve 1、查看svn版本 “rpm -qa subversion” 命令用于在 Linux 系统中查询已安装的 subversion 。\nrpm -qa subversion 如果你安装了subversion，会显示如下信息。\n2、卸载旧版本 “yum -y remove subversion” 命令卸载在 Linux 系统中已安装的 subversion 。\nyum -y remove subversion 显示“Complete”，卸载已成功；\n3、 下载安装 显示“Complete”，安装成功；\nyum -y install subversion 三、创建版本库目录 版本库目录根据你的需要，创建一个文件夹进行管理你的SVN库。这个目录位置是可以自定义的，如下图所示，是我在“/var/”路径下创建svn文件夹的过程。\n四、创建svn版本库 在版本库目录可能存在多个版本库，现在我们创建一个版本库“Note”。\n\\# svnadmin create \u0026lt;版本库名称\u0026gt; svnadmin create Note 如下图所示，创建完成后，“cd /路径”进入到我们的svn版本库位置，“ls”查看版本库。（这个位置实在版本库路径下的，下图仅作为本章节效果演示）。\n五、配置文件修改 在“conf”路径下，有三个文件需要配置修改；通过服务器远程访问、宝塔、WinSCR访问文件进行修改，通过vim指令进行配置修改；\nconf：是这个仓库配置文件（仓库用户访问账户，权限） ； format：是一个文本文件，里边只放了一个整数，表示当前文件库配置的版本号； hooks：放置hook脚步文件的目录； locks：用来放置subversion的db锁文件和db_logs锁文件的目录，用来追踪存取文件库的客户端。 1、 authz 在“conf”路径下，打开\u0026quot;authz\u0026quot;文件；\nvim打开文件后，按一下”i“，开始对文件修改，可以设置组等操作，如图所示，对用户”admin“和”note“赋予读写权限，其他为空；\nvim修改完成后，摁一下”Esc“键，输入”：wq“保存退出。\n2、 passwd 在“conf”路径下，打开\u0026quot;passwd\u0026quot;文件；对用户进行密码设置；\n#例如”admin = admin123“ #注意事项一个用户对应一个密码，在”=“左右各一个空格； 3、 svnserve.conf 在“conf”路径下，打开\u0026quot;svnserve.conf\u0026quot;文件；\nanon-access 控制非鉴权用户访问版本库的权限。 取值范围为\u0026#34;write\u0026#34;、\u0026#34;read\u0026#34;和\u0026#34;none\u0026#34;。即\u0026#34;write\u0026#34;为可读可写，\u0026#34;read\u0026#34;为只读，\u0026#34;none\u0026#34;表示无访问权限。缺省值：read auth-access 控制鉴权用户访问版本库的权限。 取值范围为\u0026#34;write\u0026#34;、\u0026#34;read\u0026#34;和\u0026#34;none\u0026#34;。即\u0026#34;write\u0026#34;为可读可写，\u0026#34;read\u0026#34;为只读，\u0026#34;none\u0026#34;表示无访问权限。缺省值：write password-db 指定用户名口令文件名。 除非指定绝对路径，否则文件位置为相对conf目录的相对路径。缺省值：passwd authz-db 指定权限配置文件名，通过该文件可以实现以路径为基础的访问控制。 除非指定绝对路径，否则文件位置为相对conf目录的相对路径。缺省值：authz realm 指定版本库的认证域，即在登录时提示的认证域名称。若两个版本库的认证域相同，建议使用相同的用户名口令数据文件。 缺省值：一个UUID(Universal Unique IDentifier，全局唯一标示)。 这个文件的配置的主要问题在：\n（1）#authz-db = authz，按照教程来说，它应该是放开的，但在放开之后就会存在检出失败的问题。在这里我是给注掉了。\n（2）“realm = /svn”改为了版本库目录路径，就是你上文创建的那个文件夹所在路径。这个也可不用修改。\n（3）为了安全考虑，”anon-access = none“，只有用户方可访问。\nPS:这个文件配置无误的话，我们就已经成功了70%。\n六、防火墙配置 subversion 的默认端口为3690，可在服务器进行配置，或者使用命令进行端口开放。\n1、关闭防火墙 service iptables stop 2、开启3690端口 /sbin/iptables -A INPUT -p tcp --dport 3690 -j ACCEPT 验证\n/sbin/iptables -L -n -v 保存\nservice iptables save 七、重启svn服务器 svnserve -d -r /版本库目录地址 查看3690是否启动。\nnetstat -apn | grep 3690 八、版本库检出 在linux服务器输入命令测试：\nsvn co svn://ip地址:3690/xxxx 八、结语 我们详细探讨了在 Linux 系统上安装和配置 Subversion（SVN）的过程。从基础的安装命令到仓库的创建，再到 防火墙 的配置，我们希望这些步骤能够帮助你顺利搭建自己的版本控制系统。SVN 是一个强大的工具，不仅能帮助开发者管理代码版本，还能促进团队协作和项目管理。\n如果你在安装或使用过程中遇到问题，欢迎共同探讨，本文中的不当之处，也欢迎指正。\n附录 如果你的svn检出失败，很有可能由以下原因引起的：\n1、防火墙端口、宝塔端口未开启；\n2、建议使用配置无误的conf文件进行比对，是否conf配置导致检出失败。\n","date":"2024-10-17T00:00:00Z","permalink":"/p/142995062/","title":"[软件部署] Linux部署SVN"},{"content":"1、定义 有限状态机简写为FSM（Finite State Machine），主要分为2大类：\n1、若输出只和状态有关而与输入无关，则称为Moore状态机\n2、输出不仅和状态有关而且和输入有关系，则称为Mealy状态机\n2、 要素 1、现态：是指当前所处的状态。\n2、条件：又称为“事件”，当一个条件被满足，将会触发一个动作，或者执行一次状态的迁移。\n3、动作：条件满足后执行的动作。动作执行完毕后，可以迁移到新的状态，也可以仍旧保持原状态。动作不是必需的，当条件满足后，也可以不执行任何动作，直接迁移到新状态。\n4、次态：条件满足后要迁往的新状态。“次态”是相对于“现态”而言的，“次态”一旦被激活，就转变成新的“现态”了。\n3、 样例 以《王者荣耀》孙悟空1技能为例：\n使用一技能后，孙悟空可以在1秒提升40%移速，在0.2秒内获得护身咒，护身咒可以抵挡一次敌方技能，抵挡成功可以获得短暂无敌和持续4秒的护盾。\n现态 条件 动作 次态 护生法咒（禁用） 技能点\u0026gt;0 升级护生法咒 护生法咒（可点击） 护生法咒（可点击） 点击护生法咒 （触发0.2秒无敌效果）无动作 护生法咒（CD中） 护生法咒（CD中） 12秒等待 （CD状态，无法点击）无动作 护生法咒（可点击） 图3-1示例图\n4、代码及不足之处 mainwindow.h\n#ifndef MAINWINDOW\\_H #define MAINWINDOW\\_H #include QT\\_BEGIN\\_NAMESPACE namespace Ui { class MainWindow; } QT\\_END\\_NAMESPACE enum state { FORBIDDEN = 0, //禁用状态 CLICKABLE= 1, //可点击 WAITING = 2 //等待中 }; class MainWindow : public QMainWindow { Q\\_OBJECT public: MainWindow(QWidget \\*parent = nullptr); ~MainWindow(); void init(); private slots: void on\\_spinBox\\_valueChanged(int arg1); void on\\_btn1\\_clicked(); private: Ui::MainWindow \\*ui; state btn\\_state = FORBIDDEN; }; #endif // MAINWINDOW\\_H mainwindow.cpp\n#include \u0026#34;mainwindow.h\u0026#34; #include \u0026#34;ui\\_mainwindow.h\u0026#34; #include MainWindow::MainWindow(QWidget \\*parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui-\u0026gt;setupUi(this); init(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::init() { //设置范围 ui-\u0026gt;spinBox-\u0026gt;setRange(0,15); //设置步长 ui-\u0026gt;spinBox-\u0026gt;setSingleStep(1); //设置初始值 ui-\u0026gt;spinBox-\u0026gt;setValue(0); //初始禁用技能 ui-\u0026gt;btn1-\u0026gt;setEnabled(false); } void MainWindow::on\\_spinBox\\_valueChanged(int arg1) { //已升级，技能可使用 if(ui-\u0026gt;spinBox-\u0026gt;value() \u0026gt; 0) { ui-\u0026gt;btn1-\u0026gt;setEnabled(true); btn\\_state = CLICKABLE; } //未升级，技能保持禁用状态 if(ui-\u0026gt;spinBox-\u0026gt;value() == 0) { ui-\u0026gt;btn1-\u0026gt;setEnabled(false); btn\\_state = FORBIDDEN; } } void MainWindow::on\\_btn1\\_clicked() { if(btn\\_state == CLICKABLE) { btn\\_state = WAITING; ui-\u0026gt;label-\u0026gt;setText(\u0026#34;0.2s无敌，护生法咒进入CD\u0026#34;); QEventLoop eventloop1; QTimer::singleShot(200, \u0026amp;eventloop1, SLOT(quit())); eventloop1.exec(); ui-\u0026gt;btn1-\u0026gt;setEnabled(false); btn\\_state = CLICKABLE; //进入cd，等待x（5）秒 ui-\u0026gt;label-\u0026gt;setText(\u0026#34;CD12s，请等待......\u0026#34;); QEventLoop eventloop; QTimer::singleShot(5000, \u0026amp;eventloop, SLOT(quit())); eventloop.exec(); ui-\u0026gt;label-\u0026gt;clear(); if(ui-\u0026gt;spinBox-\u0026gt;value() \u0026gt; 0) { ui-\u0026gt;btn1-\u0026gt;setEnabled(true); } } } 相关控件，如图4-1所示：\n图4-1 ui控件\n示例不足之处：\n1、样例更多的是在“可点击”与“CD中”，进行切换，没有很好的体现出FSM的相关特点。\n2、技能状态CD，仿真度不够。\n3、理想的情景是，透过状态来判断，且相关状态与ui显示进行绑定。\n","date":"2023-08-05T00:00:00Z","permalink":"/p/129804790/","title":"【FSM 】有效状态机~以王者荣耀吉吉国王1技能为模板的小示例"},{"content":"一、软件测试的目的 1、测试为了发现程序中的错误而执行程序的过程。\n2、好的测试方案是极可能发现迄今为止尚未发现的错误的测试方案。\n3、成功的测试是发现了至今为止尚未发现的错误的测试。\n二、测试方法 如果已经知道了产品应该具有的功能，可以通过测试来检验是否每个功能都能正常使用；\n如果知道了产品的内部工作流程，可以通过测试来检验产品内部动作是否按照规格说明书的规则来进行测试。\n1、 黑盒测试 黑盒测试（Black-Box Testing）是一种软件测试方法，它不依赖于代码的实现细节，而是按照软件标准和用户需求来测试软件的正确性和完整性。在黑盒测试中，测试人员只关注于输入和输出，以及软件在不同情况下的响应。\nps：第一次听到黑盒测试，一下子脑海中就出现了一个黑色的盒子，跟“黑匣子”有异曲同工之处。\n常用的黑盒测试方法如下：\n方法名称 说明 决策表测试 以表形式捕获各种输入组合及其各自的系统行为。它适用于在两个和两个以上输入之间具有逻辑关系的函数。 边界值测试 边界值是包含变量上限和下限的边界值。它在输入边界值时测试软件是否产生正确的输出。 状态转换测试 状态转换技术用于在向同一功能提供不同的输入值时捕获软件应用程序的行为。它适用于那些提供访问应用程序的特定尝试次数的应用程序类型。 成对测试 成对测试技术用于测试所有可能的离散值组合。这种组合方法用于测试使用复选框输入，单选按钮输入，列表框，文本框等的应用程序。 因果测试 因果厕所强调了给定结果与影响结果的所有因素之间的关系。它基于一系列要求。 用例测试 根据系统的使用情况从系统的开头到结尾识别测试用例。通过使用这种技术，测试团队创建了一个测试场景，可以从头到尾根据每个功能的功能运行整个软件。 等价类划分测试 其输入数据被划分为有效值和无效值的分区，并且所有分区必须表现出相同的行为。 2、 白盒测试 白盒测试，也称为玻璃盒测试，结构测试，透明盒测试，开箱测试和透明盒测试。它测试软件的内部编码和基础设施，重点是根据预期和期望的输出检查预定义的输入。它基于应用程序的内部工作方式，并围绕内部结构测试。在这种类型的测试中，编程测试用例需要编程技巧。白盒测试的主要目标是通过软件关注输入和输出流，并加强软件的安全性。\n常用的白盒测试方法如下：\n方法名称 说明 数据流测试 数据流测试是一组测试策略，用于检查程序的控制流程，以便根据事件的顺序探索变量的顺序。 控制流程测试 控制流测试通过控制结构确定语句或程序指令的执行顺序。程序的控制结构用于开发程序的测试用例。在该技术中，测试者选择大程序的特定部分来设置测试路径。测试用例由程序的控制图表示。 分支覆盖测试 分支覆盖技术用于覆盖控制流图的所有分支。它至少涵盖决策点的每个条件的所有可能结果。 语句覆盖测试 语句覆盖技术用于设计白盒测试用例。该技术涉及至少执行一次源代码的所有语句。它用于计算源代码中执行语句的总数，在源代码中存在的总语句中。 结束语：通过整理记录，奇怪的知识又增加了，还又一种灰盒测试，感兴趣的话可以去了解一下。非专业测试人员，但喜欢学习了解各种知识，有不当之处，还请斧正。\n","date":"2023-07-30T00:00:00Z","permalink":"/p/132001991/","title":"【软件测试】黑盒/白盒测试"},{"content":"前言：随着对程序开发的深入了解，越觉得对底层的了解及语言基础的重要性。大道至简，回过头重新学习一次c++,是另外一种风景。如有不到之处，欢迎斧正。\n一、开发的5个阶段 程序开发通常需要经过5个阶段。分别是编辑、预处理、编译、链接、运行与调试。\n如下，是相关书籍中对开发过程的介绍：\n二、编辑阶段 编辑阶段也就是我们常说的开发阶段，编辑相关源代码，实现我们的相关功能需求。\n三、预处理阶段 在编译器开始编译之前，预处理器会自动执行源程序中的预处理指令。这些预处理语句是规定在编译之前执行的语句，其处理包括将其他源程序文件包括到要编译的文件中及各种文字替换等。\n如下是部分预处理指令：\n#define 定义一个预处理宏 #undef 取消宏的定义 #if 编译预处理中的条件命令, 相当于C语法中的if语句 #ifdef 判断某个宏是否被定义, 若已定义, 执行随后的语句 #ifndef 与#ifdef相反, 判断某个宏是否未被定义 #elif 若#if, #ifdef, #ifndef或前面的#elif条件不满足, 则执行#elif之后的语句, 相当于C语法中的else-if #else 与#if, #ifdef, #ifndef对应, 若这些条件不满足, 则执行#else之后的语句, 相当于C语法中的else #endif #if, #ifdef, #ifndef这些条件命令的结束标志. defined 与#if, #elif配合使用, 判断某个宏是否被定义 #include 在这里插入代码片包含文件命令 #line 标志该语句所在的行号 #pragma 说明编译器信息 #warning 显示编译警告信息 #error 显示编译错误信息 四、编译阶段 我们在更改代码后，经常说的一句话，“先编译，后运行”。\n编译器负责将源代码转化为机器语言代码（目标代码）。编译过程分为词法分析、语法分析、代码生成3个步骤。\n1、词法分析 分析源代码语句，从语句中识别出有意义的单词（词法记号），常见的有标识符、运算符、分隔符、关键字、各种文字等等。检查到错误，会将错误信息显示给用户。\n2、语法分析 语法分析根据高级语言规则来识别程序中的逻辑结构，例如各种表达式、控制结构等。语法分析检查程序是否正确使用了语言的结构，检查相关错误并反馈给用户。\n2、代码生成 代码生成将词法分析、语法分析过程的结果生成目标程序，目标程序可以是机器指令代码，也可用汇编语言或其他中间语言表示。目标文件的扩展名为.obj。\n四、链接阶段 因为在c++程序通常包含了对其他模块定义的函数和数据的引用，如标准库、自定义库或模块。\n所以当编译器提示你链接错误的时候，可以先排查一下相关模块的引用是否正确。\n五、运行与调试阶段 首先得保证程序的有效运行，然后进行调试，看所得到的数据是否是我们所需要的。\n一个好的程序员，不但需要优秀的编码能力，debug能力也必不可少。如果能快速找到问题，会大大减少我们的开发周期。常用的调试方法如：断点调试、通过打印日志进行调试。在合适的时候使用合适的方法，会有意想不到的效果。\n","date":"2023-07-24T00:00:00Z","permalink":"/p/131904964/","title":"【C/C++】程序开发过程简介"},{"content":"#include #include #include #include int main() { HANDLE hOutput = GetStdHandle(STD\\_OUTPUT\\_HANDLE); int t = 1; while (t++) { COORD huoquan; COORD xiangLing = { 40,15 }; int R = 13; huoquan.X = xiangLing.X + 2 \\* R \\* cos(t\\*0.2); huoquan.Y = xiangLing.Y + R \\* sin(t \\* 0.2); system(\u0026#34;cls\u0026#34;); SetConsoleCursorPosition(hOutput, xiangLing); printf(\u0026#34;香菱\u0026#34;); SetConsoleCursorPosition(hOutput, huoquan); printf(\u0026#34;火圈\u0026#34;); CONSOLE\\_CURSOR\\_INFO curInfo = { 1,FALSE }; SetConsoleCursorInfo(hOutput, \u0026amp;curInfo); Sleep(200); } } 标签\n#c++ #开发语言\n","date":"2023-03-27T00:00:00Z","permalink":"/p/129806292/","title":"[原神香菱火圈]"},{"content":"rand函数 \u0026lt;stdlib.h\u0026gt;库函数 int rand(void) 返回一个范围在 0 到 RAND_MAX 之间的伪随机数。\nRAND_MAX 是一个常量，它的默认值在不同的实现中会有所不同，但是值至少是 32767。\n//rand（）%100可以求出0-99的随机数 rand（）%100+1 //就是0-100的随机数了 随机数种子 我们通过srand()函数来进行播种，根据当前时间生成随机数，保证生成数字的随机性.\nvoid srand(unsigned int seed); //我们通过当前时间，进行播种，生成的\u0026#34;种子\u0026#34;也就是随机的 //头文件中的time()函数可以得当当前的时间 srand（（unsigned）time（NULL））； 时间戳 时间戳是指格林威治时间自1970年1月1日（00:00:00 GMT）至当前时间的总秒数。\n生成随机数 生成三个随机数，进行一个测试\n​ #include #include #include int main() { int a; srand((unsigned)time(NULL)); a = rand() % 100 + 1; printf(\u0026#34;%d\\\\n\u0026#34;, a); a = rand() % 10 + 1; printf(\u0026#34;%d\\\\n\u0026#34;, a); a = rand() % 100 + 1; printf(\u0026#34;%d\\\\n\u0026#34;, a); return 0; } ​ ","date":"2022-12-04T00:00:00Z","permalink":"/p/127072764/","title":"【c语言】生成随机数"},{"content":"‘0’,‘\\0’,\u0026ldquo;0\u0026quot;的区别 1.字符’0’，是ASCII表的第一个，内存中的存放地址为00000000\n2.转义字符（Escape character），所有的ASCII码都可以用“\\”加数字（一般是8进制数字）来表示。而C中定义了一些字母前加\u0026quot;\u0026ldquo;来表示常见的那些不能显示的ASCII字符，如\\0,\\t,\\n等，就称为转义字符，因为后面的字符，都不是它本来的ASCII字符意思了。在C语言字符串中，’\\0‘是作为字符串结束的标志.\n转义字符*‘\\0’*，所代表的含义就是一个空字符。\n3.键盘上的“0”，也是十进制“0”，ASCII值是48，内存中的存放地址是00110000。\n【c语言】输出对应字符的ASCII值 中有ASCII表，可以看一下\n总结 使用字符进行加减计算的时候，可以借助0 ~ 9的ASCII值和十进制的0 ~ 9 进行转换计算。\n当需要减去’0‘的时候，要知道减去的是它的ASCII值，使用结束之后一定要转化为所需的数据类型。\n个人浅见，如有不对，请指正\n","date":"2022-10-20T00:00:00Z","permalink":"/p/127427573/","title":"【c语言】 ‘0‘,‘\\0‘,“0“的区别"},{"content":"如下，这是c语言中的格式输出，我们列举了一部分，输入字符我们使用%c，而打印出对应的ASCII值.\n1.%c 字符型格式符，作用是读入一个字符。\n2.%d 表示输出十进制有符号的整数。\n3.%u 十进制无符号整数。\n4.%f 表示输出浮点数。\n5.%s表示输出 字符串。\n6.%c表示输出单个字符。\n7.%p表示输出指针的值。\n8.%e表示输出指数形式的浮点数。\n9.%0x 表示输出无符号以十六进制表示的整数。 10.%0 表示输出无符号以八进制表示的整数。\n如果感觉输出不够明了，可以输入字符后，加这么一行代码。\n一般，我们还是希望把常用的ASCII值给记住，例如：a-97;A-65;0-48;\u0026lsquo;空格\u0026rsquo;-32。\n","date":"2022-08-23T00:00:00Z","permalink":"/p/126481115/","title":"【c语言】输出对应字符的ASCII值"}]