准备c++进阶基础(一)

13 篇文章 2 订阅

Linux系统编程

c/c++编程

1 父进程子进程

#include <stdio.h>
#include <unistd.h>

int main()
{
    int pid;
    pid = fork();
    if (pid==-1)
    {
        printf("error\n");
    }
    if (pid == 0)
        printf("child: my = %d, parent = %d\n", getpid(), getppid());
    //getpid()获取当前进程pid,getppid()获取父进程pid
    else
        printf("parent: my = %d, child = %d\n", getpid(), pid);
    return 0;
}/*父进程从fork返回处继续执行,在父进程中,fork返回子进程PID
子进程从fork返回处开始执行,在子进程中,fork返回0*/

2 异常捕获

#include<iostream>

using namespace std;

class MyClass
{
	//基类
};

class myclass :public MyClass {

	//派生类
};
/*在使用try catch注意*/
//派生类需要放在最前面,避免穿透
//int main() {
//
//	try
//	{
//		throw MyClass();
//	}
//	
//	catch (myclass) {
//
//		cout << "myclass派生类" << endl;
//	}
//	catch (MyClass)
//	{
//		cout << "Myclass基类" << endl;
//	}
//	return 0;
//}
int main() {

	try
	{
		throw myclass();//抛出异常
	}
	//捕获异常
	catch (MyClass)
	{
		cout << "Myclass基类" << endl;
	}
	catch (myclass) {

		cout << "myclass派生类" << endl;
	}
	
	return 0;
}//异常穿透执行
/*
catch (MyClass)
	{
		cout << "Myclass基类" << endl;
	}
	*/

3 结构体与函数回调

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct dynamicArray
{
	void** addr2;
	//指向的是数组空间
	void* addr1;
	//指向的是一个空间
};
void test2() {

	struct dynamicArray* addr = malloc(sizeof(struct dynamicArray));

	addr->addr2 = malloc(sizeof(void*) * 5);

	printf("\n2-----------------------%d\n", addr);
	//可以对数组空间赋值
	addr->addr2[3] = 1;
	addr->addr2[4] = 2;
	printf("%d\n", addr->addr2[3]);
	printf("%d\n", addr->addr2[4]);

	
}
void test1() {

	struct dynamicArray* addr = malloc(sizeof(struct dynamicArray));

	addr->addr1 = malloc(sizeof(void*) * 5);

	printf("1-----------------------%d\n", addr);
	//仅仅对一个空间赋值
	addr->addr1 = 1;
	printf("%d\n", addr->addr1);

}
//回调
//底层
void back_func_test(void* back_func(void*,void*)) {

	int* x;
	int y = 10;
	x = &y;

	back_func(*x,*x+10);

}
//给用户留好了接口,就是用户如果想访问那个值,用户自己决定
//用户
void back1(void *data1,void *data2) {
	//假如一个用户只想访问*x
	printf("%d\n", data1);

	//printf("%d\n", data2);
}

void back2(void* data1, void* data2) {
	//假如用户想访问*x,*x+10
	printf("%d\n", data1);

	printf("%d\n", data2);
}
int main() {

	/*test1();
	test2();*/
	printf("用户1\n");
	back_func_test(back1);
	printf("用户2\n");
	back_func_test(back2);

	return 0;
}

4 动态数组

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct dynamicArray
{
	void** addr;
	//在堆区开辟数组

	int capacity;
	//数组容量

	int Size;
	//数组大小
};
//初始化数组
struct dynamicArray* initArray(int Capacity) {

