type
status
date
slug
summary
tags
category
icon
password

03第一个C语言程序

课堂总结:略

04基础的C语言语法知识

main表示一个主函数
return表示函数的返回值
什么是函数?
我已经懂了😎
函数内部可以处理一些事情
函数可以返回一些值
add函数不可以直接被运行,需要被主函数调用
所有c语言代码都有起始入口,这个入口就是主函数main
进入主函数之后才能由主函数调用其他函数
每个c语言代码有且只能有一个主函数
编译器按照从上到下的顺序阅读代码
如果将函数定义放到主函数后面编译器会报错
主函数:
1主函数被自动调用
2返回值给调用的程序
3主函数返回值必须为int
赋值运算符:将符号右边的数值装进左边变量的运算符
变量必须先声明才能被使用
标识符命名规则:
1标识符符可以用小写字母、大写字母、数字和下划线命名
2标识符的第一个字符必须是字母或者下划线,不能是数字
3标识符是区分大小写的
4不能是关键词
什么是标识符?后续补充
int是c语言中的关键词
关键词:
1c语言标准规定的
2有特殊的意义和用途
3不能作为标识符进行使用
有一个列举了c语言中所有关键词的表格,后续自己找
常量不需要被声明
字符串也是
不能对常量进行赋值
printf是系统自带函数
printf将字符串输出到控制台
printf用占位符打印
printf(”占位1 占位2 占位3”,替换1,替换2,替换3);
%转换操作
include语句引入头文件
课堂总结:函数,变量,标识符,关键词,常量,printf,include等

05整数数据类型

类型名称
C语言中的关键词
注释
字符型
char
用于表示一个很小的整数
短整型
short
用于表示一个不怎么大的整数
整型
int
生活中一般的整数都可以表示
长整型
long
用于表示一个较大的整数
加长整型
long long
用于表示一个非常大的整数
不同的整型类型占用内存大小不一样,表示数据范围不一样
一个字节→8个晶体管→256个数值,也就是2的八次方
注意⚠️:C语言并未规定数据类型的大小范围,具体实现交由编译器和平台来决定
用sizeof关键词来测量实体占用字节的大小
例如sizeof(int)
printf(”%d\n”,sizeof(int))输出测量结果,即所占用的字节
C语言标准规定高级别的数据类型取值范围不得小于低级别的数据类型
类型
sizeof大小(不唯一)
二进制位数
取值范围算式
char
1
8位
-2的7次方~2的七次方-1
short
2
16位
-2的15次方~2的15次方-1
int
4
32位
-2的31次方~2的31次方-1
long
4
32位
-2的31次方~2的31次方-1
long long
8
64位
-2的63次方~2的63次方-1
值得注意的是,最高位被当作符号位来表示正负
不想要最高位当作符号位可以使用unsigned
类型
sizeof大小
二进制位数
取值范围算式
unsigned char
1
8
0~2的8次方-1
unsigned short
2
16
0~2的16次方-1
unsigned int
4
32
0~2的32次方-1
unsigned long
4
32
0~2的32次方-1
unsigned long long
8
64
0~2点64次方-1
课堂总结:
1如何测量数据类型大小
2如何计算类型取值范围

06浮点数据类型

整数数据类型无法表示小数(小数部分会丢失),需要用浮点数据类型表示
%d占位符用于整型
%f占位符用于浮点型
值的注意的是,浮点数并不能表示无限精确,会有误差(例如365.12345只能保证前6位准确,后面略有误差)
C语言标准规定float至少能表示6位有效数字,并且取值范围至少是10的-37次方到10的37次方
比float精度更高的类型→双精度浮点型double,float和double都可以使用%f来作为占位符
课堂总结:float类型,double类型

07变量与常量

标识符:
1由自己命名的标识
2表示变量、函数或其他实体的名称
3必须声明或者定义
关键词:
1C语言标注规定词汇
2有特殊意义和用途
3可以直接在程序中使用
 
声明变量公式:【数据类型+标识符号+分号】
先声明再使用
 
赋值变量的两种方法:
1变量声明后立即初始化,int a =100
2变量先声明才变量赋值:
int a;
a = 100;
变量可以多次赋值但是不能多次初始化
 
字面常量无需声明
编译器可判断类型
判断类型的顺序:
整数int→unsigned int→long→unsigned long→long long→unsigned long long
小数double
 
