2.1.1.2 计算机和编程语言:计算机的思维方式
程序的执行
- 解释:借助一个程序,那个程序能试图理解你的程序,然后按照你的要求执行。
- 编译:借助一个程序,就像一个翻译,把你的程序翻译成计算机真正能懂的语言——机器语言——写的程序,然后,这个机器语言写的程序就能直接执行了。
11.2.1.3 变量:变量赋值与初始化

如果变量没有初始化,就直接拿到右边去用,会出现什么呢?

得到了一个非常奇怪的结果,这是因为,在内存当中,我们有一个变量 i 我们没有给它一个初始值,那么,它正好在内存当中,在什么地方,那个地方原本有一些什么样的值在里头,它就是那个值了。
12.2.1.4 变量:变量输入
读整数
scanf("%d", &price);- 要求scanf这个函数读入下一个整数,读到的结果赋值给变量price。
scanf和printf中,f表示format格式化的意思。
13.2.1.5 变量:常量VS变量
常量(C99)
- int change = 100 - price;
- 固定不变的数,是常数。直接写在程序里,我们称作直接量(literal)。
- 更好的方式,是定义一个常量:
const int AMOUNT = 100。
#include <stdio.h>
int main()
{
const int AMOUNT = 100;
int price = 0;
printf("请输入金额(元):");
scanf("%d", &price);
int change = AMOUNT - price;
printf("找您%d元。\n", change);
return 0;
}
const(C99)
- const是一个修饰符,加在int的前面,用来给这个变量加上一个const(不变的)的属性。这个const的属性表示这个变量的值一旦初始化,就不能再修改了。
- int change = AMOUNT - price;
- 如果你试图对常量做修改,把它放在赋值运算符的左边,就会被编译器发现,指出为一个错误。
14.2.1.6 变量:浮点数



%lf对应double。

16.2.2.2 表达式:运算符优先级
注意这里优先级为1的单目运算符+、-


注意,a=6这个式子本身,是有结果的,也就是6。

17.2.2.3 表达式:交换变量
视频中4分20秒开始出现Dev C++断点调试的使用方法。
20.3.0.1 编程练习解析:PAT再解释
视频中5分30秒开始,出现了对scanf的讲解。
出现在scanf格式字符串里面的东西,是它一定要你输入的东西,而不是它会给你看的东西。
28.3.2.1 分支:嵌套的if-else


(学习笔记:能用大括号就用大括号,避免歧义。)

29.3.2.2 分支:级联的if-else if

30.3.2.3 分支:if-else的常见错误


31.3.2.4 分支:多路分支



(以下代码利用了switch-case的某个特性)

34.4.1.3 循环:do-while循环

(注意:while结尾要有分号)
35.4.2.1 循环应用:循环计算

(计算之前先保存原始的值,后面可能有用。)
40.5.1.2 第三种循环:循环的计算和选择

41.5.2.1 循环控制:循环控制
(判断素数)

(上面的代码中,设置一个标志位的写法,我认为值得借鉴。)
(判断素数的另一种写法。)

43.5.2.3 循环控制:从嵌套的循环中跳出
#include <stdio.h>
int main()
{
int x;
int one, two, five;
int exit = 0;
scanf("%d", &x);
for (one=1; one<x*10; one++)
{
for (two=1; two<x*10/2; two++)
{
for (five=1; five<x*10/5; five++)
{
if (one + tw0*2 + five*5 == x*10)
{
printf("可以用%d个1角加%d个5角得到%d元\n",
one, two, five, x);
exit = 1;
break;
}
}
if (exit == 1) break;
}
if (exit == 1) break;
}
}
(
我主要对这里的先设置一个标志int exit = 0;,然后满足某种条件后,改变标志exit = 1,进而改变程序控制流程的写法,感兴趣。
)
45.5.3.2 循环应用:整数分解
(这一段的视频值得重新一看,整数正序分解,因为C 语言中没有趁手的工具,所以这里实现起来略繁琐。)
46.5.3.3 循环应用:求最大公约数
辗转相除法求最大公约数

48.6.0.2 编程练习解析:编程练习解析4-1
(水仙花数编程实现,值得一看)
49.6.0.3 编程练习解析4-2:九九乘法表
50.6.0.4 编程练习解析4-3:统计素数求和
(关键词:素数、质数)
52.6.0.6 编程练习解析5-0:n项求和
每一项的分子是前一项分子与分母的和,分母是前一项的分子。