	if (Capacity <= 0) {
		return;

	}
	struct dynamicArray* arr = malloc(sizeof(struct dynamicArray));
	//申请结构体指针
	if (arr)
	{	
		//arr不为空
		
		arr->capacity = Capacity;
		arr->Size = 0;
		arr->addr = malloc(sizeof(void*) * Capacity);
	}
	else
	{
		printf("fail\n");
		return;
	}
	return arr;

}
//插入数据(data)向数组(arr)中的某一个位置(pos)
void insertArray(struct dynamicArray* arr, int pos, void* data) {
	if (arr) {

		if (pos<0 || pos>arr->Size)
		{
			//无效位置,强制尾插
			pos = arr->Size;
		}
	}
	
	if (data == NULL)
	{

	}
	if (arr) {
		if (arr->capacity == arr->Size)
		{
			//如果满空间,申请新空间
			int newCapacity = arr->capacity * 2;

			void** newSpace = malloc(sizeof(void*) * newCapacity);
			//把原空间,拷贝新空间
			if (newSpace)
			{
				memcpy(newSpace, arr->addr, sizeof(void*) * arr->capacity);
				//释放原空间
				free(arr->addr);
				//指向新空间
				arr->addr = newSpace;

				arr->capacity = newCapacity;
				//更新容量
			}
			
		}

		//插入数据到指定位置
		for (int i = arr->Size - 1; i >= pos; i--)
		{

			arr->addr[i + 1] = arr->addr[i];

		}
		arr->addr[pos] = data;

		arr->Size++;//更新大小
	}
}
//遍历数组
void foreachArray(struct dynamicArray* arr,void(*myprint)(void*)){

	if (arr==NULL)
	{

	}
	if (myprint==NULL)
	{

	}
	
	for (int i = 0; i < arr->Size; i++)
	{

		myprint(arr->addr[i]);

	}
	
}
//按照位置删除
void delArray(struct dynamicArray* arr,int pos) {

	if (arr)
	{

	}
	if (pos<0||pos>arr->Size-1)
	{
		return;
	}
	for (int i = pos; i < arr->Size-1; i++)
	{
		arr->addr[i] = arr->addr[i + 1];
	}
	arr->Size--;
}
//按照值删除
void delvalueArray(struct dynamicArray* arr, void* data,int(*myCompare(void*,void*))) {

	if (arr==NULL)
	{

	}
	if (data==NULL)
	{

	}
	for (int i = 0; i < arr->Size-1; i++)
	{
		if (myCompare(arr->addr[i],data))
		{
			delArray(arr, i);
			break;
		}
	}
}
struct Person
{
	char name[32];
	int age;
};
//回调函数
void myprint(void* data) {
	struct Person* p = data;

	printf("%s  %d\n", p->name, p->age);
}
int myCompare(void* data1, void* data2) {
	struct Person *p1 = data1;
	struct Person *p2 = data2;//强转

	return strcmp(p1->name,p2->name)==0 && (p1->age == p2->age);

}
//销毁数组

void desArray(struct dynamicArray* arr) {
	if (arr==NULL)
	{

	}
	//先释放堆区的数组,再释放结构体
	if (arr->addr!=NULL)
	{
		free(arr->addr);
		arr->addr = NULL;
	}

	free(arr);
	arr = NULL;

	printf("end\n");
}
void test01() {

	struct dynamicArray* ARR=initArray(5);

	//初始化数组
	struct Person p1 = { "yi",20 };
	struct Person p2 = { "er",20 };
	struct Person p3 = { "san",20 };
	struct Person p4 = { "si",20 };
	struct Person p5 = { "wu",20 };
	struct Person p6 = { "liu",20 };
	//插入数据前容量 大小
	printf("\n----%d %d\n", ARR->capacity, ARR->Size);
	insertArray(ARR, 0, &p1);
	insertArray(ARR, 1, &p2);
	insertArray(ARR, 2, &p3);
	insertArray(ARR, -1, &p4);
	insertArray(ARR, 3, &p5);
	insertArray(ARR, 4, &p6);
	//插入数据后容量 大小
	printf("\n----%d %d\n", ARR->capacity, ARR->Size);
	foreachArray(ARR, myprint);
	delArray(ARR, 1);//删除“1”位置
	printf("--------------------\n");
	foreachArray(ARR, myprint);
	printf("--------------------\n");
	struct Person p = { "san",20 };
	delvalueArray(ARR,&p,myCompare);
	foreachArray(ARR, myprint);

	desArray(ARR);
}
int main() {
	int a[32] = { 0 };
	test01();


}

5 模板

#include<iostream>
using namespace std;
//函数模板一般格式
/*
template <类型形式参数表> 返回值 函数名(形式参数,...){

	//函数体
}
*/
// template 关键字
// <> 表示模板参数(两种)
//			1.类型参数(class / typedef)
//			2.非类型参数(一般为常数)
// Type 可为int double
template <class Type> 
Type max_us(Type x, Type y) {


	return x > y ? x : y;
}