符号常量:
#define 符号常量名 数值
放在函数外面
 
课堂总结:
如何正确声明变量
变量命名初始化赋值
常量的使用

08字符常量及字符变量

字符常量由单引号包括
字符类型的占位符是%c
不同编译器中字符常量所占用的空间大小不一致
字符和数值存在一一对应映射关系
ASCII美国信息交换标准代码 0~127
字符类型仅需要一个类型
DEC表示十进制
OCT表示八进制
HEX表示十六进制
CHAR表示数值对应字符
 
字符类型其实就是整型类型,只占用一个字节
 
\n位换行符
\n结束一行打印,并从下一行开始打印
\n是一个字符而不是两个,属于转义字符
 
A对应65,a对应97
大写转换为小写需要➕32
 
sizeof(helloworld)=11
字符串为什么多占用一个字节?🧐
原来在字符串结尾处为了标记这个字符串已经结束了,会在字符串的末尾多占用一个字节,并且在这个字节里面会填写数值0,用于标识字符串结束
 
值得注意的是,数值0不等于字符0,数值0对应的十进制是48
\数值:转义字符
hello0world→字符0
hello\0world→数值0
\数值(八进制):转义字符
例如printf(”\110\145\154\154\157”);
输出为Hello
 
特殊:\12=\n
记数值比较麻烦,为了方便使用常用数值,用字母代替,所以换行有两种写法
转义序列
含义
八进制
十进制
\a
报警
7
7
\b
退格
10
8
\f
换页
14
12
\n
换行
12
10
\r
回车
15
13
\t
水平制表
11
9
\v
垂直制表
13
11
以上称为不可见字符
DEC:0~31所对应的字符为不可见字符
课堂总结:
如何表示字符并打印
如何定义字符与变量
ASCII
转义字符

09printf函数详细解析(上)

printf是一个变参函数
printf的第一个参数是字符串
printf的第一个参数是需要输出的内容
printf的第二及后续参数将依次替换占位符
占位符的类型和数量需要与后续参数一一对应
 
新概念:类型提升
printf是一个可变参数函数
将参数传入函数的可变参数中
变量会自动发生自动类型提升
char,short,int会提升为int
long,long long则不变
所以char short int的占位符都是%d
long的占位符是%ld
long long的占位符是%lld
提升前
提升后
占位符
unsigned char
unsigned int
%u
unsigned short
unsigned int
%u
unsigned int
unsigned int
%u
unsigned long
unsigned long
%lu
unsigned long long
unsigned long long
%llu
占位符的说法不准确,应该说是转换规范
转换规范:
%
-+0#
12
.4
l
d
百分号
零个或多个标志字符
十进制表示的最小字段宽度(可选)
点号表示精度范围,后面跟着十进制整数(可选)
长度指示符,可用:h\hh\l\ll\z表示(可选)
单个字符表示转换操作
转换操作
转换方式
c
字符类型
d
整型类型
e
双精度浮点型,e计数法表示,小写e
E
双精度浮点型,e计数法表示,大写E
f
双精度浮点型
o
无符号八进制整型
s
字符串
u
无符号整型
x
无符号十六进制整型
X
无符号十六进制整型
课堂总结:
类型提升
转换操作

10printf函数详细解析(下)

长度指示符
转换操作
二进制字节长度n
l
d或i
sizeof(long)
ll
d或i
sizeof(long long)
l
u或o或x或X
sizeof(unsigned long)
ll
u或o或x或X
sizeof(unsigned long long)
h
d或i
sizeof(short)
hh
d或i
sizeof(char)
h
u或o或x或X
sizeof(unsigned short)
hh
u或o或x或X
sizeof(unsigned char)
整型类型的转换操作,精度可以控制最小数字位数
浮点类型的转换操作,精度可以控制小数点后位数
 
最小字段宽度指定输出的字符最小为多少个字符,如果不足将使用空格补齐到指定的最小宽度(一个数字算一位,小数点也算一位)
 
标志0:
使用0而不是空格作为填充字符。使用最小字段宽度时,如果指定标志0,则会用0来补齐最小宽度。
标志-:
让字符左对齐
标志+:
让内容总产生符号,整数用+号,负数用-号
标志#:
八进制前加上0
十六进制前加上0X
 