(下面的代码值得一看)

54.6.1.1 数据类型:数据类型
sizeof
- 是一个运算符,给出某个类型或变量在内存中所占据的字节数
sizeof(int)sizeof(i)

55.6.1.2 数据类型:整数类型

整数
- char:1字节(8比特)
- short:2字节
- int:取决于编译器(CPU),通常的意义是“1个字”
- long:取决于编译器(CPU),通常的意义是“1个字”
- long long:8字节
当我们在说1台计算机的字长的时候,我们指的是寄存器是多少宽的,也就是说,这个寄存器是几个bit的。比如说,当我们说寄存器是32个bit的,每一个寄存器可以表达32个bit的数据,同时也是在说,CPU和RAM之间在总线上传递数据的时候,每一次的传递是32个bit,也就是说,当要从内存RAM取数据到CPU里面去,每一次就会要取32个bit。
除了32,现在更常见的是64个bit。
字长在C语言中,反映为int。int表达的是1个寄存器的大小。所以,在不同的平台、CPU上面,int会不一样大。
56.6.1.3 数据类型:整数的内部表达



所以,为什么我们要在计算机的内部使用补码呢?
最大的好处就是,如果你有了一个补码,你用补码来表示这个-1,那么,当你在做加法的时候,你不需要根据条件,去变换,把加+变成减-,你直接拿它去做普通的二进制的加法,你就会得到你想要的那个结果。
57.6.1.4 数据类型:整数的范围
整数越界
整数是以纯二进制方式进行计算的,所以:
- 11111111 + 1 –> 100000000 –> 0
- 01111111 + 1 –> 10000000 –> -128(这里我存在疑问)
- 10000000 + 1 –> 01111111 –> 127
下面的代码似乎可以解答我的疑问:


-2^(32-1) —— 2^(32-1)-1




(关键词:无符号数、unsigned
这整段视频建议重新细看、加强理解。)

58.6.1.5 数据类型:整数的格式化

(如下的代码,建议看视频的详细解释)

59.6.1.6 数据类型:选择整数类型

60.6.1.7 数据类型:浮点类型

(inf:正负的无穷大
nan:表示不是一个有效的数字
这段视频建议再去详细看。)

科学计数法
#include <stdio.h>
int main()
{
double ff = 1234.56789;
printf("%e,%f\n", ff, ff);
return 0;
}
输出:
1234568e+03,1234.567890
#include <stdio.h>
int main()
{
double ff = 1E-10;
printf("%E,%f\n", ff,ff);
return 0;
}
输出:
1.000000E-10,0.000000


61.6.1.8 数据类型:浮点的范围与精度

#include <stdio.h>
int main()
{
printf("%f\n", 12.0/0.0);
printf("%f\n", -12.0/0.0);
printf("%f\n", 0.0/0.0);
return 0;
}
$ gcc q.c
$ ./a.out
inf
-inf
-nan


62.6.1.9 数据类型:字符类型



63.6.1.10 数据类型:逃逸字符
(即转义字符)


64.6.1.11 数据类型:类型转换




65.6.2.1 其他运算:逻辑类型
bool
#include <stdio.h>;- 之后就可以使用bool和true、false。
67.6.2.3 其他运算:条件运算与逗号运算
条件运算符
count = (count > 20) ? count - 10 : count + 10;- 条件、条件满足时的值和条件不满足时的值。
69.7.1.2 函数的定义和使用:函数的定义和调用
(8分01秒开始出现了“单步进入”,讲解了调用函数时,进入函数内部、单步调试)
71.7.2.1 函数的参数和变量:函数原型
函数的先后关系
void sum(int begin, int end)
{
int i;
int sum = 0;
for (i=begin; i<=end; i++)
{
sum += i;
}
printf("%d到%d的和是%的\n", begin, end, sum)
}
int main()
{
sum(1,10);
sum(20,30);
sum(35,45);
return 0;
}
像这样把sum()写在上面,是因为:
- C的编译器自上而下顺序分析你的代码;
- 在看到sum(1,10)的时候,它需要知道sum()的样子;
- 也就是sum()要几个参数,每个参数的类型如何,返回什么类型。
void sum(int begin, int end); // 声明。这里是函数原型
int main()
{
sum(1,10);
sum(20,30);
sum(35,45);
return 0;
}
void sum(int begin, int end) // 定义。
{
int i;
int sum = 0;
for (i=begin; i<=end; i++)
{
sum += i;
}
printf("%d到%d的和是%的\n", begin, end, sum)
}