//数组模板
template <class Type,int len>

Type max_arr(Type arr[len]) {

	Type ret = arr[0];
	for (int i = 1; i < len; i++)
	{
		ret = (arr[i] > ret ? arr[i] : ret);
	}
	return ret;
}
//重载函数模板,实现字符、字符串比较
char* max_us(char* a, char* b) {

	
	if (strcmp(a,b))
	{
		return a;
	}
	else
	{
		return b;
	}
}
//类模板

int main() {
	
	int i = max_us(8, 9);
	double j = max_us(9.1, 10.9);
	
	//歧义
	//显示标识模板
	float k = max_us<float>(8.1f, 3);

	cout << i << endl;
	cout << j << endl;
	cout << k << endl;
	int a[5] = { 1,4,2,9,6 };

	//数组模板使用
	int max_a = max_arr<int, 5>(a);
	cout << max_a << endl;

	cout << "重载模板" << endl;
	cout << max_us('a', 'n') << endl;
	cout << max_us(9, 10) << endl;

	cout << "end" << endl;
	return 0;

}

6 类模板

#include<iostream>
using namespace std;
/*
类模板一般定义形式
template <类型形式参数表> class 类模板名
{
	//函数体
}

类模板成员函数定义形式
template <类型形式参数表>
返回类型 类模板名 <类型名表>::成员函数名(形式参数列表)
{
	//函数体
}

类模板的成员函数定义时的类模板名与类模板定义时要一致,
类模板不是一个真实的类,需要重新生成类,生成类的形式
类模板名 <类型实在参数表>

新生成的类定义对象的形式
类模板名 <类型实在参数表> 对象名
*/

template <class Type>
class Container
{
	Type u;
public:
	
	void begin2(const Type& itnew);//声明函数
};

template <class Type> void Container<Type>::begin2(const Type& p) {
	//函数实现
	u = p;
	cout << u << endl;
}
int main() {
	Container<int> myContainer;//定义对象
	
	int i = 100;
	myContainer.begin2(i);
	
}

7 容器vector

#include<iostream>

#include<vector>

#include<algorithm>
#include<string>
using namespace std;

//vector 容器(存放自定义数据)
class person {
public:

	person(string name, int age) {

		this->name = name;
		this->age = age;
	}
	
	string name;
	int age;

};
void test02() {
	vector<person> vp;

	person p1("a", 10);
	person p2("b", 20);
	person p3("c", 30);
	//向容器添加数据
	vp.push_back(p1);
	vp.push_back(p2);
	vp.push_back(p3);
	//遍历数据
	for (vector<person>::iterator it = vp.begin(); it!= vp.end(); it++) {

		cout << (*it).name << endl;
		cout << (*it).age << endl;
		//cout << it->name << endl;
		
	}

}
void test03() {
	vector<person*> vp;

	person p1("a", 10);
	person p2("b", 20);
	person p3("c", 30);
	//向容器添加数据
	vp.push_back(&p1);
	vp.push_back(&p2);
	vp.push_back(&p3);
	//遍历数据
	for (vector<person*>::iterator it = vp.begin(); it != vp.end(); it++) {

		cout << (*it)->name << endl;
		cout << (*it)->age << endl;
		
	}

}

//vector 容器(数组)
void myprint(int val)
{
	cout << val << endl;
}
void test01() {
	//存放整型数据的容器 varray
	vector<int> varray;

	varray.push_back(10);//向容器中添加数据
	varray.push_back(90);
	varray.push_back(19);
	//通过迭代器访问容器中数据
	vector<int>::iterator itbegin = varray.begin();
	//指向容器第一个数据
	vector<int>::iterator itend = varray.end();
	//指向容器最后一个数据的下一个数据

	while (itbegin!=itend)
	{
		cout << *itbegin << endl;
		itbegin++;
	}
	//遍历2
	for (vector<int>::iterator it = varray.begin(); it != varray.end(); it++) {

		cout << *it << endl;
	}
	//遍历3
	for_each (varray.begin(), varray.end(), myprint);
	
}
int main() {

	//test01();
	/*test02();*/
	test03();
	cout << "----------------" << endl;
}

8 嵌套容器

#include<iostream>

#include<vector>

#include<algorithm>
#include<string>
using namespace std;

