普通视图

才发现那么快,该进入高速了

2026年1月31日 14:47
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/notes/7

路是自己走的,要知道,大学前两年走到哪里取决你的意志所在。

2023-2025年我错过了很多,26年决定了我如果想升学,可能就要选考研的路子。

2026年或许跟身边人的关系拉近了,不那么僵化,因为我本身也自带孤独,我的老同桌也经常说我:猛兽总是独行,牛羊才成群结队。

一路没有同伴,一路都是自己一步一步走来的。

可笑的是有一次我睡过了头,身边的冉,我就很生气:为什么自习没有叫醒我!

又是一年的奋战,希望这篇日记告诉自己:开始清醒了,我的内心,一年后见分晓!

看完了?说点什么呢

  •  

为你踩坑系列:搭建Flarum论坛的一天一夜

2026年1月30日 23:57
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/posts/deploy/flarum-forum-setup-issues-and-solutions

苦了我一天一夜的前言

昨天半夜睡不着,哦不,是又犯捣鼓兴趣了,群里一堆论坛大佬,我也想搞一个论坛试试 (不能浪费一点我的服务器)。这篇文章也记录了我踩的坑和思路:

1、选择Docker还是直接框架搭建?

直觉告诉我,必须Docker,相比较直接的LNMP等框架,Docker占用内存小并且搭建很快速。 image.png

如果你偏要选择一点一点部署,好吧,我放在下面了 参考官方文档:安装 | Flarum Documentation

2、Docker搭建Flarum

我一开始选择Docker应用商店里面的Flarum的,妈的,发现设置不了账号密码,并且Docker部署的项目的数据库放在”虚拟空间“中,在宝塔里面也没有管理的方式 (可能我太菜了),所以我选择了docker-compose进行拉取和配置文件

image.png

2-1 创建镜像文件

docker-compose.yml 放在你想放的文件夹,比如我选择网站目录:/www/wwwroot/bbs/docker-compose.yml

另外还有 flarum.env

DEBUG=false
FORUM_URL=    #设置自己网站地址,刚开始也可以设置成公网IP+端口号

# Database configuration
DB_HOST=mariadb
DB_NAME=flarum
DB_USER=flarum
DB_PASS=         #和上方设置的密码保持一致
DB_PREF=flarum_
DB_PORT=3306

# User admin flarum (environment variable for first installation)
# /!\ admin password must contain at least 8 characters /!\
FLARUM_ADMIN_USER=        #网站管理员账户
FLARUM_ADMIN_PASS=    #密码和上面的密码保持一致
FLARUM_ADMIN_MAIL=       #管理员邮箱
FLARUM_TITLE=      #网站标题

然后docker-compose.yml写入内容 (vi 编辑,i 编辑,esc 退出编辑,:wq 保存编辑)

services:
  flarum:
    image: mondedie/flarum:stable
    container_name: flarum
    env_file:
      - flarum.env
    volumes:
      - /var/lib/docker/volumes/flarum/assets:/flarum/app/public/assets
      - /var/lib/docker/volumes/flarum/extensions:/flarum/app/extensions
      - /var/lib/docker/volumes/flarum/storage/logs:/flarum/app/storage/logs
      - /var/lib/docker/volumes/flarum/nginx:/etc/nginx/flarum
    ports:
      - 8080:8888
    depends_on:
      - mariadb

  mariadb:
    image: mariadb:10.5
    container_name: mariadb
    environment:
      - MYSQL_ROOT_PASSWORD=
      - MYSQL_DATABASE=
      - MYSQL_USER=
      - MYSQL_PASSWORD=
    volumes:
      - /var/lib/docker/mysql/db:/var/lib/mysql

2-2 拉取镜像

docker-compose up -d

然后给容器部署网站域名,并且添加SSL

2-3 更新Flarum

我是莫名其妙更新的,因为拉取插件的时候使用了 -W 导致直接更新到最新版本 1.8.x

3、Flarum需要的操作

让我们先到容器里面再操作: 比如宝塔的: image.png

然后到flarum的目录: image.png

你也可以直接:

# 进入容器
docker exec -it flarum sh

cd /flarum/app

3-1 添加中文

composer require flarum-lang/chinese-simplified
php flarum cache:clear

3-2 安装插件

composer require xxx

3-3 卸载插件

composer remove xxx

3-4 清除缓存

php flarum cache:clear

3-5 开启Debug

在app目录里面有config.php文件:

ls

然后编辑即可:

vi config.php

修改debug的false为true

4、出现的问题

4-1 无法写入文件

无法写入文件。请检查操作权限,重试或者直接从命令行运行命令。

清除缓存XHRPOST
https://bbs.tiango.wiki/api/cache
[HTTP/2 409  92ms]

Flarum\Foundation\IOException in /flarum/app/vendor/flarum/core/src/Api/Controller/ClearCacheController.php:56
Stack trace:
#0 /flarum/app/vendor/flarum/core/src/Api/Controller/AbstractDeleteController.php(24): Flarum\Api\Controller\ClearCacheController->delete()
#1 /flarum/app/vendor/flarum/core/src/Http/RouteHandlerFactory.php(41): Flarum\Api\Controller\AbstractDeleteController->handle()
#2 /flarum/app/vendor/flarum/core/src/Http/Middleware/ExecuteRoute.php(27): Flarum\Http\RouteHandlerFactory->Flarum\Http\{closure}()
#3 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\ExecuteRoute->process()
#4 /flarum/app/vendor/flarum/core/src/Api/Middleware/ThrottleApi.php(33): Laminas\Stratigility\Next->handle()
#5 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Api\Middleware\ThrottleApi->process()
#6 /flarum/app/vendor/flarum/core/src/Http/Middleware/CheckCsrfToken.php(44): Laminas\Stratigility\Next->handle()
#7 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\CheckCsrfToken->process()
#8 /flarum/app/vendor/flarum/core/src/Http/Middleware/ResolveRoute.php(69): Laminas\Stratigility\Next->handle()
#9 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\ResolveRoute->process()
#10 /flarum/app/vendor/flarum/core/src/Http/Middleware/SetLocale.php(51): Laminas\Stratigility\Next->handle()
#11 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\SetLocale->process()
#12 /flarum/app/vendor/flarum/core/src/Http/Middleware/AuthenticateWithHeader.php(58): Laminas\Stratigility\Next->handle()
#13 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\AuthenticateWithHeader->process()
#14 /flarum/app/vendor/flarum/core/src/Http/Middleware/AuthenticateWithSession.php(31): Laminas\Stratigility\Next->handle()
#15 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\AuthenticateWithSession->process()
#16 /flarum/app/vendor/flarum/core/src/Http/Middleware/RememberFromCookie.php(63): Laminas\Stratigility\Next->handle()
#17 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\RememberFromCookie->process()
#18 /flarum/app/vendor/flarum/core/src/Http/Middleware/StartSession.php(61): Laminas\Stratigility\Next->handle()
#19 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\StartSession->process()
#20 /flarum/app/vendor/flarum/core/src/Api/Middleware/FakeHttpMethods.php(29): Laminas\Stratigility\Next->handle()
#21 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Api\Middleware\FakeHttpMethods->process()
#22 /flarum/app/vendor/flarum/core/src/Http/Middleware/ParseJsonBody.php(28): Laminas\Stratigility\Next->handle()
#23 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\ParseJsonBody->process()
#24 /flarum/app/vendor/flarum/core/src/Http/Middleware/HandleErrors.php(57): Laminas\Stratigility\Next->handle()
#25 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\HandleErrors->process()
#26 /flarum/app/vendor/flarum/core/src/Http/Middleware/InjectActorReference.php(25): Laminas\Stratigility\Next->handle()
#27 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\InjectActorReference->process()
#28 /flarum/app/vendor/laminas/laminas-stratigility/src/MiddlewarePipe.php(75): Laminas\Stratigility\Next->handle()
#29 /flarum/app/vendor/middlewares/request-handler/src/RequestHandler.php(84): Laminas\Stratigility\MiddlewarePipe->process()
#30 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Middlewares\RequestHandler->process()
#31 /flarum/app/vendor/middlewares/base-path-router/src/BasePathRouter.php(99): Laminas\Stratigility\Next->handle()
#32 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Middlewares\BasePathRouter->process()
#33 /flarum/app/vendor/laminas/laminas-stratigility/src/Middleware/OriginalMessages.php(36): Laminas\Stratigility\Next->handle()
#34 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Laminas\Stratigility\Middleware\OriginalMessages->process()
#35 /flarum/app/vendor/middlewares/base-path/src/BasePath.php(73): Laminas\Stratigility\Next->handle()
#36 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Middlewares\BasePath->process()
#37 /flarum/app/vendor/flarum/core/src/Http/Middleware/ProcessIp.php(24): Laminas\Stratigility\Next->handle()
#38 /flarum/app/vendor/laminas/laminas-stratigility/src/Next.php(49): Flarum\Http\Middleware\ProcessIp->process()
#39 /flarum/app/vendor/laminas/laminas-stratigility/src/MiddlewarePipe.php(75): Laminas\Stratigility\Next->handle()
#40 /flarum/app/vendor/laminas/laminas-stratigility/src/MiddlewarePipe.php(64): Laminas\Stratigility\MiddlewarePipe->process()
#41 /flarum/app/vendor/laminas/laminas-httphandlerrunner/src/RequestHandlerRunner.php(73): Laminas\Stratigility\MiddlewarePipe->handle()
#42 /flarum/app/vendor/flarum/core/src/Http/Server.php(45): Laminas\HttpHandlerRunner\RequestHandlerRunner->run()
#43 /flarum/app/public/index.php(26): Flarum\Http\Server->listen()
#44 {main} admin.js:2:323396

问题可能:

HTTP 409 状态码
代表 “冲突”(Conflict),Flarum 的 ClearCacheController 返回这个错误通常是 缓存正在被占用或锁定。
可能是之前清理缓存的操作未完成,或者某个进程正在写缓存。

IOException
指的是 Flarum 在写入缓存文件时失败。
缓存目录不存在或不可写
缓存目录里残留了被锁定的文件
文件系统不支持锁(某些容器卷挂载方式可能不支持文件锁)

容器卷挂载问题
如果 /storage 或 /public/assets 挂载到宿主机卷上,宿主机文件系统可能 不支持 flock 或锁操作,导致清缓存失败。

查看 storage/cache 目录是否存在锁文件:

/flarum/app # ls -lh /flarum/app/storage/cache

total 16K  
drwxr-xr-x 3 991 991 4.0K Sep 6 09:47 02  
drwxr-xr-x 3 991 991 4.0K Sep 6 09:47 37  
drwxr-xr-x 3 991 991 4.0K Sep 6 09:47 77  
drwxr-xr-x 3 root root 4.0K Sep 6 09:44 ee  
/flarum/app #

显然出现锁文件root用户的:

rm -rf /flarum/app/storage/cache/ee

4-2 无法连接部署的sonic

添加中文搜索功能使用docker部署的sonic项目

具体操作:
出现下面报错:

PHP Warning: stream_socket_client(): Unable to connect to tcp://127.0.0.1:1491 (Connection refused) in /flarum/app/vendor/ppshobi/psonic/src/Client.php on line 66 Invalid sonic server detail!

可能是docker网络连接问题:
可以通过创建网络:

docker network create flarum-net

把 sonic 加入:

docker network connect flarum-net heuristic_visvesvaraya

把 flarum 也放进同一个网络(我的 flarum 容器叫 flarum):

docker network connect flarum-net flarum

在 flarum 配置里改 Sonic 地址:

    'host' => 'heuristic_visvesvaraya',
    'port' => 1491,
    'password' => 'SecretPassword', // 跟 sonic.cfg 里保持一致

重新执行:

    php flarum sonic:addtoindex

4-3 插件更新容易出现的JS问题

TypeError: can't access property "type", t is undefined
    pushObject Store.ts:125
    pushPayload Store.ts:103
    preloadedApiDocument Application.tsx:367
    ...

说明 Flarum 在加载数据时,后端返回的 API 数据不符合预期。通常发生在:

  1. 插件更新后 API schema 变了,但前端 js 还是旧的,导致 Store.pushPayload 收到的 JSON 数据里缺少 type 属性。
  2. 缓存问题:前端还在加载老版本的 JS,和后端新版不匹配。
  3. 插件 bug 或冲突:某个扩展返回了错误的 JSON(比如返回 null 或者结构不完整)。
  4. 数据库字段缺失/迁移没跑:插件升级后需要执行 php flarum migrate,不然返回的数据格式异常。
php flarum migrate
php flarum cache:clear

看完了?说点什么呢

  •  

2025年放手很多,面对很多

2026年1月1日 00:40
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/posts/nexus/goodbye-2025

壹 · 腊月的忙碌

如题,就是这样的:12月很忙的:六级考试,备课(讲了三四个PPT),重新开始自己的项目:Zhixu

1、略失望的项目与属于自己的开始

起因是11月吧,flynn的项目FlyMD,一个Tauri框架的markdown编辑器软件,我也是业余的玩家,本身就没有学几个代码,全靠AI整东西,正好我的Typecho发布插件也跟着适配flymd项目了,后面我还“夸大海口”:安卓端我来吧!(由于SAF插件问题,无法进行)

  • 实际flymd桌面端我不看好,尤其是界面设计和操作逻辑,反用户直觉。
  • 面对我提出的几个界面优化,一律被“影响软件启动”回绝了。
  • 于是,后面觉得我特别需要一个属于自己使用体验的笔记软件,特别是安卓端,这也是后面开始的:Zhixu项目。

2. 很有起步的12月

决定不保研,感觉目前身上担子很小,觉得未来也不过如此,先学习自己喜欢的,后面看造化,考研吧,毕竟我是那种后知后觉的(开水到身才行)。

贰 · 学的不多,时代之快

我一直觉得世界那么快速发展,技术如此迭代之快,我该何去何从。

  • 恐惧是第一的阻碍,勇敢尝试是第一钥匙。
  • 我的QQ签名有三个:
    1. 明明感觉距离很近,但伸手却又抓不到,即使这样,即使望尘莫及,亦有留在心中的东西,曾身处同一时间层,曾仰望过同一样东西,只要记着这些,就算相互远离,也依然可以..[2024-07-09]
    2. 为天地立心,为生民立命,为往圣继绝学,为万世开太平。[2025-04-03]
    3. 实践第一,走出自己第一步![2025-11-09]

叁 · 2025学会放手

我第一个放手是寻找“心灵之友”,相比较习惯孤独,这很符合博客圈的:跨越孤岛的交流

孤独是一个人的狂欢,狂欢是一群人的孤独。(泰戈尔)

肆 · 2025面对很多

  1. 暑假去找了家教工作,很多被拒,不过也是找到几个合适的,相比较家教我也看到很多家长与学生,以及庞大的信息差价值;
  2. 大三上学期,发现很多高端的知识不过已经尘封书本了,面对新时代,单单的知识是很难的,感觉人很需要去变通和创新;
  3. 又面对自己内心的过度消费,挣扎一下差点让自己没有饭钱,觉得不属于自己不用去寻找体验感,不过是产品的“自述价值”;
  4. 旷课不断,这学期很多课都没有去,特别是早八,一个教不会学生的课不用浪费时间,你是属于自己的,去干最可以创造自己的事情吧!

你好!2026

我很期待,我开始考研准备,开始自己的项目,这意味着2026又是不一样的一年,我来了!2026!

看完了?说点什么呢

  •  

预告:Zhixu(知序)AI 赋能待办 & 笔记 APP

2025年12月27日 02:22
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/posts/repo/zhixu-app

HansJack/ZhiXu: Zhixu(知序)AI 赋能待办 & 笔记 APP - ZhiXu - Git For Hast One

目前已经开源:

https://github.com/TGU-HansJack/ZhiXu

Tip

Zhixu 目标是制作个人知识与任务系统,优先解决两件事:信息管理混乱与多端同步困难。

看完了?说点什么呢

  •  

本地部署Mx-Space和Shiroi主题

2025年12月25日 16:28
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/posts/deploy/deploy-mx-space-shiroi

壹・为什么选择Shiro

我从24年6月开始部署属于自己的博客,Typecho在轻量化和易部署方面成为我第一个博客系统,但是久而久之发现:Typecho在编辑器和内容自定义方面严重依靠插件市场,存储方面局限本地(其他存储位置又依靠插件,导致迁移和内容管理很麻烦),这对非单纯文本的博客来说很纠结。

  1. 媒体库管理我也开发了对应插件:

https://github.com/TGU-HansJack/MediaLibrary-Typecho-Plugin-Pro

  1. 文章订阅我也做了插件:

https://github.com/TGU-HansJack/Typecho-Subscribe-Plugin

但是,Shiro的后端系统Mx-Space提供了编辑器、文件管理、邮箱订阅,并且各类开发者均为大佬,并不需要担心部署问题(相比较PHP可能对新手不友好)。

Shiro相关项目

https://github.com/mx-space/core

https://github.com/Innei/Shiro

贰・本地部署过程

前提需要:

  • 本部署为单域名服务器可能要4G内存1Panel+OpenResty后端 Docker 部署
  • 为了部署试用全部情况,我尽量写通用点教程

1、相关环境

更新并安装必要包工具

apt update && apt install git curl vim wget git-lfs -y

安装NVM

curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash

运行 source ~/.profile 命令将环境变量重新加载到当前会话中

source ~/.profile

安装 Node.JS

# 安装
nvm install 20.12.2
# 检查版本
node -v

安装 pnpm pm2

npm install -g pnpm pm2

安装sharp(非必要)

npm i -g sharp
pnpm add sharp
# 配置sharp环境变量
# export NEXT_SHARP_PATH=/root/node_modules/sharp

2、后端 Core 部署

使用命令行拉取文件

#回到根目录并创建mx-space/core的文件夹,并跳转至core文件夹下
cd && mkdir -p mx-space/core && cd $_ 
# 拉取 docker-compose.yml 文件
wget https://fastly.jsdelivr.net/gh/mx-space/core@master/docker-compose.yml

修改 docker-compose.yml 内的部分内容 域名JWT密钥加密的相关配置(默认false)

services:
  app:
    container_name: mx-server
    image: innei/mx-server:latest
    environment:
      - TZ=Asia/Shanghai
      - NODE_ENV=production
      - DB_HOST=mongo
      - REDIS_HOST=redis
      #填写自己博客的域名,多个用,相连,这里可以额外加上本机地址允许他们自己访问自己
      - ALLOWED_ORIGINS=你的域名,localhost:*,127.0.0.1:* 
      #填写你自己生成的JWT密钥,16≤密钥长度≤32 个字符(务必保存好自己的密钥不要泄露)
      - JWT_SECRET=xxxxx 
      #是否开启加密的相关配置,这边默认为false与空即可,如需加密可以参考官方配置文档
      - ENCRYPT_ENABLE=false
      - ENCRYPT_KEY=
    volumes:
      - ./data/mx-space:/root/.mx-space
    ports:
      #-'2333:2333' 修改了docker的端口映射,不开放端口
      - '127.0.0.1:2333:2333' 
    depends_on:
      - mongo
      - redis
    networks:
      - mx-space
    restart: unless-stopped
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://127.0.0.1:2333/api/v2/ping']
      interval: 1m30s
      timeout: 30s
      retries: 5
      start_period: 30s

  mongo:
    container_name: mongo
    image: mongo
    volumes:
      - ./data/db:/data/db
    networks:
      - mx-space
    restart: unless-stopped

  redis:
    image: redis:alpine
    container_name: redis
    volumes:
      - ./data/redis:/data
    healthcheck:
      test: ['CMD-SHELL', 'redis-cli ping | grep PONG']
      start_period: 20s
      interval: 30s
      retries: 5
      timeout: 3s
    networks:
      - mx-space
    restart: unless-stopped

networks:
  mx-space:
    driver: bridge

启动 Core

docker compose pull && docker compose up -d

反向代理(单域名)1panel选择静态网站后修改location部分就行了,其他面板也类似

# WebSocket 地址
location /socket.io {
    proxy_set_header Upgrade $http_upgrade; 
    proxy_set_header Connection "Upgrade"; 
    proxy_buffering off; 
    proxy_set_header Host $host; 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header X-Forwarded-Proto $scheme; 
    proxy_pass http://127.0.0.1:2333/socket.io; 
}
# API 地址
location /api/v2 {
    proxy_pass http://127.0.0.1:2333/api/v2; 
}
# 简读 render 地址
location /render {
    proxy_pass http://127.0.0.1:2333/render; 
}
# Shiro 地址
location / {
    proxy_pass http://127.0.0.1:2323; 
}
# 后台地址
location /proxy {
    proxy_pass http://127.0.0.1:2333/proxy; 
}
location /qaqdmin { #如果需要修改自己的后台地址可以改这里
    proxy_pass http://127.0.0.1:2333/proxy/qaqdmin; 
}