72.7.2.2 函数的参数和变量:参数传递


C语言在调用函数时,只能传值给函数。
当我们在main()函数中,做swap(a,b)的时候,是把a的值5交给了swap里的a、把b的值6交给了swap里的b。swap里的a、b,与main里的a、b完全没有任何关系的。
我们在swap里面,对a、b做的任何事情,是swap里的参数a、b的事情,和main的a、b没有任何关系。如上的代码,不能交换a、b的值。

73.7.2.3 函数的参数和变量:本地变量(局部变量)

(关键词:本地变量,也叫做局部变量,因为英文是local,可翻译为本地或局部。
)
也有的地方把它叫做自动变量,把它叫做自动变量是和我们后面讲的一件事情有关系,它的生存期和作用域的关系,把它叫做自动变量是因为,它的生存期是自动的。

(这一段,建议借助视频讲解和在Dev C++编译器中断点调试,可以辅助加强理解context等概念的含义。
关键词:生存期、作用域
从1分59秒开始看。
从4分09秒开始看。)
本地变量的规则

(整段视频都值得重新仔细看,介绍了作用域、生存期,可以结合Python的LEGB同时理解。
特别是8分39秒开始的地方,依次介绍了类似嵌套作用域、变量掩盖之类的概念。)
76.8.1.2 数组:数组的使用

在内存中,数组的单元是依次排列的,而且是紧密依次排列的。


77.8.1.3 数组:数组的例子
通常来说,用到数组的程序,都需要这么一些环节。

78.8.2.1 数组运算:数组运算

(以下值得一看)



79.8.2.2 数组运算:数组例子
(判断素数、质数)





(求解素数的另外一种思路的算法。)

(伪代码)

80.8.2.3 数组运算:二维数组

81.9.1.1 指针:取地址运算

为什么变量会有地址?
因为 C 语言的变量,是放在内存里的。每 1 个变量,比如说 int ,可能是 4 个字节,在内存中要占一定的地方,放在某个地方,就有 1 个地址。 & 运算符就是把地址拿出来。

(整段视频都值得重新看,
特别是6分38秒开始的,
关键词:C语言的内存模型、变量的地址、内存中的堆栈stack、自顶向下、分配变量。
)


#include <stdio.h>
int main(void)
{
int a[10];
printf("%p\n", &a);
printf("%p\n", a);
printf("%p\n", &a[0]);
printf("%p\n", &a[1]);
return 0;
}
输出:
$ gcc q.c
$ ./a.out
0x7ffe025df0d0
0x7ffe025df0d0
0x7ffe025df0d0
0x7ffe025df0d4

82.9.1.2 指针:指针


(最后2行,p为int型指针,q为int型、不是指针。)

当我们说, p 指向了 i,实际的意思是,p 的值是变量 i 的地址。



#include <stdio.h>
void f(int *p);
void g(int k);
int main(void)
{
int i = 6;
printf("&i=%p\n", &i);
f(&i);
g(i);
return 0;
}
void f(int *p)
{
printf(" p=%p\n", p);
printf("*p=%d\n", *p);
}
void g(int k)
{
printf("k=%d\n", k);
}
输出:
$ gcc w.c
$ ./a.out
&i=0x7ffd4447a5d4
p=0x7ffd4447a5d4
*p=6
k=6
这就意味着,通过 *p 这个指针,我们访问到了 p 所指的 int i 里面的值。
增加一行代码 *p = 26; :
#include <stdio.h>
void f(int *p);
void g(int k);
int main(void)
{
int i = 6;
printf("&i=%p\n", &i);
f(&i);
g(i);
return 0;
}
void f(int *p)
{
printf(" p=%p\n", p);
printf("*p=%d\n", *p);
*p = 26;
}
void g(int k)
{
printf("k=%d\n", k);
}
输出:
$ gcc w.c
$ ./a.out
&i=0x7ffd8ecfb624
p=0x7ffd8ecfb624
*p=6
k=26
k=26 意味着,在经历了 f 函数的调用了之后, i 的值被改了。
地址值 &i 被传进了函数 f(int *p),这里,仍然是值的传递,因为传进来的是地址,所以,通过这个地址,在函数内部,可以以这种方式,访问到外面的 i 变量。
因为 p 的值,就是 i 的地址。 *p 就代表了 i 。
当我们做 *p = 26 这个运算的时候,我们实际做的事情,是对 i 做的。