void test01() {

	//嵌套容器
	vector<vector<int>> vv;

	vector<int> v1;
	vector<int> v2;
	vector<int> v3;
	for (int i = 0; i < 3; i++)
	{
		v1.push_back(i + 2);
		v2.push_back(i + 3);
		v3.push_back(i + 4);
		//向三个小容器添加数据
	}
	vv.push_back(v1);
	vv.push_back(v2);
	vv.push_back(v3);
	//向大容器添加数据
	for (vector<vector<int>> ::iterator it=vv.begin();it!=vv.end(); it++){
		//遍历大容器

		for (vector<int>::iterator vit = (*it).begin();vit!=(*it).end(); vit++)
		{
			//遍历小容器
			cout << "  "<<*vit ;
		}
		cout << endl;
	}
}
int main() {

	test01();

	return 0;
}

9 new

#include<iostream>
using namespace std;
void fun() {

	int* p = new int(10);
	//p指向堆区变量,初始为10
	cout << *p << endl;
	delete p;
	p = NULL;

}
void funarr() {

	int* p1 = new int[10];
	//p指向堆区数组,大小为10
	for (int i = 0; i < 10; i++)
	{
		p1[i] = i + 100;
	}
	for (int i = 0; i < 10; i++)
	{
		cout << p1[i] << endl;

	}
	//释放数据(如果是数组加上[])
	delete[]p1;
	p1 = NULL;

}
int main() {

	fun();
	cout << "-------------" << endl;

	funarr();
	
	return 0;
}

10 引用&

10.1 指针常量

引用本质是指针常量。

#include<iostream>

using namespace std;
/*
	数据类型 &别名=原名

*/
//函数中引用传参
void swap(int &a,int &b) {
	int temp;
	temp = a;
	a = b;
	b = temp;
	cout << "A=" << a << " B=" << b << endl;
}
//引用做函数返回值

int& test01() {

	int a = 10;
	return a;

}
int& test02() {

	static int a = 16;//存在全局区

	return a;
}
int global = 190;//

int& test03() {

	return global;
}
int main() {

	int a=1;
	int b = 9;
	//创建引用
	int& A = a;//引用必须初始化

	//int& A = b;//初始化后不可更改指向(只能为a的别名)
	cout << A << endl;

	int a1 = 10;
	int b1 = 18;
	swap(a1, b1);//此时函数中的引用形参为形参的别名
	cout << "-----------------" << endl;
	int& ref = test01();
	cout << ref << endl;
	cout << ref << endl;
	//返回局部变量,非法操作,局部变量存在栈区,执行完成后被系统释放
	cout << "-----------------" << endl;
	int gl = test03();
	cout << gl << endl;
	cout << gl << endl;//全局变量

	cout << "-----------------" << endl;
	int& ref02 = test02();
	cout << ref02 << endl;
	cout << ref02 << endl;

	test02() = 1000;//如果函数返回值为引用,函数可以作为[左值]
	cout << ref02 << endl;
	cout << ref02 << endl;
	cout << "-----------------" << endl;
	int e = 10;
	int e2 = 1;

	int* const f = &e;//指针常量,指针是常量,不能更改指向
	cout << *f << endl;
	cout << "-----------------" << endl;
	const int* f2 = &e;//常量指针,常量的指针,值不能更改
	cout << *f2 << endl;
	f2 = &e2;
	cout << *f2 << endl;
	return 0;
}
10.2 常量引用
#include<iostream>

using namespace std;

void test01(const int& a) {

	//常量引用,修饰形参,防止误操作
	//a = 100;//错误,修改了值
	cout << a << endl;
}

int main() {

	int a = 11;

	//int& b = 10;//错误
	const int& b = 10;

	test01(a);

	return 0;
}

11 函数

#include<iostream>

using namespace std;
void test01(int a, int b, int c = 10);
//声明中有默认参数,实现就不能有默认参数
void test01(int a,int b,int c) {

	int sum;
	sum = a + b + c;

	cout << sum << endl;

}
//函数占位参数
//也可以有默认值
void test02(int a,int =10) {

	cout <<"占位测试 "<< a << endl;
}
int main() {

	test01(10, 10);
	test01(10, 10,80);//函数中如果设置默认参数可以少传

	test02(1,0);
	return 0;
}
11.1 函数重载
#include<iostream>

