c++语法基础课

c++语法基础注意点

一、简单顺序结构

main( )

最新版的c++不允许使用void main( )

printf格式

%05d    宽度为5,左端自动补4个0
%-5d    宽度为5,右端自动补空格
%5.1f   保留小数点一位,宽度为5

三、循环

增强for循环

范围遍历

string s = "HELLO WORLD";
for(变量类型  新的遍历变量名 : 被遍历的变量)
for(char c : s) cout << c << endl;
//取地址改变字符串内容
for(char &c : s) c = 'a';
//auto类型
//自动类型推导,但是必须初始化
for(auto c : s)//用于类型比较长的时候

四、数组

分配内存

指针数组初始化需要提前分配内存,并置0,calloc

一般数组(已经设置数组边界值)已经分配好内存,只需置0,memset

获取数组长度

  • 字符串数组长度:strlen( )

  • 万能方法:

    sizeof(a) / sizeof(a[0]) ——使用sizeof关键字

    注意:因为字符串结尾处还有一个‘ \n ’字符,所以使用该方法时会比真实长度大了1,即为strlen( ) + 1

定义变量的默认值

int n;//默认值为0

五、字符串

用地址调用数组元素

*(a+k);/*调用数组第k+1的元素*/

ASCII码值

每个常用字符都对应一个-128~127的数字

空格" "是32

’0’-‘9’是48-57

’A’-‘Z’ 是65~90

’a’-‘z’是97-122

字符可以参与运算,需要用**'单引号 ',运算时会将其当做整数**

'1' != 1

字符数组

字符数组的长度至少要比字符串的长度多1(必须要有一个空间存放’\0’)

字符串就是字符数组加上结束符’\0’

Difference:

/*单个字符用单引号'', 字符串用双引号""*/
char a[] = {'C', '+', '+'};//列表初始化,没有空字符
char a[] = {'C', '+', '+', '\0'};//列表初始化,含有空字符
char a[] = "C++";//列表初始化,自动添加空字符'\0'

字符串输入

scanf

过滤空格

%s格式的输入不需要加上&,因为字符串的数组名就是指针,指向首地址(!仅限字符串数组!)

遇到空格结束,不会过滤回车

//从数组下标唯一1开始输入,输出类似
scanf("%s", s + 1);
cin >> s + 1;
//字符串用空格或回车隔开即可
scanf("%s%s", s1, s2);
//过滤回车
scanf("\n%s",s);
cin

过滤空格

cin >> 字符串首地址,遇到空格或回车会停止,只能输入没有空格的字符串

cin.getline

可读空格,可以读取一整行

两个头文件
<string>
<iostream>

cin.getline(s, 100);

cin.getline(字符串首地址,最多读入长度);

遇到**回车’\r’**结束,可以有空格

fgets(容易出错)

可读空格,可以读取一整行

char s[100];
//fgets(s, 100, stdin)
//fgets(字符串首地址,最多读入字符数,读入的文件名(一般为stdin))
  • 该函数从stream所指的文件中读取以'\n'结尾的一行(包括'\n'在内)存到缓冲区s中,并且在该行末尾添加一个 '\0'组成完整的字符串。

  • fgets()函数的最大读取大小是其“第二个参数减1”,这是由于字符串是以’\0’为结束符的

  • 输入回车时会读入’\n’ ,输入n个字符按下回车输入,fgets()存储进第一个参数指定内存地址的是n+2个字节

字符串输出

puts

puts(字符串数组名);

puts输出自带有换行

printf

printf(“%s”, s);

常用操作

头文件:<cstring>
strlen( )

strlen(str),求字符串的长度

一般提前用新变量保存好字符串的长度再进入循环

strcmp( )

strcmp(a, b),比较两个字符串的大小,按照字典序方式比较

字典序(按照ASCII码):abc < adbe

a < b 返回-1

a == b 返回0

a > b返回1

strcpy( )

strcpy(a, b),将字符串b复制给从a开始的字符数组

思想:统计字符中字符出现的次数

开辟新的长度为26的数组,统计每个字幕出现的次数

for(int i = 0; str[i]; i ++) //str[i]至'\0'结束,循环也就停止  
    cnt[str[i] - 'a'] ++;

思想:小写字母变为下一位