课堂总结:
转换操作
长度指示符
精度
最小字段宽度
标志

11快速学会scanf函数

printf函数→二进制数据→转换规范→字符
scanf函数→键盘输入字符→转换规范→二进制
 
scanf函数: 1scanf是一个变参函数(参数的数量和类型是不确定的)
2scanf的第一个参数是字符串
3scanf的第一个参数内容为匹配字符以及转换规范
4scanf的后续参数是数据存放位置(不要遗漏&🙅)
5转换规范的写法与数量需要与后续的参数一一对应
 
值得注意的是,输入方式要按照第一个字符串的形式进行输入
例如:
scanf(”%d %d”,&a,&b);就要输入num1 num2
scanf(”%d,%d”,&a,&b);就要输入num1,num2
+-*/~就要+-*/~
总而言之,scanf会将输入的字符串与第一个字符串参数进行匹配
从而找到需要转换的部分。
若字符串匹配失败,将无法得到转换结果。
 
如果scanf将转换后的二进制存储到基本变量当中,请在变量名前加&
如果scanf将字符串存储到字符数组中,字符数组名不用加&
 
不同的转换规范代表的转换方式
长度指示符
转换规范
转换为某种类型的二进制
hh
d
char
h
d
short
d
int
l
d
long
ll
d
long long
hh
u
unsigned char
h
u
unsigned short
u
unsigned int
l
u
unsigned long
ll
u
unsigned long long
f
float
l
f
double
c
字符对应的ASCII码
s
字符串中字符对应的ASCII码
课堂总结: scanf函数使用公式
如何将字符串转换对应值

12运算符和表达式

在C语言中,整型与整型进行运算结果依然是整型,结果中的小数会被丢弃,这个过程称作截断
 
运算对象 % 运算对象:
求余运算符表达式
结果:运算对象相除的余数
 
++自增运算符
--自减运算符
++i称为前缀模式
i++称为后缀模式
有什么区别🧐?
 
前缀模式
结果:运算对象值加or减1
额外作用:运算对象自增or自减
后缀模式
结果:运算对象值本身
额外作用:运算对象自增or自减
 
何时产生额外作用🧐?
取决于编译器😑
a=1;
b = a++ + a++ + a++;
b要么等于3,要么等于6
但是a一定等于4
 
VS:累积所有自表达式求值后才会进行额外作用
GCC:每完成一个子表达式就会立即产生额外作用
 
注意⚠️:不要在一个表达式中重复对一个变量进行自增or自减
 
一元运算符:只有一个运算对象,例如自增自减
二元运算符:两个对象,例如加减
 
运算优先级
标记
操作符
类型
优先级
++--
自增、自减
后缀
16
++--
自增、自减
前缀
15
+-
正号、负号
单目
15
*/%
乘、除、取余
双目
13
+-
加、减
双目
12
=
赋值
双目
2

13类型转换

同类型的数据
char≤short≤int≤long
有符号的整型进行同类型的运算时比int级别低的类型,会转换成int,比int级别高的类型,保持不变。
unsigned char≤unsigned short≤int≤unsigned int≤unsigned long
无符号的整型进行同类型的运算时比int级别低的类型,会转换成int,比int级别高的类型,保持不变。
float≤double
浮点类型同类型运算类型是保持不变的
不同类型的数据
有符号整型不同类型运算时,若运算符两边类型均低于或等于int,那么结果为int
若运算符两边类型有高于int,结果为等级最高类型
 
无符号整型不同类型运算时,若运算符两边类型均低于或等于int,那么结果为int
若运算符两边类型有高于int,结果为等级最高类型
 
混合整型类型运算时,若运算符两边类型均低于或等于int,那么结果为int
若运算符两边类型有高于int,结果为等级最高类型
 
浮点不同类型的运算结果,为运算符两边级别最高的类型。
 
浮点与整型类型混合运算的结果为运算符两边等级最高的类型。
总结:
char≤unsigned char≤short≤unsigned short≤int≤unsigned int≤long≤unsigned long≤float≤double
  • 无论是什么样的整型运算,若运算符两边类型均低于或等于int,那么结果为int
若运算符两边类型有高于int,结果为等级最高类型。
  • 浮点不同类型的运算结果,为运算符两边级别最高的类型。
  • 浮点与整型类型混合运算的结果为运算符两边等级最高的类型。