using namespace std;

void func(int& a) {
	cout << "int& a" << endl;
}
void func(const int& a) {
	cout << "const int& a" << endl;
}
int main() {

	int a = 10;

	func(a);

	func(1);
	return 0;
}

12 封装继承多态

12.1 拷贝构造函数
#include<iostream>

using namespace std;

//拷贝构造函数

class Person {

public:
	
	Person(int age) {

		this->cage = age;
		cout << this->cage << endl;
	}
	Person(const Person& p) {
		//拷贝构造函数
		this->cage = p.cage;
		cout << this->cage << endl;
		cout << "拷贝构造函数" << endl;
	}
	~Person() {
		//析构函数
		cout << "析构函数" << endl;
	}

private:
	int cage;
};

void test01() {
	//使用一个初始化的对象初始另一个对象
	Person p1(20);
	Person p2(p1);
}
void test02(Person p) {

}
int main() {

	test01();
	
	return 0;
}
12.2 浅拷贝深拷贝
#include<iostream>
using namespace std;
class MyClass
{
public:
	int cage;
	int *cheight;
	//有参构造函数
	MyClass(int age,int height) {

		this->cheight = new int(height);
		//堆区申请空间
		this->cage = age;
	}
	MyClass(const MyClass& p) {
		//自写拷贝函数
		cage = p.cage;
		//cheight=p.cheight;//编译器默认实现
		cheight = new int(*p.cheight);
	}
	/*如果注释掉自写拷贝函数会出错。
	* 出错原因:堆区重复释放,浅拷贝执行过程。
	* 堆区释放过程,先释放p1此时p1的*cheight指向堆区释放,
	* 接着执行p,因为p的*cheight指向堆区已经释放,所以出错
	* p									p1
	* 【cage】							 【cage】栈
	* 【*cheight】\					/【*cheight】区
	*				【申请的堆区】
	*/
	/*深拷贝
	* p									p1
	* 【cage】							 【cage】
	* 【*cheight】\					 【*cheight】\
	*				【申请的堆区】					【申请的堆区】
	*/
	~MyClass();
};

MyClass::~MyClass()
{
	if (cheight!=NULL)
	{
		delete cheight;
		cheight = NULL;
		
	}
	cout << "执行析构" << endl;
	cout << cheight << endl;
	
}
void test01() {
	MyClass p(10,99);
	MyClass p1(p);//系统默认提供拷贝函数
	std::cout << p.cage << " "<<*p.cheight<<std::endl;
	std::cout << p1.cage << " "<<*p1.cheight<<std::endl;

}
int main() {

	test01();
	return 0;
}

13 初始化列表

14 this

15 友元

16 运算符重载

对已有的运算符进行定义,赋于新功能,适应新类型。

#include<iostream>

using namespace std;

class Person {

public:
	//成员函数重载+号
	
	Person operator+(Person& p) {
		Person temp;
		temp.age = this->age + p.age;

		temp.height = this->height + p.height;

		return temp;
	}
	int age;
	int height;
};
//全局函数重载+号
//Person operator+ (Person& p1,Person& p2) {
//	Person temp;
//	temp.age = p1.age + p2.age;
//	temp.height = p1.height + p2.height;
//
//	return temp;
//}
void test01() {
	Person test;
	Person p1;
	p1.age = 10;
	p1.height = 99;
	Person p2;
	p2.age = 11;
	p2.height = 100;

	test = p1 + p2;
	cout << test.age << " " << test.height << endl;

}
int main() {
	test01();//两种重载方式不能一起使用。
    /*
成员函数重载本质

Person p3=p1.operator+(p2);

全局函数重载本质

Person p3=operator+(p1,p2);
*/
	return 0;
}
#include<iostream>

using namespace std;
class Person {

public:
	int operator()(int a, int b){

		return a + b;
	}
};
void test01() {
	int a = 9;
	int b = 10;
	int temp;
	Person p;
	temp=p(a, b);//重载(),仿函数

	cout<<temp<<endl;

	cout << Person()(a, b) << endl;
	//匿名函数对象
}
int main() {

	test01();
	return 0;
}

17 多态

静态(函数重载、运算符重载)、动态(派生类、虚函数)。