//c为增强for循环中设置的变量
c = (c - 'a' + 1) % 26 + 'a';

标准库类型String(80%用string处理,常用)

头文件
//头文件
#include<string>
初始化定义
string s1; //默认的空字符串
string s2 = s1;//s2等于s1
string s3 = "jjj";
string s4(10, 'c');//s4为cccccccccc
输入

scanf不能用,会报错

cin

过滤空格

cin >> s;

getline

可读空格,可以读取一整行

getline(cin, s);

输出
cout

cout << s;

printf(耗时更少)

printf(“%s\n”, s.c_str());

c_str()调用成员函数:返回字符数组的首地址

puts

puts(s1.c_str());

c_str()调用函数返回字符数组的首地址

empty

s.empty( )

返回布尔值,s为空返回1,非空返回0

size

s.size( )

返回无符号整型的字符串长度

与strlen( )遍历一次求长的o( n )时间复杂度不同,该函数时间复杂度为o( 1 )

string比较

支持 > < >= <= == !=等所有比较操作,按字典序进行比较。

赋值
s1 = s2;

给s1赋值为s2的值

相加

必须确保每个加法运算符的两侧的运算对象至少有一个是string

不能都为字符或字符串类型

s3 = s1 + s2;
s3 += s1;
/*可以加上字符或字符串*/
s3 = s3 + "Hello" + 'H';
处理字符
  • 当成字符数组,例如可以for循环使用s[i]
  • 使用增强for循环

六、函数

组成

  • 返回类型(必须写)、函数名字、由0个或多个形参组成的列表以及函数体

  • return语句负责结束函数并返回一个值。不写会返回一个随机值。

调用

  • 用实参初始化函数对应的形参
  • 将控制权转移给被调用函数。此时,主调函数的执行被暂时中断,被调函数开始执行。

声明和定义

声明:没有函数体

定义:必须写函数体

形参列表

函数的形参列表可以为空,但是不能省略。

void f1() {/* …. */}        // 隐式地定义空形参列表
void f2(void) {/* … */}      // 显式地定义空形参列表

形参列表中的形参通常用逗号隔开,其中每个形参都是含有一个声明符的声明。即使两个形参的类型一样,也必须把两个类型都写出来:

int f3(int v1, v2) {/* … */}       // 错误
int f4(int v1, int v2) {/* … */}    // 正确

返回类型

  • 大多数类型都可作为返回类型
  • 特殊:void——表示函数不返回任何值、
  • 函数的返回类型不能是数组类型或函数类型,但可以是指向数组或者函数的指针

全局/局部/静态变量

  • 局部变量只可以在函数内部使用(重名时优先选择)
  • 全局变量可以在所有函数内使用
  • static静态,可以设置一个只在该函数内用的全局变量(节省空间,存入堆中,非栈)

参数传递

传值参数(int a)
  • 初始化一个非引用类型的变量时,函数中设定的初始值被拷贝给主函数中的变量。

  • 在函数中对变量的改动不会影响主函数中的初始值。

传引用参数(int &a)
  • 当函数的形参为引用类型时,函数中对形参的修改会影响主函数中实参的值。
  • 使用引用的作用:避免拷贝、让函数返回额外信息。
重载

函数名一样的情况无大碍,还取决于参数类型

数组形参

传引用参数

  • 一维数组形参的写法:

    void print(int *a) {/* … */}
    void print(int a[]) {/* … */}
    void print(int a[10]) {/* … */}
    
  • 多维数组形参的写法:

    多维数组中,除了第一维之外,其余维度的大小必须指定

    (c++中多维数组会被转化为一维数组的指针样式进行保存)

    void print(int (*a)[10]) {/* … */}
    void print(int a[][10]) {/* … */}
    

返回类型和return语句

两种形式
return;
return expression;
返回类型和return语句
无返回值函数
  • 没有返回值的return只能用在返回类型是void的函数中,该类函数也没必要写上return
  • 有点类似于我们用break语句退出循环。
有返回值的函数
  • 返回类型不是void,每条return都必须返回一个与函数类型相同的值

函数递归

函数内部可以调用函数本身

七、类&结构体 指针&引用

类可以将变量、数组和函数完美地打包在一起