访问https://你的域名/proxy/qaqdmin配置前、后端和api

Shiro的配置与构建

参考官方文档: 后端设置主题配置

拉取 Shiroi

未完待续。。。

pnpm i
pnpm build
pm2 start ecosystem.config.js
pm2 restart ecosystem.config.cjs --update-env

误判根目录,/root 目录下有 yarn.lock

rm /root/yarn.lock

遇到的问题

本地构建出现:

src/app/[locale]/thinking/item.tsx:305:33 - error TS2304: Cannot find name 'markdownScopedBlockquoteClassName'.

305         className={clsx('mt-4', markdownScopedBlockquoteClassName)}
                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Found 1 error in src/app/[locale]/thinking/item.tsx:305

 ELIFECYCLE  Command failed with exit code 2.
root@DS4460:~/mx-space/Shiroi#

解决方法: 将src/app/[locale]/thinking/item.tsx文件里面的:

const markdownScopedBlockquoteClassName =
  '[&_blockquote]:relative [&_blockquote]:my-2 [&_blockquote]:border-l-2 [&_blockquote]:border-accent/60 [&_blockquote]:pl-3 [&_blockquote]:text-zinc-600 dark:[&_blockquote]:text-zinc-300'

提到文件顶层(模块作用域),放在 import ... 后、export const ThinkingItem ...

参考文献

感谢大佬的教程,让我很快部署成功,本文几乎全是这些大佬的命令及其思路,本文仅用于后续查错使用,下面列出参考的大佬文章:

看完了?说点什么呢

  •  

Flymd项目新目标

2025年12月25日 02:20
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/notes/3

最近正在搞安卓端APP,Flymd在桌面端虽然是快速启动的markdown编辑器软件,但是在手机端:markdown编辑器是伪需求,碎片化+快发展的世纪,如果单单制作markdown编辑器,很难脱颖而出,甚至是“造轮子”。

Not support render this content in RSS render

看完了?说点什么呢

  •  

新思想25年1月新版必背十三道题

2025年12月25日 01:47
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/posts/materials/2025-jan-new-ideology-13-must-know-questions
哔哩哔哩视频

https://www.bilibili.com/video/BV1R26zYLESj?vd_source=85e3415720cc851cb002c86a00f2d4ed

新思想25年1月新版必背十三道题

以下按考试可能性排序:(高亮为1月新版升级点)

  1. 为什么要全面深化改革/发展新质生产力(第五章)
  2. 为什么说两个结合是我们取得成功的最大法宝(导论)
  3. 为什么要守好根脉(坚定文化自信)和魂脉/(导论,第十章)
  4. 中国式现代化的特征和意义,和重大原则(第二章)
  5. 为什么说中国式现代化离不开党的领导(第二章)
  6. 新发展理念的内涵(第六章)
  7. 如何推进高质量发展(第六章)
  8. 人类命运共同体的内涵(第十六章)
  9. 为什么江山就是人民,人民就是江山(第四章)
  10. 为什么说绿水青山就是金山银山(第十二章)
  11. 新时代的内涵,意义和变化(第一章)
  12. 总体国家安全观的内涵(第十四章)
  13. 自我革命引领社会革命(第十七章)

看完了?说点什么呢

  •  

四个做决策的方法

2025年12月21日 23:05
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/notes/1
  1. 关注最重要的事情,优先解决关键问题;
  2. 宁可不做,要做就做到最好,通过差异化竞争和细分赛道建立竞争优势;
  3. 先验证市场需求,小步快跑,快速迭代,确保核心目标明确,形成闭环逻辑;
  4. 做正确的事情,相信时间的力量,持续精进,避免重复错误动作。

看完了?说点什么呢

  •  

C 语言笔记

2025年12月21日 12:10
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/posts/programming/c-note

感谢Frank 为广大学生打开了进入现代化C语言的大门

6月份写的博文太水了,从这个笔记开始,博客文章内容均会提高到一个高度!

内容来自讲师Micro_Frank的免费课程,笔记具体来自所讲内容,如有侵权,联系博主!

第一章

第一个程序:C语言执行过程

#include <stdio.h>
int main()
{
    printf("Hello World!\n");

    return 0;
}

本程序是 C 语言的基础示例,演示了如何输出一行文本。#include <stdio.h> 语句包含了标准输入输出库,int main() 是程序的入口点,printf("Hello World!\n"); 用于打印字符串,return 0; 表示程序成功结束。

C语言故事·1

选用教材:C Primer Plus

建议英文中文对照阅读

C语言故事·2

声明 定义 赋值

#include <stdio.h>
int main()
{    //声明 declaration
    int number = 123;
    //定义 definition
    printf("%d\n, number");
    //赋值 assignment
    return 0;
}    //Frank_PPT 讲师在这一节还讲到了TAB键与制表符的使用

标识符

identifier:
    nondigit
     identifier
    digit

nondigit:
     _ a b c d e f g h i j k l m n o p q r s t u v w x y z
     A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

digit:
     0 1 2 3 4 5 6 7 8 9

编译器会将大写和小写字母视为不同的字符

add
ADD
Add
aDD

Microsoft 专用

以两条下划线开头或者以一条下划线后跟一个大写字母开头的名称。

Microsoft 使用下划线和大写字母作为宏名称的开头,并使用双下划线作为 Microsoft 特定关键字名称的开头。

有效标识符

j
count
temp1
top_of_page
skip12
LastNum

关键字

第二章 数据类型

注释

//行
    注释

/*
        块
    注
    释
*/

进制

变量

//int 变量
#include <stdio.h>

int main(){
    //integer 赋值
    int sun_flower = 9673;

    printf("阳光目前的数值:%d\n", sun_flower);

    return 0;
}

整型

语法:定义的类型 标识符 = 值

int类型在内存中存储

计算机的存储单位:

1G = 1024MB

1MB = 1024KiB

1KiB = 1024Btyes

1024Btye = 8Bit

|00000000|00000000|00000000|00000000|int|

0用于显示正负,一共可以表示 $2^{32} - 1$个值

#include <stdio.h>
int main()
{
    int number = 100;
    //以十进制表示
    printf("Decimal: %d\n", number);

    printf("Octal: %o\n", number);

    printf("Hexadeciaml (lowercase) : %x\n", number);

    printf("Hexadeciaml (uppercase) : %X\n", number);

    return 0;
}

浮点数

浮点数有:2.75、3.16E7、2e-8等

计算机怎么存储浮点数的?

浮点数:符号(1)+ 小数(23)+ 指数(8) int类型32位

One Step : 3.14159=> $314159×10^{-5}$ 先换成int类型

Two Step : 如何存储指数?$2^{8}$ = 256 从0到255, 偏127左边的数为负指数,偏值即为指数值。

float 和 double 类型

float 类型的范围 大约在 3.4E-38 和 3.4+38之间。

小数一般>1 , 所以规范化的浮点数往往大于1, 尾数(占据剩余的位数。)对于标准的浮点表示,尾数通常以1.XXXX的形式存储,隐式地前面有一个1(称为隐式前导位)。

所以 float尾数隐式长度为24位,double尾数隐式长度为53位。

单精度(32位)双精度(64位)

存储>精度 选择double , 存储<精度 选择float

浮点数的打印输出

#include <stdio.h>

int main() {

    float temperture = 36.5f;

    float humidity = 48.3f;

    float speed_of_sound = 343.5e2f;

    float lenght = 12.3f, width = 23.45f, height = 34.56f;

    printf("Temperture: %f\n", temperture);
    printf("Humidity: %f\n", humidity);
    printf("Speed_of_Sound: %f\n", speed_of_sound);
    printf("Lenght: %f x %f x %f\n", lenght width height);
//丢失精度
//double %lf , float %f
    return 0;
}

C99中对浮点数的规定

#include <stdio.h>

int main () {

float num = 123.456;

printf("Using %%f: %f\n", num);

//%e %E 科学计数法格式化输出
ptintf("Using %%e: %e\n", num);
printf("Using %%E: %E\n", num);

//%a %A 十六进制浮点数 p计数法
printf("Using %%a: %a\n", num);
printf("Using %%A: %A\n", num);

return 0;
}

浮点数的溢

#include <stdio.h>
#include <float.h>//点开看看

int main() {

    float max_float = FLT_MAX;

    float overflow = max_float * 1000.0f;
    //OverFlow 上溢

    float min_float = FLT_MIN;

    float underfloat = min_float / 1000.0f;
    //UnderFlow 下溢

    printf("Maximum Float: %e\n", max_float);
    printf("OverFloat: %e\n", overflow);
    printf("Minimum Float: %e\n", min_float);
    printf("UnderFloat: %e\n", underfloat);

    return 0;
}

Nan & Infinity

#include <stdio.h>
#include <float.h>
#include <math.h>

int main() {

    //正无穷大
    float positive_infinty = INIFITY;
    printf("Positive Infinity: %f\n", positive_infinty);

    //负无穷大
    float negative_infinty = -INIFITY;
    printf("Negative Infinity: %f\n", negative_infinty);

    //除以0产生的无穷大
    float num = 1.0f;
    float inifity = num / 0.0f;
    printf("0.0 / 0.0 = %f\n", nan);

    //Nano 0/0
    //float nan = 0.0f /0.0f;
    //printf("0.0f / 0.0f =%f\n", nan)

    //对负数开平方跟
    float negative_sqrt = sqrt(-1.0f);
    printf("sqrt(1.0f) = %f\n", nefative_sqrt);

    return 0;
}

最近偶数舍入标准(银行家舍入)

#include <stdio.h>

int main() {

    //四舍五入
    //IEEE 754
    //最近偶数舍入  round to nearest, ties to even
    //银行家舍入

    //3.14159
    float number = 3.14159f;
    printf("%.4f\n", number);

    //3.15
    //3.25
    return 0;
}

double,long double 科研与企业的区别

#include <stdio.h>

int main() {

    //double

    //float 丢失精度

    //3D渲染

    //利息 NASA

    //浮点常量 3.14
    //3.14 默认double类型 特别注明3.14f

    return 0;

}

float和double 有效精度对比 原理与计算

#include <stdio.h>

