C++ 从入门到起飞:语言基础、构造数据类型与程序结构全解析
🚀 本文将C++教材第2~4章的核心知识点串联起来,用大量示例代码 + 生动比喻 + 幽默讲解,帮你系统掌握C++从基础语法到程序架构的完整知识链。适合正在学C++的同学收藏反复翻阅!
📖 文章导航
- 第2章 C++语言基础:数据类型 → 变量常量 → 运算符表达式 → 控制结构 → 函数
- 第3章 构造数据类型:枚举 → 数组 → 指针 → 引用 → 结构与联合
- 第4章 程序的结构:变量类型 → 作用域与可见性 → 编译预处理 → 名字空间
第一篇:C++语言基础(第2章)
一、数据类型——给数据贴标签
C++中的数据类型,就像超市里的商品分类标签:零食区、饮料区、日用品区……不同类型的数据,占用的"货架空间"(内存)大小不同,能做的"操作"也不同。
1.1 基本数据类型速查表
#include <iostream>
using namespace std;
int main() {
cout << "=== C++ 基本数据类型大小 ===" << endl;
cout << "bool: " << sizeof(bool) << " 字节" << endl; // 1
cout << "char: " << sizeof(char) << " 字节" << endl; // 1
cout << "short: " << sizeof(short) << " 字节" << endl; // 2
cout << "int: " << sizeof(int) << " 字节" << endl; // 4
cout << "long: " << sizeof(long) << " 字节" << endl; // 4(或8)
cout << "long long: " << sizeof(long long) << " 字节" << endl; // 8
cout << "float: " << sizeof(float) << " 字节" << endl; // 4
cout << "double: " << sizeof(double) << " 字节" << endl; // 8
return 0;
}
💡 记忆口诀:
char一个字节最迷你,int四个字节最常用,double八个字节精度高。
1.2 有符号与无符号——正负能不能兼得?
signed int a = -42; // 有符号,可以存负数(默认就是 signed)
unsigned int b = 42; // 无符号,只能存非负数,但正数范围翻倍
// 一个有趣的坑:
unsigned int c = -1; // 不报错!但 c 不是 -1
cout << c << endl; // 输出 4294967295(无符号最大值)
// 原因:-1 的二进码是 111...111,作为无符号数解释就是最大值
⚠️ 血泪教训:拿
unsigned int和负数比大小,是C++新手的经典翻车现场。
二、变量与常量——给数据起名字
2.1 变量:可以改的"便利贴"
int age = 20; // 声明并初始化
age = 21; // ✅ 变量可以修改
cout << age << endl; // 21
// 命名规则:
int myAge = 20; // ✅ 字母、数字、下划线
int _count = 10; // ✅ 下划线开头
// int 2fast = 100; // ❌ 不能数字开头
// int my age = 20; // ❌ 不能有空格
// int int = 10; // ❌ 不能用关键字
2.2 常量:不可改的"刻在石头上的字"
// 方式一:#define 宏定义(老式写法,不推荐)
#define PI 3.14159
// 方式二:const 常变量(推荐!)
const double E = 2.71828;
// E = 3.0; // ❌ 编译错误!const 变量不能修改
// 方式三:constexpr 编译期常量(C++11)
constexpr int MAX_SIZE = 100;
💡 一句话:
#define是"文本替换"(编译前就换了),const是"真正的常量"(编译器认识它)。
三、运算符与表达式——让数据动起来
3.1 算术运算符:加减乘除取余
int a = 17, b = 5;
cout << a + b << endl; // 22
cout << a - b << endl; // 12
cout << a * b << endl; // 85
cout << a / b << endl; // 3(整数除法,小数部分被截断)
cout << a % b << endl; // 2(取余数)
// 浮点除法才是真正的除法
double x = 17.0, y = 5.0;
cout << x / y << endl; // 3.4
⚠️ 经典面试题:
1 / 2等于多少?不是 0.5,是 0!因为整数除整数还是整数。
3.2 自增自减:程序员最爱的骚操作
int a = 5;
// 后置 a++:先用再加
int b = a++; // b = 5,然后 a 变成 6
cout << "b=" << b << ", a=" << a << endl; // b=5, a=6
// 前置 ++a:先加再用
a = 5;
int c = ++a; // a 先变成 6,然后 c = 6
cout << "c=" << c << ", a=" << a << endl; // c=6, a=6
🎯 记忆法:
++a是"先自拍再发朋友圈"(先加后用),a++是"先发朋友圈再自拍"(先用后加)。
3.3 逻辑运算符:&& || !
int age = 25;
bool hasID = true;
// && 与:两个都满足才为 true
if (age >= 18 && hasID) {
cout << "可以进场!" << endl;
}
// || 或:有一个满足就为 true
if (age < 12 || age > 65) {
cout << "免票!" << endl;
}
// ! 非:取反
if (!hasID) {
cout << "请出示身份证!" << endl;
}
3.4 类型转换:自动与强制
// 隐式转换(自动,编译器悄悄帮你转)
int a = 10;
double b = a; // int → double,自动转换,b = 10.0
int c = 3.14; // double → int,自动截断,c = 3(小数部分丢失)
// 显式转换(强制,程序员手动转)
double d = 3.99;
int e = (int)d; // C风格强制转换,e = 3
int f = static_cast<int>(d); // C++风格,更安全,推荐!
💡 优先使用
static_cast<类型>(),它是C++推荐的类型转换方式,比C风格的(int)更安全。
四、控制结构——让程序会思考
4.1 判断:if-else 和 switch
// if-else:适合范围判断
int score = 85;
if (score >= 90) {
cout << "优秀!你就是学霸本人!" << endl;
} else if (score >= 80) {
cout << "良好!再冲一冲就到顶了!" << endl;
} else if (score >= 60) {
cout << "及格!万岁!" << endl;
} else {
cout << "挂科了……下次一定!" << endl;
}
// switch:适合精确匹配
int day = 3;
switch (day) {
case 1: cout << "星期一:困" << endl; break;
case 2: cout << "星期二:困" << endl; break;
case 3: cout << "星期三:还是困" << endl; break;
case 6: case 7:
cout << "周末:终于不困了!" << endl; break;
default: cout << "每天都困" << endl;
}
⚠️ switch 的坑:忘了写
break会"穿透"到下一个 case,这是新手最常犯的错误之一!
4.2 循环:for、while、do-while
// for 循环:知道循环次数时用
cout << "=== 九九乘法表(for 版)===" << endl;
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
cout << j << "×" << i << "=" << i * j << "\t";
}
cout << endl;
}
// while 循环:不知道循环次数,先判断再执行
int countdown = 5;
while (countdown > 0) {
cout << "倒计时: " << countdown << "..." << endl;
countdown--;
}
cout << "发射!🚀" << endl;
// do-while:至少执行一次,先执行再判断
int input;
do {
cout << "请输入1-10的数字(0退出): ";
cin >> input;
} while (input != 0);
4.3 转移语句:break、continue、goto
// break:跳出整个循环
for (int i = 0; i < 100; i++) {
if (i == 5) break; // 到5就停
cout << i << " "; // 输出:0 1 2 3 4
}
cout << endl;
// continue:跳过本次循环,进入下一次
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) continue; // 跳过偶数
cout << i << " "; // 输出:1 3 5 7 9
}
cout << endl;
// goto:慎用!但在跳出多层循环时偶尔有用
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (i * j > 20) goto done; // 跳出多重循环
}
}
done:
cout << "跳出来了!" << endl;
⚠️ goto 的使用原则:除非跳出多层循环且没有更好的替代方案,否则别用。代码 reviewer 看到
goto会皱眉头的。
五、函数——代码的"乐高积木"
5.1 函数的定义与调用
// 定义一个函数:计算两个数的最大值
int maxOfTwo(int a, int b) {
return (a > b) ? a : b;
}
int main() {
int result = maxOfTwo(10, 20); // 调用函数
cout << "较大值: " << result << endl; // 20
return 0;
}
5.2 函数的声明(原型)
// 如果函数定义在 main 之后,需要先声明
int add(int a, int b); // 函数声明(分号结尾)
int main() {
cout << add(3, 5) << endl; // 8
return 0;
}
int add(int a, int b) { // 函数定义
return a + b;
}
5.3 参数传递:值传递 vs 引用传递
// 值传递:函数内修改不影响外部
void changeByValue(int x) {
x = 100; // 只改了副本
}
// 引用传递:函数内修改影响外部
void changeByRef(int& x) {
x = 100; // 改了原变量
}
int main() {
int a = 1, b = 1;
changeByValue(a);
changeByRef(b);
cout << "a = " << a << endl; // 1(没变)
cout << "b = " << b << endl; // 100(变了!)
}
5.4 内联函数——省去调用开销的"快捷方式"
inline int square(int x) {
return x * x;
}
int main() {
cout << square(5) << endl; // 25
// 编译器会把 square(5) 直接展开为 5*5,省去了函数调用的开销
}
💡 内联函数适合短小精悍的函数。函数体太长的话,编译器会忽略
inline关键字。
5.5 函数重载——同名不同命
// 函数名相同,但参数列表不同(类型或个数)
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
int main() {
cout << add(1, 2) << endl; // 调用第一个,输出 3
cout << add(1.5, 2.5) << endl; // 调用第二个,输出 4.0
cout << add(1, 2, 3) << endl; // 调用第三个,输出 6
}
💡 编译器通过参数列表来区分重载函数,跟返回值类型无关!
第二篇:构造数据类型(第3章)
六、枚举类型——给数字起个好听的名字
// 用数字表示星期?太不直观了!
int day = 3; // 3 是星期几来着?
// 用枚举!一目了然
enum Weekday { MON, TUE, WED, THU, FRI, SAT, SUN };
// MON=0, TUE=1, WED=2, ... SUN=6(默认从0开始递增)
Weekday today = WED;
if (today == WED) {
cout << "今天是星期三,一周中最难熬的一天 😴" << endl;
}
// 可以指定枚举值
enum Score { FAIL = 59, PASS = 60, GOOD = 80, EXCELLENT = 90 };
Score s = GOOD;
cout << s << endl; // 80
💡 C++11 还有
enum class(强类型枚举),更安全,推荐在新项目中使用。
七、数组——同类型数据的"整齐队列"
7.1 一维数组
// 声明并初始化
int scores[5] = {90, 85, 78, 92, 88};
// 访问元素(下标从 0 开始!)
cout << "第一名的成绩: " << scores[0] << endl; // 90
cout << "第三名的成绩: " << scores[2] << endl; // 78
// 遍历数组
for (int i = 0; i < 5; i++) {
cout << "scores[" << i << "] = " << scores[i] << endl;
}
// 计算平均分
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += scores[i];
}
cout << "平均分: " << (double)sum / 5 << endl; // 86.6
7.2 二维数组——表格数据的好帮手
// 3个学生,每人4门课的成绩
int grades[3][4] = {
{90, 85, 78, 92}, // 学生0
{75, 88, 91, 80}, // 学生1
{82, 79, 95, 87} // 学生2
};
// 访问第2个学生的第3门课成绩
cout << grades[1][2] << endl; // 91
// 计算每个学生的平均分
for (int i = 0; i < 3; i++) {
int sum = 0;
for (int j = 0; j < 4; j++) {
sum += grades[i][j];
}
cout << "学生" << i << "的平均分: " << (double)sum / 4 << endl;
}
7.3 字符数组与字符串
// C风格字符串:本质是 char 数组
char name[] = "Hello"; // 自动在末尾加 '\0'
cout << name << endl; // Hello
cout << "长度: " << strlen(name) << endl; // 5(不含 '\0')
// C++ string 类:更好用!
#include <string>
string greeting = "你好世界";
cout << greeting << endl;
cout << "长度: " << greeting.length() << endl; // 4
// string 的拼接
string first = "Hello, ";
string second = "C++!";
string full = first + second; // "Hello, C++!"
cout << full << endl;
八、指针——C++的"杀手锏"(也是"劝退神器")
8.1 什么是指针?
指针就是一个变量,它存的不是数据,而是另一个变量的内存地址。
想象一下:你去快递柜取快递,柜子编号是 0x100。指针就是一张纸条,上面写着"0x100"——通过这张纸条,你能找到那个柜子里的东西。
int a = 42;
int* p = &a; // p 存了 a 的地址(& 是取地址符)
cout << "a 的值: " << a << endl; // 42
cout << "a 的地址: " << &a << endl; // 0x7ffd...
cout << "p 存的值: " << p << endl; // 和 &a 一样
cout << "p 指向的值: " << *p << endl; // 42(* 是解引用符)
*p = 100; // 通过指针修改 a 的值
cout << "修改后 a = " << a << endl; // 100
💡 一句话记忆:
&是"你在哪?“,*是"你那里有什么?”
8.2 指针与数组的亲密关系
int arr[5] = {10, 20, 30, 40, 50};
int* p = arr; // 数组名就是首元素地址!
// 以下四种写法等价:
cout << arr[2] << endl; // 30
cout << *(arr + 2) << endl; // 30
cout << p[2] << endl; // 30
cout << *(p + 2) << endl; // 30
💡 核心公式:
arr[i]≡*(arr + i)——下标访问的本质就是指针偏移后解引用。
8.3 动态内存分配
// 栈上的数组:编译期就要确定大小
// int n; cin >> n; int arr[n]; // ❌ 某些编译器不允许
// 堆上的数组:运行时动态分配
int n;
cout << "请输入数组大小: ";
cin >> n;
int* arr = new int[n]; // 在堆上分配 n 个 int
for (int i = 0; i < n; i++) {
arr[i] = i * 10;
}
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
delete[] arr; // 用完必须释放!
arr = nullptr; // 释放后置空,防止野指针
⚠️ 黄金法则:
new和delete必须配对使用!忘了delete就是内存泄漏,程序会越吃越多内存。
8.4 空指针与野指针
// ✅ 空指针:安全,明确表示"不指向任何地方"
int* p1 = nullptr; // C++11 推荐
int* p2 = NULL; // C风格,不推荐
// ❌ 野指针:未初始化,指向未知位置,极其危险!
int* p3; // 未初始化
// *p3 = 10; // 💥 未定义行为,可能崩溃
// ✅ 好习惯:释放后置空
delete p1;
p1 = nullptr; // 防止变成野指针
九、引用——变量的"外号"
9.1 引用是什么?
引用就是给一个已存在的变量取一个别名。它和原变量共用同一块内存,就像一个人有两个名字。
int a = 42;
int& ref = a; // ref 是 a 的别名
cout << "a = " << a << endl; // 42
cout << "ref = " << ref << endl; // 42
cout << "a 的地址: " << &a << endl; // 两者地址完全相同!
cout << "ref 的地址: " << &ref << endl;
ref = 100; // 通过别名修改
cout << "a = " << a << endl; // 100(原变量也变了)
9.2 引用 vs 指针:终极对比
int a = 10, b = 20;
// 指针:可以重新指向
int* p = &a;
p = &b; // ✅ 可以改指向
// 引用:终身绑定
int& ref = a;
// ref = b; // ❌ 这不是"重新绑定"!这是把 b 的值赋给 a!
| 特性 | 指针 | 引用 |
|---|---|---|
| 可以为空 | ✅ nullptr |
❌ 必须绑定有效对象 |
| 可以重新指向 | ✅ | ❌ 终身绑定 |
| 访问方式 | *p 解引用 |
直接用名字 |
| 需要初始化 | ❌ 可以不初始化(危险) | ✅ 声明时必须初始化 |
9.3 引用做函数参数(最常用!)
// 交换两个变量的值
void swap_ref(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
swap_ref(x, y);
cout << "x=" << x << ", y=" << y << endl; // x=20, y=10
}
9.4 const 引用——只读保护
void print(const int& val) {
// val = 100; // ❌ 不能修改
cout << val << endl;
}
int main() {
int a = 42;
print(a); // ✅ 传变量
print(100); // ✅ 传字面量(普通引用做不到!)
print(a + 5); // ✅ 传表达式
}
十、结构与联合——自定义数据类型
10.1 结构体(struct):把相关数据打包在一起
// 定义一个"学生"结构体
struct Student {
string name;
int age;
double score;
};
int main() {
// 创建结构体变量
Student s1 = {"张三", 20, 92.5};
Student s2 = {"李四", 21, 88.0};
// 访问成员
cout << s1.name << " " << s1.age << "岁 " << "成绩:" << s1.score << endl;
// 结构体数组
Student class1[3] = {
{"张三", 20, 92.5},
{"李四", 21, 88.0},
{"王五", 19, 95.0}
};
// 找最高分
Student best = class1[0];
for (int i = 1; i < 3; i++) {
if (class1[i].score > best.score) {
best = class1[i];
}
}
cout << "最高分: " << best.name << " " << best.score << endl; // 王五 95.0
}
10.2 结构体与指针
Student s = {"张三", 20, 92.5};
Student* p = &s;
// 指针访问成员用 ->
cout << p->name << endl; // 张三
cout << p->age << endl; // 20
cout << p->score << endl; // 92.5
// 等价于 (*p).name,但 -> 更简洁
10.3 联合体(union):共享内存的"节约达人"
// 联合体的所有成员共用同一块内存
union Data {
int i;
float f;
char c;
};
int main() {
Data d;
d.i = 42;
cout << d.i << endl; // 42
d.f = 3.14f; // 写入 f 会覆盖 i 的值
cout << d.f << endl; // 3.14
cout << d.i << endl; // 输出的是乱码!因为 i 的内存被 f 占了
cout << "联合体大小: " << sizeof(Data) << endl; // 4(取最大成员的大小)
}
💡 联合体常用于节省内存的场景,比如嵌入式开发中一个寄存器可能存不同类型的数据。
第三篇:C++程序的结构(第4章)
十一、变量的类型——它们住在哪里?
11.1 全局变量 vs 局部变量
#include <iostream>
using namespace std;
int globalVar = 100; // 全局变量:整个程序都能用
void func() {
cout << "func 看到 globalVar = " << globalVar << endl; // 100
globalVar = 200; // 可以修改全局变量
}
int main() {
int localVar = 10; // 局部变量:只在 main 函数内有效
cout << "globalVar = " << globalVar << endl; // 100
func();
cout << "func 修改后 globalVar = " << globalVar << endl; // 200
// cout << localVar; // 在其他函数里访问不了 localVar
}
11.2 变量的存储类型
// auto:自动存储(默认)
auto x = 10; // 编译器自动推导类型为 int
// register:建议编译器放在寄存器中(编译器可以忽略)
register int counter = 0;
// static:静态变量,函数结束后值不消失
void countCalls() {
static int count = 0; // 只初始化一次!
count++;
cout << "被调用了 " << count << " 次" << endl;
}
int main() {
countCalls(); // 被调用了 1 次
countCalls(); // 被调用了 2 次
countCalls(); // 被调用了 3 次
// count 变量在函数调用之间保持值不变!
}
// extern:声明外部变量(在其他文件中定义的变量)
extern int globalVar; // 告编译器:这个变量在别处定义了,别报错
💡 static 局部变量就像一个"有记忆的函数内部计数器"——函数结束它也不消失。
十二、作用域与可见性——谁能看到谁?
12.1 块作用域
int main() {
int a = 10; // a 的作用域从这里开始
if (a > 5) {
int b = 20; // b 的作用域仅在这个 if 块内
cout << a << " " << b << endl; // ✅ 可以访问 a 和 b
}
// cout << b; // ❌ 编译错误!b 在 if 块外面不可见
cout << a; // ✅ a 还在作用域内
}
12.2 同名变量的遮蔽
int x = 100; // 全局变量
int main() {
int x = 200; // 局部变量遮蔽了全局变量
cout << x << endl; // 200(局部优先)
cout << ::x << endl; // 100(用 :: 访问全局变量)
{
int x = 300; // 更内层的遮蔽
cout << x << endl; // 300
cout << ::x << endl; // 100(始终指向全局)
}
cout << x << endl; // 200(回到外层的 x)
}
⚠️ 建议:尽量避免同名变量,尤其是不要用局部变量遮蔽全局变量——代码会变得很难读。
十三、编译预处理——编译之前的"准备工作"
13.1 #include 文件包含
#include <iostream> // 包含系统头文件(从系统目录找)
#include "myheader.h" // 包含自定义头文件(先从当前目录找)
13.2 #define 宏定义
// 不带参数的宏:常量定义
#define PI 3.14159
#define MAX_SIZE 100
// 带参数的宏:类似函数(但不推荐,用 inline 函数替代)
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int main() {
cout << SQUARE(5) << endl; // 25
cout << MAX(10, 20) << endl; // 20
// ⚠️ 宏的坑:
cout << SQUARE(1 + 2) << endl;
// 如果定义成 #define SQUARE(x) x*x,会变成 1+2*1+2 = 5(错误!)
// 用 ((x)*(x)) 包好就不会出问题:((1+2)*(1+2)) = 9 ✅
}
💡 现代C++建议:用
const/constexpr替代#define常量,用inline函数替代带参宏。
13.3 条件编译——代码的"开关"
// 防止头文件重复包含(经典用法)
#ifndef MYHEADER_H
#define MYHEADER_H
// 头文件内容...
#endif // MYHEADER_H
// 调试开关
#define DEBUG
int main() {
int result = 42;
#ifdef DEBUG
cout << "[调试] result = " << result << endl; // 只在 DEBUG 模式下输出
#endif
cout << "最终结果: " << result << endl;
}
// 平台判断
#ifdef _WIN32
cout << "Windows 平台" << endl;
#elif __linux__
cout << "Linux 平台" << endl;
#elif __APPLE__
cout << "macOS 平台" << endl;
#endif
十四、名字空间——防止名字冲突的"围墙"
14.1 为什么需要名字空间?
// 假设两个库都定义了 print 函数
namespace MathLib {
void print(int x) { cout << "MathLib: " << x << endl; }
}
namespace TextLib {
void print(string s) { cout << "TextLib: " << s << endl; }
}
int main() {
MathLib::print(42); // 调用 MathLib 的 print
TextLib::print("hello"); // 调用 TextLib 的 print
// 没有冲突!名字空间把它们隔开了
}
14.2 using 声明与 using 指令
namespace MyLib {
int value = 100;
void show() { cout << "show: " << value << endl; }
}
int main() {
// 方式一:完全限定名
cout << MyLib::value << endl;
// 方式二:using 声明(引入单个名字)
using MyLib::show;
show(); // 不需要写 MyLib::show()
// 方式三:using 指令(引入整个名字空间)
using namespace MyLib;
cout << value << endl; // 直接用
}
14.3 自定义名字空间
// mymath.h
namespace MyMath {
const double PI = 3.14159;
double circleArea(double r) {
return PI * r * r;
}
double circlePerimeter(double r) {
return 2 * PI * r;
}
}
// main.cpp
#include "mymath.h"
using namespace MyMath;
int main() {
double r = 5.0;
cout << "面积: " << circleArea(r) << endl; // 78.5397
cout << "周长: " << circlePerimeter(r) << endl; // 31.4159
}
💡 最佳实践:
- 在
.h头文件中定义名字空间- 在
.cpp源文件中用using namespace或using 声明- 永远不要在头文件中写
using namespace xxx;,否则所有包含它的文件都会被污染
总结:三章知识的关系图
第2章 语言基础(C++的"砖块")
├── 数据类型 ← 砖块的种类
├── 变量与常量 ← 给砖块贴标签
├── 运算符 ← 砖块之间的连接方式
├── 控制结构 ← 砖块的排列逻辑
└── 函数 ← 把砖块组装成模块
第3章 构造数据类型(C++的"高级建材")
├── 枚举 ← 一组命名常量
├── 数组 ← 同类型数据的连续排列
├── 指针 ← 存储地址的变量(核心难点!)
├── 引用 ← 变量的别名
└── 结构/联合 ← 自定义数据打包
第4章 程序结构(C++的"建筑蓝图")
├── 变量类型 ← 数据住在哪里(栈/堆/全局区)
├── 作用域 ← 数据能被谁看到
├── 编译预处理 ← 编译前的准备工作
└── 名字空间 ← 防止名字冲突的围墙
🎯 一句话总结:第2章教你"怎么写代码",第3章教你"怎么组织数据",第4章教你"怎么管理代码"。三章合一,你就能写出结构清晰、逻辑严谨的C++程序了!
如果觉得有帮助,欢迎点赞收藏 👍 有问题可以在评论区讨论!
更多推荐
所有评论(0)