原因分析:自动类型转换:
C语言会将运算符两边的类型先经过自动类型转换再进行运算
A
B
类型
低于int
低于int
int
低于int
高于int
B
高于int
高于int
AB中等级最高的
 
 
新知识点:强制类型转换
(类型)需要转换的数据对象
例如:

14关系运算符和逻辑运算符

等于==
不等于!=
逻辑或||
逻辑与&&
逻辑非!用来取反向
 
运算符优先级
标记
操作符
类型
优先级
++--
自增、自减
后缀
16
++--
自增、自减
前缀
15
逻辑非
单目
15
+-
正号、负号
单目
15
*/%
乘、除、取余
双目
13
+-
加、减
双目
12
<>≤≥
关系
双目
10
==≠
相等、不相等
双目
9
&&
逻辑与
双目
5
||
逻辑或
双目
4
=
赋值
双目
2

15分支结构

if语句,无须多言
 
条件表达式:
测试条件 ? 表达式1:表达式2;
例如
c = x ≥ 10 ? ‘Y’:’N’;
C语言中唯一一个三元运算符
 
表达式的结果:
测试条件为真,则为表达式1
测试条件为假,则为表达式2
 
条件表达式的优先级为3

16循环结构

while循环:
while(循环条件)
{
循环行为1
循环行为2
。。。。。。。。
}
while(1)会一直看作真,C语言中,非0即为真
while(0)看作假
 
for循环:
for(计数器设置初始值;循环条件;计数器更新)备注:都可以为空
{
循环行为1
循环行为2
。。。。。。。。
}
无须多言😎
 
值得注意的是不要在while或for后面加分号
 
do while循环:
while循环先进入循环前检查循环条件是否满足,若不满足则依次都不执行
do while循环先执行一次循环行为再检查循环条件,至少会执行一次循环行为
 
do
{
循环行为
}
while(循环条件);
 
例如:
 
 
循环嵌套: 说白了就是套娃🪆
由内向外执行

17循环辅助,break和continue

对于for循环结构:
break:直接跳出循环,不会再更新计数器
continue:将立即更新计数器,再进入新循环
 
在循环嵌套中,break和continue将作用于自己直属上级循环

18多重选择,switch的使用

day=3,输出星期三
switch将从上到下对比,若不符合任意一种情况,则执行default
 
switch语句注意事项⚠️:
switch后面的括号只能填一个整型表达式
case后的常量不能有重复的
可以没有default
 
switch执行完case并不会跳出整个switch,遇到break才会跳出整个switch,否则会执行后面所有的语句,包括default
 
switch内的continue对于switch不产生影响

19初识数组

数组的元素都是类型相同的数据对象,不同的数据对象是不能组成数组的
 
初始化数组:
元素类型 数组名[元素数量]={逗号分隔元素内容};
 
访问数组内的元素:
数组名[下标]
特别注意⚠️:数组的下标是从0开始的,下标0访问的数组的第一个元素
 
C语言编译器不会检查数组是否越界
不能修改数组以外的元素
 
只声明不初始化会使数组里面都是一些无意义的数值
数组不一定要初始化,但是之后需要赋值,避免使用无意义数值
 
数组所占的空间=单个元素所占空间大小 * 数组元素个数
 
正确做法:
另一种方法(内存复制memory copy):
 

20多维数组

用数组作为数组的元素
 
int[10] B[5]
int B[5][10] 二维数组 5行10列
数组B包含了五个元素,而每个元素都含有10个int元素的数组
内部花括号可以省略
 
 

21字符串与字符数组

初始化字符数组
值得注意的是⚠️:
char str[20] = "HelloWorld"后10位由数值0填充,可以正常结尾
char str[10] = "HelloWorld"没有空间存放数值0,因此这个字符数组中的字符串就没有办法正常结尾,printf输出的时候结尾会输出乱码
 
 
使用循环测量字符串的长度:
也可以使用strlen测量字符串长度:
strlen注意事项⚠️:
strlen可以接受一个字符串作为参数
strlen返回值为这个字符串的长度
使用strlen,需要包含头文件string.h
 
strlen(str)测量从第一个元素直到\0的字符串长度
sizeof(str)测量数组本身占用空间的大小
 
scanf函数会自动帮我们在输入的字符串后面加上\0
 
 

22输入输出缓存

23函数

24函数递归