int main() {
 
    float float_num 1.0 / 3.0;
    double double_num = 1.0 / 3.0;

    printf("Float precision: %20f\n", float_num);
    printf("Double precision: %.20lf\n", double_num);
    //float 和 double 有效精度的对比
    printf("Defined max precision for double: %d\n", FLT_DIG)
    printf("Defined max precision for float: %d\n", DBL_DIG)

    //53除以log₂10  24除以log₂10  即为精确度

}

float(单精度浮点数):通常占用 4 字节(32 位)其中1位为符号位,8位为指数位,23位为尾数(有效数字)。通常有效精度约为 7 位十进制数字。

double(双精度浮点数): 通常占用 8 字节(64 位)。 1位为符号位,11位为指数位,52位为尾数。通常有效精度约为 15 到 16 位十进制数字。

浮点数的表示遵循 IEEE 754 标准。它的值可以通过以下公式表示:

sign: 符号位,决定正负。 fraction: 尾数,决定数值的精度。 exponent: 指数,决定数值的大小。 bias: 偏移量,对于 float为 127,对于 double为 1023。

银行中用定点数 (数据库MySQL)

char & ASCII

#include <stdio.h>

int main() {

    char mych = 'a'; //实际用int类型 存储, 将A转化成int类型 int(97)

    printf("mych: %c\n");

    //ASCII美国信息标准代码 一般使用7bit 包括128个字符


}

转义序列 反斜杠 \

转义序列 表示
\a 响铃(警报)
\b Backspace
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
' 单引号
" 双引号
\ 反斜杠
? 文本问号
\ ooo 八进制表示法的 ASCII 字符
\x hh 十六进制表示法的 ASCII 字符
\x hhhh 十六进制表示法的 Unicode 字符(如果此转义序列用于宽字符常量或 Unicode 字符串文本)。例如,WCHAR f = L'\x4e00' 或 WCHAR b[] = L"The Chinese character for one is \x4e00"
清除屏幕 print("\033[2J");
移动光标 print("\033[%d;%dH", 3, 3);

布尔类型 bool类型

#include <stdio.h>
#include <stdbool.h>

int main() {
    //true or false
    //转换成 1 or 0

    bool is_game_win = true;
    bool is_game_over = false;

    return 0;
}

常量const与#define宏

#include <stdio.h>
#define PI 3.14

int main() {
    //常量

    const double MAX_USER = 100;

    printf("PI: %lf\n", PI);

    return 0;

}

第二章结束语

第三章 运算符

运算符的介绍

1、算术运算符

2、关系运算符

运算符测试的关系
<第一个操作数小于第二个操作数
>第一个操作数大于第二个操作数
<=第一个操作数小于或等于第二个操作数
>=第一个操作数大于或等于第二个操作数
==第一个操作数等于第二个操作数
!=第一个操作数不等于第二个操作数

数据对象 左值和右值

#include <stdio.h>
#include <stdint.h>
#include <inttype.h>
int main() {

    //数据对象
    //左值 Lvalue
    //右值 Rvalue
    //运算符
    uint32_t apple_box = 5;

    uint32_t orange_box = 5;

    printf("苹果盒子里面有 %" PRIu32 "个苹果\n", apple_box);
    printf("橘子盒子里面有 %" PRIu32 "个橘子\n", orange_box);

    uint32_t total_fruit = apple_box + orange_box;

    printf("盒子里面有 %" PRIu32 "个水果\n", total_box);
 
    return 0;

}

多重赋值

前缀后缀递增与递减

#include <stdio.h>
#include <stdint.h>
#include <inttype.h>
int main() {

    int32_t value = 5;
    int32_t result_1;
    int32_t result_2;

    //后缀递增,先赋值,再++
    result_1 = value++;
    //前缀递减,先--,后赋值
    result_2 = --value;
    printf("After postfix increment, result_1 = %" PRIu32 ",result_2 = %" PRIu32 ", value = %" PRIu32 "\n", result_1, result_2, value);

    return 0;

}

按位移位运算符

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

    uint8_t num = 22;
    num >> 2;//高位补零,低位排挤

    return 0;
}
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

    uint8_t num = 22;
    //num >> 2; 高位补零,低位排挤

    uint8_t num = 22;
    printf("Original number: %" PRIu8 " (binary: 00010110)\n", num);

    uint8_t left_shifted = num << 2;
    printf("Left shifted by 2: %" PRIu8 " (binary: 01011000)\n", num);

    uint8_t right_shifted = num >> 2;
    printf("Right shifted by 2: %" PRIu8 " (binary: 00000101)\n", num);

    return 0;
}

乘法运算:移位运算符为什么比 直接 处理快?

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

    uint8_t num = 25;

    //uint32_t result = num * 1024;
    printf("Result: %" PRIu32 "\n", result);
    ALU 负责 基本的运算

    return 0;
}

移位运算符比直接使用乘法运算符(*)处理快的原因主要是因为底层实现的不同。

int类型需要注意左移可能导致溢出

逻辑的真与假、C关系运算符

include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

    int a = 10;
    int b = 20;
    //xxx ? xxx : xxx 判断true or false
    bool greater = a > b;
    printf("a > b: %d\n", greater);
    printf("a > b: %s\n", greater ? "true" , "false");

    bool less = a < b;
    printf("a < b: %d\n", less);
    printf("a < b: %s\n", less ? "true" , "false");

    bool not_equal = a != b;
    printf("a != b: %d\n", not_equal);
    printf("a != b: %s\n", not_equal ? "true" , "false");

    bool equal = a == b;
    printf("a == b: %d\n", equal);
    printf("a == b: %s\n", equal ? "true" , "false");

    bool greater_or_equal = a >= b;
    printf("a >= b: %d\n", greater_or_equal);
    printf("a >= b: %s\n", greater_or_equal ? "true" , "false");

    bool less_or_equal = a <= b;
    printf("a <= b: %d\n", less_or_equal );
    printf("a <= b: %s\n", less_or_equal ? "true" , "false");

    return 0;
}

条件表达式运算符

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

    int score = 89;

    printf("你的成绩等级:%s\n", score >= 60 ? "及格" : "不及格");

    return 0;
}
#include 
int main() { 
    int score = 85; 
    // 你可以根据需要修改这个分数 
    const char* result = (score >= 90) ? "优秀" : (score >= 85) ? "一般" : (score >= 60) ? "合格" : "不及格"; printf("%s\n", result); 

    return 0; 
}

按位运算符 & ^ |

运算符描述
&按位“与”运算符将其第一操作数的每个位与其第二操作数的相应位进行比较。 如果两个位均为 1,则对应的结果位将设置为 1。 否则,将对应的结果位设置为 0。
^按位“异或”运算符将其第一操作数的每个位与其第二操作数的相应位进行比较。 如果一个位是 0,另一个位是 1,则相应的结果位将设置为 1。 否则,将对应的结果位设置为 0。
|

& 按位与

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

    int a = 12;
    int b = 25;

    // & 二进制 位位比较 都是1才输出1 比如
    printf("%d\n", 12 & 25);
    //将特定位清零、检查某一位是否为1

    return 0;
}

| 按位与或

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

    int a = 2;
    int b = 5;

    // | 二进制 位位比较 有1就输出1 比如0111 
    printf("%d\n", a | b);
    //设置特定位、组合标志位

    return 0;
}

^ 按位异或

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

    int a = 2;
    int b = 10;

    // ^ 二进制 位位比较 有1 0才输出1 比如1000 
    printf("%d\n", a ^ b);
    //逻辑异或 XOR操作
    //翻转特定位、交换两个变量值、检查不同

    return 0;
}

按位取反 ~

掩码与电路遥控LED灯练习

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

void print_binary(uint8_t num);

int main() {

    uint8_t status = 0b00001100;    //初始状态

    printf("Initial status: 0b");
    print_binary(status);
    printf("\t(Binary)\n");

    status = status & 0b11111011;    //mask掩码 异或 控制
    printf(("Fanal status: 0b");
    printf("\t(Binary)\n");
    return 0;
}

void print_binary(uint8_t num);
    for (int index = 7; index >= 0; index--) {
        printf("%d", (num >> index) & 1);
    }
}

逻辑运算符 && ||

运算符描述
&&如果两个操作数具有非零值,则逻辑“与”运算符产生值 1。 如果其中一个操作数等于 0,则结果为 0。 如果逻辑“与”运算的第一个操作数等于 0,则不会计算第二个操作数。
||逻辑“或”运算符对其操作数执行“与或”运算。 如果两个操作数的值均为 0,则结果为 0。 如果其中一个操作数具有非零值,则结果为 1。 如果逻辑“或”运算的第一个操作数具有非零值,则不会计算第二个操作数。

复合赋值运算符

复合赋值运算符的操作数只能是整型和浮点型

#include <stdio.h>
/*
struct BigStruct {
    //..
    //..
};

void uodate(BigStruct& bs) {
    BigStruct temp = someExp();

    bs = bs + temp;

    bs += temp;

}
*/


int main() {

    int base_number = 8;
    int add_number = 2;
    int sub_number = 3;
    int mul_number = 2;
    int div_number = 5;
    int mod_number = 4;

    base_number += add_number;
    //In-place Modification 原地修改

    base_number -=
    base_number *=
    base_number /=
    base_number %=
    base_number <<=
    base_number >>=
    base_number &=
    base_number |=
    base_number ^=

    return 0;

}

逗号运算符

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

    uint32_t a = 1, b = 2, c = 4;

    uint32_t result = (a += 1, b -= 1, c += 3);

    printf("a = %d, b = %d, c = %d, result = %d", a, b, c, result);

    return 0;

}

Microsoft Learn

// cpp_comma_operator.cpp
#include <stdio.h>
int main () {
   int i = 10, b = 20, c= 30;
   i = b, c;
   printf("%i\n", i);

   i = (b, c);
   printf("%i\n", i);
}

Output:

20
30
func_one( x, y + 2, z );
func_two( (x--, y + 2), z );

在上面的对 func_one 的函数调用中,会传递以逗号分隔的三个参数:xy + 2 和 z。 在对 func_two 的函数调用中,圆括号强制编译器将第一个逗号解释为顺序计算运算符。 此函数调用将两个参数传递给 func_two。 第一个参数是顺序计算运算 (x--, y + 2) 的结果,具有表达式 y + 2 的值和类型;第二个参数为 z

计算的优先级和顺序

