经典案例与解析


实战案例 通过实际项目巩固理论知识

案例目录

案例1:学生成绩管理系统(入门版)

📋 案例说明

这是一个基础版的学生成绩管理系统,使用数组和结构体实现,适合初学者掌握基本的输入输出和数组操作。

**涉及知识点:**数组、循环、选择结构、函数、结构体

难度等级:⭐⭐ (初级)

💡 功能需求

  • 添加学生信息(姓名、学号、成绩)
  • 显示所有学生信息
  • 计算平均分
  • 查找最高分学生
  • 按成绩排序

💻 完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include 
#include

#define MAX_STUDENTS 50

// 学生结构体
struct Student {
char name[50];
int id;
float score;
};

// 全局变量
struct Student students[MAX_STUDENTS];
int studentCount = 0;

// 函数声明
void addStudent();
void displayStudents();
void calculateAverage();
void findTopStudent();
void sortByScore();
void showMenu();

int main() {
int choice;

while (1) {
showMenu();
printf("请选择操作(1-6):");
scanf("%d", &choice);

switch (choice) {
case 1: addStudent(); break;
case 2: displayStudents(); break;
case 3: calculateAverage(); break;
case 4: findTopStudent(); break;
case 5: sortByScore(); break;
case 6:
printf("感谢使用,再见!\n");
return 0;
default:
printf("无效选择,请重新输入!\n");
}

printf("\n按回车键继续...");
getchar(); getchar(); // 清空输入缓冲区
system("clear"); // Linux/Mac 使用 clear
// system("cls"); // Windows 使用 cls
}

return 0;
}

// 显示菜单
void showMenu() {
printf("\n");
printf("=================================\n");
printf(" 学生成绩管理系统(入门版)\n");
printf("=================================\n");
printf("1. 添加学生\n");
printf("2. 显示所有学生\n");
printf("3. 计算平均分\n");
printf("4. 查找最高分学生\n");
printf("5. 按成绩排序\n");
printf("6. 退出系统\n");
printf("=================================\n");
}

// 添加学生
void addStudent() {
if (studentCount >= MAX_STUDENTS) {
printf("\n⚠️ 学生人数已达上限!\n");
return;
}

printf("\n--- 添加学生 ---\n");
printf("学号:");
scanf("%d", &students[studentCount].id);

// 检查学号是否重复
for (int i = 0; i < studentCount; i++) {
if (students[i].id == students[studentCount].id) {
printf("⚠️ 学号已存在!\n");
return;
}
}

printf("姓名:");
scanf("%s", students[studentCount].name);
printf("成绩:");
scanf("%f", &students[studentCount].score);

studentCount++;
printf("✅ 添加成功!\n");
}

// 显示所有学生
void displayStudents() {
if (studentCount == 0) {
printf("\n⚠️ 暂无学生信息!\n");
return;
}

printf("\n--- 所有学生信息 ---\n");
printf("%-10s %-20s %s\n", "学号", "姓名", "成绩");
printf("----------------------------------------\n");

for (int i = 0; i < studentCount; i++) {
printf("%-10d %-20s %.2f\n",
students[i].id,
students[i].name,
students[i].score);
}

printf("共 %d 名学生\n", studentCount);
}

// 计算平均分
void calculateAverage() {
if (studentCount == 0) {
printf("\n⚠️ 暂无学生信息!\n");
return;
}

float sum = 0;
float max = students[0].score;
float min = students[0].score;

for (int i = 0; i < studentCount; i++) {
sum += students[i].score;
if (students[i].score > max) max = students[i].score;
if (students[i].score < min) min = students[i].score;
}

printf("\n--- 成绩统计 ---\n");
printf("平均分:%.2f\n", sum / studentCount);
printf("最高分:%.2f\n", max);
printf("最低分:%.2f\n", min);
}

