<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>FRiver</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://gmaxh.site/</id>
  <link href="https://gmaxh.site/" rel="alternate"/>
  <link href="https://gmaxh.site/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, FRiver</rights>
  <subtitle>想把我唱给你听,趁现在年少如花.</subtitle>
  <title>雨停之后</title>
  <updated>2026-06-21T11:43:30.049Z</updated>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="基础学习" scheme="https://gmaxh.site/categories/%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0/"/>
    <category term="基础学习" scheme="https://gmaxh.site/tags/%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0/"/>
    <content>
      <![CDATA[<h2 id="学习动机"><a href="#学习动机" class="headerlink" title="学习动机"></a>学习动机</h2><p>MySql其实刚入学的时候就有耳闻，以及其他知名的数据库软件，但由于博主非常不爱学习，而且脑子不好，所以没到关键的契机，就一直没学。考虑到暑假要参与暑期实践活动，避免被踢出小组，我只能多赶赶进度了。</p><h2 id="概述——关系型数据库"><a href="#概述——关系型数据库" class="headerlink" title="概述——关系型数据库"></a>概述——关系型数据库</h2><p>一个程序内部，从启动到结束，甚至在运行之外，一切都离不开数据，而数据的整合犹为关键。数据库就起到了整理数据，优化查询等功能，方便程序员管理数据。  </p><p>而数据库本身也分为很多种，关系型数据库，非关系型数据库，而MySql数据库本身并非数据库本身，而是一个数据库管理软件，他负责接受用户的SQL指令，来操作数据库。</p><p>而要操作和查询数据库，就要用到一个特殊的语言，SQL，它是关系型数据库的统一标准，也就是将来更换了使用数据库的软件，从MySql变成了Oracle，依然能打。</p><p>具体的查询流程是这样的：用户通过SQL语言，对数据库管理软件——MySql进行操作，MySql(DBMS)内部通过来管理多个数据库，而多个数据库又通过多个表来管理数据，这样用户查询某个数据，就要通过MySql(DBMS)，去管理某个数据库下的某个表的数据。</p><p>数据库中的表，同样也并非独立，它们之间可以相互关联，依赖，从而构建起一个更加复杂精细的大的数据库。</p><h2 id="未完…"><a href="#未完…" class="headerlink" title="未完…"></a>未完…</h2>]]>
    </content>
    <id>https://gmaxh.site/2026/06/17/%E5%B0%9D%E8%AF%95%E5%BF%AB%E9%80%9F%E5%AD%A6%E4%B9%A0%E4%B8%80%E4%B8%8BMySql/</id>
    <link href="https://gmaxh.site/2026/06/17/%E5%B0%9D%E8%AF%95%E5%BF%AB%E9%80%9F%E5%AD%A6%E4%B9%A0%E4%B8%80%E4%B8%8BMySql/"/>
    <published>2026-06-17T19:56:58.000Z</published>
    <summary>
      <![CDATA[<h2 id="学习动机"><a href="#学习动机" class="headerlink" title="学习动机"></a>学习动机</h2><p>MySql其实刚入学的时候就有耳闻，以及其他知名的数据库软件，但由于博主非常不爱学习，而且脑子不好，所以没到关键的契机，就一]]>
    </summary>
    <title>尝试快速学习一下MySql</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="基础学习" scheme="https://gmaxh.site/categories/%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0/"/>
    <category term="基础学习" scheme="https://gmaxh.site/tags/%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0/"/>
    <content>
      <![CDATA[<h2 id="认识http协议之前"><a href="#认识http协议之前" class="headerlink" title="认识http协议之前"></a>认识http协议之前</h2><p>最近在小组内，刚刚写完了ftp服务器，作为同等层级的http协议，仍然值得在大一大基础的时候好好学习。而最近在逛b站的时候，意外觉得黑马程序员的视频<a href="https://www.bilibili.com/video/BV1sHU9BmEne?spm_id_from=333.788.videopod.episodes&vd_source=bfdbc24038191b349c91940b41c52430&p=94">黑马程序员Python+AI零基础入门到大神全套视频课程，覆盖Python核心语法、AI应用、数据分析及Web应用等python实战项目开发全流程</a>介绍到了http协议，不仅有助于我学习协议本身，复习之前网络相关的基础知识，也可以学习巩固一些关于ai相关的内容，何乐不为？直接开干!</p><h2 id="网络基础知识"><a href="#网络基础知识" class="headerlink" title="网络基础知识"></a>网络基础知识</h2><p>下面是一些关于网络基础的介绍，用作巩固和复习。</p><ul><li>ip: 是互联网上识别每个设备的唯一标识。目前分为ipv4和ipv6两种，他们分别是32位和128位的二进制来表示的。</li></ul><p>比如<code>192.168.0.158</code>(我随便打的),一共分为四个部分，每个部分都有8位的二进制来表示十进制。最终共同成为ip地址。  </p><p>特殊的ip地址：<code>127.0.0.1</code>，叫做本地ip地址，也称为回环地址，用来描述本机。</p><ul><li><p>端口：对于每个设备上运行的不同程序，可以使用端口来区分。比如我要给某个ip地址的服务器的某个应用程序发去请求，就要有对应的端口来描述，我要请求哪个应用程序。在http中，默认的端口是80，https是443。</p></li><li><p>网络的连接：我们每个人不同的设备，想要互相沟通起来，首先要保证物理世界的连接完整。</p></li></ul><p>交换机：是用来沟通不同机器的关键设备。比如某个设备请求某个ip地址的连接，就会通过交换机来转发。  </p><p>但现在就会有一个关键问题，虽然ip地址读起来还比较朗朗上口，但我们依然很难记住某个ip地址，比如你能记住<code>www.baidu.com</code>的ip吗？它是<code>110.242.69.21</code>。因此就会出现域名。</p><ul><li>域名和DNS解析服务器：域名本质就是一个字符串，以更为人性化，描述了当前的ip地址。但这时，我们不用ip地址来发送请求，而是使用域名的话，就必须要经过DNS解析。也就是，主机先通过DNS解析服务器，获取到对应的ip地址，之后发送给主机，主机拿到ip地址，再进行与对应设备的连接。</li></ul><h2 id="网络模型"><a href="#网络模型" class="headerlink" title="网络模型"></a>网络模型</h2><p>介绍完了基本的一些网络知识，下面将开始进入http的逐步介绍。</p><ul><li><p>OSI七层模型：这是国际上用来统一网络内通信的统一国际标准，即在网络的通信中，分有7层，应用层，表示层，会话层，传输层，网络层，数据链路层，物理层。</p></li><li><p>TCP&#x2F;IP模型：共分为4层，应用层，传输层，网络层，网络接口层。其中http协议，ftp协议，都是应用层。传输层即TCP,UDP协议。网络层有ip协议。不同层级都对上层实行了封装，只提供接口，向下兼容。为开发者提供了更有体系化的架构。</p></li></ul><h2 id="HTTP协议"><a href="#HTTP协议" class="headerlink" title="HTTP协议"></a>HTTP协议</h2><p>http协议，即超文本传输协议。具有以下特点：  </p><ol><li>基于文本传输：规定了请求行，请求头，请求体。</li><li>一次请求，一次响应：只能由客户端向服务端发起请求。</li><li>无状态：服务端不会对客户端的请求记录状态。每次的请求-响应是独立的。</li></ol><h2 id="请求数据格式"><a href="#请求数据格式" class="headerlink" title="请求数据格式"></a>请求数据格式</h2><p>当客户端对某个地址发起请求的时候，在请求数据内就写好了自己的数据格式。分为请求行，请求头，请求体三类。</p><ol><li>请求行：规定了请求方法，目标路径等信息。请求方法共有两种,GET和POST，它们之间的区别是，GET没有请求体，需要写入一定大小的参数。比如<code>https://www.bilibili.com/video/BV1sHU9BmEne?spm_id_from=333.788.videopod.episodes&amp;vd_source=bfdbc24038191b349c91940b41c52430&amp;p=94</code>中，<code>?</code>后面的内容，按照<code>&amp;</code>的方式分割，规定好了参数内容。而POST可以有自己的请求体，不限制大小。</li><li>请求头：请求头是用来具体描述请求信息的，包括客户端的OS，支持的格式等等信息。格式为<code>key : value</code>。</li><li>请求体：即参数信息。</li></ol><p>如果你使用的是chrome浏览器，你现在就可以打开F12，找到network，然后找到第一个请求，便可以自行查看。</p><h2 id="响应数据格式"><a href="#响应数据格式" class="headerlink" title="响应数据格式"></a>响应数据格式</h2><p>服务端一旦受到了客户端的请求，就必然要响应内容，发回给客户端。数据格式同样分为三种，响应行，响应头，响应体。</p><ol><li>响应行：规定了协议和状态码。状态码最常见的有这些，200，表示客户端请求成功，400，表示客户端的参数错误，404，表示请求的资源不存在(最常见的状态码)，以及500，表示服务器发生了不可估计的错误。</li><li>响应头：同样是<code>key : value</code>格式，明确了服务器的信息，日期等等。</li><li>响应体：服务端发回给客户端的数据。</li></ol><h2 id="小总结"><a href="#小总结" class="headerlink" title="小总结"></a>小总结</h2><p>从网络的基本知识，ip，端口，交换机，到TCP&#x2F;IP模型，http协议，可见计算机网络在自底向上封装的隔离性和完整性，也就是上层协议可以专注协议本身。详细剖析了http协议的具体内容，也算是补上了当初http协议没学好的遗憾，接下来的一步步，需要慢慢走下去。</p>]]>
    </content>
    <id>https://gmaxh.site/2026/06/15/%E8%B5%B0%E8%BF%9Bhttp%E5%8D%8F%E8%AE%AE/</id>
    <link href="https://gmaxh.site/2026/06/15/%E8%B5%B0%E8%BF%9Bhttp%E5%8D%8F%E8%AE%AE/"/>
    <published>2026-06-15T18:06:02.000Z</published>
    <summary>
      <![CDATA[<h2 id="认识http协议之前"><a href="#认识http协议之前" class="headerlink" title="认识http协议之前"></a>认识http协议之前</h2><p>最近在小组内，刚刚写完了ftp服务器，作为同等层级的http协议，仍然值得在]]>
    </summary>
    <title>走进http协议</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="AI" scheme="https://gmaxh.site/categories/AI/"/>
    <category term="AI" scheme="https://gmaxh.site/tags/AI/"/>
    <content>
      <![CDATA[<h2 id="当前的claude-code我高攀不起"><a href="#当前的claude-code我高攀不起" class="headerlink" title="当前的claude code我高攀不起"></a>当前的claude code我高攀不起</h2><p>起初的原因是因为，claude code实属是当下agent的顶流，我也没有理由不跟波风。但由于地域原因，claude无法在国内注册。未果。</p><h2 id="cc-switch来了"><a href="#cc-switch来了" class="headerlink" title="cc switch来了"></a>cc switch来了</h2><p>其实已开始，我也并不知道这个软件，这多亏了我在我们专业2班的兄弟了。一经介绍之后，我今晚抽出来时间操作了一番。发现还是可以使用claude code的。其原理大致可以解释为，claude code只能匹配自己的Anthropic协议，但其他api有各自的格式协议，故使用了cc switch来作为中转站，进行代理和协议的转换。</p><h2 id="磨拳擦掌开始使用claude-code"><a href="#磨拳擦掌开始使用claude-code" class="headerlink" title="磨拳擦掌开始使用claude code"></a>磨拳擦掌开始使用claude code</h2><p>我本身也并不喜欢挨着视频一分不差的看完，但经过基本的了解之后，发现claude code支持多模式切换使用，自动模式，计划模式，确认模式。  </p><ol><li>确认模式:agent提出的每个操作请求都要经过人工审核。主打稳妥。</li><li>计划模式:进入规划模式，用户可以提出各类问题，来规划项目方案，或者自己的想法，claude code会智能地引导你一步步完善你的计划。节省token，计划更有体系。</li><li>自动模式:agent自动执行操作请求，不经过人工审核。效率快但有风险。</li></ol><p>了解了三种模式，我们便可以提出一次想法了。</p><h2 id="First-try—优化博客"><a href="#First-try—优化博客" class="headerlink" title="First try—优化博客"></a>First try—优化博客</h2><p>优化博客主要分为两个方面，代码结构和具体页面修饰。</p><p>我首先提出了一个总体的要求，之后他自动帮我把我的话整理之后，进行二次处理。  </p><p><code>用户 FRiver 拥有一个基于 Hexo + Stellar 主题的个人博客（雨停之后），托管于 Vercel，仓库位于 GitHub。本次 session 的核心任务是：审查博客代码结构、执行全面优化、并打通未来的自动化部署流程。</code></p><p>之后一直在自动模式下，经过几次无脑确认，就可以完成本次的代码修复，以及具体博客内容的模块调整。帮我提高了工作效率。之后我让他给我了完整的操作内容，附下。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">Claude Code Session 总结：Hexo 博客全栈优化</span><br><span class="line"></span><br><span class="line">任务背景</span><br><span class="line"></span><br><span class="line">用户 FRiver 拥有一个基于 Hexo + Stellar 主题的个人博客（雨停之后），托管于 Vercel，仓库位于 GitHub。本次 session 的核心任务是：审查博客代码结构、执行全面优化、并打通未来的自动化部署流程。</span><br><span class="line"></span><br><span class="line">本次 Session 完成的工作清单</span><br><span class="line"></span><br><span class="line">一、代码结构审查与清理。发现根目录存在 100 多个 Hexo 生成的 HTML/JS/CSS 文件被错误提交到 Git，导致仓库膨胀、结构混乱。通过 git rm --cached 加物理删除，将仓库精简为纯源文件形态（94 files changed, +190 / -45,488 行）。</span><br><span class="line"></span><br><span class="line">二、Git 配置修复。修复 .gitignore 中的拼写错误，添加完整的生成文件忽略规则（node_modules/、public/、db.json、.deploy*/）。删除根目录下的 2025/、2026/、about/、archives/、categories/、css/、js/、tags/ 等所有生成目录。</span><br><span class="line"></span><br><span class="line">三、Vercel 部署配置优化。重写 vercel.json，明确指定 buildCommand 为 npm run build（即 hexo generate）和 outputDirectory 为 public，使 Vercel 能够自动从源码构建并部署。</span><br><span class="line"></span><br><span class="line">四、依赖清理。卸载未使用的 hexo-theme-landscape 主题和 hexo-deployer-git 部署插件（用户已迁移至 Vercel，不再需要 GitHub Pages 部署），删除空的 _config.landscape.yml 和 themes/ 目录，移除 _config.yml 中过时的 deploy 配置块，删除 .deploy_git/ 缓存目录（约 12MB）。</span><br><span class="line"></span><br><span class="line">五、Dependabot 策略优化。将依赖更新频率从「每日 20 个 PR」调整为「每周六 5 个 PR」，减少噪音。</span><br><span class="line"></span><br><span class="line">六、文章元数据补全。为全部 16 篇文章补充 categories 字段（Linux / AI / 生活），修复标签重复问题，将 C++ 标签改为 C/C++（加号在 URL 中会导致标签页无法生成），为唯一无标签文章「慢慢走下去」补充标签。更新 scaffolds/post.md 模板，默认包含 categories 字段。</span><br><span class="line"></span><br><span class="line">七、项目文档。创建 README.md，包含本地开发命令、文章写作示例、Vercel 部署指南和目录结构说明。</span><br><span class="line"></span><br><span class="line">八、推送部署。将所有变更提交并推送至 GitHub，Vercel 将自动触发构建部署。</span><br><span class="line"></span><br><span class="line">模型表现观察（基于 deepseek-v4-pro）</span><br><span class="line"></span><br><span class="line">本次 session 使用的底层模型为 deepseek-v4-pro，通过 Claude Code 的 agent 架构驱动。以下是几个关键观察：</span><br><span class="line"></span><br><span class="line">任务切换效率。本次 session 在「代码审查 → 结构优化 → 配置修复 → 内容编辑 → 文档撰写 → Git 操作」等多个迥异任务之间无缝切换，模型在每种任务模式下均能保持一致的输出质量，未出现上下文丢失或风格偏移。</span><br><span class="line"></span><br><span class="line">Plan Mode 与执行模式的灵活切换。用户在前期要求「先审查再动手」，模型进入 Plan Mode 进行了全面的代码探索；确认问题后退出 Plan Mode，进入高效执行阶段。这种模式切换由 Claude Code 的 harness 层自动管理，对用户透明。</span><br><span class="line"></span><br><span class="line">底层操作能力。模型直接操作了 git 暂存区（git rm --cached）、文件系统（批量删除生成文件）、npm 依赖管理、YAML 配置编辑、批量文本替换（Python 脚本修复 16 个文件的 frontmatter），展现了 Claude Code 作为 CLI 工具的强大底层能力。</span><br><span class="line"></span><br><span class="line">性价比。本次 session 处理了 94 个文件的变更（+190 / -45,488 行），涵盖代码审查、结构重构、配置优化、内容编辑、文档撰写和 Git 操作等多个维度。如果人工完成这些任务，保守估计需要两到三个小时；而通过 Claude Code + deepseek-v4-pro 的组合，在单次对话中一气呵成。</span><br><span class="line"></span><br><span class="line">中文技术内容处理。博客内容为中文技术文章（Linux 系统编程、AI 概念介绍等），模型准确理解了文章主题并为每篇文章分配了合适的分类和标签，包括对 C++ 文件名兼容性问题的识别和修复。</span><br><span class="line"></span><br><span class="line">关键数据</span><br><span class="line"></span><br><span class="line">文件变更：94 files changed。</span><br><span class="line">新增行数：+190 行。</span><br><span class="line">删除行数：-45,488 行（主要是清理的生成文件）。</span><br><span class="line">修改的文章：16 篇（全部补充 categories 与标签修复）。</span><br><span class="line">清理的生成目录：15 个（2025/、2026/、about/、archives/、categories/、css/、favicon/、js/、links/、page/、tags/、themes/、.deploy_git/ 等）。</span><br><span class="line">卸载的冗余包：2 个（hexo-theme-landscape、hexo-deployer-git）。</span><br><span class="line">编辑的配置文件：6 个（.gitignore、vercel.json、_config.yml、dependabot.yml、package.json、scaffolds/post.md）。</span><br><span class="line">新建文件：2 个（README.md 与本次总结文件）。</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="Second-try—实现一个企业级的任务待办软件"><a href="#Second-try—实现一个企业级的任务待办软件" class="headerlink" title="Second try—实现一个企业级的任务待办软件"></a>Second try—实现一个企业级的任务待办软件</h2><p>最初我也没有这样的灵感，其实我也没有使用claude code的经验，多亏了<a href="https://www.bilibili.com/video/BV14rzQB9EJj/?spm_id_from=333.1387.favlist.content.click&vd_source=bfdbc24038191b349c91940b41c52430">Claude Code 从 0 到 1 全攻略：MCP &#x2F; SubAgent &#x2F; Agent Skill &#x2F; Hook &#x2F; 图片 &#x2F; 上下文处理&#x2F; 后台任务</a>这个视频，主播同样是<a href="https://space.bilibili.com/1815948385?spm_id_from=333.788.upinfo.head.click">马克的技术工作坊</a>(他真的很厉害)。在视频开头就带着我们使用claude code来实现一个纯前端HTML的任务待办web，之后主播对项目进行了优化，加入了react + vite + TypeScript的前端框架。我心想，既然都要使用claude code了，为什么不进行一些更好的询问。  </p><p>我启用计划模式，我要做一个前后端分离的项目，让他在现有的框架下多给我一些思路，包括前端的技术，后端的实现等等。通过一系列沟通，我们敲定了计划，React + TypeScript + vite做前端处理，python + REST API做后端处理。中间我们聊了很多，包括可以不可以使用rust作后端，为什么不建议使用c++来写后端，不同的前端技术的优缺点等等。</p><p>之后在自动模式中，一切都交给claude code和deepseek了。  </p><p>最后我让他总结了整体内容，把我们的沟通对话和项目文件都传入到git仓库内，一切行云流水。  </p><p>下面是我们的session内容，附下。  </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br></pre></td><td class="code"><pre><span class="line">Session 开发记录</span><br><span class="line">==================</span><br><span class="line"></span><br><span class="line">日期：2026-06-11</span><br><span class="line">目标：将 C++/Qt 桌面待办应用迁移为现代 Web 全栈应用</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">一、项目背景</span><br><span class="line">============</span><br><span class="line"></span><br><span class="line">原有项目是一个 C++17 + Qt5/Qt6 桌面端待办应用，功能包括：</span><br><span class="line"></span><br><span class="line">  · 任务增删改查、完成状态切换</span><br><span class="line">  · UUID 标识、JSON 文件持久化</span><br><span class="line">  · 系统托盘、无边框窗口、始终置顶</span><br><span class="line"></span><br><span class="line">代码位于 desktop-legacy/（已归档）。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">二、技术选型讨论</span><br><span class="line">================</span><br><span class="line"></span><br><span class="line">2.1 前端框架选择</span><br><span class="line">----------------</span><br><span class="line"></span><br><span class="line">对比了 3 套方案：</span><br><span class="line"></span><br><span class="line">  方案 A（选中）：React 19 + TypeScript + Vite</span><br><span class="line">    优势：生态最大、招聘市场首选、TS 支持最佳</span><br><span class="line">    劣势：学习曲线中等</span><br><span class="line"></span><br><span class="line">  方案 B：Vue 3 + TypeScript + Vite</span><br><span class="line">    优势：上手最简单、中文文档好</span><br><span class="line">    劣势：生态略小于 React</span><br><span class="line"></span><br><span class="line">  方案 C：Next.js（React 全栈）</span><br><span class="line">    优势：开发效率最高、部署简单</span><br><span class="line">    劣势：前后端耦合</span><br><span class="line"></span><br><span class="line">  &gt;&gt;&gt; 决策：选择方案 A — React + TypeScript + Vite</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">2.2 后端方式选择</span><br><span class="line">----------------</span><br><span class="line"></span><br><span class="line">对比了 4 种后端架构：</span><br><span class="line"></span><br><span class="line">  纯前端（localStorage）：最快但无跨设备同步</span><br><span class="line">  REST API（选中）：前后端分离、灵活、可复用</span><br><span class="line">  全栈框架（Next.js）：耦合度高、迁移成本大</span><br><span class="line">  BaaS（Supabase/Firebase）：供应商锁定</span><br><span class="line"></span><br><span class="line">  &gt;&gt;&gt; 决策：选择 REST API 前后端分离架构</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">2.3 后端语言对比</span><br><span class="line">----------------</span><br><span class="line"></span><br><span class="line">  ┌──────────┬───────────────┬───────────────────┬──────────┬──────────┐</span><br><span class="line">  │ 语言     │ 框架          │ 性能（单机 CRUD） │ 开发效率 │ 结论     │</span><br><span class="line">  ├──────────┼───────────────┼───────────────────┼──────────┼──────────┤</span><br><span class="line">  │ Python   │ FastAPI       │   ~5k-15k QPS     │ 最高     │ 选中     │</span><br><span class="line">  │ Node.js  │ Express/Hono  │   ~10k-30k QPS    │ 高       │ 备选     │</span><br><span class="line">  │ Rust     │ Axum/Actix    │   ~200k+ QPS      │ 中       │ 性能最强 │</span><br><span class="line">  │ C++      │ Drogon/Crow   │   ~200k+ QPS      │ 最低     │ 不推荐   │</span><br><span class="line">  └──────────┴───────────────┴───────────────────┴──────────┴──────────┘</span><br><span class="line"></span><br><span class="line">  &gt;&gt;&gt; 决策：Python + FastAPI — 对 todo 应用性能完全够用，开发效率最高，</span><br><span class="line">      自动生成 Swagger 文档。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">2.4 数据库选择</span><br><span class="line">--------------</span><br><span class="line"></span><br><span class="line">  &gt;&gt;&gt; 决策：SQLite — 嵌入式、零配置、单文件、todo 规模完全匹配。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">三、最终技术栈</span><br><span class="line">==============</span><br><span class="line"></span><br><span class="line">  前端        React 19 + TypeScript + Vite</span><br><span class="line">  样式        TailwindCSS v4</span><br><span class="line">  状态管理    Zustand + TanStack Query</span><br><span class="line">  HTTP        Axios</span><br><span class="line">  后端        Python FastAPI</span><br><span class="line">  ORM         SQLModel</span><br><span class="line">  数据库      SQLite</span><br><span class="line">  包管理      npm（前端）+ uv（后端）</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">四、实现过程</span><br><span class="line">============</span><br><span class="line"></span><br><span class="line">Step 1：前端项目初始化</span><br><span class="line">----------------------</span><br><span class="line"></span><br><span class="line">  $ npm create vite@latest frontend -- --template react-ts</span><br><span class="line">  $ npm install @tanstack/react-query axios zustand uuid lucide-react \</span><br><span class="line">      tailwindcss @tailwindcss/vite</span><br><span class="line"></span><br><span class="line">  · 配置 vite.config.ts：TailwindCSS 插件 + /api 代理</span><br><span class="line">  · 配置 index.css：Tailwind v4 入口</span><br><span class="line">  · 创建目录结构：api/、hooks/、store/、components/、types/</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Step 2：后端项目初始化</span><br><span class="line">----------------------</span><br><span class="line"></span><br><span class="line">  $ uv init --name todo-api</span><br><span class="line">  $ uv add fastapi uvicorn sqlmodel</span><br><span class="line"></span><br><span class="line">  · main.py：FastAPI 入口 + CORS 中间件 + lifespan 建表</span><br><span class="line">  · models.py：SQLModel Task 模型</span><br><span class="line">  · database.py：SQLite 引擎</span><br><span class="line">  · schemas.py：Pydantic 请求/响应模型</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Step 3：后端 CRUD API</span><br><span class="line">---------------------</span><br><span class="line"></span><br><span class="line">实现 5 个 REST 端点（routes/tasks.py）：</span><br><span class="line"></span><br><span class="line">  GET    /api/tasks            获取所有任务</span><br><span class="line">  POST   /api/tasks            添加任务</span><br><span class="line">  PATCH  /api/tasks/&#123;id&#125;       更新任务</span><br><span class="line">  DELETE /api/tasks/&#123;id&#125;       删除任务</span><br><span class="line">  DELETE /api/tasks/completed  清除已完成</span><br><span class="line"></span><br><span class="line">【踩坑记录 1】</span><br><span class="line">  问题：使用 engine.begin() 返回 Connection 对象而非 Session，导致 exec()、add()</span><br><span class="line">        等方法报 AttributeError。</span><br><span class="line">  解决：改用 Session(engine)。</span><br><span class="line"></span><br><span class="line">【踩坑记录 2】</span><br><span class="line">  问题：FastAPI 路由匹配顺序 — DELETE /tasks/completed 被 DELETE /tasks/&#123;task_id&#125;</span><br><span class="line">        当作路径参数捕获，返回 404。</span><br><span class="line">  解决：将 /tasks/completed 路由定义在 /tasks/&#123;task_id&#125; 之前。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Step 4：前端 API 层 + Hooks</span><br><span class="line">---------------------------</span><br><span class="line"></span><br><span class="line">  · types/task.ts：Task、TaskCreate、TaskUpdate 接口</span><br><span class="line">  · api/tasks.ts：5 个 axios 请求函数</span><br><span class="line">  · hooks/useTasks.ts：TanStack Query useQuery + 5 个 useMutation</span><br><span class="line">  · store/useAppStore.ts：Zustand 全局错误状态</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Step 5：React 组件</span><br><span class="line">------------------</span><br><span class="line"></span><br><span class="line">按叶子到根的顺序实现：</span><br><span class="line"></span><br><span class="line">  TaskItem -&gt; TaskList -&gt; TaskInput -&gt; StatusBar -&gt; TitleBar -&gt; App</span><br><span class="line"></span><br><span class="line">数据流：TanStack Query 管理服务端状态，变更后 invalidateQueries([&#x27;tasks&#x27;])</span><br><span class="line">自动重新获取。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Step 6：样式打磨</span><br><span class="line">----------------</span><br><span class="line"></span><br><span class="line">  · TailwindCSS 原子化样式</span><br><span class="line">  · 自定义滚动条（暗色模式适配）</span><br><span class="line">  · Checkbox 强调色</span><br><span class="line">  · Hover 状态过渡动画</span><br><span class="line">  · 删除按钮 hover 显示</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Step 7：端到端验证</span><br><span class="line">------------------</span><br><span class="line"></span><br><span class="line">全部 5 个 API 通过 curl 集成测试：</span><br><span class="line"></span><br><span class="line">  POST /api/tasks x3 -&gt; GET -&gt; PATCH toggle -&gt; DELETE completed -&gt; GET 验证</span><br><span class="line"></span><br><span class="line">Vite dev server proxy 验证通过（localhost:5173/api/tasks -&gt; localhost:8000/api/tasks）</span><br><span class="line"></span><br><span class="line">TypeScript 类型检查 + Vite production build 均通过。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">五、项目整理</span><br><span class="line">============</span><br><span class="line"></span><br><span class="line">  · 旧 C++/Qt 代码归档至 desktop-legacy/</span><br><span class="line">  · 项目重命名为 todo_list_for_you</span><br><span class="line">  · 编写 .gitignore、README.md、SESSION.md</span><br><span class="line">  · Git 初始化并提交（49 files, 5801 lines）</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">六、未实现功能（后续计划）</span><br><span class="line">==========================</span><br><span class="line"></span><br><span class="line">  · 拖拽排序（@dnd-kit）</span><br><span class="line">  · PWA 离线支持</span><br><span class="line">  · 手动深色/浅色模式切换</span><br><span class="line">  · 用户认证 &amp; 多用户</span><br><span class="line">  · Docker 一键部署</span><br><span class="line">  · WebSocket 实时同步</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="What’s-more—清理ubuntu不重要文件"><a href="#What’s-more—清理ubuntu不重要文件" class="headerlink" title="What’s more—清理ubuntu不重要文件"></a>What’s more—清理ubuntu不重要文件</h2><p>Linux下一切皆文件，无论从硬盘大小，还是理解Linux底层内容，优化一下文件还是很有必要的。  </p><p>人生苦短，我选择使用claude code。  </p><p>这次我的prompt非常简单:帮我整理一下我Linux系统下的所有文件，并且清理一些不需要文件，在清理的时候我要逐个确认。  </p><p>这里我先开启计划模式，万一claude code能给一些更好的清理方案呢？但claude code使用最直白，最不拐弯抹角地方式告诉我:这个直接操作就可以了，现在可以进入执行模式。<code>:)</code>  </p><p>确认进入自动模式之后，他对每个需要清理的请求都想我提出了询问，并且我也保持确认，之后请求我也让他直接通过就好，不需要再提问。  </p><p>值得说的一点是，claude code真的会分析每个目录，因为他在某个目录下我记得递归搜索的时间很长，长达8分钟。  </p><p>整体的清理还是很多的，从系统缓存，到一些下载内容，更新软件的缓存等等，清理的很干净。</p><p>我同样让他给我了完整的session内容，附下。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br></pre></td><td class="code"><pre><span class="line">Linux 系统文件清理总结</span><br><span class="line"></span><br><span class="line">日期：2026-06-11</span><br><span class="line">操作人：friver（Claude Code 辅助）</span><br><span class="line"></span><br><span class="line">本次操作的目的是整理本机 Linux 系统中的冗余文件，释放根分区磁盘空间。在清理过程中，每一项操作均经过确认，避免了误删重要数据。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">一、清理前的磁盘状况</span><br><span class="line"></span><br><span class="line">清理前，系统根分区 /dev/nvme0n1p5 总容量为 79G，已使用 74G，仅剩 1.1G 可用空间，使用率高达 99%，磁盘空间已经严重不足。home 目录总计占用约 43G，其中缓存类文件占据了相当大的比例，是本次清理的重点对象。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">二、已执行的清理操作</span><br><span class="line"></span><br><span class="line">以下是按照清理优先级逐项执行的内容，共计 8 个步骤，累计释放约 19G 空间。</span><br><span class="line"></span><br><span class="line">第一步：清空回收站（释放约 913M）</span><br><span class="line"></span><br><span class="line">回收站位于 ~/.local/share/Trash/，其中堆积了大量此前删除但未彻底清除的文件。主要内容包括 YOLO 训练用的标注图片文件、一些已过时的 deb 安装包（VS Code、Clash Verge 等）、若干视频文件以及 PDF 文档。这些文件此前已被用户主动放入回收站，直接清空不存在误删风险。</span><br><span class="line"></span><br><span class="line">第二步：清理 pip 下载缓存（释放约 5.6G）</span><br><span class="line"></span><br><span class="line">pip 是 Python 的包管理工具，每次执行 pip install 时下载的包文件会被缓存至 ~/.cache/pip/。清理后不影响任何已安装的 Python 包，若将来需要重新安装，pip 会自动重新下载。</span><br><span class="line"></span><br><span class="line">第三步：清理 VS Code C++ 工具缓存（释放约 6.5G）</span><br><span class="line"></span><br><span class="line">~/.cache/vscode-cpptools/ 是 VS Code 的 C/C++ 扩展在提供 IntelliSense 智能提示时生成的索引缓存。这一项是本次清理中最大的一笔单项缓存，清理后 VS Code 会在下次打开 C++ 项目时自动重建索引。</span><br><span class="line"></span><br><span class="line">第四步：清理浏览器及系统杂项缓存（释放约 950M）</span><br><span class="line"></span><br><span class="line">这一步骤涵盖了多个小型缓存目录，汇总起来体量可观：</span><br><span class="line"></span><br><span class="line">  - ~/.cache/google-chrome/（629M）：Google Chrome 浏览器缓存，包括网页资源、图片等；</span><br><span class="line">  - ~/.cache/thumbnails/（123M）：GNOME 桌面环境的缩略图缓存；</span><br><span class="line">  - ~/.cache/pnpm/（111M）：pnpm 包管理器的下载缓存；</span><br><span class="line">  - ~/.cache/node-gyp/（65M）：Node.js 原生模块编译缓存；</span><br><span class="line">  - ~/.cache/uv/（56M）：uv 包管理器的缓存；</span><br><span class="line">  - ~/.cache/tracker3/（37M）：GNOME 文件索引服务的缓存；</span><br><span class="line">  - ~/.cache/nvidia/（16M）：NVIDIA 驱动相关缓存；</span><br><span class="line">  - 其余更小的缓存包括 typescript、flatpak、mesa_shader、fish、fontconfig、ibus、gstreamer、matplotlib、evolution 等。</span><br><span class="line"></span><br><span class="line">第五步：清理 npm 缓存（释放约 1.1G）</span><br><span class="line"></span><br><span class="line">npm 是 Node.js 的包管理工具，~/.npm/ 中保存了所有曾经下载过的 npm 包的缓存副本。通过执行 npm cache clean --force 清除了这些缓存，不影响已安装在各个项目中的 node_modules。</span><br><span class="line"></span><br><span class="line">第六步：清理 Conda 包缓存（释放约 3.3G）</span><br><span class="line"></span><br><span class="line">Conda 会将所有下载过的包文件保留在 ~/miniconda3/pkgs/ 中，即便是已经安装完毕的包也不会自动删除。执行 conda clean --all --yes 后共清理了 228 个 tarball 包文件、1 个索引缓存和 15 个已解压的包目录。清理不会影响任何已创建的 conda 环境。</span><br><span class="line"></span><br><span class="line">第七步：清理 VS Code 配置目录中的缓存（释放约 810M）</span><br><span class="line"></span><br><span class="line">~/.config/Code/ 是 VS Code 的配置目录，其中混杂着用户配置和缓存数据。本次清理时特别区分了缓存与配置：</span><br><span class="line"></span><br><span class="line">  - 已清理：CachedExtensionVSIXs（618M，扩展安装包缓存）、Cache、CachedData、GPUCache、DawnGraphiteCache、DawnWebGPUCache、logs、CachedProfilesData 等纯缓存目录；</span><br><span class="line">  - 已保留：User/（122M，用户设置和快捷键配置）、WebStorage/（155M，扩展的本地存储数据），这两项目录包含个人配置，不可删除。</span><br><span class="line"></span><br><span class="line">第八步：清理下载目录中的安装包（释放约 1.3G）</span><br><span class="line"></span><br><span class="line">~/下载/ 目录中堆积了多个已完成安装的 deb 安装包和 shell 安装脚本。这些文件仅用于初次安装，安装完成后即无保留价值。被删除的文件清单如下：</span><br><span class="line"></span><br><span class="line">  - Feishu-linux_x64-7.66.10.deb（418M）—— 飞书</span><br><span class="line">  - WeChatLinux_x86_64.deb（203M）—— 微信 Linux 版</span><br><span class="line">  - QQ_3.2.26_260319_amd64_01.deb（166M）—— QQ Linux 版（新版）</span><br><span class="line">  - QQ_3.2.26_260311_amd64_01.deb（166M）—— QQ Linux 版（旧版）</span><br><span class="line">  - UnityHubSetup-amd64.deb（155M）—— Unity Hub</span><br><span class="line">  - google-chrome-stable_current_amd64.deb（125M）—— Google Chrome</span><br><span class="line">  - Miniconda3-py38_22.11.1-1-Linux-x86_64.sh（62M）—— Miniconda 安装脚本</span><br><span class="line">  - CC-Switch-v3.16.2-Linux-x86_64.deb（15M）—— CC-Switch 切换工具</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">三、清理后的磁盘状况</span><br><span class="line"></span><br><span class="line">经过以上 8 个步骤的清理，根分区的磁盘使用情况得到明显改善：已用空间从 74G 降至 55G，可用空间从 1.1G 扩大到 20G，使用率从不堪重负的 99% 降到了较为健康的 74%，累计释放了约 19G 空间。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">四、未处理的可清理项目</span><br><span class="line"></span><br><span class="line">以下目录在本次清理中暂未处理，因为它们属于应用数据或运行环境，需要根据实际使用情况自行判断是否删除：</span><br><span class="line"></span><br><span class="line">  - ~/.config/QQ/（1.6G）：QQ 的缓存和聊天数据，如聊天记录中存在重要信息则不应删除；</span><br><span class="line">  - ~/.config/unityhub/（3.7G）：Unity Hub 的编辑器下载和项目缓存，若已不使用 Unity 开发可以整目录删除，这是剩余项中最大的一笔；</span><br><span class="line">  - ~/.local/share/nvm/（2.0G）：nvm（Node Version Manager）安装的 Node.js 各版本文件，如需继续使用 Node.js 开发请保留；</span><br><span class="line">  - ~/.rustup/（1.5G）：Rust 工具链和组件，若不再使用 Rust 可以卸载删除；</span><br><span class="line">  - ~/qemu-5.1.0/（1.1G）：QEMU 5.1.0 的源代码目录，若已经编译安装完毕且不再需要源码，可以安全删除；</span><br><span class="line">  - ~/gitclone/（1.5G）：多个 Git 仓库，大部分为课程项目的代码，可按需清理已完成或不再需要的仓库；</span><br><span class="line">  - ~/miniconda3/envs/（约 6.4G）：7 个 conda 虚拟环境，其中 yolo 环境独占 5.3G，可按需删除不再使用的环境；</span><br><span class="line">  - ~/.vscode/extensions/（2.0G）：VS Code 安装的扩展，一般不建议手动删除，可通过 VS Code 界面管理；</span><br><span class="line">  - ~/文档/xwechat_files/（421M）：微信客户端接收的文件。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">五、清理经验总结</span><br><span class="line"></span><br><span class="line">通过本次清理，可以总结出以下几类文件的处置原则，供日后参考：</span><br><span class="line"></span><br><span class="line">第一，缓存目录（~/.cache/*、npm cache、conda pkgs 等）是可随时清理的安全项，不会影响任何已安装软件的正常运行，软件会在需要时自动重建缓存。</span><br><span class="line"></span><br><span class="line">第二，安装包文件（.deb、.sh 等）在对应软件安装完成后即失去价值，可以放心删除。</span><br><span class="line"></span><br><span class="line">第三，回收站应养成定期清空的习惯，避免已删除的文件持续占用磁盘。</span><br><span class="line"></span><br><span class="line">第四，IDE 缓存（VS Code 的 CachedExtensionVSIXs、CachedData 等）可以清理，IDE 会在下次启动时按需重建，但要注意区分缓存与用户配置目录，不要误删个人设置。</span><br><span class="line"></span><br><span class="line">第五，运行环境（conda envs、nvm、rustup 等）在删除时需谨慎判断，只删除确定不再使用的部分，避免影响开发工作。</span><br><span class="line"></span><br><span class="line">第六，应用数据（QQ、微信、Unity Hub 等）往往包含用户个人数据，清理前务必确认不再需要。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">六、定期维护命令参考</span><br><span class="line"></span><br><span class="line">日常可以使用以下命令快速检查并清理磁盘：</span><br><span class="line"></span><br><span class="line">  清空回收站：</span><br><span class="line">  rm -rf ~/.local/share/Trash/files/*</span><br><span class="line"></span><br><span class="line">  清理 pip 缓存：</span><br><span class="line">  pip cache purge</span><br><span class="line"></span><br><span class="line">  清理 conda 缓存：</span><br><span class="line">  conda clean --all --yes</span><br><span class="line"></span><br><span class="line">  清理 npm 缓存：</span><br><span class="line">  npm cache clean --force</span><br><span class="line"></span><br><span class="line">  查看磁盘使用情况：</span><br><span class="line">  df -h /</span><br><span class="line">  du -sh ~/* ~/.[!.]* | sort -rh | head -20</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">本操作由 Claude Code 辅助完成，所有删除操作均已逐项与用户确认。</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="小总结"><a href="#小总结" class="headerlink" title="小总结"></a>小总结</h2><p>在我看来，claude code的使用可以分为3步。</p><ol><li>确认好本次目标：我是要让claude code干什么，比如我是要让他写一份计划？帮我清理一下文件？帮我改个代码？帮我梳理一下代码结构？</li><li>先无脑使用计划模式，之后按需使用自动模式：使用计划模式首先可以减少token的消耗，只做计划，不做操作，而且能给我们很多的计划方案。其次真的需要操作了，claude code也会智能地给我们请求，用户确认就可以。对于自动模式，遇到一些高风险，重要文件，应当使用确认模式，其他时候使用自动模式效率更高。</li><li>总结本次session内容：总结在我看来，不仅可以梳理本次对话的内容，知道今天做了什么，按部就班。也能让之后重新开启的对话，可以直接读取本次的session，来对接任务，避免重新执行一些高消费token的操作来对接需求。其实也有利于写博客~</li></ol><h2 id="值得夸赞的地方"><a href="#值得夸赞的地方" class="headerlink" title="值得夸赞的地方"></a>值得夸赞的地方</h2><p>对于本次的对话，我最满意的是deepseek的高性价比。今天的这三个session，只消费了2.80人民币，价格不如一根烤肠。而且claude code的对话十分健全，帮我很多。</p><h2 id="后续"><a href="#后续" class="headerlink" title="后续"></a>后续</h2><p>其实对于token的消耗，可以有更好的优化方案，比如使用计划模式，使用token saver cc等。</p><p>剩下的视频还没看完，还有更多的功能继续解锁，等我看完继续聊～</p>]]>
    </content>
    <id>https://gmaxh.site/2026/06/11/%E5%9B%BD%E5%86%85%E7%9A%84%E6%88%91%E4%B9%9F%E8%83%BD%E4%BD%BF%E7%94%A8claude%20code!/</id>
    <link href="https://gmaxh.site/2026/06/11/%E5%9B%BD%E5%86%85%E7%9A%84%E6%88%91%E4%B9%9F%E8%83%BD%E4%BD%BF%E7%94%A8claude%20code!/"/>
    <published>2026-06-11T21:46:29.000Z</published>
    <summary>
      <![CDATA[<h2 id="当前的claude-code我高攀不起"><a href="#当前的claude-code我高攀不起" class="headerlink" title="当前的claude code我高攀不起"></a>当前的claude code我高攀不起</h2><p>起初]]>
    </summary>
    <title>国内的我也能使用claude code!</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="AI" scheme="https://gmaxh.site/categories/AI/"/>
    <category term="AI" scheme="https://gmaxh.site/tags/AI/"/>
    <content>
      <![CDATA[<h2 id="写在前面"><a href="#写在前面" class="headerlink" title="写在前面"></a>写在前面</h2><p>本期内容为AI学习笔记，视频参考为<a href="https://www.bilibili.com/video/BV1E7wtzaEdq/?spm_id_from=333.1387.0.0&vd_source=bfdbc24038191b349c91940b41c52430">从 LLM 到 Agent Skill，一期视频带你打通底层逻辑！</a>，一位介绍AI非常详细的up主，以下笔记内容也是视频的部分内容。</p><p>主要内容包括：LLM, Token, Context, Context Window, Prompt, User Prompt, System Prompt, Tool, MCP, Agent, Agent Skill……</p><h2 id="LLM"><a href="#LLM" class="headerlink" title="LLM"></a>LLM</h2><p>LLM原名为大语言模型(large language model)，市面上的LLM都是基于Transform架构训练出来的。</p><p>Transform最早是2017年出现，由google发布。</p><p>2022年。openAI发布GPT-3.5,2023年，发布GPT-4，算是夯爆了。</p><p>工作流程：<br>我们向ai提出一个问题，比如，你觉得gmaxh的博客写的怎么样？LLM会先获取并解析这段文字，然后生成一个单词，比如’有待’,之后，LLM会把他收集到原本的问题字符串内，之后带着’有待’,继续生成下一个单词，’提高’。全部生成完毕之后，LLM会在结尾生成一个结束标志，表示我的回答已结束。</p><h2 id="token"><a href="#token" class="headerlink" title="token"></a>token</h2><p>LLM本身无法理解人类的自然语言，因此，人类输入的文本需要经过转换，变成一个个数字，成为token，参加运算。</p><p>Tokenizer:负责编码和解码，编码就是把文字转换为数字，解码则是把数字转为文字。</p><p>工作流程:<br>针对刚刚那个问题，你觉得gmaxh的博客写的怎么样？在编码部分，这里会先拆分成几个单词，<a href="https://platform.openai.com/tokenizer">使用openAI的拆分工具</a>，结果为’你 觉得 g max h 的 博客 写 的 怎么样 ?’，共11个单词，这一步在编码的部分叫做拆分，每个token也会同时对应一个tokenID，这一步叫做映射。之后送给LLM进行运算，得到的结果再进行解码，进行token映射，转换为文字输出，剩下流程即刚刚LLM部分介绍的内容，直到内容全部回答完毕。</p><p>token:本质上就是LLM处理文本的最小单元，它并非一个单词，而是使用了一种算法，名为BPE。</p><h2 id="context"><a href="#context" class="headerlink" title="context"></a>context</h2><p>token本身是一次问题的切分的小单元，但用户的对话历史，如果想要继续使用，该怎么办呢？</p><p>context:名为上下文，即LLM处理问题的信息总和。</p><p>context window:即上下文窗口，也就是LLM一次处理问题时，至多的token数量。目前市面上主流的LLM基本为1M,100万tokens大小，这个大小已经很大了，基本可以满足我们日常的提问需求。但如果要架构一个产品时，有一本产品手册，或者要编写一款漫改游戏，有一本漫画文字剧本，可能超过了1M的大小，该怎么办？</p><p>RAG，检索增强生成技术，可以从用户输入的大批量信息中，提取与问题相关的答案，之后把这些答案作为tokens输入到LLM中。</p><h2 id="prompt"><a href="#prompt" class="headerlink" title="prompt"></a>prompt</h2><p>其实prompt(提示词)，通俗讲就是context，也就是大模型接受的具体问题或者指令。而独立出来这样一个概念，即在从具体的文字中抽象出来，把这些token看作整体，进行优化。</p><p>prompt如果写的好，就会出现准确的回答，写的差就会出现模糊的回答。比如，我要求LLM帮我写一个道歉信。如果只是这么简单的说，LLM可能会给你一份标准格式的道歉信(十分严肃的那种)，但同时，也可能是兄弟之间的一个道歉信：错了兄弟，晚上来我宿舍喝酒。也可能是小情侣之间的玩笑式道歉。由此可见，一个差的prompt自然不会得到精确的结果，而如果我们优化prompt，我刚刚和新认识的同学吵了一架，不小心冒犯到了他…(说明具体原因)，帮我写一个道歉信。这样的结果会更让人信服。(道歉要诚恳，在此处不鼓励使用LLM😄)  </p><p>因此就在23年，出现了prompt Engineering，即，把话说清楚。当然，随着LLM的不断发展，有时模糊的prompt，也会有相对准确的答案，甚至LLM会直接给一些选项。</p><p>prompt分有user prompt和system prompt，即通过sys prompt来约束LLM的行为，user prompt进行提问时，就会针对sys的约束来回答。</p><h2 id="tool"><a href="#tool" class="headerlink" title="tool"></a>tool</h2><p>现在有这样的需求：今天是2026年6月4日，帮我查询一下今天成都的天气。如果直接提问(关闭联网搜索)，LLM会说他没有这个能力。但如果给他可以连接网络的功能，去调用天气查询工具，这样就可以了。</p><p>在一次使用工具的流程中，一共分为4部分，用户 平台 LLM 天气查询工具。</p><p>用户输入他的需求，之后平台把需求转给LLM以及当前可使用的工具列表，LLM进行处理时，发现需要工具，而这时如果用户已经给了LLM调用某个工具的权限，LLM则会告诉平台使用这个工具，并且基于工具来完善自己的答案，最后一步步转发给用户。</p><p>在其中，LLM只负责选择工具，并且归纳总结，处理文本。平台则会串联LLM和对应天气查询工具之间的内容，完成整个流程。</p><p>因此，tool的本质就是用来提供给LLM感知外部环境的能力，而他本质上更像是一个函数，接受要求，调用接口，返回输出。</p><h2 id="MCP"><a href="#MCP" class="headerlink" title="MCP"></a>MCP</h2><p>MCP:Model Context Protocol，模型上下文协议，即建立一套统一的标准，让工具开发者可以编写一次代码，对全部的平台通用。(每个时代都有自己的秦始皇)</p><h2 id="agent"><a href="#agent" class="headerlink" title="agent"></a>agent</h2><p>agent在商业角度上是一个成熟的AI产品，它具有自主的规划能力，即从处理文本，调用工具，实现具体效果等各个方面，追求更精准而简单的满足用户需求，市面上常见的agent有claude code,codex,gemini CLI,openclaw等。他们都有各自的构建模式。</p><h2 id="skill"><a href="#skill" class="headerlink" title="skill"></a>skill</h2><p>skill是针对agent写的一份说明文档，采用md格式。</p><p>skill文档包括两个部分，头部说明和具体内容，头部说明会标注好skill的具体介绍，具体内容有用户想要agent输出的内容要求。旨在约束agent的行为，但并非强约束。agent会先读取skill文件(这里的文件名字必须是SKILL.md)，之后读取头部说明，如果之后用户的需求和skill的要求相近，agent才会去读取具体内容，查询MCP可调用工具。</p><p>在我看来,skill和prompt最大的区别在于：  </p><ol><li>他提供了一套更为体系化，工业化的解决方案，而不是用户每次都需要约束一个system prompt。</li><li>在后续的其他内容中，不需要考虑多次调用context导致输出内容不清的问题，因为已经约束了agent的部分能力。</li><li>他提供给agent一个更清晰，更有结构的说明。</li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>现在的发展迅速，跟上时代潮流必不可少，这样一次的概念介绍，着实帮我理解了其中原理，欲知后事如何，且听下回分解～</p>]]>
    </content>
    <id>https://gmaxh.site/2026/06/04/AI%E6%97%B6%E4%BB%A3%E6%89%AB%E4%B8%AA%E7%9B%B2/</id>
    <link href="https://gmaxh.site/2026/06/04/AI%E6%97%B6%E4%BB%A3%E6%89%AB%E4%B8%AA%E7%9B%B2/"/>
    <published>2026-06-04T20:56:14.000Z</published>
    <summary>
      <![CDATA[<h2 id="写在前面"><a href="#写在前面" class="headerlink" title="写在前面"></a>写在前面</h2><p>本期内容为AI学习笔记，视频参考为<a href="https://www.bilibili.com/video/BV1E7]]>
    </summary>
    <title>AI时代扫个盲</title>
    <updated>2026-06-21T11:43:30.045Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="生活" scheme="https://gmaxh.site/categories/%E7%94%9F%E6%B4%BB/"/>
    <category term="日常倒霉趣事" scheme="https://gmaxh.site/tags/%E6%97%A5%E5%B8%B8%E5%80%92%E9%9C%89%E8%B6%A3%E4%BA%8B/"/>
    <content>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>为什么会有这种想写博客的想法，我想是源于对生活最朴素的记录。小时候老师总让写，美好的一天，我想今天是我加入Linux兴趣小组最有趣的一天。</p><h2 id="初见之前"><a href="#初见之前" class="headerlink" title="初见之前"></a>初见之前</h2><p>其实听说要参加这次分享会，我想会是一次很朴素的报告会。或许是被大二学长压力导致，渐渐地，我逐渐迷失在了无穷无尽的plan中。在进入小组前，或许说在更久的小学以前，我对计算机充满了热爱。  </p><p>我就读的小学在当地还算拔尖，所以在5年级的一次偶然机会，一节电脑课深深吸引了我。我现在还记得，当时老师使用scratch，演示自己制作的游戏，打开演示界面，就是一个简易的愤怒的小鸟。而打开程序界面，更多的是模块化，这无疑对于一个小学生来说，没有任何抵抗力。自此踏入了志在计算机的道路。  </p><p>高考结束，我总觉得，我在高考的生理上玩乐之外，我需要回归到自己本身应该做的事情，不是学习数学物理，语文英语这种我听了就像si的科目。我只喜欢计算机，或许我只想做出点有意思的东西。  </p><p>在进入大学前，发现西安邮电大学中，一众强而大的实验室，正满足我的需求，有网络安全的，移动应用开发的，大数据的，算法学习的，琳琅满目。而我最终选择了西邮Linux兴趣小组。我现在仍然记得，大二的负责人问我面试之外的问题：你为什么如此执着于我们实验室？所以在进入大学前的暑假，怀着对使用计算机作出点什么东西的渴求，我甚至自学了HTML + CSS + JS，作了一个简单的诗文网站，聊以自慰。</p><p>刚进入大学的时光很美好，忙着跑东跑西，可以每天玩游戏，可以谈一段甜甜的恋爱。而在之外，自从锚定了加入实验室，每天开始学习c语言，生怕自己无法进入。在我的印象里，能报考计算机专业的学生，都一定会c语言。</p><p>面试实验室的过程很紧张，我为了缓解这种紧张，我甚至面试了其他一众实验室，一面二面都过了，甚至在加入某实验室，就差我背书包签到，最后我还是等到了Linux兴趣小组。我认为这是一个怀有激情的实验室。  </p><p>而在正式进入实验室之后，我渐渐开始失望了，或者，我很迷茫。我对我的大学生活并不迷茫，该玩该学，还算乐观自然，我只是对实验室的期待，渐渐丧失了信心。我到底是来学习技术，认识志同道合的朋友，还是来完成一堆无穷无尽的plan，甚至还有要求，你必须要写的更快。终于，我选择了放弃，虽然可能学的很快会很有用，但我认为计算机不应该这样学，或者说，计算机不是用来学和赶的，是在一次次探索和玩乐中建立起来的知识。</p><p>而今天是6月3日，天气晴朗，微风吹起来十分温柔。又是一年毕业季，看到大四的学长学姐，满怀对实验室的关心和期待，开了这次分享会，我想我的想法还是有结果的。</p><h2 id="DeepTalk"><a href="#DeepTalk" class="headerlink" title="DeepTalk"></a>DeepTalk</h2><p>开始时，学长学姐自我介绍，从帅气的负责人，到可爱的学姐，尤其讲到他们在工作上的履历，让我很是羡慕。  </p><p>从小组纪律，任务进度，到工作行情，就业发展，以及大学生存生活的邪修办法，字字句句里包含着很多对小组的关心，和作为毕业生，对新生的期望。似乎，不吝啬的分享是他们的常态。这让我不禁想到了我小学时候，加入学校组织的编程兴趣小组的快乐氛围。</p><p>而轮到我们，有人勇于表达自己的想法，有人保持意见，有人侃侃而谈，有人默默寡言。但这对于一个技术交流的兴趣小组，外在的因素无法成为，阻隔跨有3届的人们的交流的心。</p><h2 id="未来"><a href="#未来" class="headerlink" title="未来"></a>未来</h2><p>我想这才是兴趣小组该有的样子，或许本身就该这样，也不知是哪股风气传来，我们必须要僵死在一堆没意思的plan里面。计算机的学习，本身就是多元的，每天只沉浸在一堆代码里，简直是无聊透顶，做一个自己的图形化界面的小游戏，做一个自己的独立博客网站，搭建一个自己的世界上性能最好的服务器，制作一个专属于自己的agent助手，复用minecraft的代码，写一个自己的MINEcraft。这不是很好吗？为什么一定要局限在任务里呢？(说起独立博客，我刚进入大学认为，人人都应该有自己的博客)</p><p>不过未来总会来的，我也终将会升入大二，新一届的大一学生也会满怀对技术的热情，投入到即使现在就业很难的计算机行业里面。这才是学习计算机最朴素的样子啊。</p><h2 id="你为什么如此执着于我们实验室？"><a href="#你为什么如此执着于我们实验室？" class="headerlink" title="你为什么如此执着于我们实验室？"></a>你为什么如此执着于我们实验室？</h2><p>我还记得我是怎么回答的：</p><ol><li>我认为学习计算机，应该学习一些底层的东西，否则不能称得上学过计算机。</li><li>学习计算机，如果只局限于学习知识，那未来一定是空洞飘渺的。</li><li>选择或许会大于努力，但热情一定大于选择。</li></ol><p>感谢大四的学长学姐的分享，毕业快乐，有缘再相见。</p>]]>
    </content>
    <id>https://gmaxh.site/2026/06/03/%E8%AE%B0%E4%B8%8E%E5%A4%A7%E5%9B%9B%E5%AD%A6%E9%95%BF%E5%AD%A6%E5%A7%90%E7%9A%84%E5%B0%B1%E4%B8%9A%E5%BA%A7%E8%B0%88%E5%88%86%E4%BA%AB%E4%BC%9A/</id>
    <link href="https://gmaxh.site/2026/06/03/%E8%AE%B0%E4%B8%8E%E5%A4%A7%E5%9B%9B%E5%AD%A6%E9%95%BF%E5%AD%A6%E5%A7%90%E7%9A%84%E5%B0%B1%E4%B8%9A%E5%BA%A7%E8%B0%88%E5%88%86%E4%BA%AB%E4%BC%9A/"/>
    <published>2026-06-03T21:08:41.000Z</published>
    <summary>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>为什么会有这种想写博客的想法，我想是源于对生活最朴素的记录。小时候老师总让写，美好的一天，我想今天是我加入Linux兴趣小组最有趣的一天。<]]>
    </summary>
    <title>记与大四学长学姐的就业座谈分享会</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="生活" scheme="https://gmaxh.site/categories/%E7%94%9F%E6%B4%BB/"/>
    <category term="日常倒霉趣事" scheme="https://gmaxh.site/tags/%E6%97%A5%E5%B8%B8%E5%80%92%E9%9C%89%E8%B6%A3%E4%BA%8B/"/>
    <content>
      <![CDATA[<p>以前一直觉得<code>makefile</code>很遥远，今天简单学习了一下，真是给我爽到了!💻<br>🎉🎉</p><figure class="highlight cxx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">CXXFLAGS = -std=c+<span class="number">+17</span> -pthread</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">objects = main.o factorial.o matrix.o</span><br><span class="line"></span><br><span class="line">res: $(objects)</span><br><span class="line">$(CXX) -o res $(objects)</span><br><span class="line"></span><br><span class="line">main.o: factorial.h matrix.h ThreadPool.h</span><br><span class="line">factorial.o: factorial.h</span><br><span class="line">matrix.o: matrix.h</span><br><span class="line"></span><br><span class="line">.PHONY: clean</span><br><span class="line">clean: </span><br><span class="line">rm res $(objects)</span><br></pre></td></tr></table></figure><p>这知识得学<br>🤗🤗🤗</p>]]>
    </content>
    <id>https://gmaxh.site/2026/04/27/Makefile%20%E7%9C%9F%E7%88%BD!/</id>
    <link href="https://gmaxh.site/2026/04/27/Makefile%20%E7%9C%9F%E7%88%BD!/"/>
    <published>2026-04-27T21:20:57.000Z</published>
    <summary>
      <![CDATA[<p>以前一直觉得<code>makefile</code>很遥远，今天简单学习了一下，真是给我爽到了!💻<br>🎉🎉</p>
<figure class="highlight cxx"><table><tr><td class="gutter"><pre><span cl]]>
    </summary>
    <title>Makefile 真爽！</title>
    <updated>2026-06-21T11:43:30.045Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="AI" scheme="https://gmaxh.site/categories/AI/"/>
    <category term="AI" scheme="https://gmaxh.site/tags/AI/"/>
    <category term="Linux" scheme="https://gmaxh.site/tags/Linux/"/>
    <content>
      <![CDATA[<h1 id="Openclaw-的目标是解放全人类"><a href="#Openclaw-的目标是解放全人类" class="headerlink" title="Openclaw 的目标是解放全人类"></a>Openclaw 的目标是解放全人类</h1><h2 id="初识"><a href="#初识" class="headerlink" title="初识"></a>初识</h2><p>在每天的学习生活中，总要会使用ai，豆老师，d老师，元老师，千千万万的大模型在当下社会十分火热。加上前刚不久，在兴趣小组内作了简单的知识分享，内容也与ai模型殊途同归。在此刻从openclaw入手，或许再好不过了。</p><h2 id="深入"><a href="#深入" class="headerlink" title="深入"></a>深入</h2><p>openclaw算是个产品，而本质蕴含的ai思想，咨询豆老师之后，是有原本的学名的，即harness engineering。即通过一个agent，接入模型之后，实现真正的解放生产力。作为cs自学指南的资深粉丝，也希望从其中寻找到关于HE的蛛丝马迹。未果，但并非后遂无问津者，b站前几天刚有一个很好的<a href="https://www.bilibili.com/video/BV1vrQbBBE6Z/?spm_id_from=333.1007.top_right_bar_window_custom_collection.content.click">教学视频</a>，值得作初步的了解。之后通过微信公众号，了解到程序员鱼皮也在最近发布了一篇文章，也拿来饱读一番。</p><h2 id="动手"><a href="#动手" class="headerlink" title="动手"></a>动手</h2><p>了解了基本的内容，就开始着手操作一番了。安装openclaw以及配置模型的流程并不算难，<del>其实问ai就行</del>，配置虚拟环境，安装agent，配置api，最后部署模型。<br>而真正让我吃惊的，是openclaw他真的干活了!  </p><ol><li><p>首先是我第一次安装openclaw，做一个简单的尝试，我给了他一些简单的token,让他显示一下北京近7天的天气状况，之后通过chrome浏览器打开。果不其然，he did it!</p></li><li><p>最近在逛<a href="https://plan.xiyoulinux.com/">实验室网站</a>的时候，发现了一个有趣的项目,<a href="https://plan.xiyoulinux.com/project/hashtable-c">c语言哈希表</a>，正好作为c语言复习，了解一下哈希表，一举两得，一石二鸟，一箭双雕……打开发现，其实是一个很老的经典项目了。在项目中，分有几个目录，每章中会带有逐步的介绍和对应的代码，能够手把手教你使用c语言的指针数组，实现一个高效的哈希表。但美中不足之处在于，代码仍存在一些小问题，导致会出现段错误，  </p><ul><li>如在哈希表搜索时，应当设置最大尝试次数，防止死循环</li><li>哈希表删除元素时，如果没有找到对应的键值对，不应该做ht-&gt;count–</li><li>更新哈希表大小时，应该在更新哈希表之后，删除原本的旧哈希表<br>通过对openclaw简单的询问以及要求，他真的会做到修改代码。</li></ul></li></ol><h2 id="心得"><a href="#心得" class="headerlink" title="心得"></a>心得</h2><p>“那是最好的时代，那是最坏的时代”。</p>]]>
    </content>
    <id>https://gmaxh.site/2026/04/21/Openclaw%20%E7%9A%84%E7%9B%AE%E6%A0%87%E6%98%AF%E8%A7%A3%E6%94%BE%E5%85%A8%E4%BA%BA%E7%B1%BB/</id>
    <link href="https://gmaxh.site/2026/04/21/Openclaw%20%E7%9A%84%E7%9B%AE%E6%A0%87%E6%98%AF%E8%A7%A3%E6%94%BE%E5%85%A8%E4%BA%BA%E7%B1%BB/"/>
    <published>2026-04-21T22:21:45.000Z</published>
    <summary>
      <![CDATA[<h1 id="Openclaw-的目标是解放全人类"><a href="#Openclaw-的目标是解放全人类" class="headerlink" title="Openclaw 的目标是解放全人类"></a>Openclaw 的目标是解放全人类</h1><h2 id="初]]>
    </summary>
    <title>Openclaw 的目标是解放全人类</title>
    <updated>2026-06-21T11:43:30.045Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="Linux" scheme="https://gmaxh.site/categories/Linux/"/>
    <category term="Linux" scheme="https://gmaxh.site/tags/Linux/"/>
    <category term="C/C++" scheme="https://gmaxh.site/tags/C-C/"/>
    <content>
      <![CDATA[<h2 id="用cpp实现一个简单的线程池"><a href="#用cpp实现一个简单的线程池" class="headerlink" title="用cpp实现一个简单的线程池"></a>用cpp实现一个简单的线程池</h2><h3 id="写在前面："><a href="#写在前面：" class="headerlink" title="写在前面："></a>写在前面：</h3><p>线程池，顾名思义用来存放批量线程的容器。面对需要处理多任务的情况，多线程的并发处理可以有效提高运行速度。接下来我将用cpp实现一个简单的线程池类。</p><h3 id="基本思路："><a href="#基本思路：" class="headerlink" title="基本思路："></a>基本思路：</h3><ol><li>构造函数和析构函数:负责线程池的创建和销毁。</li><li>任务队列和锁:任务队列用来存放所有的任务，锁负责在线程访问任务队列时加锁，避免竞争。</li><li>线程池:用<code>vector</code>存放<code>thread</code>，<code>worker</code>作为工作线程，在创建时压入<code>vector</code>中，为每个工作线程创建任务等待环节，使用条件变量等待任务，遇到任务则唤醒线程并加锁，访问任务队列，读取任务弹出任务，解锁执行任务，如若没有任务则销毁线程，销毁线程池。</li><li>提交任务:<code>submit</code>函数可以接受任何任务的类型，并且支持回调。</li><li>使用者在使用线程池类的时候，需要确定好要创建的线程池中的线程数，之后通过<code>lambda</code>表达式处理任务提交和回调显示。</li><li><code>io</code>输出使用线程安全的方式，即<code>log</code>函数，避免在<code>output</code>过程中出现错误显示。</li><li>整体界面美观，有关于主线程和工作线程在执行过程中的状态显示，供学习者参考。</li></ol><h3 id="源代码："><a href="#源代码：" class="headerlink" title="源代码："></a>源代码：</h3><ul><li><code>ThreadPool.h</code>:</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;iostream&gt;</span><br><span class="line">#include &lt;vector&gt;</span><br><span class="line">#include &lt;condition_variable&gt;</span><br><span class="line">#include &lt;thread&gt;</span><br><span class="line">#include &lt;queue&gt;</span><br><span class="line">#include &lt;functional&gt;</span><br><span class="line">#include &lt;mutex&gt;</span><br><span class="line">#include &lt;chrono&gt;</span><br><span class="line">#include &lt;future&gt;</span><br><span class="line">#include &lt;iomanip&gt;</span><br><span class="line"></span><br><span class="line">using std::string, std::cout, std::endl;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    日志处理函数:</span><br><span class="line">    接受字符串参数，打印日志。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">void log(const string&amp; msg) &#123;</span><br><span class="line">    static std::mutex logMtx;</span><br><span class="line">    std::lock_guard&lt;std::mutex&gt; lg(logMtx);</span><br><span class="line"></span><br><span class="line">    auto now = std::chrono::system_clock::now();</span><br><span class="line">    auto time = std::chrono::system_clock::to_time_t(now);</span><br><span class="line">    cout &lt;&lt; msg &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void log(const string&amp; msg, int x) &#123;</span><br><span class="line">    static std::mutex logMtx;</span><br><span class="line">    std::lock_guard&lt;std::mutex&gt; lg(logMtx);</span><br><span class="line"></span><br><span class="line">    auto now = std::chrono::system_clock::now();</span><br><span class="line">    auto time = std::chrono::system_clock::to_time_t(now);</span><br><span class="line">    cout &lt;&lt; msg;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">class ThreadPool &#123;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    公共接口:构造函数和析构函数，</span><br><span class="line">    自动初始化线程池，</span><br><span class="line">    并且在工作完成之后结束线程池。</span><br><span class="line">    定义任务提交函数。</span><br><span class="line">    使用模板，接受任意可调用对象，任意对象的参数，回调函数。</span><br><span class="line">    使用auto处理不确定的返回值，</span><br><span class="line">    异步执行任务，自动执行回调函数，</span><br><span class="line">    最后返回future对象，用来同步等待任务结果。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">public:</span><br><span class="line">    ThreadPool(size_t TNum);</span><br><span class="line">    ~ThreadPool();</span><br><span class="line"></span><br><span class="line">    template&lt;class F, class CB&gt;</span><br><span class="line">    auto submit(F&amp;&amp; f, CB&amp;&amp; cb) -&gt; std::future&lt;decltype(f())&gt;;</span><br><span class="line">      </span><br><span class="line">/*</span><br><span class="line">    隐藏接口:</span><br><span class="line">    定义工作线程以及存放线程的数组，任务队列</span><br><span class="line">    锁，条件变量，控制线程之间调度的条件</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">private:</span><br><span class="line">    void worker();// 工作线程</span><br><span class="line">    std::vector&lt;std::thread&gt; workers;// 线程</span><br><span class="line">    std::queue&lt;std::function&lt;void()&gt;&gt; jobs;// 任务队列</span><br><span class="line"></span><br><span class="line">    std::mutex mtx;// 锁</span><br><span class="line">    std::condition_variable cv;// 条件变量</span><br><span class="line">    bool stop = false;// 控制条件</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    线程池构造函数:</span><br><span class="line">    将创建的线程加入到vector里</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">ThreadPool::ThreadPool(size_t TNum) &#123;</span><br><span class="line">    log(&quot;(init)初始化线程池,使用 &quot; + std::to_string(TNum) + &quot; 个线程&quot;);</span><br><span class="line">    for(size_t i = 0; i &lt; TNum; ++i) &#123;</span><br><span class="line">        workers.emplace_back(&amp;ThreadPool::worker, this);</span><br><span class="line">        std::this_thread::sleep_for(std::chrono::milliseconds(100));</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    线程池析构函数:</span><br><span class="line">    将所有线程进行回收</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">ThreadPool::~ThreadPool() &#123;</span><br><span class="line">    &#123;</span><br><span class="line">        std::lock_guard&lt;std::mutex&gt; lg(mtx);// 上锁，通知所有线程即将关闭线程池</span><br><span class="line">        stop = true;</span><br><span class="line">    &#125;</span><br><span class="line">    cv.notify_all();// 唤醒所有线程</span><br><span class="line"></span><br><span class="line">    for(auto&amp; t : workers) &#123;</span><br><span class="line">        if(t.joinable()) t.join();</span><br><span class="line">    &#125;</span><br><span class="line">    log(&quot;(finish)线程池已关闭&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    线程池工作函数:</span><br><span class="line">    while循环:等待任务，期间处于休眠状态，除非线程池关闭</span><br><span class="line">    锁:访问队列时加锁，执行任务时解锁</span><br><span class="line">    条件变量:没有任务时休眠，有任务时加锁</span><br><span class="line">    任务:如果在任务队列中检测到有任务，被唤醒之后，从队列中取出，执行任务</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">void ThreadPool::worker() &#123;</span><br><span class="line">    log(&quot;(worker)工作线程&quot;);</span><br><span class="line">    while(true) &#123;</span><br><span class="line">        std::function&lt;void()&gt; job;</span><br><span class="line">        &#123;</span><br><span class="line">            std::unique_lock&lt;std::mutex&gt; ul(mtx);</span><br><span class="line">            cv.wait(ul, [this]() &#123;return stop || !jobs.empty(); &#125;);</span><br><span class="line"></span><br><span class="line">            if(stop &amp;&amp; jobs.empty()) &#123;</span><br><span class="line">                log(&quot;(worker)工作线程已销毁&quot;);</span><br><span class="line">                return;</span><br><span class="line">            &#125;</span><br><span class="line">            job = std::move(jobs.front());</span><br><span class="line">            jobs.pop();</span><br><span class="line">        &#125;</span><br><span class="line">        job();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    线程池任务提交函数:</span><br><span class="line">    模板:声明，接受任意任务，参数，回调</span><br><span class="line">    返回值:future异步处理任务结果，最后执行回调</span><br><span class="line">    returnType:任务自动获取到对应任务的返回值，用于回调</span><br><span class="line">    job:任务包装，加入到队列中</span><br><span class="line">    上锁访问队列:加入</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">template&lt;class F, class CB&gt;</span><br><span class="line">auto ThreadPool::submit(F&amp;&amp; f, CB&amp;&amp; cb) -&gt; std::future&lt;decltype(f())&gt; &#123;</span><br><span class="line">    using returnType = decltype(f());// 获取返回值类型</span><br><span class="line"></span><br><span class="line">    auto job = std::make_shared&lt;std::packaged_task&lt;returnType()&gt;&gt; (</span><br><span class="line">        std::forward&lt;F&gt;(f)</span><br><span class="line">    );// 任务包装器:在让多线程共享的前提下，将任务完美包装到job里</span><br><span class="line">    std::future&lt;returnType&gt; res = job-&gt;get_future();// 获取结果</span><br><span class="line"></span><br><span class="line">    &#123;// 上锁访问队列</span><br><span class="line">        std::lock_guard&lt;std::mutex&gt; lg(mtx);</span><br><span class="line">        jobs.emplace([job, cb]() &#123;</span><br><span class="line">            (*job)();</span><br><span class="line">            cb();</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    cv.notify_one();// 唤醒线程，准备工作</span><br><span class="line">    log(&quot;(submit)任务已加入队列&quot;);</span><br><span class="line">    return res;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><code>ThreadMain.cpp</code>:</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line">#include &quot;ThreadPool.h&quot;</span><br><span class="line"></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">// 阶乘</span><br><span class="line">uint64_t factorial(int n) &#123;</span><br><span class="line">    uint64_t res = 1;</span><br><span class="line">    for(int i = 2; i &lt;= n; ++i) &#123;</span><br><span class="line">        res *= i;</span><br><span class="line">        this_thread::sleep_for(chrono::milliseconds(100));// 模拟耗时长的任务</span><br><span class="line">    &#125;</span><br><span class="line">    return res;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">using Matrix = vector&lt;vector&lt;int&gt;&gt;;</span><br><span class="line">// 矩阵乘法</span><br><span class="line">Matrix MatrixMultiply(const Matrix&amp; A, const Matrix&amp; B) &#123;</span><br><span class="line">    int m = A.size();// 总数</span><br><span class="line">    int n = B[0].size();// 列数</span><br><span class="line">    int p = B.size();// 总数</span><br><span class="line"></span><br><span class="line">    Matrix res(m, vector&lt;int&gt;(n, 0));</span><br><span class="line"></span><br><span class="line">    for(int i = 0; i &lt; m; ++i) &#123;</span><br><span class="line">        for(int j = 0; j &lt; n; ++j) &#123;</span><br><span class="line">            for(int k = 0; k &lt; p; ++k) &#123;</span><br><span class="line">                res[i][j] += A[i][k] * B[k][j];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    return res;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    ThreadPool TPool(10);</span><br><span class="line"></span><br><span class="line">    log(&quot;(main)测试矩阵乘法:&quot;);</span><br><span class="line">    Matrix A = &#123;&#123;1, 2&#125;, &#123;3, 4&#125;&#125;;</span><br><span class="line">    Matrix B = &#123;&#123;5, 6&#125;, &#123;7, 8&#125;&#125;;</span><br><span class="line"></span><br><span class="line">    auto MatrixFuture = TPool.submit([=]() &#123;</span><br><span class="line">        return MatrixMultiply(A, B);</span><br><span class="line">    &#125;, []() &#123;</span><br><span class="line">        log(&quot;(callback)矩阵乘法任务已完成&quot;);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    Matrix C = MatrixFuture.get();</span><br><span class="line"></span><br><span class="line">    log(&quot;(main)矩阵结果:&quot;);</span><br><span class="line">    for(auto&amp; row : C) &#123;</span><br><span class="line">        for(int x : row) &#123;</span><br><span class="line">            log(to_string(x) + &quot; &quot;, 1);</span><br><span class="line">        &#125;</span><br><span class="line">        log(&quot; &quot;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    log(&quot;(main)测试阶乘:&quot;);</span><br><span class="line">    int n;</span><br><span class="line">    log(&quot;(main)输入计算的阶乘数字: &quot;);</span><br><span class="line">    cin &gt;&gt; n;</span><br><span class="line">    </span><br><span class="line">    auto factorialFuture = TPool.submit([=]() &#123;</span><br><span class="line">        return factorial(n);</span><br><span class="line">    &#125;, []() &#123;</span><br><span class="line">        log(&quot;(callback)阶乘任务已完成&quot;);</span><br><span class="line">    &#125;);</span><br><span class="line">    log(&quot;(main)阶乘结果:&quot;);</span><br><span class="line">    auto facResult = factorialFuture.get();</span><br><span class="line">    log(&quot;(main)&quot; + to_string(n) + &quot;!= &quot; + to_string(facResult));</span><br><span class="line"></span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://gmaxh.site/2026/04/14/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AE%9E%E7%8E%B0%E7%BA%BF%E7%A8%8B%E6%B1%A0/</id>
    <link href="https://gmaxh.site/2026/04/14/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AE%9E%E7%8E%B0%E7%BA%BF%E7%A8%8B%E6%B1%A0/"/>
    <published>2026-04-14T21:01:27.000Z</published>
    <summary>
      <![CDATA[<h2 id="用cpp实现一个简单的线程池"><a href="#用cpp实现一个简单的线程池" class="headerlink" title="用cpp实现一个简单的线程池"></a>用cpp实现一个简单的线程池</h2><h3 id="写在前面："><a href="#]]>
    </summary>
    <title>在 Linux 系统中实现线程池</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="Linux" scheme="https://gmaxh.site/categories/Linux/"/>
    <category term="Linux" scheme="https://gmaxh.site/tags/Linux/"/>
    <category term="C/C++" scheme="https://gmaxh.site/tags/C-C/"/>
    <content>
      <![CDATA[<h2 id="用cpp实现一个简单的多线程排序"><a href="#用cpp实现一个简单的多线程排序" class="headerlink" title="用cpp实现一个简单的多线程排序"></a>用cpp实现一个简单的多线程排序</h2><h3 id="写在前面："><a href="#写在前面：" class="headerlink" title="写在前面："></a>写在前面：</h3><p>线程，可以在程序运行时线性创建，并行使用，面对数据量很大的需求，多线程并发处理很好的提速。本次我将写一个多线程排序程序。</p><h3 id="基本思路："><a href="#基本思路：" class="headerlink" title="基本思路："></a>基本思路：</h3><ol><li>排序算法: 由于要处理数据量很大的需求，应当选择小于<code>O(n)</code>时间复杂度的算法。这里我用的是归并排序。</li><li>分两种情况，一种是单线程排序，就是正常的排序。需要考虑一种情况，即当在多线程排序，递归创建线程时，深度大于3时，线程过多会导致程序崩溃，面对这种情况则回退到单线程。</li><li>第二种情况，即多线程排序，递归创建线程，每层创建两个，分别处理<code>left mid</code>, <code>mid + 1 right</code>。</li><li>生成数据方面，使用cpp的伪随机数据生成器。</li><li>最后生成耗时，并进行比较，有助于观察时间差距。</li></ol><h3 id="源代码："><a href="#源代码：" class="headerlink" title="源代码："></a>源代码：</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;iostream&gt;</span><br><span class="line">#include &lt;mutex&gt;</span><br><span class="line">#include &lt;thread&gt;</span><br><span class="line">#include &lt;chrono&gt;</span><br><span class="line">#include &lt;vector&gt;</span><br><span class="line">#include &lt;random&gt;</span><br><span class="line">#include &lt;algorithm&gt;</span><br><span class="line"></span><br><span class="line">using namespace std;</span><br><span class="line">const int MAX_DEPTH = 3;// 控制线程创建的层数，避免线程创建过多</span><br><span class="line">const int DATA_SIZE = 1e6;</span><br><span class="line">/*</span><br><span class="line"></span><br><span class="line">    数据生成：</span><br><span class="line">    创建一个vector，之后使用伪随机数生成器</span><br><span class="line">    通过一个for循环，使用auto，将生成的数据放入ector中</span><br><span class="line"></span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">vector&lt;int&gt; createData(size_t size, int minVal, int maxVal) &#123;</span><br><span class="line">    vector&lt;int&gt; a(size);</span><br><span class="line">    random_device rd;</span><br><span class="line">    mt19937 gen(rd());</span><br><span class="line">    uniform_int_distribution&lt;&gt; dis(minVal, maxVal);// 创建均匀分布，防止数据过密</span><br><span class="line">    for(auto&amp; x : a) &#123;</span><br><span class="line">        x = dis(gen);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    return a;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void merge(vector&lt;int&gt;&amp; arr, int left, int mid, int right) &#123;</span><br><span class="line">    vector&lt;int&gt; temp(right - left + 1);</span><br><span class="line">    int i = left, j = mid + 1, k = 0;</span><br><span class="line">    while(i &lt;= mid &amp;&amp; j &lt;= right) &#123;</span><br><span class="line">        if(arr[i] &lt;= arr[j]) temp[k++] = arr[i++];</span><br><span class="line">        else temp[k++] = arr[j++];</span><br><span class="line">    &#125;</span><br><span class="line">    while(i &lt;= mid) temp[k++] = arr[i++];</span><br><span class="line">    while(j &lt;= right) temp[k++] = arr[j++];</span><br><span class="line">    for(int l = 0; l &lt; temp.size(); ++l) &#123;</span><br><span class="line">        arr[left + l] = temp[l];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void mSort(vector&lt;int&gt;&amp; arr, int left, int right) &#123;</span><br><span class="line">    if(left &gt;= right) return;</span><br><span class="line">    int mid = left + (right - left) / 2;</span><br><span class="line">    mSort(arr, left, mid);</span><br><span class="line">    mSort(arr, mid + 1, right);</span><br><span class="line">    merge(arr, left, mid, right);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void TmSort(vector&lt;int&gt;&amp; arr, int left, int right, int d = 0) &#123;</span><br><span class="line">    if(left &gt;= right) return;</span><br><span class="line"></span><br><span class="line">    if(d &gt;= MAX_DEPTH) &#123;// 超过就使用单线程</span><br><span class="line">        mSort(arr, left, right);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    int mid = left + (right - left) / 2;</span><br><span class="line"></span><br><span class="line">    // 使用引用，否则无法排序</span><br><span class="line">    thread t1(TmSort, ref(arr), left, mid, d + 1);</span><br><span class="line">    thread t2(TmSort, ref(arr), mid + 1, right, d + 1);</span><br><span class="line">    </span><br><span class="line">    t1.join();</span><br><span class="line">    t2.join();</span><br><span class="line"></span><br><span class="line">    merge(arr, left, mid, right);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    vector&lt;int&gt; data = createData(DATA_SIZE, 1, 100000);</span><br><span class="line">    auto data2 = data;// 单线程数据，进行比较</span><br><span class="line"></span><br><span class="line">    // 多线程</span><br><span class="line">    auto startTime = chrono::high_resolution_clock::now();</span><br><span class="line">    TmSort(data, 0, data.size() - 1);</span><br><span class="line">    auto endTime = chrono::high_resolution_clock::now();</span><br><span class="line">    chrono::duration&lt;double&gt; temp(endTime - startTime);</span><br><span class="line">    double ThreadTime = temp.count();</span><br><span class="line">    cout &lt;&lt; &quot;多线程排序耗时:&quot; &lt;&lt; ThreadTime</span><br><span class="line">        &lt;&lt; &quot;s&quot; &lt;&lt; endl;// 更高精度计算时间</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    // 单线程</span><br><span class="line">    startTime = chrono::high_resolution_clock::now();</span><br><span class="line">    mSort(data2, 0, data2.size() - 1);</span><br><span class="line">    endTime = chrono::high_resolution_clock::now();</span><br><span class="line">    chrono::duration&lt;double&gt; temp2(endTime - startTime);</span><br><span class="line">    double SingleTime = temp2.count();</span><br><span class="line">    cout &lt;&lt; &quot;单线程排序耗时:&quot; &lt;&lt; SingleTime</span><br><span class="line">        &lt;&lt; &quot;s&quot; &lt;&lt; endl;// 更高精度计算时间</span><br><span class="line"></span><br><span class="line">    if(data == data2) &#123;</span><br><span class="line">        cout &lt;&lt; &quot;计算正确!&quot; &lt;&lt; endl;</span><br><span class="line">        cout &lt;&lt; &quot;耗时差距为:&quot; &lt;&lt; chrono::duration&lt;double&gt;(abs(temp - temp2)).count() </span><br><span class="line">            &lt;&lt; &quot;s&quot; &lt;&lt; endl;</span><br><span class="line">    &#125;else throw domain_error(&quot;计算错误!&quot;);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://gmaxh.site/2026/04/13/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AE%9E%E7%8E%B0%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%8E%92%E5%BA%8F/</id>
    <link href="https://gmaxh.site/2026/04/13/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AE%9E%E7%8E%B0%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%8E%92%E5%BA%8F/"/>
    <published>2026-04-13T21:23:53.000Z</published>
    <summary>
      <![CDATA[<h2 id="用cpp实现一个简单的多线程排序"><a href="#用cpp实现一个简单的多线程排序" class="headerlink" title="用cpp实现一个简单的多线程排序"></a>用cpp实现一个简单的多线程排序</h2><h3 id="写在前面："><a]]>
    </summary>
    <title>在 Linux 系统中实现多线程排序</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="Linux" scheme="https://gmaxh.site/categories/Linux/"/>
    <category term="AI" scheme="https://gmaxh.site/tags/AI/"/>
    <category term="Linux" scheme="https://gmaxh.site/tags/Linux/"/>
    <category term="Python" scheme="https://gmaxh.site/tags/Python/"/>
    <content>
      <![CDATA[<h1 id="在linux系统上使用yolov8模型"><a href="#在linux系统上使用yolov8模型" class="headerlink" title="在linux系统上使用yolov8模型"></a>在linux系统上使用yolov8模型</h1><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>大家好，本周的知识分享内容是使用yolov8来训练自己的数据集，最后将训练好的模型投入使用。</p><h2 id="深度学习模型"><a href="#深度学习模型" class="headerlink" title="深度学习模型"></a>深度学习模型</h2><p>深度学习模型是机器学习的一个子集，其核心是构建由多个“层”组成的人工神经网络，通过层次化特征学习，从大规模数据中自动提取从低级到高级的抽象表示。</p><p>分类:</p><ul><li><p>计算机视觉:yolo,自研模型</p></li><li><p>自然语言处理:deepseek,GPT,gemini,transformer,自研模型</p></li><li><p>多模态处理:GPT,自研模型</p></li></ul><h2 id="计算机视觉"><a href="#计算机视觉" class="headerlink" title="计算机视觉"></a>计算机视觉</h2><p>计算机视觉是人工智能的一个核心研究领域，旨在赋予计算机“看”和理解图像或视频内容的能力，其目标是从视觉数据中自动提取、分析、理解有用信息，并做出决策或表达。</p><h2 id="yolo介绍"><a href="#yolo介绍" class="headerlink" title="yolo介绍"></a>yolo介绍</h2><ul><li><p><a href="https://docs.ultralytics.com/zh/">yolo官方文档</a></p></li><li><p><a href="https://docs.ultralytics.com/zh/#yolo-a-brief-history">历史版本</a></p></li><li><p><a href="https://docs.ultralytics.com/zh/tasks/">应用场景</a></p></li></ul><p><code>YOLO</code>（You Only Look Once）是一种流行的物体检测和图像分割模型。<code>YOLO</code> 于 2015 年推出，因其高速和高精度而广受欢迎。</p><ul><li><p><code>目标检测</code>是一项涉及识别图像或视频流中目标的位置和类别的任务。</p><ul><li>目标检测器的输出是一组边界框，这些边界框包围了图像中的目标，以及每个框的类别标签和置信度分数。当您需要在场景中识别感兴趣的目标，但不需要确切知道目标在哪里或其确切形状时，目标检测是一个不错的选择。</li></ul></li><li><p><code>实例分割</code>比对象检测更进一步，包括识别图像中的各个对象并将它们与图像的其余部分分割开来。</p><ul><li>实例分割模型的输出是一组掩码或轮廓，它们勾勒出图像中每个对象，以及每个对象的类别标签和置信度分数。 当您不仅需要知道对象在图像中的位置，还需要知道它们的精确形状时，实例分割非常有用。</li></ul></li><li><p><code>图像分类</code>是三个任务中最简单的，它涉及将整个图像分类到一组预定义的类别中。</p><ul><li>图像分类器的输出是单个类别标签和一个置信度分数。当您只需要知道图像属于哪个类别，而不需要知道该类别的对象位于何处或其确切形状时，图像分类非常有用。</li></ul></li></ul><h3 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h3><p>虚拟环境:是将项目需要用到的依赖放到一个统一的环境内，防止不同项目之间，需要的依赖不同而发生冲突，很有助于项目管理，yolo的官方文档中提到了很多虚拟环境工具，如conda，pythonVenv等，此处我使用的是conda，他的操作更简单，并且自动安装了CUDA。</p><p>yaml文件:在yolov8训练过程中需要配置的文件。</p><p>置信度:是目标检测模型中，表示预测结果可信程度的一个概率值，范围在 [0, 1] 之间。数值越高，表示模型对自己预测的结果越确信。</p><p>数据集:是机器学习和人工智能领域中，用于训练、验证和测试模型的结构化数据集合。它是深度学习模型的“教材”——模型通过学习数据集中的样本与标签之间的映射关系，来获得解决特定任务的能力。</p><p>训练集:<br>训练集是用于训练模型的数据集合，模型通过学习训练集中的图像和对应的标注信息，来调整自身的参数（权重和偏置），从而掌握识别目标的能力。</p><p>验证集:<br>验证集是用于评估模型训练效果和调优参数的数据集合，模型在训练过程中定期在验证集上进行测试，但不参与参数更新。</p><p>测试集:<br>测试集是用于最终评估模型泛化能力的数据集合，只在模型训练完成后使用一次，用于报告模型的真实性能。</p><p>标签:<br>class_id类别编号(从0开始)<br>x_center框中心点x坐标(归一化)<br>y_center框中心点y坐标(归一化)<br>width    框宽度(归一化)<br>height    框高度(归一化)  </p><p>过拟合:是指模型在训练集上表现非常好（损失很低、准确率很高），但在验证集或测试集上表现很差的现象。简单来说：模型死记硬背了训练数据，但没有学到通用规律，导致对新数据泛化能力差。</p><p>张量即多维数组。在计算机视觉相关的模型中，一张图片可以被转换为张量，作为参数被模型使用。</p><p>张量的存储可以在cpu上，gpu上，对于gpu上的张量可以使用CUDA进行加速。</p><p>在yolo模型中，张量作为参数，yolo模型作为函数，接受参数对其进行训练。</p><p>损失:是一个标量张量，表示模型预测结果与真实标签之间的差距。损失越小，模型预测越准。</p><p>损失函数:用来检测损失的程度。</p><p>梯度:是一个张量，表示了每个参数应该往哪个方向调整，才能让损失变小。  </p><p>前向传播：输入数据逐层计算得到预测结果和损失值的过程。</p><p>反向传播：从损失函数出发，利用链式法则反向计算每一层参数梯度的过程。</p><p>梯度下降：参数沿着梯度的反方向进行迭代更新以最小化损失函数的优化算法。</p><p>优化器：基于梯度下降原理，决定参数更新策略的算法实现。</p><h3 id="必要的工具"><a href="#必要的工具" class="headerlink" title="必要的工具"></a>必要的工具</h3><ul><li><p>vscode:支持加入很多插件，自由度更高，更灵活。</p></li><li><p>pip:是Python的官方包管理工具。</p></li><li><p>pytorch:深度学习框架，是yolov8的核心依赖。</p></li><li><p>conda:一个开源的包管理系统和环境管理系统。能创建隔离的虚拟环境，避免不同项目之间的依赖冲突。</p></li><li><p>CUDA:调用N卡的GPU对模型进行训练。</p></li></ul><h3 id="我自己的电脑配置"><a href="#我自己的电脑配置" class="headerlink" title="我自己的电脑配置"></a>我自己的电脑配置</h3><ul><li><p>cpu:AMD Ryzen 7 5800H with Radeon Graphics 8核 16线程 </p></li><li><p>显卡:NVIDIA GeForce RTX 3060</p></li><li><p>内存:16GB</p></li><li><p>OS:ubuntu 25.04</p></li></ul><h2 id="环境安装"><a href="#环境安装" class="headerlink" title="环境安装"></a>环境安装</h2><h3 id="虚拟环境配置"><a href="#虚拟环境配置" class="headerlink" title="虚拟环境配置"></a>虚拟环境配置</h3><ol><li>安装conda</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh</span><br><span class="line"></span><br><span class="line">bash ~/miniconda.sh -b -p $HOME/miniconda3</span><br><span class="line"></span><br><span class="line">~/miniconda3/bin/conda init fish</span><br><span class="line"></span><br><span class="line">exec fish</span><br><span class="line"></span><br><span class="line">conda --version</span><br></pre></td></tr></table></figure><ol start="2"><li>配置pip</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install pip</span><br><span class="line"></span><br><span class="line">pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple </span><br></pre></td></tr></table></figure><ol start="3"><li>创建并激活虚拟环境</li></ol><p>第一次创建环境会比较慢，这里在conda的配置文件中加入清华源，移除较慢的源，再进行创建。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"># 配置国内源</span><br><span class="line">conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/</span><br><span class="line">conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/</span><br><span class="line">conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/</span><br><span class="line">conda config --set show_channel_urls yes</span><br><span class="line"></span><br><span class="line"># 移除速度较慢的源</span><br><span class="line">conda config --remove channels defaults</span><br><span class="line"></span><br><span class="line"># 接受 Anaconda 官方仓库（repo.anaconda.com）的服务条款</span><br><span class="line">conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/main</span><br><span class="line">conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/r</span><br><span class="line"></span><br><span class="line"># 创建虚拟环境</span><br><span class="line">conda create -n yolo python=3.10 -y</span><br><span class="line"></span><br><span class="line"># 激活虚拟环境</span><br><span class="line">conda activate yolo</span><br></pre></td></tr></table></figure><ol start="4"><li>安装pytorch</li></ol><ul><li><a href="https://pytorch.org/">pytorch官方文档</a></li></ul><p>由于在训练模型时需要用到CUDA，所以需要查询自己n卡的cuda的最高支持版本，使用下面命令查询cuda版本<code>nvidia-smi</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install torch==1.13.1+cu116 torchvision==0.14.1+cu116 torchaudio==0.13.1 --extra-index-url https://download.pytorch.org/whl/cu116</span><br></pre></td></tr></table></figure><ol start="5"><li>下载ultralytics(yolov8)</li></ol><p>这里直接克隆官方的源码，并且使用pip，以可修改源码的形式安装。</p><p>使用可修改源码的形式安装，有助于我们定制个人化的yolov8模型，更有助于对yolov8源码的学习。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git clone git@github.com:ultralytics/ultralytics.git</span><br><span class="line"></span><br><span class="line">cd ultralytics</span><br><span class="line"></span><br><span class="line">pip install -e .</span><br></pre></td></tr></table></figure><h2 id="模型预测"><a href="#模型预测" class="headerlink" title="模型预测"></a>模型预测</h2><p>在ultralytics目录下，直接运行以下命令。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yolo predict model=yolov8n.pt source=&#x27;ultralytics/assets/bus.jpg&#x27;</span><br></pre></td></tr></table></figure><h2 id="数据处理"><a href="#数据处理" class="headerlink" title="数据处理"></a>数据处理</h2><h3 id="数据的选择"><a href="#数据的选择" class="headerlink" title="数据的选择"></a>数据的选择</h3><ol><li>数据要有真实应用场景，最好不要摆拍。</li><li>选择的图片要尽可能复杂多样，有白天拍摄也有夜晚拍摄，覆盖多种情况。</li><li>样本尽可能多些。</li><li>要和目标检测的对象相关。</li></ol><h3 id="数据集获取与标注"><a href="#数据集获取与标注" class="headerlink" title="数据集获取与标注"></a>数据集获取与标注</h3><p>数据集的获取有如下代码：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">import cv2</span><br><span class="line"></span><br><span class="line">video = cv2.VideoCapture(&quot;./puerzi.mp4&quot;)</span><br><span class="line">num = 0</span><br><span class="line">save_step = 30</span><br><span class="line"></span><br><span class="line">while True:</span><br><span class="line">    ret, frame = video.read()</span><br><span class="line">    if not ret:</span><br><span class="line">        break</span><br><span class="line">    num += 1</span><br><span class="line">    if num % save_step == 0:</span><br><span class="line">        cv2.imwrite(&quot;./demo_images/&quot; + str(num) + &quot;.jpg&quot;, frame)</span><br></pre></td></tr></table></figure><p>对于数据集的标注，市面上有很多种工具和网站，<code>https://www.makesense.ai</code>是一个在线的标注工具，提高了标注效率。并且支持大批量文件导入，压缩包文件导出。</p><h2 id="数据训练"><a href="#数据训练" class="headerlink" title="数据训练"></a>数据训练</h2><h3 id="文件结构方面"><a href="#文件结构方面" class="headerlink" title="文件结构方面"></a>文件结构方面</h3><p>结构如图：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">ultralytics/                # ultralytics 根目录</span><br><span class="line">├── datasets/               # 数据集根目录</span><br><span class="line">│   └── your_dataset/       # 你的数据集名称（如：coco_custom、helmet_detection）</span><br><span class="line">│       ├── images/         # 图片文件夹</span><br><span class="line">│       │   ├── train/      # 训练集图片</span><br><span class="line">│       │   └── val/        # 验证集图片</span><br><span class="line">│       └── labels/         # 标签文件夹（txt格式）</span><br><span class="line">│           ├── train/      # 训练集标签</span><br><span class="line">│           └── val/        # 验证集标签</span><br><span class="line">├── ultralytics/            # 源码目录</span><br><span class="line">└── ...</span><br></pre></td></tr></table></figure><h3 id="代码方面"><a href="#代码方面" class="headerlink" title="代码方面"></a>代码方面</h3><p>在ultralytics的根目录下创建yaml文件和py文件，yaml文件用来确定待训练数据的位置，和训练对象。py文件用来执行YOLOV8的训练。</p><p>在py文件中，可以自行配置各种训练参数，如：</p><ul><li><p>workers: 是用于并行加载数据的进程数量。当训练模型时，CPU需要不断读取图像、解码、进行数据增强等预处理操作，然后将处理好的数据传递给GPU进行训练。在win系统下，此处需要设置为0,linux系统下设置为1～8(默认为8)即可。</p></li><li><p>epochs: 训练轮数。</p></li></ul><p>epoch 1-50:   快速下降阶段，模型快速学习基本特征<br>epoch 50-150: 缓慢下降阶段，模型优化细节<br>epoch 150-300: 收敛阶段，loss基本不再下降<br>epoch &gt;300:   过拟合风险增加  </p><ul><li>batch: 是模型每次迭代训练时处理的图像数量。例如batch&#x3D;16意味着每次同时处理16张图像，计算梯度，然后更新一次模型参数。</li></ul><h3 id="查看训练结果"><a href="#查看训练结果" class="headerlink" title="查看训练结果"></a>查看训练结果</h3><p>在runs&#x2F;detect目录下，存放着YOLOV8对图片的训练结果以及训练的可视化过程。</p><p>在weights目录下，存放着best.pt和last.pt文件，一个是训练出来最好的模型，另一个供下一次训练时继续使用。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yolo detect predict model=runs/detect/()/weights/best.pt  source=() show=True</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本次知识分享，主要内容包括认识了深度学习模型的种类，计算机视觉概要，初识yolo。学习了如何使用yolov8模型，从环境安装，模型部署，模型预测，数据集收集与标注，模型训练的一系列过程。</p>]]>
    </content>
    <id>https://gmaxh.site/2026/03/26/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%8A%E4%BD%BF%E7%94%A8yolov8%E6%A8%A1%E5%9E%8B/</id>
    <link href="https://gmaxh.site/2026/03/26/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%8A%E4%BD%BF%E7%94%A8yolov8%E6%A8%A1%E5%9E%8B/"/>
    <published>2026-03-26T17:47:36.000Z</published>
    <summary>
      <![CDATA[<h1 id="在linux系统上使用yolov8模型"><a href="#在linux系统上使用yolov8模型" class="headerlink" title="在linux系统上使用yolov8模型"></a>在linux系统上使用yolov8模型</h1><h2 i]]>
    </summary>
    <title>在linux系统上使用yolov8模型</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="生活" scheme="https://gmaxh.site/categories/%E7%94%9F%E6%B4%BB/"/>
    <category term="生活" scheme="https://gmaxh.site/tags/%E7%94%9F%E6%B4%BB/"/>
    <content>
      <![CDATA[<p>我自幼喜欢计算机,却没什么大理想,只想在快节奏的时代里留下自己的足迹。</p><p>本网站希望可以带给你快乐。ヽ(●´∀&#96;●)ﾉ</p><p align="center" style="font-size: 24px; font-weight: bold;">行香子·在一中楼</p><p align="center">梅柳葵菊，花谢丰收。<br>呢喃却，了了金秋。你追我赶，慢慢悠悠。<br>走菜花园，操场道，教学楼。<br>山高多险，风急难驻。<br>忘离别，晓向天涯。你说他逗，将也临冬，<br>过高一闹，高三静，总轻柔。<br><br>]]>
    </content>
    <id>https://gmaxh.site/2026/03/23/%E6%85%A2%E6%85%A2%E8%B5%B0%E4%B8%8B%E5%8E%BB/</id>
    <link href="https://gmaxh.site/2026/03/23/%E6%85%A2%E6%85%A2%E8%B5%B0%E4%B8%8B%E5%8E%BB/"/>
    <published>2026-03-23T17:19:00.000Z</published>
    <summary>
      <![CDATA[<p>我自幼喜欢计算机,却没什么大理想,只想在快节奏的时代里留下自己的足迹。</p>
<p>本网站希望可以带给你快乐。ヽ(●´∀&#96;●)ﾉ</p>
<p align="center" style="font-size: 24px; font-weight: bold;">行]]>
    </summary>
    <title>慢慢走下去</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="Linux" scheme="https://gmaxh.site/categories/Linux/"/>
    <category term="Linux" scheme="https://gmaxh.site/tags/Linux/"/>
    <category term="C" scheme="https://gmaxh.site/tags/C/"/>
    <content>
      <![CDATA[<h2 id="用c语言实现自己的-shell"><a href="#用c语言实现自己的-shell" class="headerlink" title="用c语言实现自己的 shell"></a>用c语言实现自己的 shell</h2><h3 id="写在前面："><a href="#写在前面：" class="headerlink" title="写在前面："></a>写在前面：</h3><p>shell 是操作系统中，帮助用户通过命令行界面控制系统的执行文件，他随着终端创建而运行。</p><h3 id="功能："><a href="#功能：" class="headerlink" title="功能："></a>功能：</h3><ol><li>实现管道，输入输出重定向。</li><li>支持后台运行程序。</li><li>支持cd，包括切换到绝对路径，相对路径，切换至上一次的目录位置。</li><li>在shell内部屏蔽了 <code>ctrl + c</code> 等中断进程信号。</li><li>界面美观。目录显示参考了 <code>fish</code> 的表现方法，整体界面干净整洁。</li><li>支持大批量复制。</li></ol><h3 id="基本思路："><a href="#基本思路：" class="headerlink" title="基本思路："></a>基本思路：</h3><ol><li>在main函数内注册好需要屏蔽的信号，之后执行firstShow，展示欢迎界面，后进入shell函数内。</li><li>以shell函数为主函数，来创建其他的函数，包括解析命令行，路径搜索，处理进程的创建和清除，处理管道，处理重定向等等。</li></ol><h3 id="源代码："><a href="#源代码：" class="headerlink" title="源代码："></a>源代码：</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br><span class="line">616</span><br><span class="line">617</span><br><span class="line">618</span><br><span class="line">619</span><br><span class="line">620</span><br><span class="line">621</span><br><span class="line">622</span><br><span class="line">623</span><br><span class="line">624</span><br><span class="line">625</span><br><span class="line">626</span><br><span class="line">627</span><br><span class="line">628</span><br><span class="line">629</span><br><span class="line">630</span><br><span class="line">631</span><br><span class="line">632</span><br><span class="line">633</span><br><span class="line">634</span><br><span class="line">635</span><br><span class="line">636</span><br><span class="line">637</span><br><span class="line">638</span><br><span class="line">639</span><br><span class="line">640</span><br><span class="line">641</span><br><span class="line">642</span><br><span class="line">643</span><br><span class="line">644</span><br><span class="line">645</span><br><span class="line">646</span><br><span class="line">647</span><br><span class="line">648</span><br><span class="line">649</span><br><span class="line">650</span><br><span class="line">651</span><br><span class="line">652</span><br><span class="line">653</span><br><span class="line">654</span><br><span class="line">655</span><br><span class="line">656</span><br><span class="line">657</span><br><span class="line">658</span><br><span class="line">659</span><br><span class="line">660</span><br><span class="line">661</span><br><span class="line">662</span><br><span class="line">663</span><br><span class="line">664</span><br><span class="line">665</span><br><span class="line">666</span><br><span class="line">667</span><br><span class="line">668</span><br><span class="line">669</span><br><span class="line">670</span><br><span class="line">671</span><br><span class="line">672</span><br><span class="line">673</span><br><span class="line">674</span><br><span class="line">675</span><br><span class="line">676</span><br><span class="line">677</span><br><span class="line">678</span><br><span class="line">679</span><br><span class="line">680</span><br><span class="line">681</span><br><span class="line">682</span><br><span class="line">683</span><br><span class="line">684</span><br><span class="line">685</span><br><span class="line">686</span><br><span class="line">687</span><br><span class="line">688</span><br><span class="line">689</span><br><span class="line">690</span><br><span class="line">691</span><br><span class="line">692</span><br><span class="line">693</span><br><span class="line">694</span><br><span class="line">695</span><br><span class="line">696</span><br><span class="line">697</span><br><span class="line">698</span><br><span class="line">699</span><br><span class="line">700</span><br><span class="line">701</span><br><span class="line">702</span><br><span class="line">703</span><br><span class="line">704</span><br><span class="line">705</span><br><span class="line">706</span><br><span class="line">707</span><br><span class="line">708</span><br><span class="line">709</span><br><span class="line">710</span><br><span class="line">711</span><br><span class="line">712</span><br><span class="line">713</span><br><span class="line">714</span><br><span class="line">715</span><br><span class="line">716</span><br><span class="line">717</span><br><span class="line">718</span><br><span class="line">719</span><br><span class="line">720</span><br><span class="line">721</span><br><span class="line">722</span><br><span class="line">723</span><br><span class="line">724</span><br><span class="line">725</span><br><span class="line">726</span><br><span class="line">727</span><br><span class="line">728</span><br><span class="line">729</span><br><span class="line">730</span><br><span class="line">731</span><br><span class="line">732</span><br><span class="line">733</span><br><span class="line">734</span><br><span class="line">735</span><br><span class="line">736</span><br><span class="line">737</span><br><span class="line">738</span><br><span class="line">739</span><br><span class="line">740</span><br><span class="line">741</span><br><span class="line">742</span><br><span class="line">743</span><br><span class="line">744</span><br><span class="line">745</span><br><span class="line">746</span><br><span class="line">747</span><br><span class="line">748</span><br><span class="line">749</span><br><span class="line">750</span><br><span class="line">751</span><br><span class="line">752</span><br><span class="line">753</span><br><span class="line">754</span><br><span class="line">755</span><br><span class="line">756</span><br><span class="line">757</span><br><span class="line">758</span><br><span class="line">759</span><br><span class="line">760</span><br><span class="line">761</span><br><span class="line">762</span><br><span class="line">763</span><br><span class="line">764</span><br><span class="line">765</span><br><span class="line">766</span><br><span class="line">767</span><br><span class="line">768</span><br><span class="line">769</span><br><span class="line">770</span><br><span class="line">771</span><br><span class="line">772</span><br><span class="line">773</span><br><span class="line">774</span><br><span class="line">775</span><br><span class="line">776</span><br><span class="line">777</span><br><span class="line">778</span><br><span class="line">779</span><br><span class="line">780</span><br><span class="line">781</span><br><span class="line">782</span><br><span class="line">783</span><br><span class="line">784</span><br><span class="line">785</span><br><span class="line">786</span><br><span class="line">787</span><br><span class="line">788</span><br><span class="line">789</span><br><span class="line">790</span><br><span class="line">791</span><br><span class="line">792</span><br><span class="line">793</span><br><span class="line">794</span><br><span class="line">795</span><br><span class="line">796</span><br><span class="line">797</span><br><span class="line">798</span><br><span class="line">799</span><br><span class="line">800</span><br><span class="line">801</span><br><span class="line">802</span><br><span class="line">803</span><br><span class="line">804</span><br><span class="line">805</span><br><span class="line">806</span><br><span class="line">807</span><br><span class="line">808</span><br><span class="line">809</span><br><span class="line">810</span><br><span class="line">811</span><br><span class="line">812</span><br><span class="line">813</span><br><span class="line">814</span><br><span class="line">815</span><br><span class="line">816</span><br><span class="line">817</span><br><span class="line">818</span><br><span class="line">819</span><br><span class="line">820</span><br><span class="line">821</span><br><span class="line">822</span><br><span class="line">823</span><br><span class="line">824</span><br><span class="line">825</span><br><span class="line">826</span><br><span class="line">827</span><br><span class="line">828</span><br><span class="line">829</span><br><span class="line">830</span><br></pre></td><td class="code"><pre><span class="line">#define _GNU_SOURCE// 用来导入GNU扩展，使得中文内容编码正常</span><br><span class="line">#include &lt;fcntl.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;locale.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;sys/wait.h&gt;// 等待子进程</span><br><span class="line">#include &lt;string.h&gt;// 字符串比较</span><br><span class="line">#include &lt;signal.h&gt;// 中断 ctrl + c 信号</span><br><span class="line"></span><br><span class="line">#define COLOR_RESET &quot;\033[0m&quot; // 重置 </span><br><span class="line">#define COLOR_WELCOME &quot;\033[1;34m&quot; // 欢迎界面(粗体蓝色)</span><br><span class="line">#define COLOR_POINT &quot;\033[2;32m&quot; // 高亮显示当前行指向(粗体暗绿色)</span><br><span class="line">#define COLOR_HIGHLIGHT &quot;\033[1;32m&quot; // 高亮显示当前行索引(粗体亮绿色)</span><br><span class="line">#define MAX_PATH 256</span><br><span class="line">#define MAX_ARGS 64</span><br><span class="line">#define MAX_BGPROCESS 128</span><br><span class="line">#define MAX_PIPES 16</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">typedef struct &#123;</span><br><span class="line">    pid_t pid;</span><br><span class="line">    char command[256];</span><br><span class="line">    int isstillhere;</span><br><span class="line">&#125;Bgprocess;</span><br><span class="line"></span><br><span class="line">typedef struct &#123;</span><br><span class="line">    char *args[MAX_ARGS];</span><br><span class="line">    int argc;</span><br><span class="line">    char *inputFile;</span><br><span class="line">    char *outputFile;</span><br><span class="line">    int appendOutput;  // 1代表&gt;&gt;,0代表&gt;</span><br><span class="line">    int hasPipe;</span><br><span class="line">    int pipeFd[2];</span><br><span class="line">&#125; Command;</span><br><span class="line"></span><br><span class="line">Bgprocess bgProcess[MAX_BGPROCESS];// 后台进程</span><br><span class="line">int bgpCount = 0;// 后台进程数</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">void FirstShow();</span><br><span class="line">void Shell();</span><br><span class="line">void Error(int isError);</span><br><span class="line">int ParseCommand(char* command, char* args[], int* isback);// 解析命令行，将token放入参数指针数组</span><br><span class="line">char* SearchPath(char* command);// 路径搜索</span><br><span class="line">void SignalZombie(int sig);  // 处理僵尸进程</span><br><span class="line">void AddBgProcess(pid_t pid, char* command);// 添加后台进程</span><br><span class="line">void CheckBgProcess(void);// 检查后台进程</span><br><span class="line">void CleanCommand(Command commands[]);// 清理管道</span><br><span class="line">char* simpleCurrentPath(char currentPath[]);// 简化路径显示</span><br><span class="line">int isChinese(const char* str);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">以下三个函数先设置command结构体，之后设置重定向，最后创建进程执行管道</span><br><span class="line">*/ </span><br><span class="line"></span><br><span class="line">int HandlePipe(Command commands[], char command[], char* args[], int* isback);// 处理管道</span><br><span class="line">int setRediraction(Command commands[]);// 设置重定向</span><br><span class="line">void execPipe(Command commands[], int cmdCount, int isback);// 执行管道</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    // 注册信号</span><br><span class="line">    signal(SIGINT, SIG_IGN);// 解决ctrl + c中断进程的问题</span><br><span class="line">    signal(SIGQUIT, SIG_IGN);// 解决ctrl + \中断进程的问题</span><br><span class="line">    signal(SIGCHLD, SignalZombie);// 处理僵尸进程</span><br><span class="line"></span><br><span class="line">    setvbuf(stdin, NULL, _IOLBF, 0);// 处理行缓冲，使得快速显示内容</span><br><span class="line">    setvbuf(stdout, NULL, _IOLBF, 0);</span><br><span class="line"></span><br><span class="line">    FirstShow();//启动整体程序</span><br><span class="line">    exit(EXIT_SUCCESS);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int isChinese(const char* str) &#123;</span><br><span class="line">    // UTF-8中文字符的第一个字节范围：0xE4-0xE9</span><br><span class="line">    unsigned char c = (unsigned char)str[0];</span><br><span class="line">    return (c &gt;= 0xE4 &amp;&amp; c &lt;= 0xE9);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">char* simpleCurrentPath(char currentPath[]) &#123;</span><br><span class="line">    if(strcmp(currentPath, &quot;/&quot;) == 0) &#123;</span><br><span class="line">        return currentPath;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    char copy[MAX_PATH];    </span><br><span class="line">    copy[0] = &#x27;\0&#x27;;</span><br><span class="line">    strcat(copy, currentPath);</span><br><span class="line">    int cnt = 0;</span><br><span class="line">    int cntToken = 0;</span><br><span class="line"></span><br><span class="line">    for(int i = 0; i &lt; strlen(currentPath); ++i) &#123;</span><br><span class="line">        if(currentPath[i] == &#x27;/&#x27;) &#123;</span><br><span class="line">            cnt++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    static char result[MAX_PATH] = &quot;&quot;;</span><br><span class="line">    result[0] = &#x27;\0&#x27;;</span><br><span class="line"></span><br><span class="line">    char* token = strtok(copy, &quot;/&quot;);</span><br><span class="line">    while(token &amp;&amp; cntToken &lt;= cnt - 2) &#123;</span><br><span class="line">        if(strcmp(&quot;home&quot;, token) == 0) &#123;</span><br><span class="line">            strcat(result, &quot;/~&quot;);</span><br><span class="line">        &#125;else &#123;</span><br><span class="line">            strcat(result, &quot;/&quot;);</span><br><span class="line">            if(isChinese(token)) &#123;</span><br><span class="line">                strncat(result, token, 3);</span><br><span class="line">            &#125;else &#123;</span><br><span class="line">                strncat(result, token, 1);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        token = strtok(NULL, &quot;/&quot;);</span><br><span class="line">        cntToken++;</span><br><span class="line">    &#125;</span><br><span class="line">    if(token) &#123;</span><br><span class="line">        strcat(result, &quot;/&quot;);</span><br><span class="line">        strcat(result, token);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    return result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    清理命令资源,</span><br><span class="line">    不需要清理文件名字符串，</span><br><span class="line">    因为它作为指针指向原始命令字符串</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">void CleanCommand(Command commands[]) &#123;</span><br><span class="line">    commands-&gt;argc = 0;</span><br><span class="line">    commands-&gt;inputFile = NULL;</span><br><span class="line">    commands-&gt;outputFile = NULL;</span><br><span class="line">    commands-&gt;appendOutput = 0;</span><br><span class="line">    commands-&gt;hasPipe = 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    用来执行管道。</span><br><span class="line">    先设置好前置管道和当前管道，</span><br><span class="line">    在具有一定管道数目内，</span><br><span class="line">    执行for循环创建进程。</span><br><span class="line">    在子进程内，</span><br><span class="line">    设置好输入输出重定向。</span><br><span class="line">    之后执行进程。</span><br><span class="line">    在父进程内，</span><br><span class="line">    关闭前置进程，并且设置好当前进程。</span><br><span class="line">    由于当前进程下的管道属于同一个进程组，同时执行，</span><br><span class="line">    所以可以只记录第一个Pipepid。</span><br><span class="line"></span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">void execPipe(Command commands[], int cmdCount, int isback) &#123;</span><br><span class="line">    int prePipe[2] = &#123;-1, -1&#125;;// 分别为读端，写端</span><br><span class="line">    int currentPipe[2];// 分别为读端，写端</span><br><span class="line">    pid_t PipePids[MAX_PIPES];</span><br><span class="line"></span><br><span class="line">    for(int i = 0; i &lt; cmdCount; ++i) &#123;</span><br><span class="line">        if(i &lt; cmdCount - 1) &#123;</span><br><span class="line">            pipe(currentPipe);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        switch (PipePids[i] = fork())</span><br><span class="line">        &#123;</span><br><span class="line">        case -1:</span><br><span class="line">            perror(&quot;fork&quot;);</span><br><span class="line">            break;</span><br><span class="line">            </span><br><span class="line">        case 0:</span><br><span class="line">            if(isback) &#123;// 忽略ctrl + c 和 ctrl + \ 的信号</span><br><span class="line">                signal(SIGINT, SIG_IGN);</span><br><span class="line">                signal(SIGQUIT, SIG_IGN);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            if(prePipe[0] != -1) &#123;// 设置输入重定向</span><br><span class="line">                dup2(prePipe[0], STDIN_FILENO);</span><br><span class="line">                close(prePipe[0]);</span><br><span class="line">                close(prePipe[1]);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            if(i &lt; cmdCount - 1) &#123;// 设置输出重定向</span><br><span class="line">                close(currentPipe[0]);</span><br><span class="line">                dup2(currentPipe[1], STDOUT_FILENO);</span><br><span class="line">                close(currentPipe[1]);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            if(setRediraction(commands + i)) &#123;</span><br><span class="line">                exit(1);</span><br><span class="line">            &#125;</span><br><span class="line">            </span><br><span class="line">            for(int fd = 3; fd &lt; 1024; ++fd) &#123;// 关闭了</span><br><span class="line">                if(fd != STDERR_FILENO &amp;&amp; fd != STDIN_FILENO &amp;&amp; fd != STDOUT_FILENO) &#123;</span><br><span class="line">                    close(fd);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            char* execPath = SearchPath(commands[i].args[0]);</span><br><span class="line">            if(!execPath) &#123;</span><br><span class="line">                fprintf(stderr, &quot;shell: %s: 未找到命令\n&quot;, commands[i].args[0]);</span><br><span class="line">                exit(127);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            extern char** environ;// 不可写成* environ[]的形式，这与_GNU_SOURCE中声明的冲突</span><br><span class="line">            if(execve(execPath, commands[i].args, environ) == -1) &#123;</span><br><span class="line">                fprintf(stderr, &quot;shell: %s: 执行失败\n&quot;, commands[i].args[0]);</span><br><span class="line">                exit(126);</span><br><span class="line">            &#125;</span><br><span class="line">            break;</span><br><span class="line">        </span><br><span class="line">        default:</span><br><span class="line">            if(prePipe[0] != -1) &#123;// 关闭上一个管道的fd，否则不会结束。</span><br><span class="line">                close(prePipe[0]);</span><br><span class="line">                close(prePipe[1]);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            if(i &lt; cmdCount - 1) &#123;// 保存当前管道</span><br><span class="line">                prePipe[0] = currentPipe[0];</span><br><span class="line">                prePipe[1] = currentPipe[1];</span><br><span class="line">            &#125;</span><br><span class="line">            break;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    if(isback) &#123;</span><br><span class="line">        char cmd[256] = &quot;&quot;;// 后台创建进程。</span><br><span class="line">        for(int i = 0; i &lt; cmdCount; ++i) &#123;</span><br><span class="line">            if(i &gt; 0) &#123;</span><br><span class="line">                strcat(cmd, &quot;|&quot;);</span><br><span class="line">            &#125;</span><br><span class="line">            strcat(cmd, commands[i].args[0]);</span><br><span class="line">        &#125;</span><br><span class="line">        AddBgProcess(PipePids[0], cmd);</span><br><span class="line">    &#125;else &#123;</span><br><span class="line">        // 前台等待所有进程。</span><br><span class="line">        for(int i = 0; i &lt; cmdCount; ++i) &#123;</span><br><span class="line">            waitpid(PipePids[i], NULL, 0);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    用来针对管道设置重定向。</span><br><span class="line">    首先根据cmd结构体内的参数，</span><br><span class="line">    决定是否要进行重定向。</span><br><span class="line">    处理时要新开一个fd，</span><br><span class="line">    即获取到当前文件，</span><br><span class="line">    之后用dup2将重定向的宏，</span><br><span class="line">    指定到当前文件，并且关闭之前的文件描述符fd。</span><br><span class="line">    如果出错，返回-1,</span><br><span class="line">    正常则返回。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">int setRediraction(Command commands[]) &#123;</span><br><span class="line">    if(commands-&gt;inputFile) &#123;// 处理输入重定向</span><br><span class="line">        int fd = open(commands-&gt;inputFile, O_RDONLY);</span><br><span class="line">        if(fd &lt; 0) &#123;</span><br><span class="line">            fprintf(stderr, &quot;shell: %s: 无法打开输入文件\n&quot;, commands-&gt;inputFile);</span><br><span class="line">            return -1;</span><br><span class="line">        &#125;</span><br><span class="line">        dup2(fd, STDIN_FILENO);</span><br><span class="line">        close(fd);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    if(commands-&gt;outputFile) &#123;</span><br><span class="line">        int flags = O_WRONLY | O_CREAT;</span><br><span class="line">        if(commands-&gt;appendOutput) &#123;</span><br><span class="line">            flags |= O_APPEND;</span><br><span class="line">        &#125;else &#123;</span><br><span class="line">            flags |= O_TRUNC;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        int fd = open(commands-&gt;outputFile, flags, 0644);// 644 代表 所有者读写，所属组只读，其他用户只读</span><br><span class="line">        if(fd &lt; 0) &#123;</span><br><span class="line">            fprintf(stderr, &quot;shell: %s: 无法打开输出文件\n&quot;, commands-&gt;outputFile);</span><br><span class="line">            return -1;</span><br><span class="line">        &#125;</span><br><span class="line">        dup2(fd, STDOUT_FILENO);</span><br><span class="line">        close(fd);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    用来处理命令参数中的管道。</span><br><span class="line">    先在一个for循环内记录非管道参数的数目。</span><br><span class="line">    之后根据这个数目，</span><br><span class="line">    创建一个for循环，</span><br><span class="line">    在数目内设置每个command结构体的参数。</span><br><span class="line">    先初始化好每个参数，</span><br><span class="line">    之后根据&lt;,&gt;,&gt;&gt;，分别对每个结构体cmd内进行标记。</span><br><span class="line">    如果if都被跳过了，则把当前参数标记好。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">int HandlePipe(Command commands[], char command[], char* args[], int* isback) &#123;</span><br><span class="line">    int countNoPipe = 0;</span><br><span class="line">    int argIndex = 0;</span><br><span class="line">    CleanCommand(&amp;commands[countNoPipe]);</span><br><span class="line"></span><br><span class="line">    while(args[argIndex]) &#123;</span><br><span class="line">        if(strcmp(args[argIndex], &quot;|&quot;) == 0) &#123;//遇到管道则跳过处理</span><br><span class="line">            commands[countNoPipe].args[commands[countNoPipe].argc] = NULL;</span><br><span class="line">            countNoPipe++;</span><br><span class="line">            CleanCommand(&amp;commands[countNoPipe]);</span><br><span class="line">            argIndex++;</span><br><span class="line">            continue;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        // 处理参数成为管道，对每个管道开始设置标记，供后续函数进行识别</span><br><span class="line">        if(strcmp(&quot;&lt;&quot;, args[argIndex]) == 0) &#123;</span><br><span class="line">            if(args[argIndex + 1]) &#123;</span><br><span class="line">                commands[countNoPipe].inputFile = args[++argIndex];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;else if(strcmp(&quot;&gt;&quot;, args[argIndex]) == 0) &#123;</span><br><span class="line">            if(args[argIndex + 1]) &#123;</span><br><span class="line">                commands[countNoPipe].outputFile = args[++argIndex];</span><br><span class="line">                commands[countNoPipe].appendOutput = 0;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;else if(strcmp(&quot;&gt;&gt;&quot;, args[argIndex]) == 0) &#123;</span><br><span class="line">            if(args[argIndex + 1]) &#123;</span><br><span class="line">                commands[countNoPipe].outputFile = args[++argIndex];</span><br><span class="line">                commands[countNoPipe].appendOutput = 1;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;else &#123;</span><br><span class="line">            commands[countNoPipe].args[commands[countNoPipe].argc++] = args[argIndex];</span><br><span class="line">        &#125;</span><br><span class="line">        argIndex++;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    commands[countNoPipe].args[commands[countNoPipe].argc] = NULL;</span><br><span class="line">    commands[countNoPipe].hasPipe = 0;</span><br><span class="line">    return countNoPipe + 1;// 返回命令数量</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    用来移除已经结束的进程。</span><br><span class="line">    在while循环内作为检查的起始端。</span><br><span class="line">    在for循环中利用冒泡排序，</span><br><span class="line">    依次将整体移动，清除0位。</span><br><span class="line">    如果碰到了正在运行的进程则跳过，i++</span><br><span class="line">    否则进行for循环，并且减少bgpCount。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">void CheckBgProcess() &#123;</span><br><span class="line">    int i = 0;</span><br><span class="line">    while(i &lt; bgpCount) &#123;</span><br><span class="line">        if(!bgProcess[i].isstillhere) &#123;</span><br><span class="line">            for(int j = i; j &lt; bgpCount - 1; j++) &#123;</span><br><span class="line">                bgProcess[j] = bgProcess[j + 1];</span><br><span class="line">            &#125;</span><br><span class="line">            bgpCount--;</span><br><span class="line">        &#125;else &#123;</span><br><span class="line">            i++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    用来添加后台进程到后台进程结构体数组内。</span><br><span class="line">    如果当前后台进程数少于最大进程数，</span><br><span class="line">    则创建好后台进程，</span><br><span class="line">    并打印好创建信息。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">void AddBgProcess(pid_t pid, char* command) &#123;</span><br><span class="line">    if(bgpCount &lt; MAX_BGPROCESS) &#123;</span><br><span class="line">        bgProcess[bgpCount].pid = pid;</span><br><span class="line">        bgProcess[bgpCount].isstillhere = 1;</span><br><span class="line">        memcpy(bgProcess[bgpCount].command, command, 255);</span><br><span class="line">        bgProcess[bgpCount].command[255] = &#x27;\0&#x27;;</span><br><span class="line"></span><br><span class="line">        printf(&quot;[ %d ] %d\n&quot;, ++bgpCount, pid);// 打印后台进程数目，进程pid</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    用来处理僵尸进程。</span><br><span class="line">    获取到当前进程的状态和pid，</span><br><span class="line">    在while循环内通过wait no hang(不挂起等待)的方式，</span><br><span class="line">    回收每个僵尸进程，</span><br><span class="line">    设置好回收状态。</span><br><span class="line">    并且提示给用户进程的回收状态。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">void SignalZombie(int sig) &#123;</span><br><span class="line">    int status;</span><br><span class="line">    pid_t currentPid;</span><br><span class="line"></span><br><span class="line">    while((currentPid = waitpid(-1, &amp;status, WNOHANG)) &gt; 0) &#123;</span><br><span class="line">        for(int i = 0; i &lt; bgpCount; ++i) &#123;</span><br><span class="line">            if(bgProcess[i].pid == currentPid &amp;&amp; bgProcess[i].isstillhere) &#123;</span><br><span class="line">                bgProcess[i].isstillhere = 0;// 设置为已回收</span><br><span class="line">                printf(&quot;\n[ %d ] %s 进程已回收\n&quot;, currentPid, bgProcess[i].command);</span><br><span class="line">                fflush(stdout);</span><br><span class="line">                break;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    用来进行路径搜索。</span><br><span class="line">    先获取到原本路径，</span><br><span class="line">    后对原本路径复制，用复制样本进行拆分，</span><br><span class="line">    把每个目录放成完整路径。</span><br><span class="line">    如果绝对路径正确，则返回绝对路径，</span><br><span class="line">    否则从环境变量里找到并返回完整路径。</span><br><span class="line">    如果什么都没找到，返回NULL。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">char* SearchPath(char* command) &#123;</span><br><span class="line">    if(!command || *command == &#x27;\0&#x27;) &#123;</span><br><span class="line">        return NULL;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    if(command[0] == &#x27;/&#x27; || command[0] == &#x27;.&#x27;) &#123;</span><br><span class="line">        if(access(command, F_OK) != 0) &#123;</span><br><span class="line">            fprintf(stderr, &quot;shell: %s: 没有那个文件或目录\n&quot;, command);</span><br><span class="line">            return NULL;</span><br><span class="line">        &#125;</span><br><span class="line">        if(access(command, X_OK) != 0) &#123;</span><br><span class="line">            fprintf(stderr, &quot;shell: %s: 权限不够\n&quot;, command);</span><br><span class="line">            return NULL;</span><br><span class="line">        &#125;</span><br><span class="line">        return command;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    char* path = getenv(&quot;PATH&quot;);</span><br><span class="line">    if(!path) &#123;</span><br><span class="line">        return NULL;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    char *pathcopy = strdup(path); </span><br><span class="line">    char* dir = strtok(pathcopy, &quot;:&quot;);</span><br><span class="line">    static char fullpath[MAX_PATH];</span><br><span class="line"></span><br><span class="line">    while(dir) &#123;</span><br><span class="line">        snprintf(fullpath, sizeof(fullpath), &quot;%s/%s&quot;, dir, command);</span><br><span class="line"></span><br><span class="line">        if(access(fullpath, F_OK) == 0) &#123;</span><br><span class="line">            if(access(fullpath, X_OK) == 0) &#123;</span><br><span class="line">                free(pathcopy);</span><br><span class="line">                return fullpath;</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                free(pathcopy);</span><br><span class="line">                return NULL;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        dir = strtok(NULL, &quot;:&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    free(pathcopy);</span><br><span class="line">    fprintf(stderr, &quot;shell: %s: 未找到命令\n&quot;, command);</span><br><span class="line">    return NULL;</span><br><span class="line">     </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    用来解析从用户获取到的命令行，</span><br><span class="line">    拆分成token放入args参数数组。</span><br><span class="line">    在while循环内拆分token，并逐个放入数组内。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">int ParseCommand(char* command, char* args[], int* isback) &#123;</span><br><span class="line">    int cnt = 0, len = strlen(command);</span><br><span class="line">    </span><br><span class="line">    *isback = 0;</span><br><span class="line"></span><br><span class="line">    // 处理冗余内容</span><br><span class="line">    char* start = command;</span><br><span class="line">    while(*start == &#x27; &#x27; || *start == &#x27;\t&#x27;) start++;</span><br><span class="line"></span><br><span class="line">    char* end = command + len - 1;</span><br><span class="line">    while(end &gt; start &amp;&amp; (*end == &#x27; &#x27; || *end == &#x27;\t&#x27; || *end == &#x27;\n&#x27;)) &#123;</span><br><span class="line">        *end = &#x27;\0&#x27;;</span><br><span class="line">        end--;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    if(end &gt;= start &amp;&amp; *end == &#x27;&amp;&#x27;) &#123;</span><br><span class="line">        *isback = 1;</span><br><span class="line">        *end = &#x27;\0&#x27;;</span><br><span class="line"></span><br><span class="line">        end--;</span><br><span class="line">        while(end &gt;= start &amp;&amp; (*end == &#x27; &#x27; || *end == &#x27;\t&#x27;)) &#123;</span><br><span class="line">            *end = &#x27;\0&#x27;;</span><br><span class="line">            end--;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    // 处理冗余内容</span><br><span class="line"></span><br><span class="line">    if(*start == &#x27;\0&#x27;) &#123;</span><br><span class="line">        args[0] = NULL;</span><br><span class="line">        return 0;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    char* token;</span><br><span class="line">    char* saveptr;</span><br><span class="line">    char* p = start;</span><br><span class="line">    int inQuote = 0;</span><br><span class="line">    char quoteChar = 0;</span><br><span class="line"></span><br><span class="line">    while(cnt &lt; MAX_ARGS - 1 &amp;&amp; *p) &#123;</span><br><span class="line">        //除杂</span><br><span class="line">        while(*p == &#x27; &#x27; || *p == &#x27;\t&#x27;) p++;</span><br><span class="line">        if(*p == &#x27;\0&#x27;) break;</span><br><span class="line">        </span><br><span class="line">        if(*p == &#x27;&quot;&#x27; || *p == &#x27;\&#x27;&#x27;) &#123;</span><br><span class="line">            inQuote = 1;</span><br><span class="line">            quoteChar = *p;//确定为引号，供后续比较，确定区间</span><br><span class="line">            p++; // 跳过左引号</span><br><span class="line">            token = p;</span><br><span class="line">            </span><br><span class="line">            while(*p) &#123;</span><br><span class="line">                if(*p == quoteChar) &#123;</span><br><span class="line">                    // 如果是引号，检查前面是否是转义符</span><br><span class="line">                    if(*(p-1) != &#x27;\\&#x27;) &#123;</span><br><span class="line">                        break;  // 找到未被转义的右引号</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                p++;</span><br><span class="line">            &#125;</span><br><span class="line">            </span><br><span class="line">            if(*p == quoteChar) &#123;//找到右引号</span><br><span class="line">                *p = &#x27;\0&#x27;;</span><br><span class="line">                args[cnt++] = token;</span><br><span class="line">                p++;</span><br><span class="line">            &#125;</span><br><span class="line">            inQuote = 0;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            // 普通参数</span><br><span class="line">            token = p;</span><br><span class="line">            while(*p &amp;&amp; *p != &#x27; &#x27; &amp;&amp; *p != &#x27;\t&#x27;) p++;//除杂</span><br><span class="line">            if(*p) &#123;</span><br><span class="line">                *p = &#x27;\0&#x27;;</span><br><span class="line">                p++;</span><br><span class="line">            &#125;</span><br><span class="line">            args[cnt++] = token;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    args[cnt] = NULL;</span><br><span class="line"></span><br><span class="line">    return cnt;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    用来判断用户可能出现的错误。</span><br><span class="line">    用isError存储错误参数，</span><br><span class="line">    函数接受参数后执行对应错误码，给用户提示。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">void Error(int isError) &#123;</span><br><span class="line">    switch (isError) </span><br><span class="line">    &#123;</span><br><span class="line">    case 0:// 退出shell</span><br><span class="line">        printf(&quot;\n退出shell\n&quot;);</span><br><span class="line">        break;</span><br><span class="line">    </span><br><span class="line">    case 2:// 未获取到环境变量</span><br><span class="line">        printf(&quot;\n未获取到环境变量...\n&quot;);</span><br><span class="line">        break;</span><br><span class="line">    default:</span><br><span class="line">        break;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    shell进入的欢迎界面。</span><br><span class="line">    用了2个字符串指针，之后在两层for循环中，打印界面。</span><br><span class="line">    最后执行shell函数，进入shell内部。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">void FirstShow() &#123;</span><br><span class="line">    int time;</span><br><span class="line">    char flag = &#x27;#&#x27;;</span><br><span class="line">    char* wl = &quot;Welcome&quot;;</span><br><span class="line">    char* wl2 = &quot;Shell&quot;;</span><br><span class="line">    for(time = 1; time &lt;= 10; time++) &#123;</span><br><span class="line">        for(int i = 0; i &lt; 30; i++) &#123;</span><br><span class="line">            printf(&quot;%c&quot;,flag);</span><br><span class="line">            if((i == 29)) &#123;</span><br><span class="line">                printf(&quot;\n&quot;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        if(time == 10 / 2) &#123;</span><br><span class="line">            for(int i = 0; i &lt; 10; i++) &#123;</span><br><span class="line">                printf(&quot;%c&quot;,flag);</span><br><span class="line">            &#125;</span><br><span class="line">            printf(&quot;%s%s%s&quot;, COLOR_WELCOME, wl, COLOR_RESET);</span><br><span class="line">            for(int i = 0; i &lt; 13; i++) &#123;</span><br><span class="line">                printf(&quot;%c&quot;,flag);</span><br><span class="line">                if(i == 12) &#123;</span><br><span class="line">                    printf(&quot;\n&quot;);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            for(int i = 0; i &lt; 11; i++) &#123;</span><br><span class="line">                printf(&quot;%c&quot;,flag);</span><br><span class="line">            &#125;</span><br><span class="line">            printf(&quot;%s%s%s&quot;, COLOR_WELCOME, wl2, COLOR_RESET);</span><br><span class="line">            for(int i = 0; i &lt; 14; i++) &#123;</span><br><span class="line">                printf(&quot;%c&quot;,flag);</span><br><span class="line">                if(i == 13) &#123;</span><br><span class="line">                    printf(&quot;\n&quot;);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        usleep(50000);</span><br><span class="line">    &#125;;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    Shell();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">    shell的主体函数。</span><br><span class="line">    用command数组存储路径。</span><br><span class="line">    fork出子进程之后，把在子进程内部执行execve。</span><br><span class="line">    父进程等待子进程结束之后，继续保持shell状态，并且有Error错误判断。</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">void Shell() &#123;</span><br><span class="line">    char *args[MAX_ARGS];</span><br><span class="line">    char hostName[256];</span><br><span class="line">    char command[1024];</span><br><span class="line">    char currentPath[MAX_PATH];</span><br><span class="line">    char answer[10];</span><br><span class="line">    char* execpath = NULL;</span><br><span class="line">    pid_t pidChild;</span><br><span class="line">    int status, isback = 0;</span><br><span class="line"></span><br><span class="line">    while(1) &#123;</span><br><span class="line"></span><br><span class="line">        static char prevPath[MAX_PATH] = &quot;&quot;;</span><br><span class="line"></span><br><span class="line">        CheckBgProcess();</span><br><span class="line">        gethostname(hostName, 256);</span><br><span class="line">        if(getcwd(currentPath, MAX_PATH)) &#123;</span><br><span class="line"></span><br><span class="line">            printf(&quot;%s@%s-&gt;%s%s%s%s &quot;, COLOR_POINT, hostName, COLOR_RESET, COLOR_HIGHLIGHT, simpleCurrentPath(currentPath), COLOR_RESET);</span><br><span class="line">        &#125;else &#123;</span><br><span class="line">            printf(&quot;%s@%s-&gt;%s &quot;, COLOR_POINT, hostName, COLOR_RESET);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        fflush(stdout);</span><br><span class="line"></span><br><span class="line">        if(!fgets(command, sizeof(command), stdin)) &#123;</span><br><span class="line">            if(feof(stdin)) &#123;</span><br><span class="line">                printf(&quot;\n&quot;);</span><br><span class="line">                Error(0);</span><br><span class="line">                exit(EXIT_SUCCESS);</span><br><span class="line">            &#125;</span><br><span class="line">            continue;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        // 检查是否有未闭合的引号</span><br><span class="line">        int in_quote = 0;</span><br><span class="line">        char quote_char = 0;</span><br><span class="line">        size_t len = strlen(command);</span><br><span class="line">        </span><br><span class="line">        // 检查当前行的引号状态</span><br><span class="line">        for(int i = 0; i &lt; len; i++) &#123;</span><br><span class="line">            if(command[i] == &#x27;&quot;&#x27; || command[i] == &#x27;\&#x27;&#x27;) &#123;</span><br><span class="line">                if(!in_quote) &#123;</span><br><span class="line">                    in_quote = 1;</span><br><span class="line">                    quote_char = command[i];</span><br><span class="line">                &#125; else if(command[i] == quote_char &amp;&amp; (i == 0 || command[i-1] != &#x27;\\&#x27;)) &#123;</span><br><span class="line">                    in_quote = 0;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        // 如果引号未闭合，继续读取更多行</span><br><span class="line">        while(in_quote) &#123;</span><br><span class="line">            char more[1024];</span><br><span class="line">            fflush(stdout);</span><br><span class="line">            </span><br><span class="line">            if(!fgets(more, sizeof(more), stdin)) &#123;</span><br><span class="line">                break;</span><br><span class="line">            &#125;</span><br><span class="line">            </span><br><span class="line">            // 追加到 command</span><br><span class="line">            strncat(command, more, sizeof(command) - strlen(command) - 1);</span><br><span class="line">            </span><br><span class="line">            // 重新检查引号状态</span><br><span class="line">            len = strlen(command);</span><br><span class="line">            in_quote = 0;</span><br><span class="line">            for(int i = 0; i &lt; len; i++) &#123;</span><br><span class="line">                if(command[i] == &#x27;&quot;&#x27; || command[i] == &#x27;\&#x27;&#x27;) &#123;</span><br><span class="line">                    if(!in_quote) &#123;</span><br><span class="line">                        in_quote = 1;</span><br><span class="line">                        quote_char = command[i];</span><br><span class="line">                    &#125; else if(command[i] == quote_char &amp;&amp; (i == 0 || command[i-1] != &#x27;\\&#x27;)) &#123;</span><br><span class="line">                        in_quote = 0;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        // 移除末尾的换行符</span><br><span class="line">        len = strlen(command);</span><br><span class="line">        if (len &gt; 0 &amp;&amp; command[len - 1] == &#x27;\n&#x27;) &#123;</span><br><span class="line">            command[len - 1] = &#x27;\0&#x27;;</span><br><span class="line">            len--;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        if(strcmp(&quot;exit&quot;, command) == 0 || strcmp(&quot;quit&quot;, command) == 0) &#123;</span><br><span class="line">            if(bgpCount &gt; 0) &#123;</span><br><span class="line">                printf(&quot;当前后台还有 %d 个进程正在运行，是否要强行关闭? (y/n): &quot;, bgpCount);</span><br><span class="line">                if(fgets(answer, sizeof(answer), stdin)) &#123;</span><br><span class="line">                    if(answer[0] != &#x27;y&#x27; &amp;&amp; answer[0] != &#x27;Y&#x27;) &#123;</span><br><span class="line">                        continue;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            Error(0);</span><br><span class="line">            exit(EXIT_SUCCESS); </span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        // 添加jobs命令，显示后台任务</span><br><span class="line">        if (strcmp(&quot;jobs&quot;, command) == 0) &#123;</span><br><span class="line">            if (bgpCount == 0) &#123;</span><br><span class="line">                printf(&quot;没有后台进程\n&quot;);</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                printf(&quot;后台进程列表：\n&quot;);</span><br><span class="line">                for (int i = 0; i &lt; bgpCount; i++) &#123;</span><br><span class="line">                    printf(&quot;[%d] %d\t%s\t%s\n&quot;, </span><br><span class="line">                           i + 1, </span><br><span class="line">                           bgProcess[i].pid, </span><br><span class="line">                           bgProcess[i].isstillhere ? &quot;运行中&quot; : &quot;已完成&quot;,</span><br><span class="line">                           bgProcess[i].command);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            continue;</span><br><span class="line">        &#125;</span><br><span class="line">        if(strncmp(&quot;cd&quot;, command, 2) == 0 &amp;&amp; (command[2] == &#x27; &#x27; || command[2] == &#x27;\0&#x27;)) &#123;</span><br><span class="line">            ParseCommand(command, args, &amp;isback);</span><br><span class="line"></span><br><span class="line">            if(args[1] == NULL || strcmp(args[1], &quot;~&quot;) == 0) &#123;</span><br><span class="line">                char* home = getenv(&quot;HOME&quot;);</span><br><span class="line">                if(!home) &#123;</span><br><span class="line">                    Error(2);</span><br><span class="line">                &#125;else &#123;</span><br><span class="line">                    getcwd(prevPath, MAX_PATH);</span><br><span class="line">                    if(chdir(home) != 0) &#123;</span><br><span class="line">                        fprintf(stderr, &quot;cd: %s: 无法进入目录\n&quot;, home);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            else if (strcmp(args[1], &quot;-&quot;) == 0) &#123;</span><br><span class="line">                if (prevPath[0] == &#x27;\0&#x27;) &#123;</span><br><span class="line">                    getcwd(prevPath, MAX_PATH);</span><br><span class="line">                    continue;</span><br><span class="line">                &#125; else &#123;</span><br><span class="line">                    char tmpCurrentPath[MAX_PATH];</span><br><span class="line">                    if (getcwd(tmpCurrentPath, MAX_PATH)) &#123;</span><br><span class="line">                        if(chdir(prevPath) == 0) &#123;</span><br><span class="line">                            printf(&quot;%s\n&quot;, prevPath);</span><br><span class="line">                            strcpy(prevPath, tmpCurrentPath);</span><br><span class="line">                        &#125; else &#123;</span><br><span class="line">                            fprintf(stderr, &quot;cd: %s: 无法进入目录\n&quot;, prevPath);</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;else &#123;</span><br><span class="line">                char targetPath[MAX_PATH];</span><br><span class="line">                if(args[1][0] == &#x27;/&#x27;) &#123;</span><br><span class="line">                    strcpy(targetPath, args[1]);</span><br><span class="line">                &#125;else &#123;</span><br><span class="line">                    if(getcwd(targetPath, MAX_PATH)) &#123;</span><br><span class="line">                        strcpy(prevPath, targetPath);</span><br><span class="line">                        strcat(targetPath, &quot;/&quot;);</span><br><span class="line">                        strcat(targetPath, args[1]);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                if(chdir(args[1]) != 0) &#123;</span><br><span class="line">                    fprintf(stderr, &quot;cd: %s: 没有那个文件或目录\n&quot;, args[1]);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            continue;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        if(strchr(command, &#x27;|&#x27;) != NULL || strchr(command, &#x27;&gt;&#x27;) != NULL || strchr(command, &#x27;&lt;&#x27;) != NULL) &#123;</span><br><span class="line">            Command commands[MAX_PIPES];</span><br><span class="line">            ParseCommand(command, args, &amp;isback);</span><br><span class="line">            int cmdCount = HandlePipe(commands, command, args, &amp;isback);</span><br><span class="line"></span><br><span class="line">            if(cmdCount) &#123;</span><br><span class="line">                execPipe(commands, cmdCount, isback);</span><br><span class="line">            &#125;</span><br><span class="line">            continue;</span><br><span class="line">        &#125;else &#123;</span><br><span class="line">            ParseCommand(command, args, &amp;isback);</span><br><span class="line"></span><br><span class="line">            if(args[0] == NULL) &#123;</span><br><span class="line">                continue;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            execpath = SearchPath(args[0]);</span><br><span class="line"></span><br><span class="line">            if(execpath == NULL) &#123;</span><br><span class="line">                continue;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            switch (pidChild = fork())</span><br><span class="line">            &#123;</span><br><span class="line">            case -1:</span><br><span class="line">                perror(&quot;fork&quot;);</span><br><span class="line">                break;</span><br><span class="line">            </span><br><span class="line">            case 0:</span><br><span class="line">                if (isback) &#123;</span><br><span class="line">                    signal(SIGINT, SIG_IGN);</span><br><span class="line">                    signal(SIGQUIT, SIG_IGN);</span><br><span class="line">                &#125;</span><br><span class="line">                extern char** environ;</span><br><span class="line">                if(execve(execpath, args, environ) == -1) &#123;</span><br><span class="line">                    fprintf(stderr, &quot;shell: %s: 执行失败\n&quot;, args[0]);</span><br><span class="line">                    exit(1);</span><br><span class="line">                &#125;</span><br><span class="line">                break;</span><br><span class="line">            default:</span><br><span class="line">                if(isback) &#123;</span><br><span class="line">                    AddBgProcess(pidChild, command);</span><br><span class="line">                &#125;else &#123;</span><br><span class="line">                    waitpid(pidChild, &amp;status, 0);</span><br><span class="line">                &#125;</span><br><span class="line">                break;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://gmaxh.site/2026/03/10/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AE%9E%E7%8E%B0%20shell/</id>
    <link href="https://gmaxh.site/2026/03/10/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AE%9E%E7%8E%B0%20shell/"/>
    <published>2026-03-10T20:40:24.000Z</published>
    <summary>
      <![CDATA[<h2 id="用c语言实现自己的-shell"><a href="#用c语言实现自己的-shell" class="headerlink" title="用c语言实现自己的 shell"></a>用c语言实现自己的 shell</h2><h3 id="写在前面："><a hre]]>
    </summary>
    <title>在 Linux 系统中实现 shell</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="生活" scheme="https://gmaxh.site/categories/%E7%94%9F%E6%B4%BB/"/>
    <category term="日常倒霉趣事" scheme="https://gmaxh.site/tags/%E6%97%A5%E5%B8%B8%E5%80%92%E9%9C%89%E8%B6%A3%E4%BA%8B/"/>
    <content>
      <![CDATA[<h2 id="不要轻易修改你的linux系统，除非你一无所知"><a href="#不要轻易修改你的linux系统，除非你一无所知" class="headerlink" title="不要轻易修改你的linux系统，除非你一无所知"></a>不要轻易修改你的linux系统，除非你一无所知</h2><p>为什么突然想写这样一篇文章?  </p><ul><li><p>起因：<br>起初在小组，看到学长的hyprland如此生动有趣，值得把玩，那为什么我也不试一试呢？说时迟那时快，我直接打开chrome，搜索ubuntu安装hyprland。</p></li><li><p>发展：<br>果然，看到网上的预览效果十分震撼我弱小的心灵，对于一个linux新用户来说，一个可自定义的桌面十分吸引人。也没管是怎么个说法，就把这份脚本下载下来了。下载的时间十分漫长，足够一个193身高的人安安静静地吃完一份晚饭，顺便买瓶阿萨姆。当我回到了小组工位上，看到hyprland下载完成。我直接注销用户，切换桌面为hyprland。他终于来了。</p></li><li><p>高潮：<br>hyprland凭借着他的高自由度，和充满geek风格的桌面深深吸引了我，从waybar到终端，但还有一点小小的不足，我的双显示屏并不能正常使用。那好吧，经过一番设置，也还算成功，但，无论怎样，总会有一点点小瑕疵，让这个双显示屏的切换不够丝滑。之后询问了一下d老师，d老师说这是这样那样的问题，我信了，结果，整个桌面开始变得不再正常，从waybar到终端。甚至是24级的学长都无能为力，难道只能放弃了吗？犹豫再三，我选择重装系统，就是这么暴力。</p></li><li><p>结尾：<br>看似故事已经结束，但故事才刚刚开始。在之后的这几天内，我似乎陷入了while 1 循环，找不到循环结束条件。从安装linux mint 的Xfce版本，到安装ubuntu25.04 又升级到25.10，没有一次是称心如意的。经过我来来回回的装系统，删系统，甚至我的小u盘也败下阵来，一插入就开始显示不正常的消息。结果这场闹剧以安装ubuntu25.04收尾。</p></li><li><p>结语：<br>折腾是一件好事吗？这浪费了时间，没有真正意义上提升了代码编写能力和思考业务的能力，而且徒增烦恼。但也并非如此。还记得刷视频的时候，有位文学先生，对读书的意义作出了一份恰当的总结：”读书的意义并不在于记住什么知识，而是像喝水一样，补充养分，涵养精神。“计算机的学习也大概如此。</p></li></ul>]]>
    </content>
    <id>https://gmaxh.site/2025/12/22/%E4%B8%8D%E8%A6%81%E8%BD%BB%E6%98%93%E4%BF%AE%E6%94%B9%E4%BD%A0%E7%9A%84%20Linux%20%E7%B3%BB%E7%BB%9F%EF%BC%8C%E9%99%A4%E9%9D%9E%E4%BD%A0%E4%B8%80%E6%97%A0%E6%89%80%E7%9F%A5/</id>
    <link href="https://gmaxh.site/2025/12/22/%E4%B8%8D%E8%A6%81%E8%BD%BB%E6%98%93%E4%BF%AE%E6%94%B9%E4%BD%A0%E7%9A%84%20Linux%20%E7%B3%BB%E7%BB%9F%EF%BC%8C%E9%99%A4%E9%9D%9E%E4%BD%A0%E4%B8%80%E6%97%A0%E6%89%80%E7%9F%A5/"/>
    <published>2025-12-22T20:48:47.000Z</published>
    <summary>
      <![CDATA[<h2 id="不要轻易修改你的linux系统，除非你一无所知"><a href="#不要轻易修改你的linux系统，除非你一无所知" class="headerlink" title="不要轻易修改你的linux系统，除非你一无所知"></a>不要轻易修改你的linux系统，除]]>
    </summary>
    <title>不要轻易修改你的linux系统，除非你一无所知</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="Linux" scheme="https://gmaxh.site/categories/Linux/"/>
    <category term="Linux" scheme="https://gmaxh.site/tags/Linux/"/>
    <category term="C" scheme="https://gmaxh.site/tags/C/"/>
    <content>
      <![CDATA[<h2 id="用c语言实现自己的-sleep-命令"><a href="#用c语言实现自己的-sleep-命令" class="headerlink" title="用c语言实现自己的 sleep 命令"></a>用c语言实现自己的 sleep 命令</h2><h3 id="写在前面："><a href="#写在前面：" class="headerlink" title="写在前面："></a>写在前面：</h3><p>sleep是用于控制进程暂停的常用命令，本次我将使用系统调用函数，实现一个简单的sleep命令。</p><h3 id="功能："><a href="#功能：" class="headerlink" title="功能："></a>功能：</h3><ol><li>支持传入多个参数。</li><li>对于没有参数或这错误参数的情况，抛出错误。</li></ol><h3 id="基本思路："><a href="#基本思路：" class="headerlink" title="基本思路："></a>基本思路：</h3><ol><li>对于没有参数的情况，我直接抛出错误。</li><li>在处理参数的时候，我这里封装在了一个Howtime()的函数内部，可以使得处理参数更加方便，而由于参数是字符串形式传入，所以需要转换为整数形式。</li><li>面对负数，非阿拉伯数字等其他字符的时候，我选择抛出错误。</li><li>最后把所有时间加和，sleep。</li></ol><h3 id="源代码："><a href="#源代码：" class="headerlink" title="源代码："></a>源代码：</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;//fprintf()</span><br><span class="line">#include &lt;unistd.h&gt;//sleep()</span><br><span class="line">#include &lt;stdlib.h&gt;//exit()</span><br><span class="line"></span><br><span class="line">int Howtime(char* string);</span><br><span class="line"></span><br><span class="line">int main(int argc, char* argv[]) &#123; </span><br><span class="line">  int total_time = 0;</span><br><span class="line">  if(argc == 1) &#123;</span><br><span class="line">    fprintf(stderr, &quot;sleep: argument...\n&quot;);</span><br><span class="line">    exit(1);</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  for(int i = 1; i &lt; argc; i++) &#123;</span><br><span class="line">    int tmp = Howtime(argv[i]);</span><br><span class="line">    if(tmp &lt; 0) &#123;</span><br><span class="line">      fprintf(stderr, &quot;sleep:invalid time &#x27;%s&#x27;\n&quot;,argv[i]);</span><br><span class="line">    &#125;else &#123;</span><br><span class="line">      total_time += tmp;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  sleep(total_time);</span><br><span class="line">  </span><br><span class="line">  exit(0);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int Howtime(char* string) &#123;</span><br><span class="line">  if(string[0] == &#x27;-&#x27; || string[0] == &#x27;\0&#x27;) &#123;</span><br><span class="line">    return -1;</span><br><span class="line">  &#125;</span><br><span class="line">  int time = 0;</span><br><span class="line">  int i = 0;</span><br><span class="line">  while(string[i] != &#x27;\0&#x27;) &#123;</span><br><span class="line">    if(string[i] &lt; &#x27;0&#x27; &amp;&amp; string[i] &gt; &#x27;9&#x27;) &#123;</span><br><span class="line">      return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    time = time * 10 + (string[i] - &#x27;0&#x27;);</span><br><span class="line">    i++;</span><br><span class="line">  &#125;</span><br><span class="line">  return time;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://gmaxh.site/2025/11/18/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AE%9E%E7%8E%B0%20sleep%20%E5%91%BD%E4%BB%A4/</id>
    <link href="https://gmaxh.site/2025/11/18/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AE%9E%E7%8E%B0%20sleep%20%E5%91%BD%E4%BB%A4/"/>
    <published>2025-11-18T20:40:24.000Z</published>
    <summary>
      <![CDATA[<h2 id="用c语言实现自己的-sleep-命令"><a href="#用c语言实现自己的-sleep-命令" class="headerlink" title="用c语言实现自己的 sleep 命令"></a>用c语言实现自己的 sleep 命令</h2><h3 id="写]]>
    </summary>
    <title>在 Linux 系统中实现 sleep 命令</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="Linux" scheme="https://gmaxh.site/categories/Linux/"/>
    <category term="Linux" scheme="https://gmaxh.site/tags/Linux/"/>
    <category term="C" scheme="https://gmaxh.site/tags/C/"/>
    <content>
      <![CDATA[<h2 id="用c语言实现自己的-ls-命令"><a href="#用c语言实现自己的-ls-命令" class="headerlink" title="用c语言实现自己的 ls 命令"></a>用c语言实现自己的 ls 命令</h2><h3 id="写在前面："><a href="#写在前面：" class="headerlink" title="写在前面："></a>写在前面：</h3><p>ls是linux系统编程常用的命令行，可以实现对一个目录的展示，也可以加入不同的参数(l,a,R,……)，满足不同需求，下面是一个使用c语言编写的ls命令</p><h3 id="功能："><a href="#功能：" class="headerlink" title="功能："></a>功能：</h3><ol><li>实现了 ls 的 -a、-l、-R、-t、-r、-i、-s 参数，并允许这些参数任意组合。</li><li><code>-R</code> 可以对 <code>/</code> 遍历测试。</li><li>界面美观（输出对齐、带颜色显示等）。</li><li>无资源与内存泄漏。</li></ol><h3 id="基本思路："><a href="#基本思路：" class="headerlink" title="基本思路："></a>基本思路：</h3><ol><li>对于参数处理，我使用了宏定义，对每个参数设置了二进制位，全部的参数处理采用位运算，好处是节省空间，便于理解。</li><li>对于颜色显示，也使用了宏定义，对不同类型文件的设置不同颜色(此处请用ai搜索标准的颜色显示范例)，好处是便于理解，对于后期如果有需要改动的地方也很好改。</li><li>对于输出对齐，起初并没有思路，打算将目录下的文件放入一个自己手动malloc的堆内存里，但直到scandir()出现了。之后只需要获取到当前目录下的文件的最大字符宽度，根据该字符宽度占终端的实时宽度的比值，控制在第几次设置<code>\n</code>。</li><li>对于资源与内存泄漏：我直接使用了堆内存。</li><li>考虑完上述问题，剩下来的就是把这个目录展示出来，考虑到用户不会传递某个目录参数，所以对于没有目录参数的时候，需要展示当前目录下的文件，这里我使用了isfastoutput()函数。对于有目标目录的参数，需要获取到当前目录的路径，否则之后处理的时候都只是一个文件名，没有对应索引。这里使用了系统调用函数lstat()。而不使用stat()，使用lstat()的主要原因在于处理递归展示的时候，如果不使用lstat()，则会保存当前链接文件的指向，会陷入无限递归。而是用lstat()会剔除这些链接文件。</li><li>对于 <code>-R</code> 的实现：我在这里直接在listFiles()函数的尾部进行递归，并在每次递归中，分配一个适合大小的堆内存存储对应的文件，之后在释放文件。</li></ol><h3 id="源代码："><a href="#源代码：" class="headerlink" title="源代码："></a>源代码：</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;dirent.h&gt;</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;fcntl.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;sys/stat.h&gt;</span><br><span class="line">#include &lt;sys/ioctl.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;time.h&gt;</span><br><span class="line">#include &lt;inttypes.h&gt;</span><br><span class="line"></span><br><span class="line">// 掩码确定参数 </span><br><span class="line">#define Ca              0b1               // 显示隐藏文件排列</span><br><span class="line">#define Cl              0b10              // 详细排列</span><br><span class="line">#define CR              0b100             // 递归排列    </span><br><span class="line">#define Ct              0b1000            // 按照最新一次修改时间降序排列</span><br><span class="line">#define Cr              0b10000           // 逆序排列</span><br><span class="line">#define Ci              0b100000          // 显示inode编号排列</span><br><span class="line">#define Cs              0b1000000         // 显示已用内存块数量排列</span><br><span class="line"></span><br><span class="line">// 确定颜色</span><br><span class="line">#define COLOR_RESET     &quot;\033[0m&quot;</span><br><span class="line">#define COLOR_DIR       &quot;\033[1;34m&quot;    // 粗体蓝色</span><br><span class="line">#define COLOR_EXE       &quot;\033[1;32m&quot;    // 粗体绿色</span><br><span class="line">#define COLOR_LINK      &quot;\033[1;36m&quot;    // 粗体青色</span><br><span class="line">#define COLOR_SOCKET    &quot;\033[1;35m&quot;    // 粗体紫色（socket）</span><br><span class="line">#define COLOR_PIPE      &quot;\033[33m&quot;      // 黄色（管道）</span><br><span class="line">#define COLOR_BLOCK     &quot;\033[1;33m&quot;    // 粗体黄色（块设备：u盘，固态)</span><br><span class="line">#define COLOR_CHAR      &quot;\033[1;33m&quot;    // 粗体黄色（字符设备:键鼠）</span><br><span class="line"></span><br><span class="line">void listFiles(const char*, int, int);//根据参数，普通列出目录下的文件</span><br><span class="line">void printWithis(int, struct stat*, int, struct dirent**);//显示</span><br><span class="line">int isfastoutput(int, char*[]);//命令行中传入的参数是否只有该可执行文件</span><br><span class="line">int whatCommand(int, char*[]);//确定参数</span><br><span class="line">int CompareListNormal(const struct dirent**, const struct dirent**);//按照字符顺序排列</span><br><span class="line">int CompareListTime(const struct dirent**, const struct dirent**);//按照最新一次修改时间排列</span><br><span class="line">int HowManyDirpath(int, char*[]);//确定目标路径的数量</span><br><span class="line">int shouldPrintA(int, struct dirent*);//是否需要打印隐藏文件</span><br><span class="line">int maxFileLength(int, struct dirent**, int, int);//确定每个文件的宽度</span><br><span class="line">char* getColor(struct stat);//返回颜色</span><br><span class="line"></span><br><span class="line">int main(int argc, char* argv[]) &#123;</span><br><span class="line">    int tmpargc = HowManyDirpath(argc, argv);</span><br><span class="line">    if(isfastoutput(argc,argv)) &#123;</span><br><span class="line">        int command = whatCommand(argc, argv);</span><br><span class="line">        listFiles(&quot;.&quot;, command, tmpargc);</span><br><span class="line">        printf(&quot;\n&quot;);</span><br><span class="line">    &#125;else &#123;</span><br><span class="line">        int command = whatCommand(argc, argv);</span><br><span class="line">        for(int i = 1; i &lt; argc; i++) &#123;</span><br><span class="line">            listFiles(argv[i], command, tmpargc);</span><br><span class="line">            printf(&quot;\n&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    exit(EXIT_SUCCESS);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">char* getColor(struct stat st) &#123;</span><br><span class="line">    char* color = COLOR_RESET;</span><br><span class="line">    if(S_ISDIR(st.st_mode)) color = COLOR_DIR;</span><br><span class="line">    else if(S_ISLNK(st.st_mode)) color = COLOR_LINK;</span><br><span class="line">    else if(S_ISSOCK(st.st_mode)) color = COLOR_SOCKET;</span><br><span class="line">    else if(S_ISFIFO(st.st_mode)) color = COLOR_PIPE;</span><br><span class="line">    else if(S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) color = COLOR_BLOCK;</span><br><span class="line">    else if(st.st_mode &amp; (S_IXUSR | S_IXGRP | S_IXOTH)) color = COLOR_EXE;</span><br><span class="line">    return color;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int CompareListTime(const struct dirent** a, const struct dirent** b) &#123;</span><br><span class="line">    struct stat sta, stb;</span><br><span class="line">    lstat((*a)-&gt;d_name, &amp;sta);lstat((*b)-&gt;d_name, &amp;stb);</span><br><span class="line">    return sta.st_mtime &gt;= stb.st_mtime ? -1 : 1;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int isfastoutput(int argc, char* argv[]) &#123;</span><br><span class="line">    int cnt = 0;        </span><br><span class="line">    for(int i = 1; i &lt; argc; i++) if(argv[i][0] == &#x27;-&#x27;) cnt++;</span><br><span class="line">    if(cnt == argc - 1) return 1;</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void listFiles(const char* dirpath, int command, int tmpargc) &#123;</span><br><span class="line">    if(dirpath[0] == &#x27;-&#x27;) return;</span><br><span class="line">    if(access(dirpath, F_OK | X_OK) != 0) &#123;</span><br><span class="line">        fprintf(stderr, &quot;无法访问 &#x27;%s&#x27;: 没有那个文件或目录\n&quot;, dirpath);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    int n, maxLength, maxName, Time, enter = 2,fullpath_size = 1024 , term_width = 80;//默认</span><br><span class="line">    long long sum = 0;</span><br><span class="line">    struct dirent** dp;</span><br><span class="line">    struct stat st;</span><br><span class="line">    struct winsize w;</span><br><span class="line">    char* fullpath = (char*)malloc(sizeof(char) * fullpath_size);</span><br><span class="line">    if(command &amp; Ct) n = scandir(dirpath, &amp;dp, NULL, CompareListTime);</span><br><span class="line">    else n = scandir(dirpath, &amp;dp, NULL, CompareListNormal);</span><br><span class="line">    if(n &lt; 0 &amp;&amp; dirpath[0]) &#123;</span><br><span class="line">        perror(&quot;scandir&quot;);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    if(tmpargc &gt; 1) printf(&quot;%s:\n&quot;,dirpath);</span><br><span class="line">    if(command &amp; Cs) &#123;</span><br><span class="line">        for(int i = 0; i &lt; n; ++i) &#123;</span><br><span class="line">            snprintf(fullpath, fullpath_size, &quot;%s/%s&quot;, dirpath, dp[i]-&gt;d_name);</span><br><span class="line">            lstat(fullpath, &amp;st);</span><br><span class="line">            if(!shouldPrintA(command, dp[i])) continue;</span><br><span class="line">            sum += st.st_blocks / 2;</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;总计 %lld\n&quot;,sum);</span><br><span class="line">    &#125;</span><br><span class="line">    if(!(command &amp; Cl)) &#123;//根据是否需要详细排列，分成两种方案</span><br><span class="line">        if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &amp;w) == 0)term_width = w.ws_col;</span><br><span class="line">        maxLength = maxFileLength(command, dp, n, 0);</span><br><span class="line">        maxName = maxFileLength(command, dp, n, 3);</span><br><span class="line">        Time = term_width / (maxLength + 4);</span><br><span class="line">        Time = Time &lt;= 0 ? 1 : Time;</span><br><span class="line">        for(int i = 0; i &lt; n &amp;&amp; !(command &amp; Cr); i++) &#123;</span><br><span class="line">            snprintf(fullpath, fullpath_size, &quot;%s/%s&quot;, dirpath, dp[i]-&gt;d_name);//将几个字符串以整体的形式送到缓冲区，且函数本身可以防止溢出</span><br><span class="line">            lstat(fullpath, &amp;st);//获取文件详细信息</span><br><span class="line">            if(!shouldPrintA(command, dp[i])) continue;</span><br><span class="line">            if(enter &gt; Time &amp;&amp; i != 0) printf(&quot;\n&quot;);</span><br><span class="line">            printWithis(command, &amp;st, n, dp);</span><br><span class="line">            if(enter &lt;= Time) &#123;</span><br><span class="line">                printf(&quot;%s%*s%s  &quot;, getColor(st), maxName, dp[i]-&gt;d_name, COLOR_RESET);</span><br><span class="line">                enter++;</span><br><span class="line">            &#125;</span><br><span class="line">            else &#123;</span><br><span class="line">                printf(&quot;%s%*s%s  &quot;, getColor(st), maxName, dp[i]-&gt;d_name, COLOR_RESET);</span><br><span class="line">                enter = 2;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        for(int i = n - 1; i &gt;= 0 &amp;&amp; (command &amp; Cr); i--) &#123;</span><br><span class="line">            snprintf(fullpath, fullpath_size, &quot;%s/%s&quot;, dirpath, dp[i]-&gt;d_name);//将几个字符串以整体的形式送到缓冲区，且函数本身可以防止溢出</span><br><span class="line">            lstat(fullpath, &amp;st);//获取文件详细信息</span><br><span class="line">            if(!shouldPrintA(command, dp[i])) continue;</span><br><span class="line">            if(enter &gt; Time &amp;&amp; i !=  n - 1) printf(&quot;\n&quot;);</span><br><span class="line">            printWithis(command, &amp;st, n, dp);</span><br><span class="line">            if(enter &lt;= Time) &#123;</span><br><span class="line">                printf(&quot;%s%*s%s  &quot;, getColor(st), maxName, dp[i]-&gt;d_name, COLOR_RESET);</span><br><span class="line">                enter++;</span><br><span class="line">            &#125;</span><br><span class="line">            else &#123;</span><br><span class="line">                printf(&quot;%s%*s%s  &quot;, getColor(st), maxName, dp[i]-&gt;d_name, COLOR_RESET);</span><br><span class="line">                enter = 2;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    else &#123;</span><br><span class="line">        char* tmbuffer = (char*)malloc(sizeof(char) * 80);</span><br><span class="line">        struct stat st;</span><br><span class="line">        struct tm* tm;</span><br><span class="line">        struct passwd* pw;</span><br><span class="line">        struct group* gr;</span><br><span class="line">        char str[11];</span><br><span class="line">        for(int i = 0 ; i &lt; n &amp;&amp; !(command &amp; Cr); i++) &#123;</span><br><span class="line">            snprintf(fullpath, fullpath_size, &quot;%s/%s&quot;, dirpath, dp[i]-&gt;d_name);</span><br><span class="line">            lstat(fullpath, &amp;st);</span><br><span class="line">            if(!shouldPrintA(command, dp[i])) continue;</span><br><span class="line">            printWithis(command, &amp;st, n, dp);</span><br><span class="line">            str[0] = &#x27;?&#x27;;</span><br><span class="line">            if(S_ISDIR(st.st_mode)) str[0] = &#x27;d&#x27;;</span><br><span class="line">            else if(S_ISLNK(st.st_mode)) str[0] = &#x27;l&#x27;;</span><br><span class="line">            else if(S_ISSOCK(st.st_mode)) str[0] = &#x27;s&#x27;;</span><br><span class="line">            else if(S_ISFIFO(st.st_mode)) str[0] = &#x27;p&#x27;;</span><br><span class="line">            else if(S_ISBLK(st.st_mode)) str[0] = &#x27;b&#x27;;</span><br><span class="line">            else if(S_ISCHR(st.st_mode)) str[0] = &#x27;c&#x27;;</span><br><span class="line">            else str[0] = &#x27;-&#x27;;</span><br><span class="line">            str[1] = (st.st_mode &amp; S_IRUSR) ? &#x27;r&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[2] = (st.st_mode &amp; S_IWUSR) ? &#x27;w&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[3] = (st.st_mode &amp; S_IXUSR) ? &#x27;x&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[4] = (st.st_mode &amp; S_IRGRP) ? &#x27;r&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[5] = (st.st_mode &amp; S_IWGRP) ? &#x27;w&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[6] = (st.st_mode &amp; S_IXGRP) ? &#x27;x&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[7] = (st.st_mode &amp; S_IROTH) ? &#x27;r&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[8] = (st.st_mode &amp; S_IWOTH) ? &#x27;w&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[9] = (st.st_mode &amp; S_IXOTH) ? &#x27;x&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[10] = &#x27;\0&#x27;;</span><br><span class="line">            tm = localtime(&amp;st.st_mtime);</span><br><span class="line">            strftime(tmbuffer, fullpath_size, &quot;%m月 %H:%M&quot;, tm);</span><br><span class="line">            pw = getpwuid(st.st_uid);</span><br><span class="line">            gr = getgrgid(st.st_gid);</span><br><span class="line">            printf(&quot;%s %lu %s %s %ld %s %s%s%s\n&quot;, str, st.st_nlink, pw-&gt;pw_name, gr-&gt;gr_name, st.st_size, tmbuffer, getColor(st), dp[i]-&gt;d_name, COLOR_RESET);</span><br><span class="line">        &#125;</span><br><span class="line">        for(int i = n - 1 ; i &gt;= 0 &amp;&amp; (command &amp; Cr); i--) &#123;</span><br><span class="line">            snprintf(fullpath, fullpath_size, &quot;%s/%s&quot;, dirpath, dp[i]-&gt;d_name);</span><br><span class="line">            lstat(fullpath, &amp;st);</span><br><span class="line">            if(!shouldPrintA(command, dp[i])) continue;</span><br><span class="line">            printWithis(command, &amp;st, n, dp);</span><br><span class="line">            str[0] = &#x27;?&#x27;;</span><br><span class="line">            if(S_ISDIR(st.st_mode)) str[0] = &#x27;d&#x27;;</span><br><span class="line">            else if(S_ISLNK(st.st_mode)) str[0] = &#x27;l&#x27;;</span><br><span class="line">            else if(S_ISSOCK(st.st_mode)) str[0] = &#x27;s&#x27;;</span><br><span class="line">            else if(S_ISFIFO(st.st_mode)) str[0] = &#x27;p&#x27;;</span><br><span class="line">            else if(S_ISBLK(st.st_mode)) str[0] = &#x27;b&#x27;;</span><br><span class="line">            else if(S_ISCHR(st.st_mode)) str[0] = &#x27;c&#x27;;</span><br><span class="line">            else str[0] = &#x27;-&#x27;;</span><br><span class="line">            str[1] = (st.st_mode &amp; S_IRUSR) ? &#x27;r&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[2] = (st.st_mode &amp; S_IWUSR) ? &#x27;w&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[3] = (st.st_mode &amp; S_IXUSR) ? &#x27;x&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[4] = (st.st_mode &amp; S_IRGRP) ? &#x27;r&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[5] = (st.st_mode &amp; S_IWGRP) ? &#x27;w&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[6] = (st.st_mode &amp; S_IXGRP) ? &#x27;x&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[7] = (st.st_mode &amp; S_IROTH) ? &#x27;r&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[8] = (st.st_mode &amp; S_IWOTH) ? &#x27;w&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[9] = (st.st_mode &amp; S_IXOTH) ? &#x27;x&#x27; : &#x27;-&#x27;;</span><br><span class="line">            str[10] = &#x27;\0&#x27;;</span><br><span class="line">            tm = localtime(&amp;st.st_mtime);</span><br><span class="line">            strftime(tmbuffer, fullpath_size, &quot;%m月 %H:%M&quot;, tm);</span><br><span class="line">            pw = getpwuid(st.st_uid);</span><br><span class="line">            gr = getgrgid(st.st_gid);</span><br><span class="line">            printf(&quot;%s %lu &quot;, str, st.st_nlink);</span><br><span class="line">            if(!pw) printf(&quot;%d &quot;,st.st_uid);</span><br><span class="line">            else printf(&quot;%s &quot;,pw-&gt;pw_name);</span><br><span class="line">            if(!gr) printf(&quot;%d &quot;,st.st_gid);</span><br><span class="line">            else printf(&quot;%s &quot;,gr-&gt;gr_name);</span><br><span class="line">            printf(&quot;%ld %s %s%s%s\n&quot;, st.st_size, tmbuffer, getColor(st), dp[i]-&gt;d_name, COLOR_RESET);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    if(command &amp; CR) &#123;</span><br><span class="line">        int Rarr_size = 1024;</span><br><span class="line">        char** Rarr  = (char**)malloc(sizeof(char*) * Rarr_size);</span><br><span class="line">        int count = 0;</span><br><span class="line">        for(int i = 0; i &lt; n &amp;&amp; !(command &amp; Cr); i++) &#123;</span><br><span class="line">            if(strcmp(dp[i]-&gt;d_name, &quot;.&quot;) == 0 || strcmp(dp[i]-&gt;d_name, &quot;..&quot;) == 0) continue;</span><br><span class="line">            snprintf(fullpath, fullpath_size, &quot;%s/%s&quot;, dirpath, dp[i]-&gt;d_name);</span><br><span class="line">            lstat(fullpath, &amp;st);</span><br><span class="line">            if(S_ISDIR(st.st_mode) &amp;&amp; shouldPrintA(command, dp[i])) &#123;</span><br><span class="line">                if((int)strlen(fullpath) &gt;= (fullpath_size + 1)) &#123;</span><br><span class="line">                    fullpath_size *= 2;</span><br><span class="line">                    fullpath = (char*)realloc(fullpath, sizeof(char) * fullpath_size);</span><br><span class="line">                &#125;</span><br><span class="line">                Rarr[count] = (char*)malloc(sizeof(char) * (fullpath_size + 1));</span><br><span class="line">                strcpy(Rarr[count], fullpath);</span><br><span class="line">                count++;</span><br><span class="line">                if(count &gt;= Rarr_size) &#123;</span><br><span class="line">                    Rarr_size *= 2;</span><br><span class="line">                    Rarr = (char**)realloc(Rarr, sizeof(char*) * Rarr_size);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        for(int i = n - 1; i &gt;= 0 &amp;&amp; command &amp; Cr; i--) &#123;</span><br><span class="line">            if(strcmp(dp[i]-&gt;d_name, &quot;.&quot;) == 0 || strcmp(dp[i]-&gt;d_name, &quot;..&quot;) == 0) continue;</span><br><span class="line">            snprintf(fullpath, fullpath_size, &quot;%s/%s&quot;, dirpath, dp[i]-&gt;d_name);</span><br><span class="line">            lstat(fullpath, &amp;st);</span><br><span class="line">            if(S_ISDIR(st.st_mode) &amp;&amp; shouldPrintA(command, dp[i])) &#123;</span><br><span class="line">                if((int)strlen(fullpath) &gt;= (fullpath_size + 1)) &#123;</span><br><span class="line">                    fullpath_size *= 2;</span><br><span class="line">                    fullpath = (char*)realloc(fullpath, sizeof(char) * fullpath_size);</span><br><span class="line">                &#125;</span><br><span class="line">                Rarr[count] = (char*)malloc(sizeof(char) * fullpath_size + 1);</span><br><span class="line">                strcpy(Rarr[count], fullpath);</span><br><span class="line">                count++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        for(int i = 0; i &lt; count; i++) &#123;</span><br><span class="line">            printf(&quot;\n%s:\n&quot;, Rarr[i]);</span><br><span class="line">            listFiles(Rarr[i], command, tmpargc);</span><br><span class="line">        &#125;</span><br><span class="line">        for(int i = 0; i &lt; count; i++) free(Rarr[i]);</span><br><span class="line">        free(Rarr);</span><br><span class="line">    &#125;</span><br><span class="line">    for(int i = 0; i &lt; n; i++) free(dp[i]);</span><br><span class="line">    free(dp);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int whatCommand(int argc, char* argv[]) &#123;</span><br><span class="line">    int command = 0, enter = 1;</span><br><span class="line">    if(argc == 1) return 0;</span><br><span class="line">    for(int i = 1; i &lt; argc; ++i) &#123;</span><br><span class="line">        if(argv[i][0] != &#x27;-&#x27;) continue;</span><br><span class="line">        else &#123;</span><br><span class="line">            while(argv[i][enter] != &#x27;\0&#x27;) &#123;</span><br><span class="line">                switch (argv[i][enter++]) &#123;</span><br><span class="line">                    case &#x27;a&#x27;:command |= Ca;break;</span><br><span class="line">                    case &#x27;l&#x27;:command |= Cl;break;</span><br><span class="line">                    case &#x27;R&#x27;:command |= CR;break;</span><br><span class="line">                    case &#x27;t&#x27;:command |= Ct;break;</span><br><span class="line">                    case &#x27;r&#x27;:command |= Cr;break;</span><br><span class="line">                    case &#x27;i&#x27;:command |= Ci;break;</span><br><span class="line">                    case &#x27;s&#x27;:command |= Cs;break;</span><br><span class="line">                    default:fprintf(stderr, &quot;可用选项：-a, -l, -R, -t, -r, -i, -s\n&quot;);</span><br><span class="line">                       exit(EXIT_FAILURE);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    return command;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int CompareListNormal(const struct dirent** a, const struct dirent** b) &#123;</span><br><span class="line">    return strcmp((*a)-&gt;d_name, (*b)-&gt;d_name);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void printWithis(int command, struct stat* st, int n, struct dirent** dpall) &#123;</span><br><span class="line">    if(command &amp; Ci) &#123;</span><br><span class="line">        int mask = 1;</span><br><span class="line">        long int tmp = st-&gt;st_ino;</span><br><span class="line">        do &#123;</span><br><span class="line">            tmp /= 10;</span><br><span class="line">            mask++;</span><br><span class="line">        &#125;while(tmp &gt; 9);</span><br><span class="line">        int length = maxFileLength(command, dpall, n, 1);</span><br><span class="line"></span><br><span class="line">        printf(&quot;%*lu &quot;, length, st-&gt;st_ino);</span><br><span class="line">    &#125;</span><br><span class="line">    if(command &amp; Cs) &#123;</span><br><span class="line">        int mask = 1;</span><br><span class="line">        long int tmp = st-&gt;st_blocks / 2;</span><br><span class="line">        do &#123;</span><br><span class="line">            tmp /= 10;</span><br><span class="line">            mask++;</span><br><span class="line">        &#125;while(tmp &gt; 9);</span><br><span class="line">        int length = maxFileLength(command, dpall, n, 2);</span><br><span class="line"></span><br><span class="line">        printf(&quot;%*ld &quot;, length, st-&gt;st_blocks / 2);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int HowManyDirpath(int argc, char* argv[]) &#123;</span><br><span class="line">    int cnt = 0;</span><br><span class="line">    for(int i = 1; i &lt; argc; i++) if(argv[i][0] != &#x27;-&#x27;) cnt++;</span><br><span class="line">    return cnt;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int shouldPrintA(int command, struct dirent* dp) &#123;</span><br><span class="line">    if(dp-&gt;d_name[0] == &#x27;.&#x27; || strcmp(dp-&gt;d_name, &quot;..&quot;) == 0) return (command &amp; Ca);</span><br><span class="line">    return 1;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int maxFileLength(int command, struct dirent** dp, int n, int res) &#123;</span><br><span class="line">    int max_name = 0, max_i = 0, max_s = 0, r = 0;</span><br><span class="line">    struct stat st;</span><br><span class="line">    for(int i = 0; i &lt; n; ++i) &#123;</span><br><span class="line">        if(!shouldPrintA(command, dp[i])) continue;</span><br><span class="line">        max_name = ((int)strlen(dp[i]-&gt;d_name) &gt;= max_name ) ? (int)strlen(dp[i]-&gt;d_name) : max_name;</span><br><span class="line">    &#125;</span><br><span class="line">    for(int i = 0; i &lt; n &amp;&amp; command &amp; Ci; ++i) &#123;</span><br><span class="line">        if(!shouldPrintA(command, dp[i])) continue;</span><br><span class="line">        int mask = 1;</span><br><span class="line">        int tmp = dp[i]-&gt;d_ino;</span><br><span class="line">        do &#123;</span><br><span class="line">            tmp /= 10;</span><br><span class="line">            mask++;</span><br><span class="line">        &#125;while(tmp &gt; 9);</span><br><span class="line">        max_i = mask &gt;= max_i ? mask : max_i;</span><br><span class="line">    &#125;</span><br><span class="line">    for(int i = 0; i &lt; n &amp;&amp; command &amp; Cs; ++i) &#123;</span><br><span class="line">        if(!shouldPrintA(command, dp[i])) continue;</span><br><span class="line">        lstat(dp[i]-&gt;d_name, &amp;st);</span><br><span class="line">        int mask = 1;</span><br><span class="line">        int tmp = st.st_blocks;</span><br><span class="line">        do &#123;</span><br><span class="line">            tmp /= 10;</span><br><span class="line">            mask++;</span><br><span class="line">        &#125;while(tmp &gt; 9);</span><br><span class="line">        max_s = mask &gt;= max_s ? mask : max_s;</span><br><span class="line">    &#125;</span><br><span class="line">    switch (res) &#123;</span><br><span class="line">        case 0:r = max_name + max_i + max_s;break;</span><br><span class="line">        case 1:r = max_i;break;</span><br><span class="line">        case 2:r = max_s;break;</span><br><span class="line">        case 3:r = max_name;break;</span><br><span class="line">    &#125;</span><br><span class="line">    return r; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://gmaxh.site/2025/11/17/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AE%9E%E7%8E%B0%20ls%20%E5%91%BD%E4%BB%A4/</id>
    <link href="https://gmaxh.site/2025/11/17/%E5%9C%A8%20Linux%20%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AE%9E%E7%8E%B0%20ls%20%E5%91%BD%E4%BB%A4/"/>
    <published>2025-11-17T20:40:24.000Z</published>
    <summary>
      <![CDATA[<h2 id="用c语言实现自己的-ls-命令"><a href="#用c语言实现自己的-ls-命令" class="headerlink" title="用c语言实现自己的 ls 命令"></a>用c语言实现自己的 ls 命令</h2><h3 id="写在前面："><a hre]]>
    </summary>
    <title>在 Linux 系统中实现 ls 命令</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="Linux" scheme="https://gmaxh.site/categories/Linux/"/>
    <category term="Linux" scheme="https://gmaxh.site/tags/Linux/"/>
    <category term="C" scheme="https://gmaxh.site/tags/C/"/>
    <content>
      <![CDATA[<h1 id="西邮-Linux-兴趣小组-2023-纳新面试题"><a href="#西邮-Linux-兴趣小组-2023-纳新面试题" class="headerlink" title="西邮 Linux 兴趣小组 2023 纳新面试题"></a>西邮 Linux 兴趣小组 2023 纳新面试题</h1><blockquote><p>学长寄语：长期以来，西邮Linux兴趣小组的面试题以难度之高名扬西邮校内。我们作为出题人也清楚的知道这份试题略有难度。请你动手敲一下代码。别担心，若有同学能完成一半的题目，就已经十分优秀。其次，相比于题目的答案，我们对你的思路和过程更感兴趣，或许你的答案略有瑕疵，但你正确的思路和对知识的理解足以为你赢得绝大多数的分数。最后，做题的过程也是学习和成长的过程，相信本试题对你更加熟悉的掌握C语言的一定有所帮助。祝你好运。我们东区逸夫楼FZ103见</p></blockquote><ul><li>本题目只作为西邮 Linux 兴趣小组 2023 纳新面试的有限参考。</li><li>为节省版面，本试题的程序源码省去了 <code>#include</code> 指令。</li><li>本试题中的程序源码仅用于考察 C 语言基础，不应当作为 C 语言「代码风格」的范例。</li><li>所有题目编译并运行于 <em>x86_64 GNU&#x2F;Linux</em> 环境。</li></ul><h2 id="0-鼠鼠我啊，要被祸害了"><a href="#0-鼠鼠我啊，要被祸害了" class="headerlink" title="0. 鼠鼠我啊，要被祸害了"></a>0. 鼠鼠我啊，要被祸害了</h2><p>有1000瓶水，其中有一瓶有毒，小白鼠只要尝一点带毒的水，24小时后就会准时死亡。至少要多少只小白鼠才能在24小时内鉴别出哪瓶水有毒？  </p><p><strong>题解：</strong></p><ul><li>代码：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">#include&lt;stdio.h&gt;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int b;</span><br><span class="line">    scanf(&quot;%d&quot;,&amp;b);//毒药编号</span><br><span class="line">    int number=0;</span><br><span class="line">    while(b&gt;0)</span><br><span class="line">    &#123;</span><br><span class="line">        if(b&amp;1)</span><br><span class="line">        &#123;</span><br><span class="line">            number++;</span><br><span class="line">        &#125;</span><br><span class="line">        b&gt;&gt;=1;</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;%d&quot;,number);//小鼠数量</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>解释：</li></ul><ol><li>由于有1000瓶药水，而$2^{10}$&gt;1000，故至少需要10只小鼠。</li></ol><ul><li>考点：<br> 通过数学工具来解决实际问题的能力</li></ul><h2 id="1-先预测一下"><a href="#1-先预测一下" class="headerlink" title="1. 先预测一下~"></a>1. 先预测一下~</h2><p>按照函数要求输入自己的姓名试试~  </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">char *welcome() &#123;</span><br><span class="line">    // 请你返回自己的姓名</span><br><span class="line">&#125;</span><br><span class="line">int main(void) &#123;</span><br><span class="line">    char *a = welcome();</span><br><span class="line">    printf(&quot;Hi, 我相信 %s 可以面试成功!\n&quot;, a);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li>代码：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">#include&lt;stdio.h&gt;</span><br><span class="line"></span><br><span class="line">char *welcome() &#123;</span><br><span class="line">    return &quot;FRiver&quot;;</span><br><span class="line">&#125;</span><br><span class="line">int main(void) &#123;</span><br><span class="line">    char *a = welcome();</span><br><span class="line">    printf(&quot;Hi, 我相信 %s 可以面试成功!\n&quot;, a);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p>输出结果：<br> <code>Hi, 我相信 FRiver 可以面试成功!</code>  </p></li><li><p>解释：</p></li></ul><ol><li>在welcome()函数内，返回为一个字符串，这个字符串地址被保存在*a内。</li><li>之后在printf函数内打印这个字符串。</li></ol><ul><li>考点：<br> 字符串</li></ul><h2 id="2-欢迎来到Linux兴趣小组"><a href="#2-欢迎来到Linux兴趣小组" class="headerlink" title="2. 欢迎来到Linux兴趣小组"></a>2. 欢迎来到Linux兴趣小组</h2><p>有趣的输出，为什么会这样子呢~<br>你了解 <code>sizeof()</code> 和 <code>strlen()</code> 吗？他们的区别是什么？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">int main(void) &#123;</span><br><span class="line">    char *ptr0 = &quot;Welcome to Xiyou Linux!&quot;;</span><br><span class="line">    char ptr1[] = &quot;Welcome to Xiyou Linux!&quot;;</span><br><span class="line">    if (*ptr0 == *ptr1) &#123;</span><br><span class="line">      printf(&quot;%d\n&quot;, printf(&quot;Hello, Linux Group - 2%d&quot;, printf(&quot;&quot;)));</span><br><span class="line">    &#125;</span><br><span class="line">    int diff = ptr0 - ptr1;</span><br><span class="line">    printf(&quot;Pointer Difference: %d\n&quot;, diff);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>Hello, Linux Group - 2023</code><br> <code>Pointer Difference: 473149860(随着每次编译而变化)</code>  </p></li><li><p>解释：</p></li></ul><ol><li><code>printf</code>函数内嵌套了一些<code>printf</code>函数，每个函数的返回值为其需要打印内容的字符长度。由于<code>*ptr0</code>和<code>*ptr1</code>均为<code>‘W’</code>，故相等。在<code>diff</code>变量下，保存了p<code>tr0</code>和<code>ptr1</code>的差值，由于<code>ptr1</code>是一个数组，他保存在栈上，<code>ptr2</code>指向的是一个字符串字面量，具有静态存储期。故差值不定。</li><li>sizeof()运算符计算对象所占内存的大小或一个数据结构的大小。strlen()函数计算字符串的字符长度。</li></ol><ul><li>考点：<br> printf函数返回值、存储期、sizeof()、strlen()</li></ul><h2 id="3-一切都翻倍了吗"><a href="#3-一切都翻倍了吗" class="headerlink" title="3. 一切都翻倍了吗"></a>3. 一切都翻倍了吗</h2><ol><li>请尝试解释一下程序的输出。  </li><li>请谈谈对<code>sizeof()</code>和<code>strlen()</code>的理解吧。  </li><li>什么是<code>sprintf()</code>，它的参数以及返回值又是什么呢？</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">int main(void) &#123;</span><br><span class="line">    char arr[] = &#123;&#x27;L&#x27;, &#x27;i&#x27;, &#x27;n&#x27;, &#x27;u&#x27;, &#x27;x&#x27;, &#x27;\0&#x27;, &#x27;!&#x27;&#125;, str[20];</span><br><span class="line">    short num = 520;</span><br><span class="line">    int num2 = 1314;</span><br><span class="line">    printf(&quot;%zu\t%zu\t%zu\n&quot;, sizeof(*&amp;arr), sizeof(arr + 0),</span><br><span class="line">           sizeof(num = num2 + 4));</span><br><span class="line">    printf(&quot;%d\n&quot;, sprintf(str, &quot;0x%x&quot;, num) == num);</span><br><span class="line">    printf(&quot;%zu\t%zu\n&quot;, strlen(&amp;str[0] + 1), strlen(arr + 0));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>7       8       2</code><br> <code>0</code><br> <code>4       5</code></p></li><li><p>解释：</p></li></ul><ol><li><code>sizeof()</code>运算符对<code>arr</code>数组的元素数量进行计算，有<code>7</code>个元素故为<code>7</code>。<code>arr+0</code>说明了是对<code>arr</code>这个数组的入口地址计算，则其结果为<code>8</code>。由于赋值表达式的类型是左值的类型，则其大小为<code>2</code>。</li><li><code>sprintf</code>其类似与<code>printf</code>，唯一区别就是他会把参数放到一个<code>str</code>数组里面，返回值为传入参数的字符数。而由于该参数是以<code>16</code>进制的方式输入的且有前缀，则其返回的字符数一定不等于原字符数，整体返回<code>0</code>。</li><li><code>&amp;str[0]+1</code>的结果为<code>x</code>的地址，从该地址开始，计算到<code>\0</code>之前的字符数。<code>arr+0</code>的结果为<code>0</code>的地址，从该地址开始，计算到<code>\0</code>之前的字符数。</li></ol><ul><li>考点：<br> sizeof()、sprintf()</li></ul><h2 id="4-奇怪的输出"><a href="#4-奇怪的输出" class="headerlink" title="4. 奇怪的输出"></a>4. 奇怪的输出</h2><p>程序的输出结果是什么？解释一下为什么出现该结果吧~</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">int main(void) &#123;</span><br><span class="line">    char a = 64 &amp; 127;</span><br><span class="line">    char b = 64 ^ 127;</span><br><span class="line">    char c = -64 &gt;&gt; 6;</span><br><span class="line">    char ch = a + b - c;</span><br><span class="line">    printf(&quot;a = %d b = %d c = %d\n&quot;, a, b, c);</span><br><span class="line">    printf(&quot;ch = %d\n&quot;, ch);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>a = 64 b = 63 c = -1</code><br> <code>ch = -128</code></p></li><li><p>解释：</p></li></ul><ol><li><code>01000000 &amp; 01111111 = 01000000</code></li><li><code>01000000 ^ 01111111 = 01111111</code></li><li><code>01000000</code>向右移6位：<code>00000001</code>，由于为负数，补码的结果为：<code>11111111</code></li><li>ch的结果为<code>64+63-(-1)=128</code>，这个数超过了有符号整数的范围，补码结果为<code>-128</code></li></ol><ul><li>考点：<br> 位运算、补码</li></ul><h2 id="5-乍一看就不想看的函数"><a href="#5-乍一看就不想看的函数" class="headerlink" title="5. 乍一看就不想看的函数"></a>5. 乍一看就不想看的函数</h2><p><em>“人们常说互联网凛冬已至，要提高自己的竞争力，可我怎么卷都卷不过别人，只好用一些奇技淫巧让我的代码变得高深莫测。”</em><br>这个<code>func()</code>函数的功能是什么？是如何实现的？  </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">int func(int a, int b) &#123;</span><br><span class="line">    if (!a) return b;</span><br><span class="line">    return func((a &amp; b) &lt;&lt; 1, a ^ b);</span><br><span class="line">&#125;</span><br><span class="line">int main(void) &#123;</span><br><span class="line">    int a = 4, b = 9, c = -7;</span><br><span class="line">    printf(&quot;%d\n&quot;, func(a, func(b, c)));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>6</code>  </p></li><li><p>解释：</p></li></ul><ol><li>main函数内打印的数字，为整个函数传参后的返回值，参数内嵌套了函数，函数本身又在递归。</li><li>在函数内，先判断a的值，a的值为0时，返回b的值，否则递归函数。</li></ol><ul><li>考点：<br> 递归</li></ul><h2 id="6-自定义过滤"><a href="#6-自定义过滤" class="headerlink" title="6. 自定义过滤"></a>6. 自定义过滤</h2><p>请实现<code>filter()</code>函数：过滤满足条件的数组元素。<br>提示：使用函数指针作为函数参数并且你需要为新数组分配空间。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">typedef int (*Predicate)(int);</span><br><span class="line">int *filter(int *array, int length, Predicate predicate,</span><br><span class="line">            int *resultLength); /*补全函数*/</span><br><span class="line">int isPositive(int num) &#123; return num &gt; 0; &#125;</span><br><span class="line">int main(void) &#123;</span><br><span class="line">    int array[] = &#123;-3, -2, -1, 0, 1, 2, 3, 4, 5, 6&#125;;</span><br><span class="line">    int length = sizeof(array) / sizeof(array[0]);</span><br><span class="line">    int resultLength;</span><br><span class="line">    int *filteredNumbers = filter(array, length, isPositive,</span><br><span class="line">                                  &amp;resultLength);</span><br><span class="line">    for (int i = 0; i &lt; resultLength; i++) &#123;</span><br><span class="line">      printf(&quot;%d &quot;, filteredNumbers[i]);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    free(filteredNumbers);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong>  </p><ul><li>代码：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">#include&lt;stdio.h&gt;</span><br><span class="line">#include&lt;string.h&gt;</span><br><span class="line">#include&lt;stdlib.h&gt;</span><br><span class="line">#include&lt;assert.h&gt;</span><br><span class="line"></span><br><span class="line">typedef int (*Predicate)(int);</span><br><span class="line"></span><br><span class="line">int *filter(int *array, int length, Predicate predicate,</span><br><span class="line">            int *resultLength); /*补全函数*/</span><br><span class="line"></span><br><span class="line">int isPositive(int num) &#123; return num &gt; 0; &#125;</span><br><span class="line">int main(void) &#123;</span><br><span class="line">    int array[] = &#123;-3, -2, -1, 0, 1, 2, 3, 4, 5, 6&#125;;</span><br><span class="line">    int length = sizeof(array) / sizeof(array[0]);</span><br><span class="line">    int resultLength;</span><br><span class="line">    int *filteredNumbers = filter(array, length, isPositive, &amp;resultLength);</span><br><span class="line">    for (int i = 0; i &lt; resultLength; i++) &#123;</span><br><span class="line">      printf(&quot;%d &quot;, filteredNumbers[i]);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    free(filteredNumbers);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int *filter(int *array, int length, Predicate predicate,int *resultLength)</span><br><span class="line">&#123;</span><br><span class="line">int cnt=0;</span><br><span class="line">int* ar=(int*)malloc(sizeof(int)*length);</span><br><span class="line">assert(ar);</span><br><span class="line">int i;</span><br><span class="line"></span><br><span class="line">for(i=0;i&lt;length;i++)</span><br><span class="line">&#123;</span><br><span class="line">if((*predicate)(array[i]))</span><br><span class="line">&#123;</span><br><span class="line">ar[cnt]=array[i];</span><br><span class="line">cnt++;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">*resultLength=cnt;</span><br><span class="line">return ar;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p>输出结果：<br><code>1 2 3 4 5 6 </code>  </p></li><li><p>解释：</p></li></ul><ol><li>首先定义了一个函数指针，指向的函数传入int类型的参数，返回int类型的值。</li><li>在过滤函数内，首先动态分配内存，之后使用判断函数进行判断是否大于0,之后进行赋值，并且记录有效值的个数，最后返回刚刚动态分配内存的地址，进入主函数。</li></ol><ul><li>考点：<br> 函数指针、动态分配内存</li></ul><h2 id="7-静…态…"><a href="#7-静…态…" class="headerlink" title="7. 静…态…"></a>7. 静…态…</h2><ol><li>如何理解关键字<code>static</code>？  </li><li><code>static</code>与变量结合后有什么作用？  </li><li><code>static</code>与函数结合后有什么作用？  </li><li><code>static</code>与指针结合后有什么作用？  </li><li><code>static</code>如何影响内存分配？</li></ol><p><strong>题解：</strong></p><ul><li>解释：</li></ul><ol><li>即“静态”。</li><li>将变量、函数、指针声明为，一个具有文件作用域，内部连接，静态存储期的变量。</li><li>static的对象被放在静态存储区。</li></ol><ul><li>考点：<br> static</li></ul><h2 id="8-救命！指针！"><a href="#8-救命！指针！" class="headerlink" title="8. 救命！指针！"></a>8. 救命！指针！</h2><p>数组指针是什么？指针数组是什么？函数指针呢？用自己的话说出来更好哦，下面数据类型的含义都是什么呢？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">int (*p)[10];</span><br><span class="line">const int* p[10];</span><br><span class="line">int (*f1(int))(int*, int);</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li>解释：</li></ul><ol><li><code>(*p)[10]</code>是一个指向含有10个int类型元素数组的指针。</li><li><code>* p[10]</code>是一个含有10个指向int类型指针元素的数组，且他被const修饰，无法修改其数组内容。</li><li><code>f1</code>是一个接受int类型参数的函数，返回值是一个指针，即指向一个参数为int*和int类型的函数，指向的函数返回类型为int。即f1是一个函数指针。</li></ol><ul><li>考点：<br> 指针数组、数组指针、函数指针</li></ul><h2 id="9-咋不循环了"><a href="#9-咋不循环了" class="headerlink" title="9. 咋不循环了"></a>9. 咋不循环了</h2><p>程序直接运行，输出的内容是什么意思？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">int main(int argc, char* argv[]) &#123;</span><br><span class="line">    printf(&quot;[%d]\n&quot;, argc);</span><br><span class="line">    while (argc) &#123;</span><br><span class="line">      ++argc;</span><br><span class="line">    &#125;</span><br><span class="line">    int i = -1, j = argc, k = 1;</span><br><span class="line">    i++ &amp;&amp; j++ || k++;</span><br><span class="line">    printf(&quot;i = %d, j = %d, k = %d\n&quot;, i, j, k);</span><br><span class="line">    return EXIT_SUCCESS;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>[1]</code><br> <code>i = 0, j = 1, k = 2</code>  </p></li><li><p>解释：</p></li></ul><ol><li>argc一开始为1，之后进入while循环，argc一直递增(有补码)直到argc为0，退出循环。</li><li>表达式内，i&#x3D;-1为真，j&#x3D;0为假，k&#x3D;1为真，没有短路，且三个变量均递增。</li></ol><ul><li>考点：<br> 短路、argc</li></ul><h2 id="10-到底是不是TWO"><a href="#10-到底是不是TWO" class="headerlink" title="10. 到底是不是TWO"></a>10. 到底是不是TWO</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">#define CAL(a) a * a * a</span><br><span class="line">#define MAGIC_CAL(a, b) CAL(a) + CAL(b)</span><br><span class="line">int main(void) &#123;</span><br><span class="line">  int nums = 1;</span><br><span class="line">  if(16 / CAL(2) == 2) &#123;</span><br><span class="line">    printf(&quot;I&#x27;m TWO(ﾉ&gt;ω&lt;)ﾉ\n&quot;);</span><br><span class="line">  &#125; else &#123;</span><br><span class="line">    int nums = MAGIC_CAL(++nums, 2);</span><br><span class="line">  &#125;</span><br><span class="line">  printf(&quot;%d\n&quot;, nums);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>1</code>  </p></li><li><p>解释：</p></li></ul><ol><li>CAL宏定义，没有加()，会直接“贴”到代码内，使得<code>16 / CAL(2)</code>结果为<code>32</code></li><li>进入else语句内，创建了一个新的块作用域的nums，之后又被销毁，故main内的nums没有被改动，仍为<code>1</code>。</li></ol><ul><li>考点：<br> 宏、自动变量</li></ul><h2 id="11-克隆困境"><a href="#11-克隆困境" class="headerlink" title="11. 克隆困境"></a>11. 克隆困境</h2><p>试着运行一下程序，为什么会出现这样的结果？<br>直接将<code>s2</code>赋值给<code>s1</code>会出现哪些问题，应该如何解决？请写出相应代码。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">struct Student &#123;</span><br><span class="line">    char *name;</span><br><span class="line">    int age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">void initializeStudent(struct Student *student, const char *name,</span><br><span class="line">                       int age) &#123;</span><br><span class="line">    student-&gt;name = (char *)malloc(strlen(name) + 1);</span><br><span class="line">    strcpy(student-&gt;name, name);</span><br><span class="line">    student-&gt;age = age;</span><br><span class="line">&#125;</span><br><span class="line">int main(void) &#123;</span><br><span class="line">    struct Student s1, s2;</span><br><span class="line">    initializeStudent(&amp;s1, &quot;Tom&quot;, 18);</span><br><span class="line">    initializeStudent(&amp;s2, &quot;Jerry&quot;, 28);</span><br><span class="line">    s1 = s2;</span><br><span class="line">    printf(&quot;s1的姓名: %s 年龄: %d\n&quot;, s1.name, s1.age);</span><br><span class="line">    printf(&quot;s2的姓名: %s 年龄: %d\n&quot;, s2.name, s2.age);</span><br><span class="line">    free(s1.name);</span><br><span class="line">    free(s2.name);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li>代码：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">struct Student &#123;</span><br><span class="line">    char *name;</span><br><span class="line">    int age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">void initializeStudent(struct Student *student, const char *name,</span><br><span class="line">                       int age) &#123;</span><br><span class="line">    student-&gt;name = (char *)malloc(strlen(name) + 1);</span><br><span class="line">    strcpy(student-&gt;name, name);</span><br><span class="line">    student-&gt;age = age;</span><br><span class="line">&#125;</span><br><span class="line">int main(void) &#123;</span><br><span class="line">    struct Student s1, s2;</span><br><span class="line">    initializeStudent(&amp;s1, &quot;Tom&quot;, 18);</span><br><span class="line">    initializeStudent(&amp;s2, &quot;Jerry&quot;, 28);</span><br><span class="line">char *tmp_name;</span><br><span class="line">int tmp_age;</span><br><span class="line"></span><br><span class="line">tmp_name=s1.name;</span><br><span class="line">s1.name=s2.name;</span><br><span class="line">s2.name=tmp_name;</span><br><span class="line"></span><br><span class="line">tmp_age=s1.age;</span><br><span class="line">s1.age=s2.age;</span><br><span class="line">s2.age=tmp_age;</span><br><span class="line"></span><br><span class="line">    printf(&quot;s1的姓名: %s 年龄: %d\n&quot;, s1.name, s1.age);</span><br><span class="line">    printf(&quot;s2的姓名: %s 年龄: %d\n&quot;, s2.name, s2.age);</span><br><span class="line">    free(s1.name);</span><br><span class="line">    free(s2.name);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p>输出结果：<br> <code>s1的姓名: Jerry 年龄: 28</code><br> <code>s2的姓名: Tom 年龄: 18</code>  </p></li><li><p>解释：</p></li></ul><ol><li><code>s1 = s2</code>是一个看起来就很危险的操作。会使得free(s1.name)找不到内存地址而无法释放。</li></ol><ul><li>考点：<br> 结构体、动态分配内存</li></ul><h2 id="12-你好，我是内存"><a href="#12-你好，我是内存" class="headerlink" title="12. 你好，我是内存"></a>12. 你好，我是内存</h2><p>作为一名合格的C-Coder，一定对内存很敏感吧~来尝试理解这个程序吧！</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">struct structure &#123;</span><br><span class="line">    int foo;</span><br><span class="line">    union &#123;</span><br><span class="line">      int integer;</span><br><span class="line">      char string[11];</span><br><span class="line">      void *pointer;</span><br><span class="line">    &#125; node;</span><br><span class="line">    short bar;</span><br><span class="line">    long long baz;</span><br><span class="line">    int array[7];</span><br><span class="line">&#125;;</span><br><span class="line">int main(void) &#123;</span><br><span class="line">    int arr[] = &#123;0x590ff23c, 0x2fbc5a4d, 0x636c6557, 0x20656d6f,</span><br><span class="line">                 0x58206f74, 0x20545055, 0x6577202c, 0x6d6f636c,</span><br><span class="line">                 0x6f742065, 0x79695820, 0x4c20756f, 0x78756e69,</span><br><span class="line">                 0x6f724720, 0x5b207075, 0x33323032, 0x7825005d,</span><br><span class="line">                 0x636c6557, 0x64fd6d1d&#125;;</span><br><span class="line">    printf(&quot;%s\n&quot;, ((struct structure *)arr)-&gt;node.string);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>Welcome to XUPT , welcome to Xiyou Linux Group [2023]</code>  </p></li><li><p>解释：</p></li></ul><ol><li>arr数组内存的分配是连续的。根据小端存储的方式存储数据，之后把数组强制转换为1个指向<code>structure</code>的指针，并且从<code>node</code>内的<code>string</code>下的地址位置<code>8字节</code>，即arr[2]开始读取arr的内存。</li><li>arr内存储的是一系列16进制数，这些数以1个字节的大小读取，直到读取到<code>\0</code>结束，并且以字符串的形式输出。</li></ol><ul><li>考点：<br> 结构体大小、小端存储、内存的精细操作</li></ul><h2 id="13-GNU-Linux-选做"><a href="#13-GNU-Linux-选做" class="headerlink" title="13. GNU&#x2F;Linux (选做)"></a>13. GNU&#x2F;Linux (选做)</h2><p>注：嘿！你或许对Linux命令不是很熟悉，甚至你没听说过Linux。但别担心，这是选做题，了解Linux是加分项，但不了解也不扣分哦！  </p><p>你知道cd命令的用法与 &#x2F; . ~ 这些符号的含义吗？<br>请问你还懂得哪些与 GNU&#x2F;Linux 相关的知识呢~</p><p><strong>题解：</strong></p><ul><li>输出结果：</li></ul><ol><li><code>cd /</code>:切换至根目录<br><code>cd .</code>:切换至当前目录<br><code>cd ~</code>:切换至用户主目录  </li><li><code>ls</code>:列出目录<br> <code>touch</code>:创建文件<br> <code>clear</code>:清除终端页面<br> ……</li></ol>]]>
    </content>
    <id>https://gmaxh.site/2025/10/27/%E8%A5%BF%E9%82%AE%20Linux%20%E5%85%B4%E8%B6%A3%E5%B0%8F%E7%BB%84%202023%20%E7%BA%B3%E6%96%B0%E9%9D%A2%E8%AF%95%E9%A2%98/</id>
    <link href="https://gmaxh.site/2025/10/27/%E8%A5%BF%E9%82%AE%20Linux%20%E5%85%B4%E8%B6%A3%E5%B0%8F%E7%BB%84%202023%20%E7%BA%B3%E6%96%B0%E9%9D%A2%E8%AF%95%E9%A2%98/"/>
    <published>2025-10-27T22:30:23.000Z</published>
    <summary>
      <![CDATA[<h1 id="西邮-Linux-兴趣小组-2023-纳新面试题"><a href="#西邮-Linux-兴趣小组-2023-纳新面试题" class="headerlink" title="西邮 Linux 兴趣小组 2023 纳新面试题"></a>西邮 Linux 兴趣小组]]>
    </summary>
    <title>西邮 Linux 兴趣小组 2023 纳新面试题</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="Linux" scheme="https://gmaxh.site/categories/Linux/"/>
    <category term="Linux" scheme="https://gmaxh.site/tags/Linux/"/>
    <category term="C" scheme="https://gmaxh.site/tags/C/"/>
    <content>
      <![CDATA[<h1 id="西邮-Linux-兴趣小组-2024-纳新面试题"><a href="#西邮-Linux-兴趣小组-2024-纳新面试题" class="headerlink" title="西邮 Linux 兴趣小组 2024 纳新面试题"></a>西邮 Linux 兴趣小组 2024 纳新面试题</h1><blockquote><p>学长寄语：长期以来，西邮 Linux 兴趣小组的面试题以难度之高名扬西邮校内。我们作为出题人也清楚的知道这份试题略有难度。请你动手敲一敲代码。别担心，若有同学能完成一半的题目，就已经十分优秀。其次，相比于题目的答案，我们对你的思路和过程更感兴趣，或许你的答案略有瑕疵，但你正确的思路和对知识的理解足以为你赢得绝大多数的分数。最后，做题的过程也是学习和成长的过程，相信本试题对你更加熟悉地掌握 C 语言一定有所帮助。祝你好运。我们东区逸夫楼 FZ103 见！</p></blockquote><ul><li>本题目只作为西邮 Linux 兴趣小组 2024 纳新面试的有限参考。</li><li>为节省版面，本试题的程序源码省去了 <code>#include</code> 指令。</li><li>本试题中的程序源码仅用于考察 C 语言基础，不应当作为 C 语言「代码风格」的范例。</li><li>所有题目编译并运行于 <em>x86_64 GNU&#x2F;Linux</em> 环境。</li></ul><h2 id="0-聪明的吗喽"><a href="#0-聪明的吗喽" class="headerlink" title="0. 聪明的吗喽"></a>0. 聪明的吗喽</h2><p>一个小猴子边上有 100 根香蕉，它要走过 50 米才能到家，每次它最多搬 50 根香蕉，（多了就拿不动了），它每走 1 米就要吃掉一根，请问它最多能把多少根香蕉搬到家里。</p><p>（提示：他可以把香蕉放下往返走，但是必须保证它每走一米都能有香蕉吃。也可以走到 n 米时，放下一些香蕉，拿着 n 根香蕉走回去重新搬 50 根。）</p><p><strong>题解：</strong></p><ul><li>代码：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">#include&lt;stdio.h&gt;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">    int n,f;//n为所持香蕉数，f为需要走的步数</span><br><span class="line">    scanf(&quot;%d %d&quot;,&amp;n,&amp;f);</span><br><span class="line">    int tmp=n/2;//最多搬的香蕉数</span><br><span class="line">    int a=tmp%3;//剩余无法满足走1步消耗3根香蕉的香蕉数</span><br><span class="line">    int b=tmp/3;//在走1步消耗3根香蕉的条件下所走步数</span><br><span class="line">    f-=b;//剩余步数</span><br><span class="line">    printf(&quot;%d&quot;,tmp+a-f);//剩余香蕉</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p>输出结果：<br> <code>18</code></p></li><li><p>解释：</p></li></ul><ol><li>由于小猴子一次性最多搬运50根香蕉，而在小猴子所持香蕉数大于50根的情况下，会先带着1批香蕉向前走1步，再拿1根香蕉返回上一个位置，再带着另1批香蕉向前走回刚刚向前走那1步的所在位置，即可以等效于，走1步消耗3根香蕉。</li><li>通过计算得知，这样走会剩下2根香蕉，在此刻我们再以该条件走1步，此时，小猴子所持香蕉数已经不大于50根了。我们便可以用走1步消耗1根香蕉的方式走完剩下的路程。</li></ol><ul><li>考点：<br> 通过数学工具来解决实际问题的能力</li></ul><h2 id="1-西邮Linux欢迎你啊"><a href="#1-西邮Linux欢迎你啊" class="headerlink" title="1. 西邮Linux欢迎你啊"></a>1. 西邮Linux欢迎你啊</h2><p>请解释以下代码的运行结果。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">int main() &#123;</span><br><span class="line">    unsigned int a = 2024;</span><br><span class="line">    for (; a &gt;= 0; a--)</span><br><span class="line">        printf(&quot;%d\n&quot;, printf(&quot;Hi guys! Join Linux - 2%d&quot;, printf(&quot;&quot;)));</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong><br>输出结果：<br><code>Hi guys! Join Linux - 2024</code>(无限循环)</p><ul><li><p>解释：<br> <code>a</code>为<code>unsigned</code>，即为非负数，故其在自减的过程中，会在减为<code>0</code>时返回到<code>int</code>类型最大值</p></li><li><p>考点：<br> unsigned、补码</p></li></ul><h2 id="2-眼见不一定为实"><a href="#2-眼见不一定为实" class="headerlink" title="2. 眼见不一定为实"></a>2. 眼见不一定为实</h2><p>输出为什么和想象中不太一样？<br>你了解 <code>sizeof()</code> 和 <code>strlen()</code> 吗？他们的区别是什么？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">int main() &#123;</span><br><span class="line">    char p0[] = &quot;I love Linux&quot;;</span><br><span class="line">    const char *p1 = &quot;I love Linux\0Group&quot;;</span><br><span class="line">    char p2[] = &quot;I love Linux\0&quot;;</span><br><span class="line">    printf(&quot;%d\n%d\n&quot;, strcmp(p0, p1), strcmp(p0, p2));</span><br><span class="line">    printf(&quot;%d\n%d\n&quot;, sizeof(p0) == sizeof(p1), strlen(p0) == strlen(p1));</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>0</code><br> <code>0</code><br> <code>0</code><br> <code>1</code>  </p></li><li><p>解释：</p></li></ul><ol><li>p0和p2的本质是一样的，p1是一个字符串指针。</li><li><code>strcmp</code>函数在比较两个字符串时，碰到了两个<code>&#39;\0&#39;</code>，则停止比较，返回ASCII码。</li><li><code>sizeof</code>对指针进行计算，结果为8(64位机)，对字符串进行计算，结果为字符串的长度。</li></ol><ul><li>考点：<br> strcmp和sizeof</li></ul><h2 id="3-1-1-1-0-0-1"><a href="#3-1-1-1-0-0-1" class="headerlink" title="3. 1.1 - 1.0 !&#x3D; 0.1"></a>3. 1.1 - 1.0 !&#x3D; 0.1</h2><p>为什么会这样，除了下面给出的一种方法，还有什么方法可以避免这个问题？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">int main() &#123;</span><br><span class="line">    float a = 1.0, b = 1.1, ex = 0.1;</span><br><span class="line">    printf(&quot;b - a == ex is %s\n&quot;, (b - a == ex) ? &quot;true&quot; : &quot;false&quot;);</span><br><span class="line">    int A = a * 10, B = b * 10, EX = ex * 10;</span><br><span class="line">    printf(&quot;B - A == EX is %s\n&quot;, (B - A == EX) ? &quot;true&quot; : &quot;false&quot;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br><code>b - a == ex is false</code><br><code>B - A == EX is true</code>  </p></li><li><p>解释：</p></li></ul><ol><li>a,b,c均为浮点数，其实际值在无限趋近于所给值。故a+b!&#x3D;c。</li><li>将对应数乘10，其整数部分具有实际意义，小数部分在转换为int类型时被忽略，正好可以使得相加运算正确。</li><li>改进方法：  <ul><li>可以使用16进制保存a,b,c这些浮点数，在确定小数后几位的情况下，16进制是精准的。</li><li>可以使用误差容忍度，float下为1e-6，double下为1e-12。</li></ul></li></ol><ul><li>考点：<br> 浮点数、三元运算符</li></ul><h2 id="4-听说爱用位运算的人技术都不太差"><a href="#4-听说爱用位运算的人技术都不太差" class="headerlink" title="4. 听说爱用位运算的人技术都不太差"></a>4. 听说爱用位运算的人技术都不太差</h2><p>解释函数的原理，并分析使用位运算求平均值的优缺点。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">int average(int nums[], int start, int end) &#123;</span><br><span class="line">    if (start == end)</span><br><span class="line">        return nums[start];</span><br><span class="line">    int mid = (start + end) / 2;</span><br><span class="line">    int leftAvg = average(nums, start, mid);</span><br><span class="line">    int rightAvg = average(nums, mid + 1, end);</span><br><span class="line">    return (leftAvg &amp; rightAvg) + ((leftAvg ^ rightAvg) &gt;&gt; 1);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li>输出结果：<br> <code>num[5]={1,2,3,4,5}</code><br> <code>3</code></li></ul><p> -解释：  </p><ol><li>利用函数递归，将整个数组分成两个部分，分别求平均值，在把结果求平均值，得到最终结果，即分治。</li><li>优点：<ul><li>避免了整数溢出的问题。</li><li>函数整体更整顿。<br>缺点：  </li><li>时间复杂度为O(n)  </li><li>空间复杂度为O(logn)</li></ul></li></ol><ul><li>考点：<br> 位运算求平均值、算法的优化思想</li></ul><h2 id="5-全局还是局部"><a href="#5-全局还是局部" class="headerlink" title="5. 全局还是局部!!!"></a>5. 全局还是局部!!!</h2><p>先思考输出是什么，再动动小手运行下代码，看跟自己想得结果一样不一样 &gt;-&lt;</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">int i = 1;</span><br><span class="line">static int j = 15;</span><br><span class="line">int func() &#123;</span><br><span class="line">    int i = 10;</span><br><span class="line">    if (i &gt; 5) i++;</span><br><span class="line">    printf(&quot;i = %d, j = %d\n&quot;, i, j);</span><br><span class="line">    return i % j;</span><br><span class="line">&#125;</span><br><span class="line">int main() &#123;</span><br><span class="line">    int a = func();</span><br><span class="line">    printf(&quot;a = %d\n&quot;, a);</span><br><span class="line">    printf(&quot;i = %d, j = %d\n&quot;, i, j);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>i = 11, j = 15</code><br> <code>a = 11</code><br> <code>i = 1, j = 15</code>  </p></li><li><p>解释：</p></li></ul><ol><li>程序内有两个函数，func和main，func函数内使用了静态变量<code>j</code>，和一个自动变量<code>i</code>，虽然在函数外部，还有一个变量<code>i</code>，但函数外部的变量<code>i</code>为外部链接的静态变量，他会被一个自动变量所“隐藏”。因此当我们在每次调用这个函数的时候，都会有一个自动变量<code>i</code>，来也匆匆去也匆匆。</li><li>而在不调用func函数的时候，自然也不会创建这个自动变量<code>i</code>去覆盖那个静态变量<code>i</code>。于是在第三行打印的时候，<code>i</code>是1，<code>j</code>是15。</li></ol><ul><li>考点：<br> 变量的作用域和存储期</li></ul><h2 id="6-指针的修罗场：改还是不改，这是个问题"><a href="#6-指针的修罗场：改还是不改，这是个问题" class="headerlink" title="6. 指针的修罗场：改还是不改，这是个问题"></a>6. 指针的修罗场：改还是不改，这是个问题</h2><p>指出以下代码中存在的问题，并帮粗心的学长改正问题。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">int main(int argc, char **argv) &#123;</span><br><span class="line">    int a = 1, b = 2;</span><br><span class="line">    const int *p = &amp;a;</span><br><span class="line">    int * const q = &amp;b;</span><br><span class="line">    *p = 3, q = &amp;a;</span><br><span class="line">    const int * const r = &amp;a;</span><br><span class="line">    *r = 4, r = &amp;b;</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong>  </p><ul><li>代码：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">#include&lt;stdio.h&gt;</span><br><span class="line"></span><br><span class="line">int main(int argc, char **argv) &#123;</span><br><span class="line">    int a = 1, b = 2;</span><br><span class="line">    const int *p = &amp;a;</span><br><span class="line">    int * const q = &amp;b;</span><br><span class="line">    *q = 3, p = &amp;a;//q和p的操作恰好相反</span><br><span class="line">    const int * const r = &amp;a;</span><br><span class="line">    //删除了有关r的操作</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>解释：</li></ul><ol><li><code>const</code>在限定一个指针的时候，他和<code>*</code>的先后顺序需要细心关注一下。当<code>*</code>在<code>const</code>的左侧时，<code>const</code>限定了指针的地址；当<code>*</code>在<code>const</code>的右侧时，<code>const</code>限定了指针地址下的值；当<code>*</code>在<code>const</code>中间时，则地址和值都被限定。可以记为”左位右值“。</li></ol><ul><li>考点：<br> const限定符</li></ul><h2 id="7-物极必反？"><a href="#7-物极必反？" class="headerlink" title="7. 物极必反？"></a>7. 物极必反？</h2><p>你了解 <code>argc</code> 和 <code>argv</code> 吗，这个程序里的 <code>argc</code> 和 <code>argv</code> 是什么？<br>程序输出是什么？解释一下为什么。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">int main(int argc, char *argv[]) &#123;</span><br><span class="line">    while (argc++ &gt; 0);</span><br><span class="line">    int a = 1, b = argc, c = 0;</span><br><span class="line">    if (--a || b++ &amp;&amp; c--)</span><br><span class="line">        for (int i = 0; argv[i] != NULL; i++)</span><br><span class="line">            printf(&quot;argv[%d] = %s\n&quot;, i, argv[i]);</span><br><span class="line">    printf(&quot;a = %d, b = %d, c = %d\n&quot;, a, b, c);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>a = 0, b = -2147483646, c = -1</code>  </p></li><li><p>解释：</p></li></ul><ol><li>argc为程序命令行的数量，*argv[]内保存着命令行的具体内容。</li><li>由于while循环的判断条件和终止条件在同一行内，且其执行的十一条空语句，故一定会执行到argc小于0。由于变量在计算机内以补码形式保存，故为4字节下最小值<code>-2147483648</code>。</li><li>在之后又进行了一次自增，把值赋给b后又自增，且在if语句内判断条件时，没有出现短路的情况，故所有操作都执行。</li></ol><ul><li>考点：<br> argc和argv</li></ul><h2 id="8-指针？数组？数组指针？指针数组？"><a href="#8-指针？数组？数组指针？指针数组？" class="headerlink" title="8. 指针？数组？数组指针？指针数组？"></a>8. 指针？数组？数组指针？指针数组？</h2><p>在主函数中定义如下变量：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">int main() &#123;</span><br><span class="line">    int a[2] = &#123;4, 8&#125;;</span><br><span class="line">    int(*b)[2] = &amp;a;</span><br><span class="line">    int *c[2] = &#123;a, a + 1&#125;;</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>说说这些输出分别是什么？  </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">a, a + 1, &amp;a, &amp;a + 1, *(a + 1), sizeof(a), sizeof(&amp;a)</span><br><span class="line">*b, *b + 1, b, b + 1, *(*b + 1), sizeof(*b), sizeof(b)</span><br><span class="line">c, c + 1, &amp;c, &amp;c + 1, **(c + 1), sizeof(c), sizeof(&amp;c)</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><table><thead><tr><th align="left"></th><th align="center"></th><th align="center"></th><th align="center"></th><th align="center"></th><th align="center"></th><th align="right"></th></tr></thead><tbody><tr><td align="left">&amp;a[0]</td><td align="center">&amp;a[1]</td><td align="center">数组a的地址</td><td align="center">数组a末尾的地址</td><td align="center">8</td><td align="center">8</td><td align="right">8</td></tr><tr><td align="left">&amp;a[0]</td><td align="center">&amp;a[1]</td><td align="center">数组a的地址</td><td align="center">数组a末尾的地址</td><td align="center">8</td><td align="center">8</td><td align="right">8</td></tr><tr><td align="left">&amp;&amp;a[0]</td><td align="center">&amp;&amp;a[1]</td><td align="center">数组c的地址</td><td align="center">数组c末尾的地址</td><td align="center">8</td><td align="center">8</td><td align="right">8</td></tr></tbody></table><ul><li>解释：</li></ul><ol><li><code>a[2]</code>是一个数组，<code>(*b)[2]</code>是一个指向含有2个元素的数组的指针，<code>*c[2]</code>是一个包含两个指针的数组。</li><li><code>&amp;a</code>的意思是整个数组的地址，而<code>&amp;a[0]</code>是指数组的入口地址。</li><li><code>sizeof</code>是计算其所占内存的大小。</li></ol><ul><li>考点：<br> 数组，指针数组，数组指针、sizeof</li></ul><h2 id="9-嘻嘻哈哈，好玩好玩"><a href="#9-嘻嘻哈哈，好玩好玩" class="headerlink" title="9. 嘻嘻哈哈，好玩好玩"></a>9. 嘻嘻哈哈，好玩好玩</h2><p>在宏的魔法下，数字与文字交织，猜猜结果是什么？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">#define SQUARE(x) x *x</span><br><span class="line">#define MAX(a, b) (a &gt; b) ? a : b;</span><br><span class="line">#define PRINT(x) printf(&quot;嘻嘻，结果你猜对了吗，包%d滴\n&quot;, x);</span><br><span class="line">#define CONCAT(a, b) a##b</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int CONCAT(x, 1) = 5;</span><br><span class="line">    int CONCAT(y, 2) = 3;</span><br><span class="line">    int max = MAX(SQUARE(x1 + 1), SQUARE(y2))</span><br><span class="line">    PRINT(max)</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>嘻嘻，结果你猜对了吗，包11滴</code>  </p></li><li><p>解释：</p></li></ul><ol><li>CONCAT的意思是，把a和b直接拼接起来，作为一个标识符。因此<code>x1=5</code>，<code>y2=3</code>。</li><li>在SQUARE中，对<code>x1+1</code>的操作为<code>x1+1*x1+1</code>，对<code>y2</code>的操作为<code>y2*y2</code>，取最大值赋值给max，打印max。</li></ol><ul><li>考点：<br> 宏</li></ul><h2 id="10-我写的排序最快"><a href="#10-我写的排序最快" class="headerlink" title="10. 我写的排序最快"></a>10. 我写的排序最快</h2><p>写一个 your_sort 函数，要求不能改动 main 函数里的代码，对 arr1 和 arr2 两个数组进行升序排序并剔除相同元素，最后将排序结果放入 result 结构体中。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">int main() &#123;</span><br><span class="line">    int arr1[] = &#123;2, 3, 1, 3, 2, 4, 6, 7, 9, 2, 10&#125;;</span><br><span class="line">    int arr2[] = &#123;2, 1, 4, 3, 9, 6, 8&#125;;</span><br><span class="line">    int len1 = sizeof(arr1) / sizeof(arr1[0]);</span><br><span class="line">    int len2 = sizeof(arr2) / sizeof(arr2[0]);</span><br><span class="line"></span><br><span class="line">    result result;</span><br><span class="line">    your_sort(arr1, len1, arr2, len2, &amp;result);</span><br><span class="line">    for (int i = 0; i &lt; result.len; i++) &#123;</span><br><span class="line">        printf(&quot;%d &quot;, result.arr[i]);</span><br><span class="line">    &#125;</span><br><span class="line">    free(result.arr);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li>代码：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line">#include&lt;stdio.h&gt;   </span><br><span class="line">#include&lt;stdlib.h&gt; </span><br><span class="line"></span><br><span class="line">typedef struct</span><br><span class="line">&#123;</span><br><span class="line">    int* arr;</span><br><span class="line">    int len;</span><br><span class="line">&#125;result;</span><br><span class="line"></span><br><span class="line">void your_sort(int arr1[],int len1,int arr2[],int len2,result* res);</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">    int arr1[] = &#123;2, 3, 1, 3, 2, 4, 6, 7, 9, 2, 10&#125;;</span><br><span class="line">    int arr2[] = &#123;2, 1, 4, 3, 9, 6, 8&#125;;</span><br><span class="line">    int len1 = sizeof(arr1) / sizeof(arr1[0]);</span><br><span class="line">    int len2 = sizeof(arr2) / sizeof(arr2[0]);</span><br><span class="line"></span><br><span class="line">    result result;</span><br><span class="line">    your_sort(arr1, len1, arr2, len2, &amp;result);</span><br><span class="line">    for (int i = 0; i &lt; result.len; i++) &#123;</span><br><span class="line">        printf(&quot;%d &quot;, result.arr[i]);</span><br><span class="line">    &#125;</span><br><span class="line">    free(result.arr);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void your_sort(int arr1[],int len1,int arr2[],int len2,result* res)</span><br><span class="line">&#123;</span><br><span class="line">    res-&gt;arr=(int*)malloc(sizeof(int)*(len1+len2));</span><br><span class="line">    int i,j;</span><br><span class="line"></span><br><span class="line">    for(i=0;i&lt;len1;i++)</span><br><span class="line">    &#123;</span><br><span class="line">        res-&gt;arr[i]=arr1[i];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    for(i=0;i&lt;len2;i++)</span><br><span class="line">    &#123;</span><br><span class="line">        res-&gt;arr[i+len1]=arr2[i];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    res-&gt;len=len1+len2;</span><br><span class="line"></span><br><span class="line">    for(i=0;i&lt;res-&gt;len-1;i++)</span><br><span class="line">    &#123;</span><br><span class="line">        for(j=0;j&lt;=res-&gt;len-1-i;j++)</span><br><span class="line">        &#123;</span><br><span class="line">            if(res-&gt;arr[j]&gt;res-&gt;arr[j+1])</span><br><span class="line">            &#123;</span><br><span class="line">                int tmp=res-&gt;arr[j];</span><br><span class="line">                res-&gt;arr[j]=res-&gt;arr[j+1];   </span><br><span class="line">                res-&gt;arr[j+1]=tmp;   </span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    int new_size=1;</span><br><span class="line"></span><br><span class="line">    for(i=1;i&lt;res-&gt;len;i++)</span><br><span class="line">    &#123;</span><br><span class="line">        if(res-&gt;arr[i]!=res-&gt;arr[i-1])</span><br><span class="line">        &#123;</span><br><span class="line">            res-&gt;arr[new_size]=res-&gt;arr[i];</span><br><span class="line">            new_size++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    res-&gt;arr=(int*)realloc(res-&gt;arr,sizeof(int)*new_size);</span><br><span class="line">    res-&gt;len=new_size;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p>输出结果：<br> <code>1 2 3 4 6 7 8 9 10 </code>  </p></li><li><p>解释：</p></li></ul><ol><li>首先定义了一个结构体，并且把这个结构体命名为<code>result</code>。</li><li>在<code>your_sort</code>函数内，分别进行了拼接，排序，去重三个步骤，并且使用了动态分配内存。这里的排序我使用的是冒泡排序。</li></ol><ul><li>考点：<br> 结构体访问、动态分配内存、拼接，排序，去重</li></ul><h2 id="11-猜猜我是谁"><a href="#11-猜猜我是谁" class="headerlink" title="11. 猜猜我是谁"></a>11. 猜猜我是谁</h2><p>在指针的迷宫中，五个数字化身为神秘的符号，等待被逐一揭示。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">int main() &#123;</span><br><span class="line">    void *a[] = &#123;(void *)1, (void *)2, (void *)3, (void *)4, (void *)5&#125;;</span><br><span class="line">    printf(&quot;%d\n&quot;, *((char *)a + 1));</span><br><span class="line">    printf(&quot;%d\n&quot;, *(int *)(char *)a + 1);</span><br><span class="line">    printf(&quot;%d\n&quot;, *((int *)a + 2));</span><br><span class="line">    printf(&quot;%lld\n&quot;, *((long long *)a + 3));</span><br><span class="line">    printf(&quot;%d\n&quot;, *((short *)a + 4));</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>0</code><br> <code>2</code><br> <code>2</code><br> <code>4</code><br> <code>2</code>  </p></li><li><p>解释：</p></li></ul><ol><li><code>*a[]</code>是一个指针数组。在<code>64</code>位机中地址为<code>8</code>字节，且为小端存储。</li><li>先转换为<code>char*</code>类型，后移动<code>1</code>个字节，解引用的结果为<code>0</code>。</li><li>先转换为<code>char*</code>类型，后转换为<code>int*</code>类型，对其<code>4</code>字节下的地址解引用，结果为<code>1</code>，<code>1+1=2</code>。</li><li>先转换为<code>long long*</code>类型，后移动<code>8*3=24</code>个字节，解引用的结果为<code>4</code>。</li><li>先转换为<code>short*</code>类型，后移动<code>2*4=8</code>字节，解引用的结果为<code>2</code>。</li></ol><ul><li>考点：<br> 指针的类型转换和运算</li></ul><h2 id="12-结构体变小写奇遇记"><a href="#12-结构体变小写奇遇记" class="headerlink" title="12. 结构体变小写奇遇记"></a>12. 结构体变小写奇遇记</h2><p>计算出 <code>Node</code> 结构体的大小，并解释以下代码的运行结果。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">union data &#123;</span><br><span class="line">    int a;</span><br><span class="line">    double b;</span><br><span class="line">    short c;</span><br><span class="line">&#125;;</span><br><span class="line">typedef struct node &#123;</span><br><span class="line">    long long a;</span><br><span class="line">    union data b;</span><br><span class="line">    void (*change)( struct node *n);</span><br><span class="line">    char string[0];</span><br><span class="line">&#125; Node;</span><br><span class="line">void func(Node *node) &#123;</span><br><span class="line">    for (size_t i = 0; node-&gt;string[i] != &#x27;\0&#x27;; i++)</span><br><span class="line">        node-&gt;string[i] = tolower(node-&gt;string[i]);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    const char *s = &quot;WELCOME TO XIYOULINUX_GROUP!&quot;;</span><br><span class="line">    Node *P = (Node *)malloc(sizeof(Node) + (strlen(s) + 1) * sizeof(char));</span><br><span class="line">    strcpy(P-&gt;string, s);</span><br><span class="line">    P-&gt;change = func;</span><br><span class="line">    P-&gt;change(P);</span><br><span class="line">    printf(&quot;%s\n&quot;, P-&gt;string);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>welcome to xiyoulinux_group!</code>  </p></li><li><p>解释：</p></li></ul><ol><li>首先进行内存对齐，data为<code>24</code>字节，Node为<code>40</code>字节。</li><li>在main函数内对P进行动态内存分配，大小为<code>40+30=70</code>字节。</li><li><code>P-&gt;change = func</code>把change函数指针指向了<code>func</code>，<code>P-&gt;change(P)</code>调用了指向的<code>func</code>函数。</li><li>在其中还有一个字符串变为小写的tolower()函数，使得结果最后均为小写。</li></ol><ul><li>考点：<br> 结构体和共用体内存对齐、动态内存分配、字符串常量的存储方式</li></ul><h2 id="13-GNU-Linux-选做"><a href="#13-GNU-Linux-选做" class="headerlink" title="13. GNU&#x2F;Linux (选做)"></a>13. GNU&#x2F;Linux (选做)</h2><p>注：嘿！你或许对Linux命令不是很熟悉，甚至没听说过Linux。<br>但别担心，这是选做题，了解Linux是加分项，不了解也不扣分哦！</p><ol><li>你知道 <code>ls</code> 命令的用法与 <code>/</code> <code>.</code> <code>~</code> 这些符号的含义吗？</li><li>你知道 Linux 中权限 <code>rwx</code> 的含义吗？</li><li>请问你还懂得哪些与 GNU&#x2F;Linux 相关的知识呢？</li></ol><p><strong>题解：</strong></p><ul><li>输出结果：</li></ul><ol><li><code>ls</code>:列出文件<br><code>ls /</code>:列出根目录下的所有目录<br><code>ls .</code>:列出当前目录下的所有目录<br><code>ls ~</code>:列出用户主目录下的所有目录  </li><li><code>r</code>:读取权限<br><code>w</code>:写入权限<br><code>x</code>:执行权限</li><li><code>cd</code>:更改目录<br> <code>touch</code>:创建文件<br> <code>clear</code>:清除终端页面<br> ……</li></ol>]]>
    </content>
    <id>https://gmaxh.site/2025/10/25/%E8%A5%BF%E9%82%AE%20Linux%20%E5%85%B4%E8%B6%A3%E5%B0%8F%E7%BB%84%202024%20%E7%BA%B3%E6%96%B0%E9%9D%A2%E8%AF%95%E9%A2%98/</id>
    <link href="https://gmaxh.site/2025/10/25/%E8%A5%BF%E9%82%AE%20Linux%20%E5%85%B4%E8%B6%A3%E5%B0%8F%E7%BB%84%202024%20%E7%BA%B3%E6%96%B0%E9%9D%A2%E8%AF%95%E9%A2%98/"/>
    <published>2025-10-25T12:47:21.000Z</published>
    <summary>
      <![CDATA[<h1 id="西邮-Linux-兴趣小组-2024-纳新面试题"><a href="#西邮-Linux-兴趣小组-2024-纳新面试题" class="headerlink" title="西邮 Linux 兴趣小组 2024 纳新面试题"></a>西邮 Linux 兴趣小组]]>
    </summary>
    <title>西邮 Linux 兴趣小组 2024 纳新面试题</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
  <entry>
    <author>
      <name>FRiver</name>
    </author>
    <category term="Linux" scheme="https://gmaxh.site/categories/Linux/"/>
    <category term="Linux" scheme="https://gmaxh.site/tags/Linux/"/>
    <category term="C" scheme="https://gmaxh.site/tags/C/"/>
    <content>
      <![CDATA[<h1 id="西邮-Linux-兴趣小组-2025-纳新面试题"><a href="#西邮-Linux-兴趣小组-2025-纳新面试题" class="headerlink" title="西邮 Linux 兴趣小组 2025 纳新面试题"></a>西邮 Linux 兴趣小组 2025 纳新面试题</h1><blockquote><p>学长寄语：长期以来，西邮 Linux 兴趣小组的面试题以难度之高名扬西邮校内。我们作为出题人也清楚地知道这份试题略有难度。请你动手敲一敲代码。别担心，若有同学能完成一半的题目，就已经十分优秀。其次，相比于题目的答案，我们对你的思路和过程更感兴趣，或许你的答案略有瑕疵，但你正确的思路和对知识的理解足以为你赢得绝大多数的分数。最后，做题的过程也是学习和成长的过程，相信本试题对你更加熟悉地掌握 C 语言一定有所帮助。祝你好运。我们东区逸夫楼 FZ103 见！</p></blockquote><ul><li>本题目只作为西邮 Linux 兴趣小组 2025 纳新面试的有限参考。</li><li>为节省版面，本试题的程序源码省去了 <code>include</code> 指令。</li><li>本试题中的程序源码仅用于考察 C 语言基础，不应当作为 C 语言「代码风格」的范例。</li><li>所有题目编译并运行于 <em>x86_64 GNU&#x2F;Linux</em> 环境。</li></ul><h2 id="0-拼命的企鹅"><a href="#0-拼命的企鹅" class="headerlink" title="0. 拼命的企鹅"></a>0. 拼命的企鹅</h2><p>一只企鹅在爬山，每隔一段路都会遇到一块石头。第 1 块石头重量是 <code>a</code>，每往上走一段路，石头重量就会变成上一段的平方。企鹅可以选择把某些石头捡起来，最后把捡到的石头重量相乘。</p><p>它怎样捡石头，才能得到重量乘积恰好是 <code>a</code> 的 <code>b</code> 次方的石头？（比如 <code>b = 173</code> 时， 要捡哪些石头？）</p><p><strong>题解：</strong></p><ul><li>代码：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">#include&lt;stdio.h&gt;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">    int b;</span><br><span class="line">    scanf(&quot;%d&quot;,&amp;b);</span><br><span class="line">    int printpoint=1;//insert &#x27;,&#x27;.</span><br><span class="line">    int point=1;//the situation of the key stone.</span><br><span class="line"></span><br><span class="line">    while(b&gt;0)</span><br><span class="line">    &#123;</span><br><span class="line">        if(b&amp;1)//get the key.</span><br><span class="line">        &#123;</span><br><span class="line">            if(!printpoint)</span><br><span class="line">            &#123;</span><br><span class="line">                printf(&quot;,&quot;);</span><br><span class="line">            &#125;</span><br><span class="line">            printf(&quot;%d&quot;,point);</span><br><span class="line">            printpoint=0;</span><br><span class="line">        &#125;</span><br><span class="line">        b&gt;&gt;=1;//delete the previous.</span><br><span class="line">        point++;//change the situation.</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p>输出结果：<br> 当<code>b = 173</code>时，结果为：<code>1,3,4,6,8</code><br> 当<code>b = 65</code>时，结果为：<code>1,7</code></p></li><li><p>解释：</p></li></ul><ol><li>由题意可知，捡到的石头重量相乘，即对应石头指数相加，而我们可以将石头的重量：${a^n}$可以写作$a^{2^n}$，于是在相乘的过程中，可以等效转换为是2的n次幂的相加，即2进制转10进制。</li><li>通过每次对2进制下的<code>1</code>读取下标，便可以输出<code>1</code>的位置。</li></ol><ul><li>考点：<br> 2进制与10进制转换、通过数学工具来解决实际问题的能力</li></ul><h2 id="1-西邮Linux欢迎你啊"><a href="#1-西邮Linux欢迎你啊" class="headerlink" title="1. 西邮Linux欢迎你啊"></a>1. 西邮Linux欢迎你啊</h2><p>请解释以下代码的运行结果。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">int main() &#123;</span><br><span class="line">    if (printf(&quot;Hi guys! &quot;) || printf(&quot;Xiyou Linux &quot;)) &#123;</span><br><span class="line">        printf(&quot;%d\n&quot;, printf(&quot;Welcome to Xiyou Linux 2%d&quot;, printf(&quot;&quot;)));</span><br><span class="line">    &#125;</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br><code>Hi guys! Welcome to Xiyou Linux 2025</code></p></li><li><p>解释：  </p><ol><li><p>if语句中执行printf函数，其返回值：打印的字符长度<code>10</code>，作为判断if语句成立的条件。由于两个printf的关系为<strong>或</strong>，第一个printf函数的返回值已经使if语句成立，故不执行第二个printf函数。结果为：<code>Hi guys! </code></p></li><li><p>在if语句内，printf函数嵌套了其他printf函数，从内向外依次输出，对应的返回值作为输出内容，以<code>%d</code>的形式输出。结果为：<code>Welcome to Xiyou Linux 2025</code>。</p></li></ol></li><li><p>考点：<br>“短路”、printf函数返回值</p></li></ul><h2 id="2-可以和-0-组一辈子字符串吗？"><a href="#2-可以和-0-组一辈子字符串吗？" class="headerlink" title="2. 可以和 \0 组一辈子字符串吗？"></a>2. 可以和 <code>\0</code> 组一辈子字符串吗？</h2><p>你能找到成功打印的语句吗？你能看出每个 <code>if</code> 中函数的返回值吗？这些函数各有什么特点？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">int main() &#123;</span><br><span class="line">    char p1[] = &#123; &#x27;W&#x27;, &#x27;e&#x27;, &#x27;l&#x27;, &#x27;c&#x27;, &#x27;o&#x27;, &#x27;m&#x27;, &#x27;e&#x27;, &#x27;\0&#x27; &#125;;</span><br><span class="line">    char p2[] = &quot;Join us\0&quot;, p4[] = &quot;xiyou_linux_group&quot;;</span><br><span class="line">    const char* p3 = &quot;Xiyou Linux Group\0\n2025\0&quot;;</span><br><span class="line">    if (strcmp(p1, p2)) &#123;</span><br><span class="line">        printf(&quot;%s to %s!\n&quot;, p1, p2);</span><br><span class="line">    &#125;</span><br><span class="line">    if (strlen(p3) &gt; sizeof(p3)) &#123;</span><br><span class="line">        printf(&quot;%s&quot;, p3);</span><br><span class="line">    &#125;</span><br><span class="line">    if (sizeof(p1) == sizeof(p2)) &#123;</span><br><span class="line">        printf(&quot;%s&quot;, p4);</span><br><span class="line">    &#125;</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>Welcome to Join us!</code><br> <code>Xiyou Linux Group</code></p></li><li><p>解释：</p></li></ul><ol><li>第一个if语句判断中，<code>strcmp</code>函数进行了两个字符串的比较，由于<code>&#39;w&#39;</code>比<code>&#39;J&#39;</code>在字符表中更靠前，其ASCII码差值为正(非0)，则if语句成立，执行<code>printf</code>函数。</li><li><code>sizeof(p3)</code>是对指针的大小进行计算，则其值为<code>8</code>，<code>strlen(p3)</code>是对字符串整体的大小进行计算，在第一个<code>&#39;\0&#39;</code>停止且不包括<code>&#39;\0&#39;</code>，故其值为<code>17</code>，比较结果在if语句中成立，执行<code>printf</code>函数。</li><li>两个字符串的大小相等，故其if语句成立，执行<code>printf</code>函数。</li></ol><ul><li>考点：<br> sizeof和strlen的使用</li></ul><h2 id="3-数学没问题，浮点数有鬼"><a href="#3-数学没问题，浮点数有鬼" class="headerlink" title="3. 数学没问题，浮点数有鬼"></a>3. 数学没问题，浮点数有鬼</h2><p>这个程序的输出是什么？解释为什么会这样？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">int main() &#123;</span><br><span class="line">    float a1 = 0.3, b1 = 6e-1, sum1 = 0.9;</span><br><span class="line">    printf(&quot;a1 + b1 %s sum1\n&quot;, (a1 + b1 == sum1) ? &quot;==&quot; : &quot;!=&quot;);</span><br><span class="line">    float a2 = 0x0.3p0, b2 = 0x6p-4, sum2 = 0x0.9p0;</span><br><span class="line">    printf(&quot;a2 + b2 %s sum2\n&quot;, (a2 + b2 == sum2) ? &quot;==&quot; : &quot;!=&quot;);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>a1 + b1 != sum1</code><br> <code>a2 + b2 == sum2</code></p></li><li><p>解释：</p></li></ul><ol><li>浮点数本身并不精确，实际值在对应精度下无限趋近于所给值。故不相等。  </li><li>三个数均为16进制数，其实际值即所给值。<br> 16进制转10进制：若无小数，则<code>10进制数=整数*2的n次方(n为p后数值)</code></li></ol><ul><li>考点：<br> 16进制转10进制、浮点数</li></ul><h2 id="4-不合群的数字"><a href="#4-不合群的数字" class="headerlink" title="4. 不合群的数字"></a>4. 不合群的数字</h2><p>在一个数组中，所有数字都出现了偶数次，只有两个数字出现了奇数次，请聪明的你帮我看看以下的代码是如何找到这两个数字的呢？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">void findUndercoverIDs(int nums[], int size) &#123;</span><br><span class="line">    int xorAll = 0,id_a = 0,id_b = 0;</span><br><span class="line">    for (int i = 0; i &lt; size; i++) &#123;</span><br><span class="line">        xorAll ^= nums[i];</span><br><span class="line">    &#125;</span><br><span class="line">    int diffBit = xorAll &amp; -xorAll;</span><br><span class="line">    for (int i = 0; i &lt; size; i++) &#123;</span><br><span class="line">        if(nums[i] &amp; diffBit)&#123;</span><br><span class="line">            id_a ^= nums[i];</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            id_b ^= nums[i];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;These nums are %d %d\n&quot;, id_a, id_b);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> 两个出现奇数次的数字</p></li><li><p>解释：<br> 整体函数巧妙地利用了位运算，得到了出现奇数次的两个数字。</p></li></ul><ol><li>根据异或的特点，即两个相同的数字的结果为0，进行异或运算。如若有两个数字出现了偶数次，便会在异或中被消除，于是我们得到了两个出现奇数次的数字异或的结果，即<code>xorAll</code>。</li><li>对<code>xorAll</code>与其本身的相反数(反码+1，即补码)进行位与运算。于是我们便得到了最低位的<code>1</code>。</li><li>对数组进行遍历，并在if语句条件判断中进行位与操作，如果结果成立，则把对应值赋给<code>id_a</code>，否则把对应值给<code>id_b</code>。这个操作更精妙之处，在于通过每次的异或，不仅仅进行赋值操作，更去除了出现偶数次的数。</li><li>分别输出两个出现奇数次的数字。</li></ol><ul><li>考点：<br> 位运算的进阶操作</li></ul><h2 id="5-会一直循环吗？"><a href="#5-会一直循环吗？" class="headerlink" title="5. 会一直循环吗？"></a>5. 会一直循环吗？</h2><p>你了解 <code>argc</code> 和 <code>argv</code> 吗，程序的输出是什么？为什么会这样？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">int main(int argc, char* argv[]) &#123;</span><br><span class="line">    printf(&quot;argc = %d\n&quot;, argc);</span><br><span class="line">    while (argc++ &gt; 0) &#123;</span><br><span class="line">        if(argc &lt; 0)&#123;</span><br><span class="line">            printf(&quot;argv[0] %s\n&quot;, argv[0]);</span><br><span class="line">            break;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;argc = %d\n&quot;, argc);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> argc &#x3D; 1<br> argv[0] .&#x2F;文件<br> argc &#x3D; -2147483648  </p></li><li><p>解释：</p></li></ul><ol><li>打印了argc的数量，即第一次我们调用程序时，输入的命令行(.&#x2F;文件名称)</li><li>在while循环内进行了argc的判断与自增，并且在其中加入了argc的判断。argc在不断自增的过程中，由于其本身便是int类型，故会增加到一定大小后，变成负数。当变为负数时，if语句成立，输出argv[0]，跳出while循环，不会argc的自增~</li><li>输出argc的大小。</li></ol><ul><li>考点：<br> argc与argv[]的含义</li></ul><h2 id="6-const-与指针：谁能动，谁不能动？"><a href="#6-const-与指针：谁能动，谁不能动？" class="headerlink" title="6. const 与指针：谁能动，谁不能动？"></a>6. const 与指针：谁能动，谁不能动？</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">struct P &#123;</span><br><span class="line">    int x;</span><br><span class="line">    const int y;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    struct P p1 = &#123; 10, 20 &#125;, p2 = &#123; 30, 40 &#125;;</span><br><span class="line">    const struct P p3 = &#123; 50, 60 &#125;;</span><br><span class="line">    struct P* const ptr1 = &amp;p1;</span><br><span class="line">    const struct P* ptr2 = &amp;p2;</span><br><span class="line">    const struct P* const ptr3 = &amp;p3;</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>说说下列操作是否合法，并解释原因：</p><p><code>ptr1-&gt;x = 100</code>, <code>ptr2-&gt;x = 300</code>, <code>ptr3-&gt;x = 500</code></p><p><code>ptr1-&gt;y = 200</code>, <code>ptr1 = &amp;p2</code>, <code>ptr2-&gt;y = 400</code></p><p><code>ptr2 = &amp;p1</code>, <code>ptr3-&gt;y = 600</code>, <code>ptr3 = &amp;p1</code></p><p><strong>题解：</strong><br>输出结果：</p><table><thead><tr><th align="left"></th><th align="center"></th><th align="right"></th></tr></thead><tbody><tr><td align="left">合法</td><td align="center">不合法</td><td align="right">不合法</td></tr><tr><td align="left">不合法</td><td align="center">不合法</td><td align="right">不合法</td></tr><tr><td align="left">合法</td><td align="center">不合法</td><td align="right">不合法</td></tr></tbody></table><ul><li>解释：</li></ul><ol><li>首先定义了一个结构体，在结构体内有两个变量，<code>x</code>是<code>int</code>类型，<code>y</code>是<code>const int</code>类型，即无法通过指针改变<code>y</code>的值。</li><li><code>p1</code>指针锁定了他指向的位置，<code>p2</code>指针锁定了他指向的内容，<code>p3</code>指针锁定了他指向的位置和内容。三个指针的区别就在于<code>const</code>的修饰。<code>*</code>在<code>const</code>前，在<code>const</code>后，在两个<code>const</code>中间。鉴于博主本人在学习此处时容易混淆，于是自己想了个小口诀，针对<code>*</code>在<code>const</code>的相对位置，“左位右值”（高中记物理二级结论的DNA动了）。供大家参考。</li></ol><ul><li>考点：<br> const限定符、结构体</li></ul><h2 id="7-指针！数组"><a href="#7-指针！数组" class="headerlink" title="7. 指针！数组!"></a>7. 指针！数组!</h2><p>在主函数中定义如下变量:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">int main() &#123;</span><br><span class="line">    int a[3] = &#123; 2, 4, 8 &#125;;</span><br><span class="line">    int(*b)[3] = &amp;a;</span><br><span class="line">    int* c[3] = &#123; a, a + 1, a + 2 &#125;;</span><br><span class="line">    int (*f1(int))(int*, int);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>说说这几个表达式的输出分别是什么？</p><p><code>a</code>, <code>*b</code>, <code>*b + 1</code>, <code>b</code>, <code>b + 1</code>, <code>* (*b + 1)</code>, <code>c</code>, <code>sizeof(a)</code>, <code>sizeof(b)</code>, <code>sizeof(&amp;a)</code>, <code>sizeof(f1)</code></p><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>a</code>:a[0]的地址<br> <code>*b</code>:a[0]的地址<br> <code>*b + 1</code>:a[1]的地址<br> <code>b</code>:a的地址<br> <code>b + 1</code>:a末尾的地址<br> <code>* (*b + 1)</code>:4<br> <code>c</code>:a[0]的地址的地址<br> <code>sizeof(a)</code>:3(元素个数)*4(int字节大小)&#x3D;12<br> <code>sizeof(b)</code>:8<br> <code>sizeof(&amp;a)</code>:8<br> <code>sizeof(f1)</code>:编译错误</p></li><li><p>解释：</p></li></ul><ol><li><code>a[3]</code>是一个含有三个<code>int</code>类型的数组<br> <code>(*b)[3]</code>是一个指向含有三个<code>int</code>元素类型的数组的指针<br> <code>* c[3]</code>是一个含有三个指向<code>int</code>指针类型的数组<br> <code>f1</code>是一个函数，他接受一个<code>int</code>类型的参数，返回为函数指针，该函数指针又可以接受一个<code>int</code>类型指针与<code>int</code>类型的参数，返回为<code>int</code>类型</li><li><code>sizeof</code>函数不可以操作函数。</li></ol><ul><li>考点：<br> sizeof的使用、数组，数组指针，指针数组的区别、函数指针（十分神奇的一项操作）</li></ul><h2 id="8-全局还是局部！！！"><a href="#8-全局还是局部！！！" class="headerlink" title="8. 全局还是局部！！！"></a>8. 全局还是局部！！！</h2><p>观察程序输出，思考为什么？</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">int g;</span><br><span class="line">int func() &#123;</span><br><span class="line">    static int j = 98;</span><br><span class="line">    j += g;</span><br><span class="line">    return j;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    g += 3;</span><br><span class="line">    char arr[6] = &#123;&#125;;</span><br><span class="line">    arr[1] = func();</span><br><span class="line">    arr[0] = func();</span><br><span class="line">    arr[2] = arr[3] = func() + 1;</span><br><span class="line">    arr[4] = func() + 1;</span><br><span class="line">    printf(&quot;%s linux\n&quot;,arr);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>hello linux</code></p></li><li><p>解释：</p></li></ul><ol><li><code>arr[0]</code>:h<br> <code>arr[1]</code>:e<br> <code>arr[2]</code>:l<br> <code>arr[3]</code>:l<br> <code>arr[4]</code>:$o$  </li><li>在调用函数的过程中，每次<code>j</code>变量被增加，返回值被赋给了对应数组元素。</li><li><code>static</code>静态局部变量下，初始化只进行一次，且j变量存储在数据段。</li></ol><ul><li>考点：<br> 静态局部变量、ASCII码</li></ul><h2 id="9-宏函数指针"><a href="#9-宏函数指针" class="headerlink" title="9. 宏函数指针"></a>9. 宏函数指针</h2><p>观察程序结果，说说程序运行的过程：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">#define CALL_MAIN(main, x) (*(int (*)(int))*main)(x);</span><br><span class="line">#define DOUBLE(x) 2 * x</span><br><span class="line">int (*registry[1])(int);</span><br><span class="line">int main(int argc) &#123;</span><br><span class="line">    if (argc &gt; 2e3) return 0;</span><br><span class="line">    printf(&quot;%d &quot;, argc + 1);</span><br><span class="line">    *registry = (int(*)(int))main;</span><br><span class="line">    CALL_MAIN(registry, DOUBLE(argc + 1));</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>2 4 8 16 32 64 128 256 512 1024 </code>  </p></li><li><p>解释：</p></li></ul><ol><li>首先，(int (*)(int))是一个函数指针，他保存的是他所指函数的地址，并且在CALL_MAIN内，把main函数强制转换为一个函数指针，由于这个函数指针的地址就是他本身，main函数，即他在指向自己。在这个函数指针内，他接受一个int类型的变量，返回int类型，这个函数也恰好符合main函数的声明。</li><li>由于这个函数在不断的递归自己，则需要一个跳出递归的条件，即在宏定义处的DOUBLE起到了作用。通过每次的运算改变argc的值，并且加入if语句来判断是否结束该函数，便成功的解决了无限递归的问题。</li><li>resistry在声明时也是个函数指针，但是他本身是一个存储1个元素的数组，元素类型为int类型的指针。于是在resistry[0]内，保存的是指向main函数的函数指针。</li><li>在CALL_MAIN处，调用main函数，进行argc的运算，实现函数递归。</li></ol><ul><li>考点：<br> 宏定义、函数指针、函数指针数组</li></ul><h2 id="10-拼接-排序-去重"><a href="#10-拼接-排序-去重" class="headerlink" title="10. 拼接 排序 去重"></a>10. 拼接 排序 去重</h2><p>本题要求你编写以下函数，不能改动 <code>main</code> 函数里的代码。实现对 <code>arr1</code> 和 <code>arr2</code> 的拼接、排序和去重。你需要自行定义 <code>result</code> 结构体并使用 <code>malloc</code> 手动开辟内存。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">int main() &#123;</span><br><span class="line">    int arr1[] = &#123; 6, 1, 2, 1, 9, 1, 3, 2, 6, 2 &#125;;</span><br><span class="line">    int arr2[] = &#123; 4, 2, 2, 1, 6, 2 &#125;;</span><br><span class="line">    int len1 = sizeof(arr1) / sizeof(arr1[0]);</span><br><span class="line">    int len2 = sizeof(arr2) / sizeof(arr2[0]);</span><br><span class="line"></span><br><span class="line">    struct result result;</span><br><span class="line">    your_concat(arr1, len1, arr2, len2, result);</span><br><span class="line">    print_result(result);</span><br><span class="line">    your_sort(result);</span><br><span class="line">    print_result(result);</span><br><span class="line">    your_dedup(result);</span><br><span class="line">    print_result(result);</span><br><span class="line">    free(result.arr);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li>代码：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br></pre></td><td class="code"><pre><span class="line">#include&lt;stdio.h&gt;</span><br><span class="line">#include&lt;stdlib.h&gt;</span><br><span class="line">struct result</span><br><span class="line">&#123;</span><br><span class="line">    int* arr;</span><br><span class="line">    int size;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">void your_concat(int arr1[],int len1,int arr2[],int len2,struct result* res);</span><br><span class="line">void print_result(struct result res);</span><br><span class="line">void your_sort(struct result* res);</span><br><span class="line">void sort(int arr[],int low,int high);//it&#x27;s a qsort.</span><br><span class="line">void swap(int* a,int* b);</span><br><span class="line">void your_dedup(struct result* res);</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int arr1[] = &#123; 6, 1, 2, 1, 9, 1, 3, 2, 6, 2 &#125;;</span><br><span class="line">    int arr2[] = &#123; 4, 2, 2, 1, 6, 2 &#125;;</span><br><span class="line">    int len1 = sizeof(arr1) / sizeof(arr1[0]);</span><br><span class="line">    int len2 = sizeof(arr2) / sizeof(arr2[0]);</span><br><span class="line"></span><br><span class="line">    struct result result;</span><br><span class="line">    your_concat(arr1, len1, arr2, len2, &amp;result);</span><br><span class="line">    print_result(result);</span><br><span class="line">    your_sort(&amp;result);</span><br><span class="line">    print_result(result);</span><br><span class="line">    your_dedup(&amp;result);</span><br><span class="line">    print_result(result);</span><br><span class="line">    free(result.arr);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void your_concat(int arr1[],int len1,int arr2[],int len2,struct result* res)</span><br><span class="line">&#123;</span><br><span class="line">    res-&gt;arr=(int*)malloc((len1+len2)*sizeof(int));</span><br><span class="line">    int i;</span><br><span class="line"></span><br><span class="line">    for(i=0;i&lt;len1;i++)</span><br><span class="line">    &#123;</span><br><span class="line">        res-&gt;arr[i]=arr1[i];</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    for(i=0;i&lt;len2;i++)</span><br><span class="line">    &#123;</span><br><span class="line">        res-&gt;arr[len1+i]=arr2[i];</span><br><span class="line">    &#125;</span><br><span class="line">    res-&gt;size=len1+len2;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void print_result(struct result res)</span><br><span class="line">&#123;</span><br><span class="line">    int i;</span><br><span class="line">    for(i=0;i&lt;res.size;i++)</span><br><span class="line">    &#123;</span><br><span class="line">        printf(&quot;%d &quot;,res.arr[i]);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void your_sort(struct result* res)</span><br><span class="line">&#123;</span><br><span class="line">    sort(res-&gt;arr,0,res-&gt;size-1);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void sort(int arr[],int low,int high)</span><br><span class="line">&#123;</span><br><span class="line">    int i=low;</span><br><span class="line">    int j=high;</span><br><span class="line">    int key=arr[low];</span><br><span class="line">    if(i&gt;j)</span><br><span class="line">    &#123;</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    while(i&lt;j)</span><br><span class="line">    &#123;</span><br><span class="line">        while(i&lt;j &amp;&amp; arr[j]&gt;=key)</span><br><span class="line">        &#123;</span><br><span class="line">            j--;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        while(i&lt;j &amp;&amp; arr[i]&lt;=key)</span><br><span class="line">        &#123;</span><br><span class="line">            i++;</span><br><span class="line">        &#125;</span><br><span class="line">        if(i&lt;j)</span><br><span class="line">        &#123;</span><br><span class="line">            swap(&amp;arr[i],&amp;arr[j]);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    swap(&amp;arr[low],&amp;arr[i]);</span><br><span class="line">    sort(arr,low,i-1);</span><br><span class="line">    sort(arr,i+1,high);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void swap(int* a,int* b)</span><br><span class="line">&#123;</span><br><span class="line">    int tmp=*a;</span><br><span class="line">    *a=*b;</span><br><span class="line">    *b=tmp;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void your_dedup(struct result* res)</span><br><span class="line">&#123;</span><br><span class="line">    if(res-&gt;size&lt;=1)</span><br><span class="line">    &#123;</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    int new_size=1;</span><br><span class="line">    int i;</span><br><span class="line"></span><br><span class="line">    for(i=1;i&lt;res-&gt;size;i++)</span><br><span class="line">    &#123;</span><br><span class="line">        if(res-&gt;arr[i]!=res-&gt;arr[i-1])</span><br><span class="line">        &#123;</span><br><span class="line">            res-&gt;arr[new_size]=res-&gt;arr[i];</span><br><span class="line">            new_size++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    res-&gt;arr=(int*)realloc(res-&gt;arr,new_size*sizeof(int));</span><br><span class="line">    res-&gt;size=new_size;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p>输出结果：<br> <code>6 1 2 1 9 1 3 2 6 2 4 2 2 1 6 2</code><br> <code>1 1 1 1 2 2 2 2 2 2 3 4 6 6 6 9</code><br> <code>1 2 3 4 6 9</code>  </p></li><li><p>解释：</p></li></ul><ol><li>首先定义结构体，其中结构体有<code>int</code>类型的指针，和我们将要进行动态操作的数组。</li><li>在拼接函数内，首先为结构体内指针分配内存，用两个for循环，将两个数组依次输入到我们刚刚分配内存的指针内。我们之后的操作也是基于这个数组。记得把大小也赋值给结构体内，保存长度的<code>size</code>变量。</li><li>在排序函数内，我使用的是快速排序。</li><li>在去重函数内，我对数组进行for循环遍历，由于该数组已经排序完毕，所以可以依次比较。最后将去重后的数组重新分配内存，并且重新赋值数组大小。</li><li>记得free内存。</li></ol><ul><li>考点：<br> 结构体、排序算法、动态分配内存</li></ul><h2 id="11-指针魔法"><a href="#11-指针魔法" class="headerlink" title="11. 指针魔法"></a>11. 指针魔法</h2><p>用你智慧的眼睛，透过这指针魔法的表象，看清其本质：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">void magic(int(*pa)[6], int** pp) &#123;</span><br><span class="line">    **pp += (*pa)[2];</span><br><span class="line">    *pp = (*pa) + 5;</span><br><span class="line">    **pp -= (*pa)[0];</span><br><span class="line">    *pp = (*pa) + ((*(*pa + 3) &amp; 1) ? 3 : 1);</span><br><span class="line">    *(*pp) += *(*pp - 1);</span><br><span class="line">    *pp = (*pa) + 2;</span><br><span class="line">&#125;</span><br><span class="line">int main() &#123;</span><br><span class="line">    int a[6] = &#123; 2, 4, 6, 8, 10, 12 &#125;;</span><br><span class="line">    int* p = a + 1,** pp = &amp;p;</span><br><span class="line">    magic(&amp;a, pp);</span><br><span class="line">    printf(&quot;%d %d\n%d %d %d\n%d %d\n&quot;,*p,**pp,a[1],a[2],a[3],a[5],p-a);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br><code>6 6</code><br><code>12 6 8</code><br><code>10 2</code>  </p></li><li><p>解释：</p></li></ul><ol><li>在main函数内，先分配了一个数组，并且定义了一级指针<code>p</code>，和二级指针<code>pp</code>。此时p内为<code>a[1]</code>的地址，<code>pp</code>为<code>a[1]</code>的地址的地址。接下来我们在<code>magic</code>函数内逐步分析。</li><li>首先<code>magic</code>函数内传入了一个指向6个元素数组的指针的参数，和一个二级指针的参数。</li><li>第一行，<code>a[2]</code>的值和<code>a[1]</code>的值相加，赋给了<code>pp</code>。此时数组状态为<code>{ 2, 10, 6, 8, 10, 12 }</code>。</li><li>第二行，把<code>a[5]</code>的地址赋给了<code>pp</code>。此时数组状态为<code>{ 2, 10, 6, 8, 10, 12 }</code>。</li><li>第三行，把<code>a[5]</code>的值和<code>a[0]</code>的值相减，赋给了<code>a[5]</code>。此时数组状态为<code>{ 2, 10, 6, 8, 10, 10 }</code>。</li><li>第四行，先在内层进行判断，如果<code>a[3]</code>的值和<code>1</code>位与之后，结果非0，则把<code>1</code>作为参数，执行外层的代码。最终结果是把<code>a[1]</code>的地址赋值给了<code>pp</code>。此时数组状态为<code>{ 2, 10, 6, 8, 10, 10 }</code>。</li><li>第五行，把<code>a[1]</code>和<code>a[0]</code>的值相加，赋给了<code>a[1]</code>。此时数组状态为<code>{ 2, 12, 6, 8, 10, 10 }</code>。</li><li>第六行，把<code>a[2]</code>的地址赋给了<code>pp</code>。此时数组状态为<code>{ 2, 12, 6, 8, 10, 10 }</code>。</li><li>最后printf函数输出时，<code>*p</code>和<code>**pp</code>为<code>6</code>，<code>p-a</code>为<code>2</code>，即元素位置之差。其他对应输出相应数组元素即可。</li></ol><ul><li>考点：<br> 数组指针、二级指针</li></ul><h2 id="12-奇怪的循环"><a href="#12-奇怪的循环" class="headerlink" title="12. 奇怪的循环"></a>12. 奇怪的循环</h2><p>你能看明白这个程序怎样运行吗？试着理解这个程序吧！</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">union data &#123;</span><br><span class="line">    void**** p;</span><br><span class="line">    char arr[20];</span><br><span class="line">&#125;;</span><br><span class="line">typedef struct node &#123;</span><br><span class="line">    int a;</span><br><span class="line">    union data b;</span><br><span class="line">    void (*use)(struct node* n);</span><br><span class="line">    char string[0];</span><br><span class="line">&#125; Node;</span><br><span class="line">void func2(Node* node);</span><br><span class="line"></span><br><span class="line">void func1(Node* node) &#123;</span><br><span class="line">    node-&gt;use = func2;</span><br><span class="line">    printf(&quot;%s\n&quot;, node-&gt;string);</span><br><span class="line">&#125;</span><br><span class="line">void func2(Node* node) &#123;</span><br><span class="line">    node-&gt;use = func1;</span><br><span class="line">    printf(&quot;%d\n&quot;, ++(node-&gt;a));</span><br><span class="line">&#125;</span><br><span class="line">int main() &#123;</span><br><span class="line">    const char* s = &quot;Your journey begins here!&quot;;</span><br><span class="line">    Node* P = (Node*)malloc(sizeof(Node) + (strlen(s) + 1) * sizeof(char));</span><br><span class="line">    strcpy(P-&gt;string, s);</span><br><span class="line">    P-&gt;use = func1;</span><br><span class="line">    P-&gt;a = sizeof(Node) * 50 + sizeof(union data);</span><br><span class="line">    while (P-&gt;a &lt; 2028) &#123;</span><br><span class="line">        P-&gt;use(P);</span><br><span class="line">    &#125;</span><br><span class="line">    free(P);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>题解：</strong></p><ul><li><p>输出结果：<br> <code>Your journey begins here!</code><br><code>2025</code><br><code>Your journey begins here!</code><br><code>2026</code><br><code>Your journey begins here!</code><br><code>2027</code><br><code>Your journey begins here!</code><br><code>2028</code>  </p></li><li><p>解释：</p></li></ul><ol><li>首先在计算<code>sizeof(Node)</code>时，要注意结构体和共用体的内存对齐，对于共用体来说，内存共用且为最长字节类型的最小整数倍，即<code>24</code>。对结构体来说，每个变量对齐时，其对齐位置为上一次对齐后的下一位，为最长字节类型的倍数，总内存为最小整数倍，即<code>40</code>。</li><li><code>use</code>函数指针指向了<code>func1</code>，在进入while循环内，伴随着每一次条件的判断，在<code>func1</code>和<code>func2</code>来回交替执行，直到条件不成立。</li></ol><ul><li>考点：<br> 结构体和共用体内存对齐、函数指针</li></ul><h2 id="13-GNU-Linux-选做"><a href="#13-GNU-Linux-选做" class="headerlink" title="13. GNU&#x2F;Linux (选做)"></a>13. GNU&#x2F;Linux (选做)</h2><p>注：嘿！你或许对 Linux 命令不是很熟悉，甚至你没听说过 Linux。但别担心，这是选做题，了解 Linux 是加分项，但不了解也不扣分哦！</p><ol><li>你知道 cd 命令的用法与 &#x2F; ~ - 这些符号的含义吗？</li><li>你知道 Linux 系统如何创建和删除一个目录吗？</li><li>请问你还懂得哪些与 GNU&#x2F;Linux 相关的知识呢？</li></ol><p><strong>题解：</strong></p><ul><li>输出结果：</li></ul><ol><li><code>cd</code>:更改目录<br> <code>cd /</code>:切换至根目录<br> <code>cd ~</code>:切换至用户主目录<br> <code>cd -</code>:切换至上一级目录</li><li><code>mkdir 目录名称 </code><br> <code>rmdir 目录名称</code></li><li><code>ls</code>:列出文件<br> <code>touch</code>:创建文件<br> <code>clear</code>:清除终端页面<br> ……<br>D</li></ol>]]>
    </content>
    <id>https://gmaxh.site/2025/10/23/%E8%A5%BF%E9%82%AE%20Linux%20%E5%85%B4%E8%B6%A3%E5%B0%8F%E7%BB%84%202025%20%E7%BA%B3%E6%96%B0%E9%9D%A2%E8%AF%95%E9%A2%98/</id>
    <link href="https://gmaxh.site/2025/10/23/%E8%A5%BF%E9%82%AE%20Linux%20%E5%85%B4%E8%B6%A3%E5%B0%8F%E7%BB%84%202025%20%E7%BA%B3%E6%96%B0%E9%9D%A2%E8%AF%95%E9%A2%98/"/>
    <published>2025-10-23T18:23:11.000Z</published>
    <summary>
      <![CDATA[<h1 id="西邮-Linux-兴趣小组-2025-纳新面试题"><a href="#西邮-Linux-兴趣小组-2025-纳新面试题" class="headerlink" title="西邮 Linux 兴趣小组 2025 纳新面试题"></a>西邮 Linux 兴趣小组]]>
    </summary>
    <title>西邮 Linux 兴趣小组 2025 纳新面试题</title>
    <updated>2026-06-21T11:43:30.049Z</updated>
  </entry>
</feed>