复杂抽象,比较庞大

  • private

    后面的内容是私有成员变量,在类的外部不能访问

  • public

    后面的内容是公有成员变量,在类的外部可以访问

class Person {
    int age;//类默认为private
    private:
    	int age, height;
    	double monney;
    	string books[N];
    public:
    	int get_height()
        {
            return height;
        }
    public:
    	string name;
		void say()
        {
            cout << "I'm" << endl;
        }
    	int get_age()
        {
            return age;
        }
    	void add_money(double x)
        {
            money += x;
        }
}Person1, Person2;
int main()
{
    Person c;
    c.name = "hxh";
    c.age = 18;//错误!因为age是private类型的变量
    c.add_money(10000);
}

结构体

比较短,存和数据相关的

struct Person {
	int age;//结构体默认是public
};

内存空间分配方式

程序的进程保存在堆栈中,保存形式为十六进制

  • 动态数据区:

    • 局部变量存在里,未设定初值,每次分配的位置不一样,所以每次都不一样
    • 向下增长,从上往下分配
  • 静态数据区:

    • 全局/静态变量存在里,设定初始值为0
    • 向上增长,从下往上分配

1 byte = 8 bit

指针

指针指向存放变量的值的地址。因此我们可以通过指针来修改变量的值。

//找到变量地址,需要转化成指针类型
char c = 'a';
cout << (void*)&c << endl;

//将变量值赋给指针
int* p = &a;//(int*)类型的p的值是变量a的地址
cout << *p << endl;//读取指针p指向的变量的值
*p = a;//修改p指向的变量的值

区别&注意点

  • 不同点在于类默认是private,结构体默认是public。

  • 指针访问 ->

  • **普通访问 **

  • new

    struct Node {
        int val;
        Node* next;
        /*构造函数初始值列表*/
       // 结点类型(输入值) : 变量1(传值), 变量2(传值) {}
        Node(int _val) : val(_val), next(nullptr) {}
    };
    int main()
    {
        //定义Node类型的变量,p保存的是变量地址
        Node* p = new Node(1);
        auto q = new Node(2);//auto自动设置,因为new Node()自动返回Node*类型
        auto o = new Node(3);
        //定义Node类型的变量,结点值是1
        Node node = Node(1);
    }
    
数组——特殊的指针
int a[5] = {1, 2, 3, 4, 5};
int *p = a;//p的值是数组a的地址
C++的引用语法
  • 指针指向一块内存,内部存储的内容是所指的内存的地址

  • 引用是模块内存的别名,跟原来的变量实质上是同一个东西。

  • 指针和引用都可以作为函数参数,改变实参的值。

//和指针类似,相当于给a取个别名
int& p = a;

int a = 996;
int *p = &a; // p是指针, &在此是求地址运算
int &r = a; // r是引用, &在此起标识作用
单链表
#include<iostream>

using namespace std;

struct Node
{
    int val;
    Node* next;
    
    Node(int _val) : val(_val), next(nullptr) {}
}
int main()
{
    auto p = new Node(1);
    auto q = new Node(2);
    auto o = new Node(3);
    
    p->next = q;
    q->next = o;
    
    Node* head = p;
    /*添加结点*/
    Node* u = new Node(4);
    u->next = head;
    head = u;
    /*删除结点*/
    head->next = head->next->next;
    /*链表的遍历*/
    for(Node* i = head; i; i = i->next)
        cout << i->val << endl;
   
    return 0;
}

八、STL

STL是提高c++编写效率的一个利器。

vector

vector是变长数组,支持随机访问不支持在任意位置O(1)插入。为了保证效率,元素的增删一般应该在末尾进行。

  • 利用倍增实现动态增长
    • 长度不够时进行1/2拷贝,n(1/2 + 1/4 + 1/8 + …),平均每次时间复杂度是o(1)
    • 定义的耗时比数组慢,使用的效率快

声明

#include <vector> 	//头文件
vector<int> a;		//相当于一个长度动态变化的int数组
vector<int> b[233];	//相当于第一维长233,第二位长度动态变化的int数组
    
struct rec{…};
vector<rec> c;		//自定义的结构体类型也可以保存在vector中

size( )

  • size函数返回vector的实际长度(包含的元素个数)
  • 时间复杂度都是O(1)
  • 所有的STL容器都支持这个方法,含义也相同