// 查找最高分学生
void findTopStudent() {
if (studentCount == 0) {
printf("\n⚠️ 暂无学生信息!\n");
return;
}

int topIndex = 0;
for (int i = 1; i < studentCount; i++) {
if (students[i].score > students[topIndex].score) {
topIndex = i;
}
}

printf("\n--- 最高分学生 ---\n");
printf("学号:%d\n", students[topIndex].id);
printf("姓名:%s\n", students[topIndex].name);
printf("成绩:%.2f\n", students[topIndex].score);
}

// 按成绩排序(冒泡排序)
void sortByScore() {
if (studentCount == 0) {
printf("\n⚠️ 暂无学生信息!\n");
return;
}

// 冒泡排序
for (int i = 0; i < studentCount - 1; i++) {
for (int j = 0; j < studentCount - 1 - i; j++) {
if (students[j].score < students[j + 1].score) {
// 交换
struct Student temp = students[j];
students[j] = students[j + 1];
students[j + 1] = temp;
}
}
}

printf("\n✅ 排序完成!\n");
displayStudents();
}

🔍 代码解析

1. 数据结构设计
1
2
3
4
5
struct Student {
char name[50]; // 姓名:字符数组
int id; // 学号:整型
float score; // 成绩:浮点型
};

**解析:**使用结构体将学生的不同类型数据组合在一起,便于统一管理。

2. 全局变量的使用
1
2
struct Student students[MAX_STUDENTS];
int studentCount = 0;

解析:

  • students数组:存储所有学生信息
  • studentCount:记录当前学生数量,避免每次都遍历数组
  • 使用#define MAX_STUDENTS 50定义常量,便于修改最大容量
3. 菜单系统的实现
1
2
3
4
5
6
7
8
9
while (1) {  // 无限循环
showMenu();
scanf("%d", &choice);
switch (choice) {
case 1: addStudent(); break;
// ...
case 6: return 0; // 退出程序
}
}

解析:

  • while(1)实现无限循环,直到用户选择退出
  • switch语句根据用户选择调用不同函数
  • return 0直接退出程序,结束main函数
4. 冒泡排序算法
1
2
3
4
5
6
7
8
9
10
for (int i = 0; i < studentCount - 1; i++) {
for (int j = 0; j < studentCount - 1 - i; j++) {
if (students[j].score < students[j + 1].score) {
// 交换两个结构体
struct Student temp = students[j];
students[j] = students[j + 1];
students[j + 1] = temp;
}
}
}

解析:

  • 外层循环控制排序轮数(n个数需要n-1轮)
  • 内层循环比较相邻元素
  • studentCount - 1 - i:每轮后最大元素已就位,减少比较次数
  • 使用临时变量temp交换两个结构体
5. 输入验证
1
2
3
4
5
6
7
// 检查学号是否重复
for (int i = 0; i < studentCount; i++) {
if (students[i].id == students[studentCount].id) {
printf("学号已存在!\n");
return;
}
}

**解析:**在添加学生前检查学号唯一性,避免数据重复。

📊 运行示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
=================================
学生成绩管理系统(入门版)
=================================
1. 添加学生
2. 显示所有学生
3. 计算平均分
4. 查找最高分学生
5. 按成绩排序
6. 退出系统
=================================
请选择操作(1-6):1

--- 添加学生 ---
学号:1001
姓名:张三
成绩:85.5
✅ 添加成功!

请选择操作(1-6):1

--- 添加学生 ---
学号:1002
姓名:李四
成绩:92.0
✅ 添加成功!

请选择操作(1-6):2

--- 所有学生信息 ---
学号 姓名 成绩
----------------------------------------
1001 张三 85.50
1002 李四 92.00
共 2 名学生

请选择操作(1-6):3

--- 成绩统计 ---
平均分:88.75
最高分:92.00
最低分:85.50