符号 ^1^操作类型结合性
[ ] ( ) . ->
++ --(后缀)
表达式从左到右
sizeof & * + - ~ !
++ --(前缀)
一元从右到左
typecasts一元从右到左
* / %乘法从左到右
+ -加法从左到右
<< >>按位移动从左到右
< > <= >=关系从左到右
== !=相等从左到右
&按位“与”从左到右
^按位“异或”从左到右
|按位“与或”从左到右
&&逻辑“与”从左到右
||逻辑“或”从左到右
? :条件表达式从右到左
= *= /= %=
+= -= <<= >>= &=
^= |=
简单和复合赋值 ^2^从右到左
,顺序计算从左到右

^1^ 运算符按优先级的降序顺序列出。 如果多个运算符出现在同一行或一个组中,则它们具有相同的优先级。

^2^ 所有简单的和复合的赋值运算符都有相同的优先级。

表达式可以包含优先级相同的多个运算符。 当多个具有相同级别的这类运算符出现在表达式中时,计算将根据该运算符的结合性按从右到左或从左至右的顺序来执行。 计算的方向不影响在相同级别包括多个乘法 (*)、加法 (+) 或二进制按位(&| 或 ^)运算符的表达式的结果。 语言未定义运算的顺序。 如果编译器可以保证一致的结果,则编译器可以按任意顺序随意计算此类表达式。

只有顺序计算 (,)、逻辑“与”(&&)、逻辑“或” (||)、条件表达式 (? :) 和函数调用运算符构成序列点,因此,确保对其操作数的计算采用特定顺序。 函数调用运算符是一组紧跟函数标识符的圆括号。 确保顺序计算运算符 (,) 按从左到右的顺序计算其操作数。 (函数调用中的逗号运算符与顺序计算运算符不同,不提供任何此类保证。)有关详细信息

逻辑运算符还确保按从左至右的顺序计算操作数。 但是,它们会计算确定表达式结果所需的最小数目的操作数。 这称作“短路”计算。 因此,无法计算表达式的一些操作数。 例如,在下面的表达式中

x && y++

仅当 y++ 为 true(非零)时,才计算第二操作数 (x)。 因此,如果 y 为 false (0),则 x 不增加。

示例

以下列表显示编译器如何自动绑定多个示例表达式:

展开表

表达式自动绑定
a & b ||c(a & b) ||c
a = b ||ca = (b ||c)
q && r ||s--(q && r) ||s--

在第一个表达式中,按位“与”运算符 (&) 的优先级高于逻辑“或”运算符 (||) 的优先级,因此,a & b 构成了逻辑“或”运算的第一操作数。

在第二个表达式中,逻辑“或”运算符 (||) 的优先级高于简单赋值运算符 (=) 的优先级,因此,b || c 在赋值中分组为右操作数。 请注意,赋给 a 的值为 0 或 1。

第三个表达式显示可能会生成意外结果的格式正确的表达式。 逻辑“与”运算符 (&&) 的优先级高于逻辑“或”运算符 (||) 的优先级,因此,将 q && r 分组为操作数。 由于逻辑运算符确保按从左到右的顺序计算操作数,因此 q && r 先于 s-- 被计算。 但是,如果 q && r 计算的结果为非零值,则不计算 s--,并且 s 不会减少。 如果 s 未减少会导致程序出现问题,则 s-- 应显示为表达式的第一操作数,或者在单独的运算中应减少 s

以下表达式是非法的并会在编译时生成诊断消息:

非法表达式默认分组
p == 0 ? p += 1: p += 2( p == 0 ? p += 1 : p ) += 2

在此表达式中,相等运算符 (==) 的优先级最高,因此,将 p == 0 分组为操作数。 条件表达式运算符 (? :) 具有下一个最高级别的优先级。 其第一操作数是 p == 0,第二操作数是 p += 1。 但是,条件表达式运算符的最后一个操作数被视为 p 而不是 p += 2,因为与复合赋值运算符相比,p 的匹配项将更紧密地绑定到条件表达式运算符。 由于 += 2 没有左操作数,因此发生语法错误。 您应使用括号以防止此类错误发生并生成可读性更高的代码。 例如,可以按如下所示使用括号来更正和阐明前面的示例:

( p == 0 ) ? ( p += 1 ) : ( p += 2 )

请参阅

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

    int32_t result;

    result = a * b + c << d >e ? b : c * sizeof(++e) / sizeof(int32_t);

    printf(Result: %" PRId32 ", result);

    return 0;
}

一元操作符号中,& - + 等前缀 *为解引用运算符

&按位与与 前缀&不一样,后者优先级高!

第三章 分支与控制

决策控制

如果天气晴朗 ——选出去玩;

逻辑 && || ;

人是有决策能力的,逻辑的判断让程序去·选择!

前提是:让程序去判断 ”天气状态“ 是否为true , false


比如 一个天气应用程序:

温度< 30° 温度> 30°


编程语言:

  • 要应用到实际环境
  • 灵活性,随机
  • 不可能全面,若有完美 定是谎言

if语句和if else

#include <stdio.h>
#include <stdint.h>
#include <inttype.h>
#include <stdbool.h>

int main() {

    uint32_t number = 100;

    //if 语句
    if (number > 10) {
        printf("这个数大于10!\n");
        printf("这个数大于10!\n");

    }

    if (number >=100) {
        printf("这个数大于等于100!\n");


    } 
    else {
        printf("这个数小于100!\n");

    }


    return 0;
}

逻辑与或的短路行为

#include <stdio.h>
#include <stdint.h>
#include <inttype.h>
#include <stdbool.h>

int main() {

    bool is_weather_sunny = false;
    bool is_venue_available = true;

    if (is_weather_sunny && is_venue_available) {
        printf("活动如期举行!\n");
        }
    else {
        printf("活动不能如期举行!\n");
    if (!is_weather_sunny) {
        printf("原因:天气不晴朗!\n")
        }
    if (!is_vueue_available) {
        printf("原因:没有场地!\n")
        }

    return 0;
}
//自动贩卖机
//只支持硬币
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>

int main(void)

{

    const uint32_t PRICE = 3;    //drink's price

    uint32_t balance = 0;        //now total_coin

    uint32_t coin;                //every coin in it

    puts("drink's price is $5 please!");

    while (balance < PRICE)    //在投够数额前
    {
        puts("don't!");    //拒绝交易

        scanf_s("%" PRIu32, &coin);


        if (coin == 1 || coin == 2 || coin == 5) //确定金额类型
        {
        balance += coin;    //赋值 加等

        printf("你已经投入 $%" PRIu32 "\n", balance);
        }
        else {

        printf("sorry!我们不接受 $%" PRIu32 "的硬币\n", coin);
        }
    }

    if (balance > PRICE) {
        printf("找零:%" PRIu32 "\n", balance - PRICE);
    }
    return 0;
}
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>

int main(void)
{

        //玩家进入不同条件的房间

    uint32_t coins= 15;
    bool is_vip = true;
    bool have_special_tool = false;

    if (is_vip) {
        puts("vip Enter!\n");
    }
    else {
        puts("not_vip Exit!\n");
    }

    if (coins >= 10 || have_special_tool) {
        puts("Enter!\n")
    }
    else {
        puts("Exit!\n");
    }
    return 0;
}
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>

int main(void)
{
    const uint32_t all_laps = 100;

    uint32_t current_laps = 0;

    puts("开始!");

    while (current_laps < all_laps)
    {
        current_laps++;

        printf("完成第 %"PRIu32"圈。\n", current_laps);
    }
    return 0;
}
//自动贩卖机
//只支持硬币
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>

int main(void)

{

    const uint32_t price = 10;    //drink's price

    uint32_t balance = 0;        //now total_coin

    uint32_t coin;                //every coin in it

    puts("drink's price is $5 please!");

    while (balance < price)    //在投够数额前 只有在够的时候才开始循环
    {
        puts("don't!");    //拒绝交易

        //模拟投币
        scanf_s("%" priu32, &coin);


        if (coin == 1 || coin == 2 || coin == 5) //确定金额类型
        { 
        balance += coin;    //赋值 加等 计数

        printf("你已经投入 $%" priu32 "\n", balance);
        }
        else {

        printf("sorry!我们不接受 $%" priu32 "的硬币\n", coin);
        }
    }

    if (balance > price) {
        printf("找零:%" priu32 "\n", balance - price);
    }
    return 0;
}

//一定要写printf 可以看到效果。

//遇到循环问题
//不要在循环中多次运用,来避免不必要的错误


//写一个计算机求和


#include <stdio.h>
#include <inttypes.h>

int main(void)
{
    uint32_t sum = 0;    //设置初始数字和为0

    uint32_t number = 1;    //第一次number的值

    while (number != 0)    //设置0为退出循环的方法
    {
        scanf_s("%" PRIu32, &number);    //scanf重新赋值number,第一次number值实际没有用到。
        sum += number;
    }

    printf("所求的和sum是 %" PRIu32 "\n", sum);

    return 0;
}






#include <stdio.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>

int main()
{
    uint32_t sum = 0;    //设置初始数字和为0

    char input[50];    //我们将用户输入的字符转换成数字

    char* end;

    puts("请输入一系列数字,用回车隔开,我们计算他们的和,输出q结束");

    while (true)    //设置0为退出循环的方法
    {
        errno = 0;

        puts("输入一个数字:");

        scanf_s(" %49s", &input, 50);

        if (input[0] == 'q' && input[1] == '\0') {
            break;
        }

        long number = strtol(input, &end, 10);
        //将输入的字符转换成数字,并且加到总和sum中
        //0的ASCII为48
        if (end == input || *end !='\0') {
            printf("无效输入,请输入一个数字或是字符q\n");

        }
        else if (errno == ERANGE || number < 0 || number > UINT32_MAX){
            printf("数字超出范围!请输入小于或等于 %u 的正整数\n", UINT32_MAX);
        }
        else {
            sum += (uint32_t)number;
        }

    }

    printf("所求的和sum是 %" PRIu32 "\n", sum);

    return 0;
}
#include <stdio.h>
#include <inttypes.h>
#include <stdbool.h>

int main()
{
    uint32_t sum = 0;    //设置初始数字和为0

    uint32_t number;    //第一次number的值

    puts("请输入一系列数字,用回车隔开,我们计算他们的和,输出0结束");

    while (true)    //设置0为退出循环的方法
    {

        scanf_s(" % " PRIu32, &number);

        if (number == 0) {
            break;
        }

        sum += number;
    }

    printf("所求的和sum是 %" PRIu32 "\n", sum);

    return 0;
}
//卫语句的使用:租车案例
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>

void check_car_rent(uint8_t age, uint8_t driving_exp_years);

int main(void) 
{
    check_car_rent(22, 3);

    return 0;
}

void check_car_rent(uint8_t age, uint8_t driving_exp_years) {
//卫语句
    if (age < 21) {
        puts("不符合条件,年龄不足!");
        return 0;
    }

    if (driving_exp_years < 1) {
        puts("不符合条件,驾驶年龄不足!");
        return 0;
    }
}
//简化逻辑表达式
#include <stdbool.h>
#include <inttypes.h>

int main(void) 
{
    //逻辑表达式应该简化!
    bool is_weekend = true;
    bool has_enter = true;

    if (!has_enter) {
        return 0;
    }

    return 0;
}

状态机:管理复杂状态的转换

#include <stdbool.h>
#include <inttypes.h>

int main(void)
{
    //状态机:管理复杂状态的转换,使用switch case

    uint8_t traffic_state = 0;

    switch (traffic_state)
    {
    case 0:
        puts("red");
        traffic_state = 1;
        break;
    case 1:
        puts("yellow");
        traffic_state = 2;
        break;
    case 2:
        puts("green");
        traffic_state = 0;
        break;
    default:
        puts("???");
        break;
    }

    return 0;
}

switch-case 与 if-else 的区别

//switch-case 与 if-else 的区别
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>

int mian(void)
{


    return 0;
}

循环在生活中的作用

//循环在生活中的作用


#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>

int main(void)
{
    int32_t number;

    scanf_s("请输入: %d %d %d", &number, &number, &number);//在实际开发中不用scanf
    //not write \n in it
    printf("已经扫描到你输入的数字为: %d %d %d\n", number, number, number);

    return 0;
}

do-while 和 while 的区别

//do-while 和 while 的区别

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main(void)
{
    uint32_t total_laps = 10;

    uint32_t current_laps = 0;

    puts("罚跑开始!");

    do {

        current_laps++;
        printf("跑步者完成第%" PRIu32 "圈\n", current_laps);
    } while (current_laps < total_laps);

    return 0;
}



do-while 的实际作用

//do-while 的实际作用

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main(void)
{

    uint32_t choice;

    do 
    {

        puts("****主菜单****");
        puts("1. 新游戏");
        puts("2. 载入游戏");
        puts("3. 退出");
        scanf_s("%" PRIu32, &choice);

        switch (choice) 
        {
        case 1:
            puts("****创建新游戏!");
            break;
        case 2:
            puts("****载入存档!");
            break;
        case 3:
            puts("****退出游戏!");
            break;
        }

    } while (choice != 3);

    return 0;

}



随机数猜数游戏案例

//随机数猜数游戏案例
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <time.h>
#include <stdlib.h>

int main(void)
{
    uint32_t secret_num, guess, status;
    char buffer[50];

    srand(time(NULL));
    //生成1-100的随机数
    secret_num = rand() % 100 + 1;

    puts("猜猜嘛!");

    do {
        puts("请输入你猜的数:");

        fgets(buffer, sizeof(buffer), stdin);
        status = sscanf_s(buffer, "%d", &guess);
        //卫语句
        if (status != 1) {
                puts("输入无效!");
                continue;
        }

        if (guess < secret_num) {
            puts("太小了!");
        }
        else if (guess > secret_num) {
            puts("太大了!");
        }

    } while (guess != secret_num);

    printf("恭喜你,猜对了!");

    return 0;
}

continue语句

//continue语句
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void) {

    uint32_t sum = 0;
    int32_t number;

    puts("请输入一系列的正整数,可以输入负数,输入0结束");

    while (1) {
        puts("请输入一个数字");

        scanf_s("%d", &number);

        if (number == 0) {
            break;
        }
        if (number < 0) {
            continue;    //continue 直接跳过这次循环
        }
        sum += number;//计数
    }
    printf("计算结果为:%" PRIu32 "\n", sum);

    return 0;

}