a.size();

empty( )

  • empty函数返回一个bool类型,表明vector是否为空
  • 时间复杂度都是O(1)
  • 所有的STL容器都支持这两个方法,含义也相同
a.empty;

clear

  • clear函数把vector清空,只有0个元素
a.clear();

迭代器

迭代器就像STL容器的“指针”,可以用星号“*****”操作符解除引用

//一个保存int的vector的迭代器声明方法为:
//it保存a的首地址,
vector<int>::iterator it = a.begin();
begin( )
a.begin(); === &a[0]
*a.begin(); === a[0]
end( )
  • 左开右闭,[begin, end)

  • end函数返回vector的尾部,即第n个元素再往后的“边界n + 1“。

  • *a.end()与a[n]都是越界访问,其中n=a.size(),即容器长度

遍历方法
  • 类似数组

    for(int i = 0; i < a.size(); i++) cout << a[i] << ' ';
    //增强for循环
    for(int x : a) cout << x << ' ';
    
  • 迭代器遍历

    //可以用auto代替i的类型定义
    for(vector<int>::iterator i = a.begin(); i != a.end(); i++) cout << *i << ' ';
    
front / back
  • front函数返回vector的第一个元素,等价于*a.begin() 和 a[0]。

  • back函数返回vector的最后一个元素,等价于 a[a.size() – 1],a.end()的前一个位置。

push_back() / pop_back()
  • a.push_back(x) 把元素x插入到vector a的尾部。时间复杂度o(1)

  • b.pop_back() 删除vector a的最后一个元素。时间复杂度o(1)

queue

头文件queue主要包括循环队列queue和优先队列priority_queue两个容器。

先进先出的顺序

循环队列queue

声明
#include<queue> 	//头文件
queue<int> q;
操作
q.push(1);//队头插入一个元素
q.pop();//弹出队尾元素
q.front();//返回队头元素
q.back();//返回队尾元素

优先队列priority_queue

声明
#include<queue> 	//头文件
priority_queue<int> q;		// 大根堆(优先返回大的数)
priority_queue<int, vector<int>, greater<int>> q;	// 小根堆(返回最小值)
priority_queue<pair<int, int>>q;

struct rec{
    int a,b;
    //重载小于号
	bool operator< (const Rec& t) const
	{
		return a < t.a;//降序出列,从小到大排序,从大到小出列
        或者
        return a > t.a;//升序排列,从大到小排序,从小到大出列
	};
}; 
priority_queue<rec> q;//结构体rec中必须重载小于号函数
操作
a.push(1);//插入一个数,按顺序自动调整
a.top();//取最大值
a.pop();//删除最大值
清空队列
q = queue<int>();//重新初始化

stack

声明

#include <stack>//头文件
stack<int> stk;

操作

stk.push;//向栈顶插入
stk.top();//返回栈顶元素
stk.pop;//弹出删除栈顶元素

deque

  • 双端队列deque是一个支持在两端高效插入或删除元素的连续线性存储空间。它就像是vector和queue的结合。

  • 与vector相比,deque在头部增删元素仅需要O(1)的时间,vector需要o(n)时间

  • 与queue相比,deque像数组一样支持随机访问。

声明

#include<deque>;
deque<int> a;

操作

[] 随机访问
a.begin/end();/*返回deque的头/尾迭代器*/
a.front/back(); /*返回队头/队尾元素*/
a.push_back(1); /*从队尾入队*/
a.push_front(1); /*从队头入队*/
a.pop_back(); /*从队尾出队*/
a.pop_front(); /*从队头出队*/
a.clear(); /*清空队列*/

set

  • 头文件set主要包括set和multiset两个容器,分别是“有序集合”和“有序多重集合”

  • 前者的元素不能重复,而后者可以包含若干个相等的元素。

  • set和multiset的内部实现是一棵红黑树,它们支持的函数基本相同。

声明

#include<set>
using namespace std;

set<T泛型> name;//定义的标准方式
set<int> a;//元素不能重复
multiset<double> a;//元素可以重复

struct rec{
	int a,b;
	bool operator< (const Rec& t) const
	{
		return a<t.a;
	};//重载小于号,使其从小到大排列,默认小顶堆
}; 
set<rec> s;	// 结构体rec中必须重载小于号函数