🎯 知识点总结

  • ✅ 结构体的定义和使用
  • ✅ 数组的遍历和操作
  • ✅ 函数的声明和调用
  • ✅ switch-case 多分支选择
  • ✅ 冒泡排序算法
  • ✅ 输入验证

⚡ 扩展练习

  1. 添加删除学生功能
  2. 添加修改学生信息功能
  3. 实现按学号查找功能
  4. 将数据保存到文件(第8章内容)
  5. 添加成绩等级评定(优秀、良好、及格、不及格)

案例2:简易计算器

📋 案例说明

一个支持四则运算的简易计算器,可以处理连续运算,帮助理解函数调用和循环控制。

**涉及知识点:**函数、循环、switch、运算符、字符处理

难度等级:⭐ (入门)

💡 功能需求

  • 支持加、减、乘、除四则运算
  • 可以连续进行多次运算
  • 除数为0时给出提示
  • 支持清除和退出

💻 完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include 
#include // 用于 toupper() 函数

// 函数声明
double add(double a, double b);
double subtract(double a, double b);
double multiply(double a, double b);
double divide(double a, double b);
void clearInputBuffer();

int main() {
double num1, num2, result;
char operator;
char choice;

printf("=================================\n");
printf(" 简易计算器\n");
printf("=================================\n");

do {
printf("\n请输入第一个数字:");
while (scanf("%lf", &num1) != 1) {
clearInputBuffer();
printf("⚠️ 输入无效,请重新输入数字:");
}

printf("请输入运算符 (+, -, *, /):");
clearInputBuffer();
scanf("%c", &operator);

printf("请输入第二个数字:");
while (scanf("%lf", &num2) != 1) {
clearInputBuffer();
printf("⚠️ 输入无效,请重新输入数字:");
}

// 执行运算
switch (operator) {
case '+':
result = add(num1, num2);
printf("\n结果:%.2lf + %.2lf = %.2lf\n", num1, num2, result);
break;

case '-':
result = subtract(num1, num2);
printf("\n结果:%.2lf - %.2lf = %.2lf\n", num1, num2, result);
break;

case '*':
result = multiply(num1, num2);
printf("\n结果:%.2lf × %.2lf = %.2lf\n", num1, num2, result);
break;

case '/':
if (num2 == 0) {
printf("\n⚠️ 错误:除数不能为0!\n");
} else {
result = divide(num1, num2);
printf("\n结果:%.2lf ÷ %.2lf = %.2lf\n", num1, num2, result);
}
break;

default:
printf("\n⚠️ 错误:无效的运算符 '%c'\n", operator);
}

// 询问是否继续
printf("\n是否继续计算?(Y/N):");
clearInputBuffer();
scanf("%c", &choice);

} while (toupper(choice) == 'Y');

printf("\n感谢使用计算器,再见!\n");
return 0;
}

// 加法
double add(double a, double b) {
return a + b;
}

// 减法
double subtract(double a, double b) {
return a - b;
}

// 乘法
double multiply(double a, double b) {
return a * b;
}

// 除法
double divide(double a, double b) {
return a / b;
}

// 清空输入缓冲区
void clearInputBuffer() {
int c;
while ((c = getchar()) != '\n' && c != EOF);
}

🔍 代码解析

1. 函数的模块化设计
1
2
3
double add(double a, double b) {
return a + b;
}

解析:

  • 每种运算封装为独立函数
  • 使用double类型支持小数运算
  • 函数参数和返回值都是double类型
2. 输入验证
1
2
3
4
while (scanf("%lf", &num1) != 1) {
clearInputBuffer();
printf("⚠️ 输入无效,请重新输入数字:");
}

解析:

  • scanf返回成功读取的项目数
  • 如果用户输入非数字,scanf返回0
  • clearInputBuffer()清空错误的输入
3. 除零检查
1
2
3
4
5
6
7
8
case '/':
if (num2 == 0) {
printf("\n⚠️ 错误:除数不能为0!\n");
} else {
result = divide(num1, num2);
printf("\n结果:%.2lf ÷ %.2lf = %.2lf\n", num1, num2, result);
}
break;