83.9.1.3 指针:指针的使用




84.9.1.4 指针:指针与数组

(函数参数里的数组是指针。
从视频0分59秒开始看起)


(“*ar、ar[]在函数参数表中出现,是等价的”)



(const 常量)

85.9.1.5 指针:指针与const


上图。如果指针是const,比如int * const q = &i;,在这种情况下,q这个指针是const,它的意思是说,q的值不能被改变,什么是q的值?就是i的地址,就是q指向了i这个事实不能被改变,也就是q不能再指向别人了,它们之间的关系是永久的。


(对上图和上上图的一点说明:)
p可以指向别人,i可以被赋以别的值,但是通过p去修改i就不可以。

如果const在*前面,那么,表示它所指的东西不能被修改;
如果const在*后面,那么,表示指针不能被修改;



86.9.2.1 指针运算:指针运算

当我们给一个指针加1的时候,它不是在地址值上加1,它在地址值上加一个sizeof(那个指针所指的类型)。

所以对指针做一个加1的动作,意味着,我们要把它移到下一个单元去。


(当做两个指针相减的时候,它给你的是两个地址的差除以sizeof(它的类型),也就是,在这两个地址之间,有几个这样类型的东西在,或者说,能放几个这样类型的东西。)





87.9.2.2 指针运算:动态内存分配

(0分52秒开始,略为完整地介绍了动态内存分配malloc、内存释放free()。
第12行:
malloc返回的结果是是void *,而a是int*,所以我们还要类型转换一下。(在前面加上(int*))。
)




(第8行:每次申请100兆的空间,然后把申请到的空间,交给p,(p=malloc(100*1024*1024))中,对p做了一个赋值。赋值也是个表达式,有个结果,结果就是p得到的malloc的那个结果。
while ( (p=malloc(100*1024*1024)) ){
cnt++;
}
这样的代码同时做了2件事情:
1.把malloc的结果赋给了p这个变量;
2.要让p得到的这个值,拿来做while的条件。
如果p得到的地址不是0,那就意味着它得到了一个有效的地址,那么,我们循环要继续,要让cnt去加加。
如果它得到的地址是0,那么while就要退出来。
)

(着重:首地址)

88.10.1.1 字符串:字符串
(在字符数组的最后一个元素,使用'\0')



89.10.1.2 字符串:字符串变量

(0分28秒开始。
关键词:程序的代码段、只读、保护机制。)



90.10.1.3 字符串:字符串的输入输出







91.10.1.4 字符串:字符串数组,以及程序参数





92.10.2.1 字符串函数:单字符输入输出


93.10.2.3 字符串函数: 字符串函数 strlen


(作为参数,数组的形式和指针的形式是一样的,因为,数组传进去,也是指针,所以,我们在这里全部用指针的形式来表达了。)
size_t strlen(const char *s)的参数中,const char *s的前面有 1 个const,含义是,希望函数strlen()不修改传进去数组char *s。
94.10.2.3 字符串函数:字符串函数strcmp

(4分01秒开始,对strcmp的重新实现,值得一看。
包括数组实现和指针实现。
)
95.10.2.4 字符串函数: 字符串函数 strcpy



(5分20秒开始,分析并重新实现了strcpy,有数组、指针版本。)
96.10.2.5 字符串函数strcat



97.10.2.6 字符串函数:字符串搜索函数


98.11.1.1 枚举:枚举








99.11.2.1 结构:结构类型





(上 面的代码中,main函数外的struct date { sth. }是在声明一种新的结构类型,main函数内的struct date today = sth.是在定义这种结构类型的一个结构变量。
)



(数组变量的名字,就是数组的地址。)
100.11.2.2 结构:结构:结构与函数








101.11.2.3 结构:结构中的结构
(结构数组)





102.11.3.1 联合:类型定义


(上面,Date是别名。)


103.11.3.2 联合: 联合




104.12.1.1 全局变量:全局变量