continue与break的联用条件判断

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main() {
    uint32_t number;
    
    puts("请输入数字(0-100),输入-1后结束程序");
    
    while (1) {
        puts("请输入一个数字:");
        scanf_s("%d", &number);
        //卫语句!检查条件结束
        if (number == -1) {
            break;
        }
        if (number < 0 || number > 100) {
            continue;//跳过本次循环的剩余部分。
        }
        sum += number;
    }
    
    return 0;
}

初探for循环

//初探for循环
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void)
{
    //for循环
    const uint32_t total_laps = 10;    //目标圈数

    //uint32_t current_lap = 0;    初始化当前圈数

    puts("跑步者开始跑步");

    for (uint32_t current_lap = 0;current_lap <= total_laps;current_lap++) {
        printf("跑步者完成第 %" PRIu32 " 圈\n", current_lap);
    }

    return 0;

}

整数平方求和

//整数平方求和
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void)
{
     /*
        目的为了计算从1到n(n由玩家输入)的所有整数的平方和

     */
    uint32_t number;

    uint32_t sum_of_squares = 0;

    puts("输入整数n");

    scanf_s("%u", &number);

    for (uint32_t index = 1; index <= number; index++) {
        sum_of_squares += index * index;
    }

    printf("%" PRIu32 "\n", sum_of_squares);
    return 0;
}

倒数五个数

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void) {

    /*
        星光大道
        倒数五个数
    */

    uint32_t start_number;
    
    puts("Please enter a positive integer");
    scanf_s("%" SCNu32, &start_number);

    puts("The countdown begins");
    for (uint32_t index_number = start_number; index_number > 0; index_number--)
    {
        printf("%" SCNu32 "\n", index_number);
    }
    puts("The countdown stop");
    return 0;
}
//扩展sleep
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <windows.h>

int main(void) 
{

    /*
        星光大道
        倒数五个数
    */

    uint32_t start_number;
    
    puts("Please enter a positive integer");
    scanf_s("%" SCNu32, &start_number);

    puts("The countdown begins");
    for (uint32_t index_number = start_number; index_number > 0; index_number--)
    {
        printf("%" SCNu32 "\n", index_number);
      Sleep(1000);
    }
    puts("The countdown stop");
    return 0;
}

阶乘

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <windows.h>
//阶乘

int main(void) {

    uint32_t number;
    uint32_t factorial = 1;

    puts("Please enter a positive integer :");
    scanf_s("%" SCNu32, &number);

    for (uint32_t index = 1; index <= number; index++) {
        factorial *= index;
    }

    printf("%" PRIu32 "! = %" PRIu32 "\n", number, factorial);

    return 0;
}

开方

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>

int main(void)
{
    double number = 4.00;

    printf("%lf\n", sqrt(121));

    return 0;
}

素数

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>

int main(void)
{
    uint32_t num;

    bool is_prime = true;

    puts("Please enter a positive integer,except for 1,we will check if it is prime:");

    scanf_s("%" SCNu32, &num);

    if (num <= 1) {
        is_prime = false;
    }
    else {
        //for , 检查除了1和它本身之外的因数
        for (uint32_t i = 2; i * i <= num; i++) {
            if (num % i == 0) {
                is_prime = 0;
                break;
            }
        }
    }
    return 0;
}
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>

int main(void)
{
    uint32_t size;
    puts("请输入图案的大小: ");
    scanf_s("%" SCNu32, &size);

    //特点:长和宽一样
    puts("打印正方形图案");

    for (uint32_t i = 0; i < size; i++) {
        for (uint32_t j = 0; j < size; j++)
        {
            printf("* ");
        }
        printf("\n");
    }
    return 0;
}

p118数组定义时下标需要常量

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

#define SIZE 5

int main(void)
{
    const int index = 10;//这里const在定义/编译时也是变量。
    
    uint32_t numbers[SIZE] = { 1,2,3,4,5 };//这里SIZE必须是常量{右值},而非变量{左值},即数组长度固定。
   uint32_t numbers[SIZE] = { 0 };//这里把第一元素初始化为0
    printf("%" PRIu32 "\n", numbers[0]);
    
    return 0;
}

p119数组的注意事项

下面介绍数组在使用的时候容易出现的错误:

p119数组的注意事项

下面介绍数组在使用的时候容易出现的错误:

错误一:越界访问

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

#define SIZE 5

int main(void)
{
   uint32_t numbers[SIZE] = { 0 };
    printf("%" PRIu32 "\n", numbers[5]);//这里只能访问0-4的元素!
//index "5" is out of valid index range "0" to "4" for ...
    return 0;
}

错误二:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

#define SIZE 5

int main(void)
{
   uint32_t numbers[SIZE] = { 0 };
    printf("%" PRIu32 "\n", numbers[5]);//这里只能访问0-4的元素!
//index "5" is out of valid index range "0" to "4" for ...
    return 0;
}

数组的案例:分数

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

#define STUDENT_COUNT 5
int main(void)
{
    
    
    uint32_t grades[STUDENT_COUNT] = { 85, 92, 88, 96, 66 };

    uint32_t sum = 0;

    uint32_t max_grade = grades[0];

    uint32_t min_grade = grades[0];

    puts("所有人的成绩单如下:");

    for (uint32_t index = 0; index < STUDENT_COUNT; index++) {
    
        printf("学生%" PRIu32 "的成绩:%" PRIu32 "\n", index +1, grades[index]);
        
        sum += grades[index];

        if (grades[index] > max_grade) {
            max_grade = grades[index];

        }

        if (grades[index] < min_grade) {
            min_grade = grades[index];

        }
        

    }

    double average = (double)sum / STUDENT_COUNT;

    printf("\n平均成绩:%.2f\n", average);
    printf("最高成绩:%d\n", max_grade);
    printf("最低成绩:%d\n", min_grade);
    return 0;
}

unicode字符编码与wchar宽字符

wchar.h
unicode字符编码与wchar宽字符
中文字符集为GBK
具体存储原理不在讨论范围
\n ASCII码
相应的,各种语言等等使用不同编码

locale.h header file

货币的格式、时间格式等等,比如MM/DD/YYYY DD/MM/YYYY

某些语言的字符串排序比较是不同的。

p126 二维数组及隐式确定数组大小的初始化