#include<iostream>

using namespace std;
class Animal {

public:
	/*void speak1() {
		cout << "动物speak" << endl;
	}*/
	//虚函数
	virtual void speak1() {
		cout << "动物speak" << endl;
	}
};//父类
//子类继承父类
class cat :public Animal {

public:
	void speak1() {

		cout << "猫speak" << endl;
	}
};
class dog :public Animal {

public://子类重写了父类函数
	//重写:返回值、函数名、参数类型相同
	void speak1() {

		cout << "狗speak" << endl;
	}
};
void dospeak(Animal& animal) {

	animal.speak1();
}
int main() {
	//实现:想让各种类小动物说话
	cat c1;
	dospeak(c1);//我想猫说话,可是实现动物说话
	//如果想实现想让各种类小动物说话,需要虚函数关键字
	/*
	* 动态条件:
	* 有继承关系
	* 子类重写父类虚函数
	* 动态使用:
	* 父类指针或引用,执行类对象
	*/
	dog d1;
	dospeak(d1);//父类指针或引用,执行类对象
	return 0;
}
17.1 多态原理

在父类的虚函数中,虚函数类似指针,会指向一个虚函数表。子类继承父类会把虚函数表重新拷贝一份,所以要在子类中重写虚函数,更改指向。

18 纯虚函数抽象类

#include<iostream>

using namespace std;

class Person {

public:
	virtual void func()=0;
	//纯虚函数
	//只要有一个纯虚函数就是抽象类
	//抽象类不能实例化
	//抽象类的子类必须重写抽象类(父类)的纯虚函数
};

class Son :public Person{

	virtual void func() {

		cout << "Son 类" << endl;
		//抽象类的子类必须重写抽象类(父类)的纯虚函数,否则还是抽象类
	}
};
int main() {
	//Person p;
	//new Person;//抽象类不能实例化
	Person* p = new Son;
	/*
	* 纯虚函数更多提供一个接口,new 不同之类对象,父类指针访问
	*/
	p->func();
	return 0;
}

19 虚析构纯虚析构

#include<iostream>
#include<string>
using namespace std;
//虚析构解决父类指针释放子类对象时不完全
class Person {
public:
	Person() {

		cout<<"Person构造函数"<<endl;
	}
	/*~Person() {

		cout << "Person析构函数" << endl;
	}*/
	virtual ~Person() {

		cout << "Person析构函数" << endl;
	}//父类虚析构

	//virtual ~Person() = 0;纯虚析构


	virtual void speak1() = 0;
	//纯虚函数
};

//纯虚析构实现
//Person::~Person() {
//
//
//}
class son6 :public Person {

public:
	son6(string name) {

		cout << "son有参构造函数" << endl;
		_name = new string(name);//堆区什么时候释放
	}
	virtual void speak1() {

		cout << *_name<<" "<<"son " << endl;
	}
	~son6() {
		if (_name!=NULL)
		{
			cout << "son 堆区释放" << endl;
			delete _name;
			_name = NULL;//堆区释放

		}
	}
	string* _name;
};

void test01() {

	Person* p = new son6("HH");//父类指针,子类对象
	//堆区建立
	p->speak1();
	//父类指针在析构时候,不会调用子类析构函数,会导致子类堆区内存泄露
	//即:son 堆区不能释放(~son6()未执行)
	//解决:父类析构改成虚析构
	delete p;
	//释放

}
int main() {
	
	test01();//多态
	return 0;
}

纯虚析构需要实现

20 模板分文件编写

.hpp .cpp

#pragma once
#include<iostream>
#include<string>
//类与实现写在一起
using namespace std;
//类模板
template<class T1, class T2>

class Person {

public:
	Person(T1 name, T2 age);

	void showPerson();//类外实现成员函数
	T1 mname;
	T2 mage;
};
/*----------------------------------------*/
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {

	this->mname = name;
	this->mage = age;//类外实现构造
}
/*----------------------------------------*/
template<class T1, class T2>
void Person<T1, T2>::showPerson() {

	//类外实现成员函数
	cout << "输出:" << this->mname << " " << this->mage << endl;
}
/*-------------------------------------
#include"practice.hpp"
int main() {

	Person<string, int> obj("Tom", 10);

	obj.showPerson();

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值