size/empty/clear

与vector类似

迭代器

  • set和multiset的迭代器称为“双向访问迭代器”,不支持“随机访问”,支持星号(*)解除引用,仅支持”++”和–“两个与算术相关的操作。

  • 设it是一个迭代器,例如set::iterator it;

  • 若把it++,则it会指向“下一个”元素。这里的“下一个”元素是指在元素从小到大排序的结果中,排在it下一名的元素。同理,若把it–,则it将会指向排在“上一个”的元素。

set<int>::iterator it = a.begin();
it++; it--;
++it; --it;

//遍历时常用
for(it = s.begin(); it != s.end(); it++)
    printf("%d\n", *it);//解引用

begin/end

  • s.begin() 是指向集合中最小元素的迭代器。
  • s.end() 是指向集合中最大元素的下一个位置的迭代器。换言之,就像vector一样,是一个“前闭后开”的形式。因此–s.end()是指向集合中最大元素的迭代器。

insert元素插入

  • s.insert(x)把一个元素x插入到集合s中
  • 时间复杂度为O(logn)。
  • 在set中,若元素已存在,则不会重复插入该元素,对集合的状态无影响。

find

  • s.find(x) 在集合s中查找等于x的元素,并返回指向该元素的迭代器。若不存在,则返回s.end()。

    if(a.find(x) == a.end()) //判断x在a中是否存在
    
  • 时间复杂度为O(logn)。

lower_bound/upper_bound

  • s.lower_bound(x) 查找大于等于x的元素中最小的一个,并返回指向该元素的迭代器。
  • s.upper_bound(x) 查找大于x的元素中最小的一个,并返回指向该元素的迭代器。

erase

  • 设x是一个元素,s.erase(x) 从s中删除所有等于x的元素,时间复杂度为O(k+logn),其中k是被删除的元素个数。
  • 设it是一个迭代器,s.erase(it) 从s中删除迭代器it指向的元素,时间复杂度为O(logn)

count

s.count(x) 返回集合s中等于x的元素个数,时间复杂度为 O(k +logn),其中k为元素x的个数。

  • set不存在返回1,存在返回0
  • multiset存在返回个数

map

声明

  • map容器是一个键值对key-value的映射,其内部实现是一棵以key为关键码的红黑树。
  • Map的key和value可以是任意类型,其中key必须定义小于号运算符。
#include<map>
using namespace std;
//程序中默认指定了std命令空间,可以省略std:
std::map<std::string, int>mymap{{"emm", 10}, {"STL", 20}};
//创建空容器 + 初始化
map<key_type, value_type> name;

//此处和数组差不多
map<int, int> a;//二元组
a[1] = 2;
cout << a[1] << endl;

map<string, vector<int>> a;
a["hhh"] = vector<int>({1, 2, 3, 4});
cout << a["hhh"][2] << endl;

//重载小于号,使从小到大排列
struct Node {  
	int d, e;  
	bool operator < (const Node x) const 
    {  
	return d < x.d;      //从小到大排序
    }   
    Node(int d, int e):d(d), e(e){}  
}; 

size/empty/clear/begin/end/count/lower_bound/upper_bound/max_size/swap

均与set类似。

Insert/erase

与set类似,但其参数均是pair<key_type, value_type>

a.insert({"a", {}});

find

h.find(x) 在变量名为h的map中查找key为x的二元组,用法与set类似。

a.find(key) == a.end()

[ ]操作符

  • h[key] 返回key映射的value的引用,时间复杂度为O(logn)。

  • []操作符是map最吸引人的地方。我们可以很方便地通过h[key]来得到key对应的value,还可以对h[key]进行赋值操作,改变key对应的value。

九、位运算、常用库函数

位运算

位运算符

移位运算符优先级最高

& 与

0 & 0 = 0
0 & 1 = 0
1 & 1 = 1

| 或

0 | 0 = 0
1| 0 = 1
0 | 1 = 1
1 | 1 = 1

~ 非

~ 0 = 1
~ 1 = 0

^ 异或

a⊕b = (¬a ∧ b) ∨ (a ∧¬b)

0 ^ 0 = 0
1 ^ 1 = 0
1 ^ 0 = 1
    
//int类型的两个数异或
3 ^ 6 = (011) & (110) = (101) = 5

