跳到主要内容
C++ 基础实战:从循环控制到算法入门 | 极客日志
C++ 算法
C++ 基础实战:从循环控制到算法入门 C++ 基础实战涵盖循环控制、函数模块化、结构体定义、字符串处理、递归回溯及高精度计算。通过实际代码示例解析变量作用域、内存管理及常见算法逻辑,适合初学者系统学习 C++ 核心概念与解题思路。
开源信徒 发布于 2026/3/29 更新于 2026/4/25 1 浏览C++ 基础实战:从循环控制到算法入门
C++ 作为一门强大的语言,其核心在于对内存和逻辑的掌控。本文将从基础的循环结构讲起,逐步深入到函数、结构体及常见算法,帮助初学者建立扎实的编程思维。
for 循环计数器
for 循环是处理已知迭代次数场景的首选工具。基本语法如下:
for (定义计数变量; 定义结束条件; 每次循环所做的动作)
示例解析
for (int i = 1 ; i <= 10 ; i++)
计数器就是在 for 循环有了一定执行范围的基础上创建了一个变量,进行自增计数。
完整示例
#include <iostream>
using namespace std;
int main () {
int n;
cin >> n;
int cnt = 0 ;
for (int i = 1 ; i <= n; i++) {
cnt++;
}
cout << cnt;
return 0 ;
}
练习题目:斐波那契数列
题目描述
斐波那契数列是一个特殊的数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55……
数列的第一项和第二项都是 1,从第三项开始,每一项是其前面两项之和。
输入正整数 n,编程输出该数列的第 n 项。
代码实现
#include <iostream>
using namespace std;
a[ ];
{
n;
cin >> n;
a[ ] = , a[ ] = ;
( i = ; i <= n; i++) {
a[i] = a[i - ] + a[i - ];
}
cout << a[n];
;
}
long
long
55
int main ()
int
1
1
2
1
for
int
3
1
2
return
0
函数与模块化编程 将重复逻辑封装成函数,可以提高代码的可读性和复用性。
#include <iostream>
using namespace std;
long long a[55 ];
int fbnq (int n) {
a[1 ] = 1 , a[2 ] = 1 ;
for (int i = 3 ; i <= n; i++) {
a[i] = a[i - 1 ] + a[i - 2 ];
}
return a[n];
}
int main () {
int n;
cin >> n;
cout << fbnq (n);
return 0 ;
}
函数类型与用法 函数类型 特点 用法 int 返回值为 int 类型 int 函数名 (int 新创建变量的名称) long long 返回值为 long long 类型 long long 函数名 (long long 新创建变量的名称) bool 返回值类型为 bool,即不是 true 就是 false bool 函数名 (bool 新创建的变量名称) void 无返回值,函数内不要有 return,若有,请注意很有可能报错,强制停止此函数运行请写"return;" void 函数名 (int 新创建的变量名)
提示 :类型 函数名 (int/long long/bool/其他类型 新创建的变量名) 输入变量名的类型 void 是不合法的!若使用了会报错。
练习题目:费用计算 题目描述
根据重量 w 计算费用。w<=1 时费用为 13;否则费用为 13 + ceil((w-1)/0.5)。
#include <cstdio>
#include <cmath>
using namespace std;
int express (double w) {
int money;
w = round (w * 10 ) / 10 ;
if (w <= 1 ) {
money = 13 ;
} else {
w = ceil ((w - 1 ) / 0.5 );
money = 13 + w;
}
return money;
}
int main () {
double w;
scanf ("%lf" , &w);
printf ("%d\n" , express (w));
return 0 ;
}
多重循环(for 循环 Plus 版) for (int i = 1 ; i <= n; i++) {
for (int j = 1 ; j <= n; j++) {
}
}
练习题目:饲料调配 题目描述
给定三种饲料的营养成分需求,寻找满足条件的饲料配比方案。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
int main () {
int a, b, c;
cin >> a >> b >> c;
int a1, b1, c1; cin >> a1 >> b1 >> c1;
int a2, b2, c2; cin >> a2 >> b2 >> c2;
int a3, b3, c3; cin >> a3 >> b3 >> c3;
for (int i = 0 ; i < 100 ; i++)
{
for (int j = 0 ; j < 100 ; j++)
{
for (int k = 0 ; k < 100 ; k++) {
if (!i && !j && !k) {
continue ;
}
int x = a1 * i + a2 * j + a3 * k;
int y = b1 * i + b2 * j + b3 * k;
int z = c1 * i + c2 * j + c3 * k;
if (x * b == y * a && y * c == b * z && x % a == 0 ) {
cout << i << " " << j << " " << k << " " << x / a << endl;
return 0 ;
}
}
}
}
cout << "NONE" ;
return 0 ;
}
while 循环 while 循环本质逻辑与 for 循环大差不差,适用于条件未知但需持续判断的场景。
while (true )
{
cout << "作者真帅" ;
}
结构体
C++ 结构体的基本概念 在 C++ 中,结构体得到了极大的增强,几乎和类一样强大,唯一区别是默认访问权限为 public(类为 private)。
#include <iostream>
#include <string>
using namespace std;
struct Student {
string name;
int age;
float score;
};
int main () {
Student stu1;
stu1. name = "张三" ;
stu1. age = 20 ;
stu1. score = 85.5 ;
cout << "姓名:" << stu1. name << endl;
cout << "年龄:" << stu1. age << endl;
cout << "成绩:" << stu1. score << endl;
return 0 ;
}
结构体的定义方式
基本定义 #include <iostream>
#include <string>
using namespace std;
struct Person {
string name;
int age;
string phone;
};
struct Car {
string brand;
string model;
int year;
} car1, car2;
int main () {
typedef struct {
string city;
string street;
int number;
} Address;
Address addr = {"北京" , "长安街" , 1 };
Person p;
Car myCar;
return 0 ;
}
结构体的初始化
多种初始化方法 #include <iostream>
#include <string>
using namespace std;
struct Student {
string name;
int age;
float score;
};
int main () {
Student stu1 = {"张三" , 20 , 85.5 };
Student stu2 = {.name = "李四" , .age = 21 , .score = 92.0 };
Student stu3 ("王五" , 22 , 88.5 ) ;
Student stu4{};
Student stu5;
stu5. name = "赵六" ;
stu5. age = 23 ;
stu5. score = 90.5 ;
cout << stu1. name << " " << stu1. age << " " << stu1. score << endl;
cout << stu4. name << " " << stu4. age << " " << stu4. score << endl;
return 0 ;
}
结构体成员访问 #include <iostream>
#include <string>
using namespace std;
struct Point {
int x;
int y;
void display () {
cout << "Point(" << x << ", " << y << ")" << endl;
}
double distance () {
return sqrt (x * x + y * y);
}
};
int main () {
Point p1 = {3 , 4 };
cout << "x = " << p1. x << ", y = " << p1. y << endl;
p1. display ();
cout << "到原点的距离:" << p1. distance () << endl;
Point *ptr = &p1;
ptr->x = 5 ;
ptr->y = 12 ;
cout << "修改后:" ;
ptr->display ();
return 0 ;
}
结构体数组 #include <iostream>
#include <string>
#include <iomanip>
using namespace std;
struct Student {
string name;
int age;
float score;
};
int main () {
Student class1[3 ] = {{"张三" , 20 , 85.5 }, {"李四" , 21 , 92.0 }, {"王五" , 22 , 88.5 }};
cout << "班级学生信息:" << endl;
cout << setw (10 ) << "姓名" << setw (6 ) << "年龄" << setw (8 ) << "成绩" << endl;
cout << "------------------------" << endl;
for (int i = 0 ; i < 3 ; i++) {
cout << setw (10 ) << class1[i].name << setw (6 ) << class1[i].age << setw (8 ) << fixed << setprecision (1 ) << class1[i].score << endl;
}
Student* class2 = new Student[2 ];
class2[0 ] = {"赵六" , 19 , 78.5 };
class2[1 ] = {"孙七" , 20 , 95.0 };
delete [] class2;
return 0 ;
}
结构体嵌套 #include <iostream>
#include <string>
using namespace std;
struct Address {
string city;
string street;
int number;
void show () {
cout << city << " " << street << " " << number << "号" ;
}
};
struct Contact {
string phone;
string email;
};
struct Student {
string name;
int age;
Address addr;
Contact contact;
void showInfo () {
cout << "姓名:" << name << endl;
cout << "年龄:" << age << endl;
cout << "地址:" ;
addr.show ();
cout << "\n电话:" << contact.phone << endl;
cout << "邮箱:" << contact.email << endl;
}
};
int main () {
Student stu = {"张三" , 20 , {"北京" , "长安街" , 1 }, {"13800138000" , "[email protected] " }};
stu.showInfo ();
cout << "\n城市:" << stu.addr.city << endl;
cout << "电话:" << stu.contact.phone << endl;
return 0 ;
}
结构体与函数 #include <iostream>
#include <string>
using namespace std;
struct Rectangle {
double width;
double height;
double area () {
return width * height;
}
};
void printRect1 (Rectangle r) {
cout << "宽:" << r.width << ",高:" << r.height << ",面积:" << r.area () << endl;
}
void printRect2 (const Rectangle &r) {
cout << "宽:" << r.width << ",高:" << r.height << ",面积:" << r.area () << endl;
}
void modifyRect (Rectangle *r, double w, double h) {
r->width = w;
r->height = h;
}
Rectangle createRect (double w, double h) {
return {w, h};
}
int main () {
Rectangle r1 = {10 , 5 };
printRect1 (r1);
printRect2 (r1);
modifyRect (&r1, 20 , 10 );
cout << "修改后:" ;
printRect2 (r1);
Rectangle r2 = createRect (15 , 8 );
cout << "新矩形:" ;
printRect2 (r2);
return 0 ;
}
结构体与运算符重载 #include <iostream>
using namespace std;
struct Vector2 {
float x, y;
Vector2 (float x = 0 , float y = 0 ) : x (x), y (y) {}
Vector2 operator +(const Vector2& other) const {
return Vector2 (x + other.x, y + other.y);
}
Vector2 operator *(float scalar) const {
return Vector2 (x * scalar, y * scalar);
}
friend ostream& operator <<(ostream& os, const Vector2& v) {
os << "(" << v.x << ", " << v.y << ")" ;
return os;
}
};
int main () {
Vector2 v1 (3 , 4 ) ;
Vector2 v2 (1 , 2 ) ;
Vector2 v3 = v1 + v2;
Vector2 v4 = v1 * 2 ;
cout << "v1 = " << v1 << endl;
cout << "v2 = " << v2 << endl;
cout << "v1 + v2 = " << v3 << endl;
cout << "v1 * 2 = " << v4 << endl;
return 0 ;
}
结构体与动态内存 #include <iostream>
#include <string>
using namespace std;
struct Node {
int data;
Node* next;
Node (int val) : data (val), next (nullptr ) {}
};
struct DynamicArray {
int * arr;
int size;
DynamicArray (int n) : size (n) {
arr = new int [size];
for (int i = 0 ; i < size; i++) {
arr[i] = i * 10 ;
}
}
~DynamicArray () {
delete [] arr;
cout << "内存已释放" << endl;
}
void display () {
for (int i = 0 ; i < size; i++) {
cout << arr[i] << " " ;
}
cout << endl;
}
};
int main () {
Node* head = new Node (1 );
head->next = new Node (2 );
head->next->next = new Node (3 );
Node* current = head;
while (current) {
cout << current->data << " " ;
current = current->next;
}
cout << endl;
while (head) {
Node* temp = head;
head = head->next;
delete temp;
}
DynamicArray da (5 ) ;
da.display ();
return 0 ;
}
结构体 vs 类的对比 #include <iostream>
using namespace std;
struct MyStruct {
int a;
void func () {
cout << "Struct function" << endl;
}
};
class MyClass {
int a;
public :
void func () {
cout << "Class function" << endl;
}
};
struct Point {
int x, y;
};
class Shape {
private :
Point center;
public :
virtual void draw () = 0 ;
};
int main () {
MyStruct s;
s.a = 10 ;
s.func ();
MyClass c;
c.func ();
return 0 ;
}
实用示例:学生成绩管理系统 #include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
struct Student {
string id;
string name;
int age;
double score;
Student (string id, string name, int age, double score) : id (id), name (name), age (age), score (score) {}
void display () const {
cout << "学号:" << id << ",姓名:" << name << ",年龄:" << age << ",成绩:" << score << endl;
}
};
struct Class {
string className;
vector<Student> students;
void addStudent (const Student& stu) {
students.push_back (stu);
}
void showAll () {
cout << "\n=== " << className << " 学生列表 ===" << endl;
for (const auto & stu : students) {
stu.display ();
}
}
double getAverageScore () {
if (students.empty ()) return 0 ;
double sum = 0 ;
for (const auto & stu : students) {
sum += stu.score;
}
return sum / students.size ();
}
void sortByScore () {
sort (students.begin (), students.end (), [](const Student& a, const Student& b) {
return a.score > b.score;
});
}
};
int main () {
Class c1 = {"计算机 1 班" };
c1. addStudent ({"2024001" , "张三" , 20 , 85.5 });
c1. addStudent ({"2024002" , "李四" , 21 , 92.0 });
c1. addStudent ({"2024003" , "王五" , 20 , 78.5 });
c1. addStudent ({"2024004" , "赵六" , 22 , 95.0 });
c1. showAll ();
cout << "\n班级平均分:" << c1. getAverageScore () << endl;
c1. sortByScore ();
cout << "\n=== 按成绩排序后 ===" ;
c1. showAll ();
return 0 ;
}
ASCII 码 ASCII 码就像一个字符的身份证,每一个字符都有一个数字来代表。怎么判断一个字符的'身份证'是多少呢?请看下面示例。
#include <iostream>
using namespace std;
int main () {
char s = 'A' ;
int a = s;
cout << a;
return 0 ;
}
有一个小提示,字符 A-Z 是挨在一起的,所以我们知道了 A 的身份证是 65,就可以推出 B 的字符是 66,以此类推。注意,小写字符和大写字符不是挨在一起的,所以需要记好'a'的身份证是 97。
string 类型 不知道大家是否学过 Python 的字符串,在 Python 中,字符串是可以像数组那样进行下标操作的。而不幸的是,C++ 中正常的 char 类型字符串无法进行下标操作,而 string 类型可以。不过请注意,string 类型没有负索引这个东西 。
练习题目:史莱姆融合 题目描述
有 N 只史莱姆排成一排,每只的颜色用一个英文小写字母表示,所有史莱姆的颜色排列成一个字符串 S。
接下来同样颜色的史莱姆会融合成一只,直到所有相邻的史莱姆颜色都不同。问最后剩下几只史莱姆?
输入格式
第 1 行,1 个正整数 N
第 2 行,字符串 S,表示每只史莱姆的颜色
#include <iostream>
using namespace std;
int main () {
int n;
cin >> n;
string s;
cin >> s;
int count = 1 ;
for (int i = 1 ; i < n; i++) {
if (s[i] != s[i - 1 ])
{
count++;
}
}
cout << count << endl;
return 0 ;
}
string 字符串操作
字符串拼接 string s = "作者" ;
string n = "真帅" ;
string m = s + n;
cout << m;
练习题目:贪婪的送礼者 题目描述
N 个人互相送礼,每个人有一定初始金额,按照规则转账,求最终每个人的余额。
#include <bits/stdc++.h>
using namespace std;
map<string, int > money;
int n, l, have;
string name[105 ], x, buddy;
int main () {
cin >> n;
for (int i = 1 ; i <= n; i++) cin >> name[i];
for (int i = 1 ; i <= n; i++) {
cin >> x >> have >> l;
if (l == 0 ) continue ;
money[x] -= have;
int give = floor (have / l);
money[x] += (have - l * give);
for (int j = 1 ; j <= l; j++) {
cin >> buddy;
money[buddy] += give;
}
}
for (int i = 1 ; i <= n; i++) cout << name[i] << " " << money[name[i]] << endl;
return 0 ;
}
递归初步
1.1 递归的含义与历史 递归是计算机科学的一个不可分割的算法。就像西方不能失去耶路撒冷一样,递归指的是一个函数直接或间接读取自己的过程。但在我们使用递归的时候要注意不要写成死循环,并且我们也要明确我们写这个递归的目的,要逐步地把问题缩小化。
1.2 举个栗子
从前有座山,山中有座庙,庙里有个老和尚,老和尚在讲故事,讲的是什么呀?从前有座山,山中有座庙,庙里有个老和尚在讲故事……
像这样的故事没有丝毫特点,就像你写死循环的时候重复给机器讲一个'故事',机器就会困得睡着了,因此就'睡着了'。
1.3 代码示例 int dg (int n) {
if (n == 87 )
{
return 1 ;
}
return dg (n + 1 );
}
练习题目:欧几里得算法 #include <bits/stdc++.h>
using namespace std;
int gcd (int a, int b) {
if (a % b == 0 ) {
return b;
} else {
return gcd (b, a % b);
}
}
int main () {
int a, b;
cin >> a >> b;
cout << gcd (a, b);
return 0 ;
}
拔高题目:子集和问题 这道题难度较高,使用了我们还未学到的回溯算法,可以自己深研以下。
#include <iostream>
using namespace std;
int n, m, p[15 ], ans;
bool vis[15 ];
void dfs (int step) {
if (step == n + 1 ) {
int sum = 0 ;
for (int i = 1 ; i <= n; i++) {
if (vis[i] == 1 ) {
sum += p[i];
}
}
if (sum == m) {
ans++;
}
return ;
}
vis[step] = 1 ;
dfs (step + 1 );
vis[step] = 0 ;
dfs (step + 1 );
}
int main () {
cin >> n >> m;
for (int i = 1 ; i <= n; i++) {
cin >> p[i];
}
dfs (1 );
cout << ans << endl;
return 0 ;
}
回溯法
1.1 前言 在上一个知识点递归初步里的拔高题目 AC 代码使用了回溯法,在这个知识点部分我们来学习回溯法。
1.1.1 什么是回溯法? 回溯指的是在做题时一种试错过程中不可缺少的部分。比如说,如果我们发现一种路线不可行,那么我们立即使用下一条路线,而回到原来选择的那个分支的方法,我们称为回溯法 ,或者说这也是种枚举的过程。
1.1.2 回溯法有什么用呢 有人说,回溯法的底层逻辑就是递归,有回溯的地方就有递归。而回溯在做背包一类的题目中有显著优势,背包这个东西我们后文会提到。
2. 回溯模板 #include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
bool vis[10 ];
int plan[10 ];
int n;
void dfs (int step) {
if (step == n + 1 ) {
for (int i = 1 ; i <= n; i++) {
cout << plan[i] << " " ;
}
cout << endl;
return ;
}
for (int i = 1 ; i <= n; i++) {
if (vis[i] == 1 ) {
continue ;
}
plan[step] = i;
vis[i] = 1 ;
dfs (step + 1 );
vis[i] = 0 ;
}
}
int main () {
cin >> n;
dfs (1 );
return 0 ;
}
高精度算法
1. 加法
1.1 前言 在大家的小学时期怎样计算两个数相加呢?想必有的人会使用竖式的方法,而高精度就是来模拟竖式加法。
1.2 代码逻辑 我们知道了高精度加法的具体逻辑,就是模拟人类计算多位数加多位数时使用的竖式计算方式,而在加的时候就会出现多一位的情况。有时我们就会出现这种尴尬的方式,数组下表 0 的那个部分给到了数字 9,而多的那一位就没有地方了。也许有的人会说,那把 9 的下表设为 1 不就行了,但是有时数位不会多出来一位,若是这样的话有时输出就会出现前导 0,所以,我们就要请出这个方法了——逆序存储。因为这样的话若是没有多出来的那一位就不会出现前导 0 了,因为逆序输出的时候记好是否有多出来的那一位就可以了。
1.3 逆序存储代码 void add (string s, int a[]) {
a[0 ] = s.size ();
for (int i = 1 ; i <= a[0 ]; i++) {
a[i] = s[a[0 ] - i] - '0' ;
}
}
1.4 核心代码 在我们加法运算的过程中,一定会出现进位的情况,而我们就要推出进位变量 carry,核心代码实现如下:
void addBIG (int a[], int b[], int c[]) {
c[0 ] = max (a[0 ], b[0 ]);
int carry = 0 ;
for (int i = 1 ; i <= c[0 ]; i++) {
int t = a[i] + b[i] + carry;
c[i] = t % 10 ;
carry = t / 10 ;
}
if (carry > 0 ) {
c[++c[0 ]] = carry;
}
}
1.5 输出 最后一步也是最重要的一步——逆序输出。因为我们前文说到是逆序存入,so 我们要逆序输出,这样才能输出正确。
1.6 整体代码 #include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
void s2BIG (string s, int a[]) {
a[0 ] = s.size ();
for (int i = 1 ; i <= a[0 ]; i++) {
a[i] = s[a[0 ] - i] - '0' ;
}
}
void printBIG (int a[]) {
for (int i = a[0 ]; i >= 1 ; i--) {
cout << a[i];
}
cout << endl;
}
void addBIG (int a[], int b[], int c[]) {
c[0 ] = max (a[0 ], b[0 ]);
int u = 0 ;
for (int i = 1 ; i <= c[0 ]; i++) {
int t = a[i] + b[i] + u;
c[i] = t % 10 ;
u = t / 10 ;
}
if (u > 0 ) {
c[++c[0 ]] = u;
}
}
int a[1000005 ], b[100005 ], c[100005 ];
string sa, sb;
int main () {
cin >> sa >> sb;
s2BIG (sa, a);
s2BIG (sb, b);
addBIG (a, b, c);
printBIG (c);
return 0 ;
}
2. 高精度减法
1.1 前言 高精减和高精加区别并没有那么大,因为这个仅仅把加变为减,把进位改为退位,因此原理还是模拟人类竖式计算。
1.2 示例 #include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
void s2BIG (string s, int a[]) {
a[0 ] = s.size ();
for (int i = 1 ; i <= a[0 ]; i++) {
a[i] = s[a[0 ] - i] - '0' ;
}
}
void printBIG (int a[]) {
for (int i = a[0 ]; i >= 1 ; i--) {
cout << a[i];
}
cout << endl;
}
void addBIG (int a[], int b[], int c[]) {
c[0 ] = max (a[0 ], b[0 ]);
int u = 0 ;
for (int i = 1 ; i <= c[0 ]; i++) {
int t = a[i] + b[i] + u;
c[i] = t % 10 ;
u = t / 10 ;
}
if (u > 0 ) c[++c[0 ]] = u;
}
bool cmpBIG (int a[], int b[]) {
if (a[0 ] != b[0 ]) return a[0 ] < b[0 ];
for (int i = a[0 ]; i >= 1 ; i--)
if (a[i] != b[i]) return a[i] < b[i];
return false ;
}
void subBIG (int a[], int b[], int c[]) {
c[0 ] = max (a[0 ], b[0 ]);
int u = 0 ;
for (int i = 1 ; i <= c[0 ]; i++) {
int t = a[i] - b[i] - u;
if (t < 0 ) {
c[i] = t + 10 ;
u = 1 ;
} else {
c[i] = t;
u = 0 ;
}
}
while (c[c[0 ]] == 0 && c[0 ] > 1 ) c[0 ]--;
}
int a[1005 ], b[1005 ], c[1005 ];
string sa, sb;
int main () {
cin >> sa >> sb;
s2BIG (sa, a);
s2BIG (sb, b);
if (cmpBIG (a, b) == true ) subBIG (b, a, c);
else subBIG (a, b, c);
printBIG (c);
return 0 ;
}
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online