25调试代码

26指针

八个晶体管为一组称为一个字节
 
记录一个数据对象在内存中的存储位置需要两个信息,数据对象的首地址和数据对象占用存储空间的大小
 
取地址运算符&,写在数据对象的左边
用于获取数据对象的首地址和所需存储空间的大小
 
声明指针类型:
目标数据类型 * 变量名
指针类型的值就是目标数据对象的首地址
通过类型本身来标记目标数据对象的空间大小
 
取值运算符 *
*指针:根据指针中存储的首地址和空间大小找到目标数据对象
 
指针所占用的字节大小,还和编译器或者编译配置有关
 
x86→32位→地址范围0~2的32次方,指针类型占用4字节
x64→63位→地址范围0~2的64次方,指针类型占用8字节
 
不同类型的指针不能相互赋值,会出现编译错误
但是可以强制执行赋值操作,即强制转换指针类型
pn为int类型的指针,*pn表达式会从首地址开始取四个字节的数据,将其转换为int类型作为表达式的结果,而*pc表达式会从首地址开始取一个字节的数据,因此即使把n的地址强制赋值给pc,取值后的结果也不一样

27指针运算

指针类型与整型相减:
sizeof(目标数据对象)被称作步长
指针类型➕n后,将首地址向后移动n*步长个字节
指针类型➖n后,将首地址向前移动n*步长个字节
 
值得注意的是,*(p - 1)不能写成*p - 1
因为取值运算符的优先级高于算数运算符
需要先让首地址移动,再进行取值操作
 
同类型的指针相减:
指针类型相减后,结果为两个首地址差值除以步长
 
 
指针类型与整型进行乘除运算
同类型的指针相加
同类型的指针乘除
以上三种都没有实际意义
 

28指针与数组

第一个元素获取数组首地址:
数组元素在内存中是连续的
那么第一个元素的首地址就是整个数组的首地址
 
数组名获取数组首地址:
数组名出现在表达式中数组名将会转换为指向数组的第一个元素的指针
(例外:1对数组名使用sizeof时,2对数组名使用取地址运算符&时)
 
指针访问数组:
*(数组名+偏移量)
 
A[k]:
中括号被称作下标运算符,优先级高于一切其他运算符
过程:A[k]——>*(A+k)
编辑器会将下标运算符的这种形式最终转换成指针的形式来进行运算
总结:下标运算符最终会展开为指针的形式
 
 

29指针作为参数传递

实参与行参相互独立:
main函数中调用swap函数是将a的值1传递给了x,将b的值2传递给了y
xy只是数值发生变化,首地址没有变化
因此x和y的值无论怎么进行交换都不会影响到a和b的值
 
 
指针作为参数传递:
由于在被调函数内部无法直接修改主调函数的变量
考虑不传递数值,而传递首地址
修改代码:
 
理解scanf为什么要加&:
scanf会先读取从键盘的输入转化后存储到变量n当中
被调函数sanf无法直接修改在主调函数中的变量n
因此将变量n的指针传入scanf函数
通过指针使得scanf函数可以间接地修改主调函数中的变量
 
⚠️:
指针保存的不仅是目标数据对象的首地址,还有指针的类型 即数据对象的存储空间
不同类型的指针是不能相互赋值或传递的
 
 
void*类型指针:
好处:任意类型的指针都可以直接赋值给void*
 
修改代码:
让swap函数更加通用,可以交换更多类型的变量
 

30多级指针与指针数组

指针的指针:
int*数据对象的指针被称作 二级指针
 
指针数组:
从函数中返回指针:
函数之间的变量是独立的
函数返回后,函数内的变量没有存在意义,会被系统回收
如果不想变量被回收,可以在变量前加上关键词static
这样即使函数运行结束,变量也不会被回收
从函数中返回多个变量:
NULL是一个符号常量
由#define NULL 0定义的一个符号常量
将指针初始化为0是一个非常好的编程习惯
 

31指针与多维数组

声明数组时必须至少有一个方括号
 
多维数组与指针:
数组指针移动和取值:
 
指针访问与下标访问:
访问数组元素有两种方法
第一种:数组名[下标]
第二种:*(数组名+偏移量)
进化版
第一种:指针[下标]
第二种:*(指针+偏移量)
后面一部分需要继续研究
 
对数组取地址:
 