>> 右移

  • 右边减一个数字位,相当于 / 2

  • a >> k === a/pow(2, k)

<< 左移

  • 右边加0,相当于 * 2

  • a << k === a * pow(2, k)

常用操作:
  • 求x的第k位数字 x >> k & 1

    a = 110110
    a >> k = 1101
    a >> k & 1 = (1101) & (0001) = 1
    
  • lowbit(x) = x & -x,lowbit(x) 为返回x的最后一位1和后i面的0

a = 10101100100000
~a = 01010011011111
~a + 1 = 01010011100000
a & (~a + 1) = 100000
负数用补码表示,补码和反码一样

常用库函数

reverse 翻转

时间复杂度为o(n)

//头文件
#include <algorithm>
using namespace std;
  • 翻转一个vector

    reverse(a.begin(), a.end());
    
  • 翻转一个数组

    左闭右合[ , )

    reverse(a, a + n);
    
  • 翻转一个字符串

    reverse(str.begin(),str.end();
    
unique 去重
//头文件
#include <algorithm>
using namespace std;
  • 使用unique的容器重复元素必须靠在一块
  • 返回去重之后的尾迭代器(或指针),仍然为前闭后开,即这个迭代器是去重之后末尾元素的下一个位置。
  • 该函数常用于离散化,利用迭代器(或指针)的减法,可计算出去重后的元素个数。

把一个vector去重:

int m = unique(a.begin(), a.end()) – a.begin();//m为去重后的元素个数
a.erase(unique(a.begin(), a.end()), a.end());//删除后面重复元素,保留前面不重复的部分

把一个数组去重,元素存放在下标1~n:

int m = unique(a, a + n) – a;//m为去重后的元素个数
random_shuffle 随机打乱
//头文件
#include <algorithm>
using namespace std;

用法与reverse相同

random_shuffle(a.begin(), a.end());
random_shuffle(a, a + n)
sort

头文件:

#include <algorithm>
using namespace std;
  • 对两个迭代器(或指针)指定的部分进行快速排序

  • 参数和reverse的用法一样,可以在第三个参数传入定义大小比较的函数,或者重载“小于号”运算符。

  • sort()函数可以对给定区间所有元素进行排序。它有三个参数sort(begin, end, cmp),其中begin为指向待sort()的数组的第一个元素的指针,end为指向待sort()的数组的最后一个元素的下一个位置的指针,cmp参数为排序准则,cmp参数可以不写(即为sort(begin, end))默认从小到大进行排序。如果我们想从大到小排序可以将cmp参数写为greater()就是对int数组进行排序,当然<>中我们也可以写double、long、float等等。

sort(a.begin(),a.end());//从小到大排序
sort(a.begin(), a.end(), greater<int>());//从大到小排序
int a[MAX_SIZE];
//全局函数
bool cmp(int a, int b)//a是否应该排在b的前面 
{
    return a > b; //如果a > b, 那么a应该排在b的前面,则为降序排列
    或者
    return a < b;//如果a < b,那么a应该排在b的前面,则为升序排列
}
sort(a, a + n, cmp);

把自定义的结构体vector排序,重载“小于号”运算符:

struct rec
{
    int id, x, y; 
    bool operator <(const rec &t)const 
	{
		return x < t.x;
	}
}
vector<rec> a;
sort(a.begin(), a.end()); 
lower_bound/upper_bound 二分

头文件:

#include <algorithm>
using namespace std;
  • lower_bound 的第三个参数传入一个元素x,在两个迭代器(指针)指定的部分上执行二分查找,返回指向第一个大于等于x的元素的位置的迭代器(指针)。

    int a[] = {1, 2, 3, 4, 5,, 6};
    int* p = lower_bound(a, a + 5, 7);
    
    • 有序int数组中查找大于等于x的最小整数的下标

      int t = lower_bound(a, a + n, x) – a;
      
    • 有序vector 中查找小于等于x的最大整数(假设一定存在)

      int y = upper_bound(a.begin(), a.end(), x) - a.begin();
      
  • upper_bound 的用法和lower_bound大致相同,唯一的区别是查找第一个大于x的元素。当然,两个迭代器(指针)指定的部分应该是提前排好序的。

    • 用法与lower_bound一致
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值