**解析:**在执行除法前检查除数,防止程序崩溃。

4. 输入缓冲区处理
1
2
3
4
void clearInputBuffer() {
int c;
while ((c = getchar()) != '\n' && c != EOF);
}

解析:

  • 读取并丢弃缓冲区中的剩余字符
  • 直到遇到换行符或文件结束符
  • 避免scanf读取残留字符
5. 大小写不敏感的判断
1
} while (toupper(choice) == 'Y');

**解析:**使用toupper()函数将输入转换为大写,用户输入Y或y都可以继续。

📊 运行示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
=================================
简易计算器
=================================

请输入第一个数字:10
请输入运算符 (+, -, *, /):*
请输入第二个数字:5

结果:10.00 × 5.00 = 50.00

是否继续计算?(Y/N):y

请输入第一个数字:20
请输入运算符 (+, -, *, /):/
请输入第二个数字:0

⚠️ 错误:除数不能为0!

是否继续计算?(Y/N):n

感谢使用计算器,再见!

🎯 知识点总结

  • ✅ 函数的定义和调用
  • ✅ switch-case 语句
  • ✅ do-while 循环
  • ✅ 输入验证
  • ✅ 字符处理函数
  • ✅ 浮点数运算

⚡ 扩展练习

  1. 添加幂运算(^)和取模运算(%)
  2. 支持多个运算符的连续计算(如:5 + 3 * 2)
  3. 添加括号支持
  4. 记录计算历史
  5. 添加科学计算器功能(三角函数、对数等)

案例3:猜数字游戏

📋 案例说明

经典的猜数字游戏,计算机随机生成一个数字,玩家通过输入数字来猜测,系统会提示”大了”或”小了”。

**涉及知识点:**随机数、循环、条件判断、函数

难度等级:⭐ (入门)

💡 功能需求

  • 随机生成1-100之间的数字
  • 玩家输入猜测的数字
  • 提示”大了”、”小了”或”猜对了”
  • 记录猜测次数
  • 提供有限次机会(如10次)

💻 完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include 
#include
#include

#define MAX_ATTEMPTS 10
#define MIN_NUM 1
#define MAX_NUM 100

// 函数声明
int generateRandomNumber(int min, int max);
void playGame();
void printWelcome();
void printGameOver(int secret, int attempts);

int main() {
char choice;

// 初始化随机数种子
srand(time(NULL));

printWelcome();

do {
playGame();

printf("\n想再玩一次吗?(Y/N):");
scanf(" %c", &choice);
// 清空输入缓冲区
while (getchar() != '\n');

} while (choice == 'Y' || choice == 'y');

printf("\n感谢游玩,再见!\n");
return 0;
}

// 生成指定范围内的随机数
int generateRandomNumber(int min, int max) {
return min + rand() % (max - min + 1);
}

// 打印欢迎信息
void printWelcome() {
printf("\n");
printf("=================================\n");
printf(" 猜数字游戏\n");
printf("=================================\n");
printf("规则:\n");
printf("- 我已经想好了一个 %d 到 %d 之间的数字\n", MIN_NUM, MAX_NUM);
printf("- 你有 %d 次机会来猜它\n", MAX_ATTEMPTS);
printf("- 我会告诉你猜大了还是小了\n");
printf("=================================\n");
}

// 打印游戏结束信息
void printGameOver(int secret, int attempts) {
printf("\n=================================\n");
printf(" 游戏结束\n");
printf("=================================\n");
printf("正确答案是:%d\n", secret);
printf("你用了 %d 次机会\n", attempts);
}