105.12.1.2 全局变量: 静态本地变量

#include <stdio.h>
int f(void);
int gAll = 12;
int main(int argc, char const *argv[])
{
f();
f();
f();
return 0;
}
int f(void)
{
static int all = 1;
printf("in %s all=%d\n", __func__, all);
all += 2;
printf("agn in %s all=%d\n", __func__, all);
return all;
}
输出:
$ gcc q.c
$ ./a.out
in f all=1
agn in f all=3
in f all=3
agn in f all=5
in f all=5
agn in f all=7
(
个人理解:
这里的 静态本地变量 ,让我联想起了 Python 中的 生成器 和 yield 。
有时间一定要去读 《 Python 源码分析》,了解下生成器的内部实现。
)

106.12.1.3 全局变量: 后记

- 返回本地变量的地址是危险的
如果有 1 个函数,你要让它返回 1 个指针,那么,你如果返回的是本地变量的地址,这是危险的。
因为一旦离开这个函数,本地变量就不存在了。
#include <stdio.h>
int* f(void);
void g(void);
int main(int argc, char const *argv[])
{
int *p = f();
printf("*p=%d\n", *p);
g();
printf("*p=%d\n", *p);
return 0;
}
int* f(void)
{
int i=12;
return &i;
}
void g(void)
{
int k = 24;
printf("k=%d\n", k);
}
我的输出:
$ gcc q.c
q.c: In function ‘f’:
q.c:19:9: warning: function returns address of local variable [-Wreturn-local-addr]
return &i;
^
$ ./a.out
Segmentation fault (core dumped)
视频中的输出:
。。。
1 warning generated.
*p=12
k=24
*p=24
*p 又变成 24 了,但这个过程中,没有人对 *p 和 i 做任何事情,但是 p 所指的那个地方却变成了 24 了。
你可以自己改一点这里的程序,如果在 f 函数里打印出 i 的地址,在 g 函数里打印出 k 的地址,你会发现它们是一样的。
返回 1 个本地变量的地址,让外面的程序继续使用它是有风险的。因为这个函数结束以后,那个本地变量的地址会被继续分配给别人去使用的。
- 返回全局变量或静态本地变量的地址是安全的
因为,全局变量或静态本地变量的地址和函数没关系,它们是全局生存期的。
返回在函数内
malloc的内存是安全的,但是容易造成问题最好的做法是返回传入的指针

107.12.2.1 编译预处理和宏: 宏定义


#include <stdio.h>
#define PI 3.14159
#define FORMAT "%f\n"
#define PI2 2*PI // pi * 2
#define PRT printf("%f ", PI); \
printf("%f\n", PI2)
int main(int argc, char const *argv[])
{
printf(FORMAT, PI2*3.0);
PRT;
return 0;
}
输出:
$ gcc q.c
$ ./a.out
18.849540
3.141590 6.283180


108.12.2.2 编译预处理和宏: 带参数的宏
像函数的宏
#define cube(x) ((x)*(x)*(x))- 宏可以带参数



宏定义的结尾不要加上分号 ; 。


109.12.3.1 大程序结构: 多个源代码文件



110.12.3.2 大程序文件: 头文件






111.12.3.3 大程序结构: 声明

- 定义时产生代码的东西
比如说函数、全局变量。

在头文件中方的不是声明,而是定义,会造成问题。



112.13.1.1 文件: 格式化输入输出


#include <stdio.h>
int main(int argc, char const *argv[])
{
printf("%9d\n", 123);
printf("%-9d\n", 123);
printf("%+9d\n", 123);
printf("%+-9d\n", 123);
printf("%-+9d\n", 123);
printf("%-+9d\n", -123);
printf("%-9d\n", -123);
printf("%09d\n", 123);
return 0;
}
输出:
#include <stdio.h>
int main(int argc, char const *argv[])
{
printf("%9d\n", 123);
printf("%-9d\n", 123);
printf("%+9d\n", 123);
printf("%+-9d\n", 123);
printf("%-+9d\n", 123);
printf("%-+9d\n", -123);
printf("%-9d\n", -123);
printf("%09d\n", 123);
return 0;
}