#include <stdio.h>
#include <inttypes.h>
int main(void) {
    //隐式确定数组大小的初始化

    int arr[] = { 0 };

    printf("%d\n", arr[1]);// 试图访问超出范围的元素
    //在vs中自动编辑占内存,会自动输出为0,编译器可能会将未使用的内存初始化为零
    //索引“1”超出了“0”至“0”的有效范围(对于可能在堆栈中分配的缓冲区“arr”)


    char greeting[] = "Hello";

    //二维数组隐式确定数组中行数可以省略的,但是前提是数组的每一个元素必须都初始化!

    int matrix[][3] = {
        {1,2,3},
        {4,5,6},
        {7,8,9},
        {0,0,0}
    };
    
    //选修:函数中确定初始化

    void processMatrix(int matrix[][3], int rows);
    for (uint32_t i = 0; i < 4; i++) {
        for (uint32_t j = 0; j < 3; j++) {
            printf("%" PRIu32 " ", matrix[i][j]);
        }
        printf("\n");
    }
    return 0;
}

p124数组案例:字母次数统计

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <limits.h>
#include <ctype.h>

#define LETTER_COUNT 26

int main(void)
{
    uint32_t frequency[LETTER_COUNT] = { 0 };

    char text[] = "Example text for frequency analysis.\0";

    // 统计每个字母出现的次数
    for (uint32_t i = 0; text[i] != '\0'; i++)
    {
        char ch = tolower(text[i]);

        if (ch >= 'a' && ch <= 'z') {
            frequency[ch - 'a']++;
        }
    }

    puts("Character Frequency:\n");
    for (int i = 0; i < LETTER_COUNT; i++) {
        if (frequency[i] > 0) {
        printf("'%c': %d\n", 'a' + i, frequency[i]); 
        }
    }
    return 0;
}

加强后

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <limits.h>
#include <ctype.h>
#include <string.h>  // 包含 strcspn 函数

#define LETTER_COUNT 26
#define MAX_TEXT_LENGTH 256  // 定义最大输入长度

int main(void)
{
    uint32_t frequency[LETTER_COUNT] = { 0 };

    char text[MAX_TEXT_LENGTH];  // 用于存储用户输入的文本

    //char text[] = "Example text for frequency analysis.\0";
    printf("请输入文本: ");
    fgets(text, sizeof(text), stdin);  // 使用 fgets 读取一行文本

    //处理换行符
    text[strcspn(text, "\n")] = '\0';  // 将换行符替换为字符串结束符


    //统计每个字母出现的次数
    for (uint32_t i = 0; text[i] != '\0'; i++)
    {
        char ch = tolower(text[i]);

        if (ch >= 'a' && ch <= 'z') {
            frequency[ch - 'a']++;
        }
    }
    puts("Character Frequency:\n");
    for (int i = 0; i < LETTER_COUNT; i++) {
        if (frequency[i] > 0) {
            printf("'%c': %d\n", 'a' + i, frequency[i]);
        }
    }
    return 0;
}

数组的知识汇总

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <limits.h>
#include <ctype.h>

#define MAX_SIZE 10

int main(void)
{
    //数组 Array 连续不断
    uint32_t number_arr[MAX_SIZE] = { 0 };//初始化

    //元素 Element 每一个格子里面的数据

    //下标 Index 比如number_arr[index]

    //长度 Length/Size 指可以容纳多少的元素

    //数组的内存分布 Memory Layout uint32_t占4个字节

    //遍历 数组的值查找元素、统计信息、修改元素、排序等操作对数组中的每个元素进行访问
    return 0;
}

p128五子棋棋盘的绘制

#include<inttypes.h>
#include<Windows.h>
#include<stdio.h>
#include<stdint.h>
#include<locale.h>
#include<wchar.h>

#define board_size 15//定义五子棋的大小

int main(void)
{
    // 设置控制台代码页为 UTF-8
    SetConsoleOutputCP(65001);

    //设置区域为当前系统默认
    setlocale(LC_ALL, "");

    wchar_t board[board_size][board_size];
    uint8_t x, y;

    //状态
    wchar_t current_player = 0x25CF;

    //初始化棋盘
    for (uint32_t i = 0; i < board_size; i++) {
        for (uint32_t j = 0; j < board_size; j++) {
            board[i][j] = 0x00B7;
        }
    }

    
        wchar_t control = L'y';
        while (control == L'y' || control == L'Y') {
            system("cls");//清屏
            for (uint32_t i = 0; i < board_size; i++) {
                for (uint32_t j = 0; j < board_size; j++) {
                    //board[i][j] = 0x00B7;
                    wprintf(L"%lc ", board[i][j]);
                }
                printf("\n");
            }
            while (1) {
                printf("玩家 %lc 请输入坐标 (0 - %d) , 中间用空格隔开:\n", current_player, board_size - 1);
                if (scanf_s("%" SCNu8 " %" SCNu8, &x, &y) != 2) {
                    while (getchar() != '\n');
                    wprintf(L"输入无效,请重新输入。\n");
                    system("pause");
                    continue;
                }

                if (x < board_size && y < board_size && board[x][y] == 0x00B7) {
                    board[x][y] = current_player;
                    current_player = (current_player == 0x25CF) ? 0x25CB : 0x25CF;
                    break;
                }
                else {
                    wprintf(L"无效的移动,请重试!");
                    while (getchar() != '\n');//清空输入缓冲
                }
            }
            system("cls");
            for (uint32_t i = 0; i < board_size; i++) {
                for (uint32_t j = 0; j < board_size; j++) {
                    wprintf(L"%lc ", board[i][j]);
                }
                wprintf(L"\n");
            }
            wprintf(L"是否继续? (y / n):");
            while (getchar() != '\n');//清空输入缓冲
            wscanf_s(L" %lc", &control, 1);
        }
        printf("游戏结束了!");

    return 0;
}

第六章

第七章

131 function函数的介绍与作用

#include <stdio.h>  
​  
void print_line() {  
    printf("-------");  
}  
​  
int main() {  
    // function 功能块  
​  
    // 模块化  
    // 功能抽离,达到复用性!  
    for (int i = 0; i < 5; i++)  
    {  
        printf("---\n");  
    }  
​  
    //printf("-------");  
    print_line();  
​  
    for (int i = 0; i < 5; i++)  
    {  
        printf("---\n");  
    }  
​  
    //printf("-------");  
    print_line();  
​  
    for (int i = 0; i < 5; i++)  
    {  
        printf("---\n");  
    }  
​  
    //printf("-------");  
    print_line();  
​  
    for (int i = 0; i < 5; i++)  
    {  
        printf("---\n");  
    }  
​  
    printf("-------");  
​  
    for (int i = 0; i < 5; i++)  
    {  
        printf("---\n");  
    }  
​  
    printf("-------");  
    //我们发现有一些重复的东西,相当于功能块,打包一起后可以直接调用  
    return 0;  
}

132 函数声明与定义的规则

#include <stdio.h>  
​  
/*  
void print_line() {  
    printf("-------");  
}  
*/  
    //定义在前面?x  
​  
    //我们也可以先声明,后编写,再定义!  
​  
​  
​  
//先声明  
void print_line();  
​  
​  
int main() {  
    // function 功能块  
​  
    // 模块化  
    // 功能抽离,达到复用性!  
    for (int i = 0; i < 5; i++)  
    {  
        print_line();   //调用  
    }  
​  
    //printf("-------");  
    print_line();  
​  
​  
​  
      
    //我们发现有一些重复的东西,相当于功能块,打包一起后可以直接调用  
    return 0;  
}  
// 函数定义  
void print_line() {  
    printf("-------");  
}

133 函数的参数

#include <stdio.h>  
#include <stdbool.h>  
​  
//但是我们想输出不同的内容怎么办?  
​  
//声明  
void greet(int age, bool gender);  
​  
void add(int num_1, int num_2);  
​  
int add_2(int num_1, int num_2);  
​  
int main() {  
    //调用  
    greet(18, 1);  
    //实际参数 18 在调用中使用  
​  
    add(7, 8);  
​  
    int number = add_2(7, 8);  
    printf("%d\n", number);  
}  
//函数定义  
void greet(int age, bool gender) {  
    //形式参数 int age  
    printf("age=%d, 性别:%s\n", age, gender ? "男" : "女");  
}  
​  
​  
void add(int num_1, int num_2) {  
​  
    printf("sum=%d\n", num_1 + num_2);  
​  
}  
​  
int add_2(int num_1, int num_2) {  
​  
    return num_1 + num_2;  
    //函数返回值与前面的int一致!  
}

134 案例:求面积函数

//## 134案例:求面积函数

#include <stdio.h>
#include <stdbool.h>
#define PI 3.14

double square_area(double side);
double rectangle_area(double length, double width);
double circle_area(double redius);

int main() {

    printf("%lf\n", square_area(6.0));
    
    printf("%lf\n", rectangle_area(6.0, 7.0));

    printf("%lf\n", circle_area(6.0));

    return 0;
}

double square_area(double side) {
    return side * side;
}
double rectangle_area(double length, double width) {
    return length * width;
}
double circle_area(double redius) {
    return redius * redius * PI;
}

134案例:求面积函数

//### 134案例:求面积函数

#include <stdio.h>
#include <stdbool.h>
#define PI 3.14

double square_area(double side);
double rectangle_area(double length, double width);
double circle_area(double redius);

int main() {

    printf("%lf\n", square_area(6.0));
    
    printf("%lf\n", rectangle_area(6.0, 7.0));

    printf("%lf\n", circle_area(6.0));

    return 0;
}

double square_area(double side) {
    return side * side;
}
double rectangle_area(double length, double width) {
    return length * width;
}
double circle_area(double redius) {
    return redius * redius * PI;
}

135 函数编写要领

//## 135 函数编写要领

#include <stdio.h>
#include <stdbool.h>

bool is_leap_year(int year);

int main() {

    /*
        1.明确函数目的,明确功能将帮助你决定哪些输入是必须的(形式参数/模板),以及如何报告工作结果。

        2.识别需要的输入

        3.确定函数的输出

        4.使用适当的数据类型

        5.函数命名清晰,并且先声明

    */
    int year = 2025;
    
    printf("%d年%s\n", year, is_leap_year(year) ? "是闰年" : "不是闰年");

    return 0;
}