// 游戏主逻辑
void playGame() {
int secret = generateRandomNumber(MIN_NUM, MAX_NUM);
int guess;
int attempts = 0;
int found = 0;

printf("\n游戏开始!你有 %d 次机会。\n", MAX_ATTEMPTS);

while (attempts < MAX_ATTEMPTS && !found) {
printf("\n剩余机会:%d 次\n", MAX_ATTEMPTS - attempts);
printf("请输入你的猜测 (%d-%d):", MIN_NUM, MAX_NUM);

// 输入验证
if (scanf("%d", &guess) != 1) {
printf("⚠️ 请输入有效的数字!\n");
// 清空输入缓冲区
while (getchar() != '\n');
continue;
}

// 检查范围
if (guess < MIN_NUM || guess > MAX_NUM) {
printf("⚠️ 请输入 %d 到 %d 之间的数字!\n", MIN_NUM, MAX_NUM);
continue;
}

attempts++;

// 比较猜测
if (guess == secret) {
printf("\n🎉 恭喜你,猜对了!\n");
printf("你用了 %d 次就猜到了答案 %d\n", attempts, secret);

// 评价
if (attempts <= 3) {
printf("评价:太厉害了!简直是神猜手!\n");
} else if (attempts <= 6) {
printf("评价:很不错!继续加油!\n");
} else {
printf("评价:运气还是不错的!\n");
}

found = 1;
} else if (guess < secret) {
printf("📈 太小了!再大一点!\n");

// 提示范围
if (secret - guess <= 10) {
printf("💡 提示:非常接近了!\n");
} else if (secret - guess <= 30) {
printf("💡 提示:有点接近了!\n");
}
} else {
printf("📉 太大了!再小一点!\n");

// 提示范围
if (guess - secret <= 10) {
printf("💡 提示:非常接近了!\n");
} else if (guess - secret <= 30) {
printf("💡 提示:有点接近了!\n");
}
}
}

// 游戏结束
if (!found) {
printf("\n😢 很遗憾,你没有在 %d 次内猜中。\n", MAX_ATTEMPTS);
printGameOver(secret, attempts);
}
}

🔍 代码解析

1. 随机数生成
1
2
srand(time(NULL));  // 初始化随机数种子
int secret = rand() % (MAX_NUM - MIN_NUM + 1) + MIN_NUM;

解析:

  • srand(time(NULL)):使用当前时间作为种子,确保每次运行结果不同
  • rand():生成0到RAND_MAX之间的随机数
  • rand() % (max - min + 1) + min:生成[min, max]范围内的随机数
2. 输入验证
1
2
3
4
5
6
7
8
9
10
if (scanf("%d", &guess) != 1) {
printf("⚠️ 请输入有效的数字!\n");
while (getchar() != '\n');
continue;
}

if (guess < MIN_NUM || guess > MAX_NUM) {
printf("⚠️ 请输入 %d 到 %d 之间的数字!\n", MIN_NUM, MAX_NUM);
continue;
}

**解析:**验证输入是否为有效数字且在指定范围内。

3. 游戏循环控制
1
2
3
while (attempts < MAX_ATTEMPTS && !found) {
// 游戏逻辑
}

解析:

  • 两个条件:未超过最大尝试次数 且 未猜中
  • found标志控制游戏是否结束
4. 智能提示
1
2
3
4
5
if (secret - guess <= 10) {
printf("💡 提示:非常接近了!\n");
} else if (secret - guess <= 30) {
printf("💡 提示:有点接近了!\n");
}

**解析:**根据差距大小提供不同的提示信息,增强游戏性。

5. 评价系统
1
2
3
4
5
6
7
if (attempts <= 3) {
printf("评价:太厉害了!简直是神猜手!\n");
} else if (attempts <= 6) {
printf("评价:很不错!继续加油!\n");
} else {
printf("评价:运气还是不错的!\n");
}

**解析:**根据猜测次数给出不同的评价,增加趣味性。

📊 运行示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
=================================
猜数字游戏
=================================
规则:
- 我已经想好了一个 1 到 100 之间的数字
- 你有 10 次机会来猜它
- 我会告诉你猜大了还是小了
=================================