#include <stdio.h>
int main(int argc, char const *argv[])
{
printf("%9.2f\n", 123.0);
return 0;
}
输出:
$ gcc q.c
$ ./a.out
123.00
printf("%9.2f\n", 123.0);中,9.2f的含义是,输出 1 个浮点数,后面是 2 位小数,前面的空位、整数位、小数点位加上小数位,一共是 9 位。
#include <stdio.h>
int main(int argc, char const *argv[])
{
printf("%*d\n", 6, 123);
return 0;
}
输出:
$ gcc q.c
$ ./a.out
123
printf("%*d\n", 6, 123);中 * 意思是, 6 是用来满足这个 * 的, 6 会被填到 * 里面去; 123 是用来满足这个 d 的。
所以,输出包括前面的 3 个空格加后面的 3 位数,总共占据 6 个位置。


#include <stdio.h>
int main(int argc, char const *argv[])
{
int num;
printf("%drf%n\n", 12345, &num);
printf("%d\n", num);
return 0;
}
输出:
$ gcc q.c
$ ./a.out
12345rf
7
printf("%drf%n\n", 12345, &num);中, %n 的含义是,当 printf 执行到这个地方的时候,已经输出了多少个字符,然后填到 &num 指针所指的那个变量里面去。

#include <stdio.h>
int main(int argc, char const *argv[])
{
int num;
scanf("%*d%d", &num);
printf("%d\n", num);
return 0;
}
输出:
$ gcc q.c -o test
$ ./test
123 345
345
说明:把前面的 123 跳过,然后读到了 345 。 * 的意思是跳过。

#include <stdio.h>
int main(int argc, char const *argv[])
{
int num;
scanf("%i", &num);
printf("%d\n", num);
return 0;
}
输出:
$ gcc q.c -o test
$ ./test
123
123
$ ./test
0x12
18
$ ./test
012
10

113.13.1.2 文件: 文件输入输出

$ gcc q.c -o test
$ ./test
12345
12345
$ ./test > 12.out
12345
$ cat 12.out
12345
$ cat > 12.in
12345(备注:这里可能需要输入 Ctrl + D 终止。)
$ cat 12.in
12345
$ ./test < 12.in
12345
$ ./test < 12.in > 12.out
$ cat 12.out
12345
这是叫做程序运行时的重定向。


#include <stdio.h>
int main(int argc, char const *argv[])
{
FILE *fp = fopen("12.in", "r");
if ( fp ) {
int num;
fscanf(fp, "%d", &num);
printf("%d\n", num);
fclose(fp);
} else {
printf("无法打开文件\n");
}
return 0;
}
$ gcc q.c -o test
$ ./test
12345
$ rm 12.in
$ ./test
无法打开文件

114.13.1.3 文件: 二进制文件






(视频中,这里有一段代码,建议看视频。)


115.13.2.1 位运算: 按位运算








(视频中,有代码,建议看视频。)


对 1 个数,做 2 次异或,就翻回去了。

116.13.2.2 位运算:移位运算


117.13.2.3 位运算:位运算例子

118.13.2.4 位运算: 位段


119.14.1.1 可变数组: 可变数组



120.14.1.2 可变数组:可变数组的数据访问
121.14.1.3 可变数组:可变数组的自动增长
122.14.2.1 链表:可变数组的缺陷
123.14.2.2 链表: 链表

#include _NODE_H_
#define _NODE_H_
typedef struct _node {
int value;
struct _node *next;
} Node;
# endif
124.14.2.3 链表:链表的函数
125.14.2.4 链表:链表的搜索
126.14.2.5 链表:链表的删除


127.14.2.6 链表:链表的清除

断点调试
Dev C++的断点调试
参考文献:
1. C语言 - 翁恺 - 浙江大学。

这是一份关于浙江大学翁恺教授的《C语言程序设计(第3版)》的学习笔记,涵盖了从变量、运算符、表达式、分支、循环到函数、数组、指针、字符串、结构体等多个核心概念的详细讲解,还包括了编程实践中的数据类型选择、内存管理、错误处理等方面的内容。笔记强调了理解计算机思维方式、变量的赋值与初始化、循环控制、函数调用及参数传递的重要性,并提供了多种编程技巧和实例解析。
》 - 翁恺 - 学习笔记&spm=1001.2101.3001.5002&articleId=79754780&d=1&t=3&u=6bbe3fd60b3c4b9f9de6eb83249f3602)
7830

被折叠的 条评论
为什么被折叠?