bool is_leap_year(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

看完了?说点什么呢

  •  

又又又更换博客,一些思考

2025年12月21日 00:39
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/posts/nexus/thoughts-on-changing-blog-multiple-times

缘由

受够了捣鼓Typecho系统,在AI时代,我相信很容易实现全部功能(+PHP是世界上最好的语言),但是介于我本身精力不足(+INFP的犹豫不决)。

我很喜欢换来换去,本身我对我写的文章的态度就是:这只是 倾述/抒发内心情感+分享欲 的方法,我本地存着全部文章,但是每次转系统,都会一堆文章链接被迫 “404”。

如果你需要哪些文章的细节,请告诉我,我会重新发布(如果能帮助你)。

想法

我发现这一年什么都 “没有” 干,全部计划都停于 “表象”,我跟 “枯了心” 的树,接近期末,我不确定未来,尽可能去寻找 “我该干什么”。

偏向去打工,我更想去创业,但囊中羞涩,家贫,仅有一身干劲。

结语

但愿自己改掉 “瞬息万变” 的想法,去多想想自己处境和未来,而不是 “白日梦”。

看完了?说点什么呢

  •  

到了大学我才知道:朋友会变得越来越少

2025年8月20日 23:02
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/posts/short/college-realization-fewer-friends

我不了解你们是怎么定义朋友的,我将朋友和最真挚的友谊划等号。你可以有许多玩伴,但朋友可能就一个或者没有。朋友应该是共同语言并且知根知底你的人,必须给你尊重和价值。我就感觉很失败,目前就有一个得我心,得知己者得天下嘛。

大学生活那些事

大学第一年是我第一次走出贫困小县城去看看外面到底是啥样。遇到第一个舍友是广东的,其他两个不怎么聊天(他们也不主动聊天),广东的舍友是我第一眼就看中上去聊聊天什么的,大大方方的,也毛毛躁躁,粗中有细吧。

后面军训时候遇到同班另外两个人,最后军训结束也拍了合照。(这里提一句:同班都可能不认识,因为大家总是在自己的小圈子去维护)

我自带的自学耐性在他们三个人话里成了卷狗(相比较其他矛盾这已经触及我底线,我认为学习是很难得的,特别是在高中自学两年考到这里的人)

大一下学期吧,好像去北京玩了,4月4这样,不出意外的话,我记得因为另外两个人找宿找成4人间2人住。由于路程引发了矛盾,后面就不谈这事了,几个人去玩的,很紧很累。

矛盾发生在去唐山吧,在大二上学期,很难得再去玩玩,在末尾的时候,点了KTV通宵的,因为水不让自带,说给1元当服务费并且直言这是给我们面子,说在北方要讲义气。这我就不爽了,到了里面发现到处是小蟑螂,更是让我难受,几个人看我很难受就不让我去前台对峙,让一个人去前台换房间。

后面就有点远离我,绝得我容易计较。在大二上学期期末的时候,我得知他们互相约去学习,我当时已经知道玩伴少了三个。于是跟广东的舍友划清了界限,和另外两个不聊天了,自己干自己的事。其一是没有尊重,其二是没有价值。我发了个qq说还上钱,谁哪里在乎那1点多元呢?

以前的朋友再也难联系

张兄是高二开始认识的理科偏科同班,他数学思维深深吸引了我,他是一个很努力的人,周末或者晚自习结束,我经常跟他做一些题目,去问问他独到的理解。很多时候期末一起吃饭或者周末聊聊天,相比较其他朋友,同爱好的朋友是最舒服的,不会去探讨其他问题,更让我惊讶的是他高考结束后报考师范,并且定向了本校,由于我学的数学已经不够跟他去聊聊天,我们很快大学半年后就丧失聊天的机遇。

姜兄是我初二就开始认识的,经常跟另外两个朋友玩,后面也是一起考到最顶尖的班级。经常做的事情就是一起晚上回到家抄完作业互相汇报速度:已经抄完了!你怎么那么快?!我的出租房离学校很远,路上也很多时候是他顺路带我到半路,路上谈谈色色的很正常(毕竟都青春期了)。有一次考试英语还是靠他中途去上厕所放的小抄(千万不要作弊,欺骗自己)。高中就因为分班经常不能见面了,大学也是如此。他应该是正常朋友,不是兴趣使然,也不是利益使然,更多是陪伴你身边,更多是了解你,能给你出谋划策,甚至愿意牺牲自己一点去帮助你。高中结束办升学宴,邀请了我去吃席,后面因为喝水好像跟别人弄混了,我觉得不好意思就当天下午早早离开了。大一结束,我去他家玩,大学一年过去我很瘦,而且那时经常熬夜,身上的钱都花在服务器一些身上,吃饭也很少花钱,他说给我200当饭钱不要花在其他身上。现在很多时候无法一起玩,这或许也是能一直聊聊天的原因,深交也不利。

后记

我很想了解你们怎么定义朋友的,欢迎在评论区留言!

看完了?说点什么呢

  •  

博客圈的三类“麻烦”,对此我提出建议

2025年8月27日 15:53
该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://www.hansjack.com/posts/short/blogs-three-troubles-suggestions
  1. 搬弄是非者:这类人言谈缺乏诚意,往往因心理失衡或嫉妒心作祟,喜欢通过夸大或虚构事实来抬高自己。由于自身优点有限,常在他人提及别人长处时,以贬低的方式回应。
  2. 混淆视听者:故意散布模糊是非的言论,行为动机不纯,试图扰乱他人的判断,影响交流环境。
  3. 好事干涉者:总爱插手别人的事务,尤其喜欢无端介入与己无关的话题,这种行为极易引起他人反感。

应当认识到,绝大多数个人博主在网站维护方面投入有限,相关知识也较为匮乏。他们中有学生、非专业人士以及来自不同地区和职业的人,大家聚集于博客圈子,主要是为了交流想法、分享经验,形成一种轻松互助的氛围。

然而,上述三类人却时常破坏这种环境,对博客的维护构成持续威胁。有些人火上浇油,比如在别人的网站遭受攻击时仍不断进行测速,频繁使用测速工具——这对仅希望友好交流的博主来说十分烦扰;有些人善于混淆视听,用虚伪的言辞伪装自己,扮演不伦不类的“中间人”角色;还有些人多管闲事、蓄意挑起争端,根本不在意事态是否与自己有关。

基于以上现象,我对开放圈子提出以下建议:

  1. 社群交流中应禁止评论涉及隐私的信息,开盒、CC攻击、IP泄露等行为必须杜绝;
  2. 友善沟通,理性表达不同意见;
  3. 塑造积极健康的“圈子文化”,弘扬正能量。

看完了?说点什么呢

  •  

可替换Obsidian和Typora的开源笔记软件,强烈推荐

2025年12月11日 20:32

官网与项目

官网:飞速Markdown · FlyMD
项目:GitHub - flyhunterl/flymd

为什么选择 FlyMD?

pasted-20251211-201707-hj1q.png

  • 从 0.3 版本迭代至 0.7+ 版本,功能持续完善:毫秒级启动、双向链接、图床支持、PDF/Office 格式解析、专注模式、主题定制等实用功能全覆盖。

  • 链接自动抓取标题,复制网址即可生成 [标题](链接) 格式,剪藏资料、整理内容时能轻松保持格式规范。

pasted-20251211-201429-ccps.gif

  • 支持所见即所得、源码、阅读三种模式自由切换,分屏「源码+阅读」同步滚动功能,让长文写作可随时预览效果。

pasted-20251211-201624-ao0k.gif

核心特性速览

1. 知识网络与导航

  • 「关系图谱(Graph View)」与「双向链接」功能,实现笔记间互相引用,通过侧栏和悬浮面板可直接查看关联内容,点击即可跳转。

pasted-20251211-202150-bt1k.png

  • 大纲、书签、脚注、PDF 书签等结构化导航工具齐全,即便是长文档也能快速定位目标内容。

2. 便捷辅助功能

  • 支持文本润色、格式调整,可实现 Markdown 渲染与代码高亮;支持自定义配置,满足不同用户的使用习惯。
  • 夜间模式、自定义字体等设置全局生效;涵盖翻译、TODO 清单生成、关联内容推荐等快捷功能,提升操作效率。

pasted-20251211-202248-ccyw.png

3. 写作效率神器

  • 「智能悬浮工具条」随选中文本自动弹出,支持自定义 Ctrl+1\~6 快捷设置标题层级,一键插入链接、图片,支持纯文本粘贴。

pasted-20251211-202407-4wqm.png

  • 自动补全括号、脚注,支持 Mermaid/LaTeX 语法渲染、代码块一键生成,为用户提供接近专业级的 Markdown 编辑体验。

4. 富媒体与图床管理

  • 内置「PicList 图床」与「S3 图床相册」,粘贴图片自动上传并回填链接,可统一管理历史上传记录。
  • 右键图片即可上传至对象存储,或保存至本地 images/ 目录;未配置图床时自动智能兼容,避免素材链接失效。

5. 文档转换与资料整理

  • 一键将 Word/Excel 文件解析为 Markdown 格式,自动提取 data:URL 格式图片并保存至当前文档 images/ 目录,生成相对路径插入文本。
  • 支持 PDF 高精度解析、多通道批量导出,超宽表格可横向滚动查看,适用于学术写作、报告撰写、知识库维护等场景。

6. 同步与协同

  • 支持 WebDAV 多目录同步与离线快照,具备自动重试机制;扩展 Git 功能,可查看提交历史与差异高亮,保障文档版本安全。

pasted-20251211-202808-a4h4.png

  • TODO 事项与提醒功能支持多渠道推送,覆盖微信、短信、邮箱、钉钉、飞书等平台,助力任务管理。

7. 个性化与沉浸体验

  • 主题、排版、颜色、字体均可全局自定义,夜间模式与紧凑标题栏设计,让界面风格更统一协调。
  • 专注模式与分屏模式自由切换,满足写作、阅读、预览等不同场景需求;自动记忆窗口尺寸、自定义停靠状态,避免操作流程被打断。

适用

  • 博客作者/内容创作者 :快速抓取链接标题、自动排版、图床管理一站式完成,提升创作效率。
  • 知识管理/学术用户 :双向链接与关系图谱助力构建知识网络,PDF 解析与脚注功能满足大规模文档整理需求。
  • 团队协作与效率党 :WebDAV/Git 版本管理保障文档安全,毫秒级启动速度不占用工作时间,适配高效办公节奏。

FlyMD 以轻量体积实现毫秒级启动,同时集成格式转换、同步协作、深度编辑等丰富功能。只需安装常用功能插件,就能体验极速启动与智能编辑的双重优势,让写作与知识管理效率同步提升。

  •  
❌