游戏开始!你有 10 次机会。

剩余机会:10 次
请输入你的猜测 (1-100):50
📈 太小了!再大一点!
💡 提示:有点接近了!

剩余机会:9 次
请输入你的猜测 (1-100):75
📉 太大了!再小一点!
💡 提示:非常接近了!

剩余机会:8 次
请输入你的猜测 (1-100):65
📉 太大了!再小一点!
💡 提示:非常接近了!

剩余机会:7 次
请输入你的猜测 (1-100):60
📉 太大了!再小一点!
💡 提示:非常接近了!

剩余机会:6 次
请输入你的猜测 (1-100):58
🎉 恭喜你,猜对了!
你用了 5 次就猜到了答案 58
评价:很不错!继续加油!

🎯 知识点总结

  • ✅ 随机数生成和使用
  • ✅ 循环控制
  • ✅ 条件判断
  • ✅ 函数的模块化设计
  • ✅ 输入验证
  • ✅ 标志变量的使用

⚡ 扩展练习

  1. 添加难度选择(简单:1-50,中等:1-100,困难:1-200)
  2. 记录并显示历史猜测
  3. 添加计时功能
  4. 实现排行榜功能
  5. 添加多人对战模式

更多案例

由于篇幅限制,以下是其他经典案例的简要说明和代码框架。

04图书管理系统(进阶版)

**功能:**图书信息的增删改查、借阅管理、文件存储

**涉及知识点:**链表、文件操作、结构体、动态内存

难度:⭐⭐⭐⭐ (中高级)

查看完整代码 →

05通讯录管理系统

**功能:**联系人管理、分组、搜索、导入导出

**涉及知识点:**字符串处理、文件操作、动态数组

难度:⭐⭐⭐ (中级)

查看完整代码 →

06贪吃蛇游戏

**功能:**经典贪吃蛇游戏,界面控制、碰撞检测

**涉及知识点:**二维数组、游戏循环、键盘控制

难度:⭐⭐⭐⭐⭐ (高级)

查看完整代码 →

学习建议

💡 理解原理

不要只是复制粘贴代码,要理解每一行代码的作用和背后的原理。

💡 动手实践

自己动手敲一遍代码,然后尝试修改和扩展功能。

💡 调试技巧

学会使用printf调试,在关键位置输出变量值,观察程序运行过程。

💡 举一反三

从一个案例出发,思考如何实现类似的其他功能。

常见问题解答

Q1: 为什么要使用函数而不是把所有代码写在main里?

A: 使用函数有以下好处:

  • 模块化:将复杂问题分解为小问题
  • 复用性:同一功能可以在多处调用
  • 可维护性:修改某个功能只需修改对应的函数
  • 可读性:代码结构清晰,易于理解

Q2: scanf后面的getchar()是干什么的?

A: 这是用来清空输入缓冲区的。scanf读取数字后,缓冲区可能残留换行符等字符,会影响后续的字符读取。getchar()会读取并丢弃这些残留字符。

Q3: 什么时候使用数组,什么时候使用链表?

A:

  • 数组:大小固定,访问快速(O(1)),适合元素数量已知的情况
  • 链表:大小可变,插入删除方便(O(1)),适合频繁增删的情况

Q4: 如何避免数组越界?

A:

  • 始终从0开始遍历到size-1
  • 使用#define定义数组大小,避免硬编码
  • 添加边界检查
  • 使用安全的函数(如fgets代替gets)

Q5: 什么时候应该使用动态内存分配?

A: 当满足以下条件之一时:

  • 编译时不知道需要多少内存
  • 需要大数组,可能超出栈大小
  • 数据结构需要动态增长
  • 需要在函数间传递大量数据

© 2025 Rl. 使用 Stellar 创建
站点访问量 Loading... 站点访客数 Loading... 页面访问量 Loading...