⚠️:&&arr是不对的
&arr确实可以获取到一个指针,但是这个指针是一个临时数据对象,应当将其赋值给变量才能够保存它的值
 

32指针与三维数组示例

指针访问三维数组:

33声明器

声明与使用形式统一:

34函数指针与数组

 

35字符串与字符指针

字符串常量不可修改:
 
字符数组:
字符数组可以被修改:
 
字符数组与指针:
使用指针处理字符串:

36const关键词

const修饰数组元素:
当使用const关键词修饰char时,将禁止修改char,数组string的元素无法被修改,其后面的语句如果尝试修改数组的任意一个元素,则编译报错(仅能读取,但不能修改)
⚠️:const关键词是可以加在char旁边的,无论加在左边还是右边都有这个效果
 
const修饰指针指向数据:
const修饰指针本身:
 

37字符串处理函数

如果需要处理字符串处理函数,需要
 
获取字符串长度strlen:
strlen函数可以获取字符数组中的字符串长度
从第一个字符开始计数,直到遇到\0为止,并返回累计的长度(不算上\0)
 
字符串拼接函数strcat:
strcat函数可以将字符串拼接到目标字符串后面
 
字符串复制函数strcpy:
strcpy函数可以将源字符串复制到目标字符串当中
字符串复制函数会从首元素开始逐个覆盖目标字符串
例如
des=ILove\0
src=You\0
strcpy(des,src)=You\0e\0
输出被\0截断,输出You
 
字符串比较函数strcmp:
strcmp函数可以比较两个字符串,若一致返回0
如果字符串不一致,从左到右找出不一样的第一对字母,比较当前字符的ASCII码大小,返回值为前者的ASCII码减去后者的ASCII码
 

38实现字符串处理函数

strlen函数:
strcat函数:
strcpy函数:
strcmp函数:

39初识结构化数据

姓名
性别
身高
体重
Timmy
1
170
60
David
1
175
65
Jane
2
165
55
交互式程序:
system是头文件stdlib.h中的函数
它的参数是一串字符串
例如:
system(”cls”);清楚控制台中之前先试过的字符
system(”pause”);暂停程序执行,按任意键后继续执行
 
聚合数据: 新关键词struct(结构)
如何访问数据🧐?
完整代码:

40结构

 
在第一次声明结构变量时,在struct与花括号之间填写上一个结构别名,如果以后再次需要使用这种结构,仅需要使用struct加别名就可以声明这种结构的变量
OR
⚠️:如果结构类型声明在一个函数中,那么别名只能在这个函数内部使用
 
初始化结构:
⚠️:
初始化列表由花括号包括
花括号内为结构成员需要被初始化的值
初始化值按照结构成员声明时的顺序依次排列
每个初始化值之间由逗号分隔
 
 
结构数组:
 
嵌套结构:
一个结构可以作为另一个结构的成员
 
指向结构的指针:
指针可以指向基本数据类型或者数组,当然也可以指向结构
 
成员间接运算符:
示例代码:
 
结构在函数中传递:
错误代码示例:
正确代码:
 
⚠️:将一个结构从函数返回也是可以的
 

41联合与枚举

联合与结构:
联合的关键词为union
联合的语法非常类似于结构的语法
因为联合中的各成员之间有重叠的部分
所以存储一个成员后将覆盖掉其他成员的数据
 
联合应用举例:
 
枚举:
枚举是一种特殊的整型,关键词enum
1—>eInteger
2—>eFloat
3—>eString
如果我不想从0开始呢🧐?
甚至可以指定数值
 
枚举应用:
 
例题:

42标识符作用

43预处理指令

44typedef关键词

45条件编译

46多文件代码

47更复杂的多文件代码

48存储类别

49文件1

50文件2

51文件3

52位操作

53动态内存管理

54主函数参数

记一次用树莓派搭建MC服务器谷歌搜索语法
Loading...
R4nd0m99
R4nd0m99
一个普通的JNUer
Latest posts
记一次用树莓派搭建MC服务器
2025-2-7
记一次用树莓派搭建Terraria服务器
2025-2-7
记一次用树莓派搭建青龙面板
2025-2-7
关于极简主义
2025-2-7
关于短视频
2025-2-7
Linux指令
2025-2-7
Announcement
🎉个人博客已经上线🎉
-- 感谢您的支持 ---