关于串的学习

目录

一、定义

二、基本操作

(一)存储结构

(二)初始化

(三)检查空间 

(四)串赋值(把一个字符串常量赋值给顺序串S,成功返回true,否则返回FALSE,赋值前需要判空)

(五)串赋值(将T串赋给S)

(六)取子串(串S中从第pos个位置开始,取长度为len的子串T)

(七)子串定位(串的模式匹配:主串S中查找是否存在和串T值相同的子串,若存在返回true,否则返回false)

(八)插入子串(在第pos个元素之后插入子串)

(九)串连接(将顺序串T连接在顺序串S之后)

(十)删除子串

(十一)求串长

(十二)遍历

三、完整代码

四、完整代码2


一、定义

  • 串是零个或多个任意字符组成的有限序列
  • 串的特点:
  •       串是一种特殊的线性表,数据元素之间呈线性关系
  •       串是数据对象限定为字符集(如中文字符、英文字符、数字字符、标点符号等)
  • 子串:串中任意个连续字符组成的子序列称为该串的子串
  •         例如:"abcde"的子串有:""、"a"、"ab"、"abc"、"abcd"和"abcde"等
  • 真子串:是指不包含自身的所有子串。
  • 主串:包含子串的串相应地称为主串。
  • 字符位置:字符在序列中的序号为该字符在串中的位置。
  • 子串位置:子串的第一个字符在主串中的位置。
  •            例如a='BEI'  b='BEIJING',a在b中的位置是1
  • 空格串:由一个或多个空格组成的串,与空串不同。空串不含有任何字符。
  • 串相等:当且仅当两个串的长度相等并且各个对应位置上的字符都相等时,这两个串才是相等的。但是所有空串是相等的。 
  • 注意:
  • 串是一种线性表。
  • 串和线性表的不同点:
    • 串的数据元素是字符,即每个数据元素都是一个字符。
    • 线性表的操作主要是针对某个数据元素进行的,而串的操作则主要是针对串的整体或某一部分子串进行的 

二、基本操作

(一)存储结构

//静态存储
#define MaxLen 255
typedef struct
{
	char ch[MaxLen];//每个分量存储一个字符
	int length;//串的实际长度
}SString;

//动态存储
typedef struct
{
	char* ch;
	int Length;//实际长度
	int capacity;//最大容量
}SString;

以下操作针对动态存储 

(二)初始化

bool StrInit(SString& S)//初始化
{
	S.ch = NULL;
	S.Length =S.capacity= 0;
	return true;
}

(三)检查空间 

bool Check(SString& S)//检查空间容量
{
	if (S.capacity == S.Length)
	{
		int newcapacity = S.capacity == 0 ? 4 : S.capacity * 2;
		char* temp = (char*)realloc(S.ch, newcapacity * sizeof(char));
		if (temp == 0)
		{
			cout << "开辟空间失败!" << endl;
			exit(-1);
		}
		else
		{
			S.ch = temp;
			S.capacity = newcapacity;
		}
	}
	return true;
}

(四)串赋值(把一个字符串常量赋值给顺序串S,成功返回true,否则返回FALSE,赋值前需要判空)

bool StrAssign(SString& S, char* chars)//一个字符串常量赋值给顺序串S
{
	int i, j;
	char* c;
	for (i = 0, c = chars; *c; i++, c++);//计算一个字符串常量的长度
	if (i == 0)//说明字符串常量是0,就不用给SString开辟空间
		return false;
	else
	{
		Check(S);
		for (j = 0; j < i; j++)
		{
			S.ch[j] = chars[j];
			S.Length = i;
		}
	}
	return true;
}

(五)串赋值(将T串赋给S)

bool StrCopy(SString& S, SString T)
{
	if (S.ch != NULL)//先释放掉原来的空间
	{
		S.ch= NULL;
		free(S.ch);//注意此处虽然free函数进行了动态内存的释放和回收,但实际中未完全释放,S.ch依然会指向
		//动态开辟的空间,而非指向NULL。当第一次使用完空间,如果未退出继续运行代码,再次赋值就会发生错误,
		//只需在free函数前把S.ch进行赋值NULL操作即可
	}
	if (S.Length != 0)
	{
		StrInit(S);
	}
	for (int i = 0; i < T.Length; i++)
	{
		Check(S);
		if (S.ch == NULL)
			return false;
		S.ch[i] = T.ch[i];
		S.Length = T.Length;

	}
	return true;
}

(六)取子串(串S中从第pos个位置开始,取长度为len的子串T)

第一种
bool SubString(SString S, SString &T, int pos, int len)//取子串,此处pos代表元素下标
{
	if (pos<0 || pos>S.Length - 1 || len<0 || len>S.Length - pos)
		return false;
	else
	{
		if (T.ch != NULL)
		{
			T.ch = NULL;
			free(T.ch);
		}
		if (T.Length != 0)
			StrInit(T);
		int i;
		for (i = 0; i < len; i++)
		{
			Check(T);
			T.ch[i] = S.ch[pos + i];
			T.Length = len;
		}
		return true;
	}
	return true;
}


第二种
bool SubString(SString S, SString &T, int pos, int len)//取子串,此处pos代表元素的位置
//串S中从第POS个位置开始,取长度为len的子串T
{
	if (pos<1 || pos>S.Length  || len<0 || len>S.Length - pos+1)
		return false;
	else
	{
		if (T.ch != NULL)
		{
			T.ch = NULL;
			free(T.ch);
		}
		if (T.Length != 0)
			StrInit(T);
		int i;
		for (i = 0; i < len; i++)
		{
			Check(T);
			if (T.ch==NULL)
				return false;
			T.ch[i] = S.ch[pos -1+ i];
			T.Length = len;
		}
		return true;
	}
	return true;
}

(七)子串定位(串的模式匹配:主串S中查找是否存在和串T值相同的子串,若存在返回true,否则返回false)

 

//第一种方式
bool Index(SString S, SString T,int &m)//子串定位
{
	int k = 0;
	int i = k, j = 0;
	while (i<S.Length && j < T.Length)
	{
		if (S.ch[i] == T.ch[j])
		{
			i++;
			j++;
		}
		else
		{
			k++;
			i = k;
			j = 0;
		}
	}
	if (j == T.Length)//子串定位成功后,用m返回T串的第一个字符在S串中的下标
	{
		m = k+1;//因为k表示下标,所有k+1表示子串第一个字符在S串中的位置
		return true;
	}
	else
		return false;

}

//第二种方式
bool Index(SString S, SString T,int &pos)//子串定位
{
	int i = 0, j = 0;
	while (i<S.Length && j < T.Length)
	{
		if (S.ch[i] == T.ch[j])
		{
			i++;
			j++;
		}
		else
		{
			i=i-j+1
			j = 0;
		}
	}
	if (j == T.Length)//子串定位成功后,用m返回T串的第一个字符在S串中的下标
	{
		pos =i-j;//pos=i-T.Length
		return true;
	}
	else
		return false;

}

 

(八)插入子串(在第pos个元素之后插入子串)

 

bool Insert(SString& S, int pos, SString T)//插入子串,pos表示下标
{
	if (pos<0 || pos>S.Length)
		return false;
	if (T.ch != 0)
	{
		//S.ch = (char*)realloc(S.ch, T.Length * sizeof(char));//在S串后增加T.Length个空间
		int i;
		for (i = S.Length - 1; i >= pos; i--)
		{
			Check(S);
			S.ch[i + T.Length] = S.ch[i];//从S串的最后一个字符开始,依次向后移动T.Length长度
		}
		//方法二
		//for (i = 0; i < T.Length; i++) //从下标为pos的字符开始,每个字符向后移动T.Length长度
		//{
		//	S.ch[S.Length-1-i+T.Length]=S.ch[S.Length-1-i]
		//}
		for (i = 0; i < T.Length; i++)
		{
			S.ch[pos + i] = T.ch[i];
		}
		S.Length = S.Length + T.Length;
	}
	return true;
}

(九)串连接(将顺序串T连接在顺序串S之后)

bool StrConcat(SString& S, SString T)//串连接
{
	int i;
	if (T.Length != 0)
	{
		for (i = 0; i < T.Length; i++)
		{
			Check(S);
			S.ch[i + S.Length] = T.ch[i];
		}
		S.Length = S.Length + T.Length;
	}
	return true;

}

(十)删除子串

第一种:pos代表下标
bool StrDel(SString& S, int pos, int len)//删除子串
{
	int i;
	if (pos<0 || pos>S.Length-1 || len<0 || len>S.Length - pos)
		return false;
	else
	{
		for (i = pos + len; i < S.Length; i++)
		{
			S.ch[i - len] = S.ch[i];
		}
		S.ch = (char*)realloc(S.ch, (S.Length - len) * sizeof(char));
		if (S.ch == NULL)return false;
		S.Length = S.Length - len;
		return true;
	}

}

第二种:pos代表元素位置
bool StrDel2(SString& S, int pos, int len)//删除子串
{
	int i;
	if (pos<1 || pos>S.Length || len<0 || len>S.Length - pos+1)
		return false;
	else
	{
		for (i = pos + len-1; i < S.Length; i++)
		{
			S.ch[i - len] = S.ch[i];
		}
		S.ch = (char*)realloc(S.ch, (S.Length - len) * sizeof(char));
		if (S.ch == NULL)return false;
		S.Length = S.Length - len;
		return true;
	}

}

(十一)求串长

int StrLen(SString S)//求串长
{
	return S.Length;
}

(十二)遍历

bool Print(SString S)//打印
{
	for (int i = 0; i < S.Length; i++)
	{
		cout << S.ch[i];
	}
	cout << endl;
	return true;
}

三、完整代码

#pragma once
#include<cstring>
#include<cstdlib>
#include<stdbool.h>
#include<iostream>
using namespace std;
typedef struct
{
	char* ch;
	int Length;//实际长度
	int capacity;//最大容量
}SString;
bool StrInit(SString& S);//初始化
bool StrAssign(SString& S, char* chars);//一个字符串常量赋值给顺序串S
bool Check(SString& S);//检查空间容量
bool StrCopy(SString& S, SString T);//将T串赋给S
bool SubString(SString S, SString& T, int pos, int len);//取子串,此处pos代表元素的位置
//串S中从第pos个位置开始,取长度为len的子串T
bool Index(SString S, SString T, int &m);//子串定位
bool Insert(SString& S, int pos, SString T);//插入子串
bool StrConcat(SString& S, SString T);//串连接
bool StrDel(SString& S, int pos, int len);//删除子串,pos是元素下标
bool StrDel2(SString& S, int pos, int len);//删除子串,pos是元素的位置
int StrLen(SString S);//求串长
bool Print(SString S);//打印
#include"SString1.h"
bool StrInit(SString& S)
{
	S.ch = NULL;
	S.Length = S.capacity = 0;
	return true;
}
bool Check(SString& S)//检查空间容量
{
	if (S.capacity == S.Length)
	{
		int newcapacity = S.capacity == 0 ? 4 : S.capacity * 2;
		char* temp = (char*)realloc(S.ch, newcapacity * sizeof(char));
		if (temp == 0)
		{
			cout << "开辟空间失败!" << endl;
			exit(-1);
		}
		else
		{
			S.ch = temp;
			S.capacity = newcapacity;
		}
	}
	return true;
}
bool StrAssign(SString& S, char* chars)//一个字符串常量赋值给顺序串S
{
	int i, j;
	char* c;
	for (i = 0, c = chars; *c; i++, c++);//计算一个字符串常量的长度
	if (i == 0)//说明字符串常量是0,就不用给SString开辟空间
		return false;
	else
	{
		Check(S);
		for (j = 0; j < i; j++)
		{
			S.ch[j] = chars[j];
			S.Length = i;
		}
	}
	return true;
}

//方法二:将T串赋给S
//bool StrCopy(SString& S, SString T)
//{
//	if (S.ch == NULL)//先释放掉原来的空间
//
//		free(S.ch);
//	if (S.Length != 0)
//	{
//		S.Length = 0;
//		S.ch = NULL;
//	}
//	if (!(S.ch = (char*)malloc(sizeof(char))))
//		return false;
//	else
//	{
//		for (int i = 0; i < T.Length; i++)
//		{
//			S.ch[i] = T.ch[i];
//			S.Length = T.Length;
//		}
//	}
//	return true;
//}

bool StrCopy(SString& S, SString T)
{
	if (S.ch != NULL)//先释放掉原来的空间
	{
		S.ch= NULL;
		free(S.ch);//注意此处虽然free函数进行了动态内存的释放和回收,但实际中未完全释放,S.ch依然会指向
		//动态开辟的空间,而非指向NULL。当第一次使用完空间,如果未退出继续运行代码,再次赋值就会发生错误,
		//只需在free函数前把S.ch进行赋值NULL操作即可
	}
	if (S.Length != 0)
	{
		StrInit(S);
	}
	for (int i = 0; i < T.Length; i++)
	{
		Check(S);
		if (S.ch == NULL)
			return false;
		S.ch[i] = T.ch[i];
		S.Length = T.Length;

	}
	return true;
}

//bool SubString(SString S, SString &T, int pos, int len)//取子串,此处pos代表元素下标
//{
//	if (pos<0 || pos>S.Length - 1 || len<0 || len>S.Length - pos)
//		return false;
//	else
//	{
//		if (T.ch != NULL)
//		{
//			T.ch = NULL;
//			free(T.ch);
//		}
//		if (T.Length != 0)
//			StrInit(T);
//		int i;
//		for (i = 0; i < len; i++)
//		{
//			Check(T);
//			T.ch[i] = S.ch[pos + i];
//			T.Length = len;
//		}
//		return true;
//	}
//	return true;
//}
bool SubString(SString S, SString &T, int pos, int len)//取子串,此处pos代表元素的位置
//串S中从第POS个位置开始,取长度为len的子串T
{
	if (pos<1 || pos>S.Length  || len<0 || len>S.Length - pos+1)
		return false;
	else
	{
		if (T.ch != NULL)
		{
			T.ch = NULL;
			free(T.ch);
		}
		if (T.Length != 0)
			StrInit(T);
		int i;
		for (i = 0; i < len; i++)
		{
			Check(T);
			if (T.ch==NULL)
				return false;
			T.ch[i] = S.ch[pos -1+ i];
			T.Length = len;
		}
		return true;
	}
	return true;
}
bool Index(SString S, SString T,int &m)//子串定位
{
	int k = 0;
	int i = k, j = 0;
	while (i<S.Length && j < T.Length)
	{
		if (S.ch[i] == T.ch[j])
		{
			i++;
			j++;
		}
		else
		{
			k++;
			i = k;
			j = 0;
		}
	}
	if (j == T.Length)//子串定位成功后,用m返回T串的第一个字符在S串中的下标
	{
		m = k+1;//因为k表示下标,所有k+1表示子串第一个字符在S串中的位置
		return true;
	}
	else
		return false;

}
bool Insert(SString& S, int pos, SString T)//插入子串,pos表示下标
{
	if (pos<0 || pos>S.Length)
		return false;
	if (T.ch != 0)
	{
		//S.ch = (char*)realloc(S.ch, T.Length * sizeof(char));//在S串后增加T.Length个空间
		int i;
		for (i = S.Length - 1; i >= pos; i--)
		{
			Check(S);
			S.ch[i + T.Length] = S.ch[i];//从S串的最后一个字符开始,依次向后移动T.Length长度
		}
		//方法二
		//for (i = 0; i < T.Length; i++) //从下标为pos的字符开始,每个字符向后移动T.Length长度
		//{
		//	S.ch[S.Length-1-i+T.Length]=S.ch[S.Length-1-i]
		//}
		for (i = 0; i < T.Length; i++)
		{
			S.ch[pos + i] = T.ch[i];
		}
		S.Length = S.Length + T.Length;
	}
	return true;
}
bool StrConcat(SString& S, SString T)//串连接
{
	int i;
	if (T.Length != 0)
	{
		for (i = 0; i < T.Length; i++)
		{
			Check(S);
			S.ch[i + S.Length] = T.ch[i];
		}
		S.Length = S.Length + T.Length;
	}
	return true;

}
bool StrDel(SString& S, int pos, int len)//删除子串
{
	int i;
	if (pos<0 || pos>S.Length-1 || len<0 || len>S.Length - pos)
		return false;
	else
	{
		for (i = pos + len; i < S.Length; i++)
		{
			S.ch[i - len] = S.ch[i];
		}
		S.ch = (char*)realloc(S.ch, (S.Length - len) * sizeof(char));
		if (S.ch == NULL)return false;
		S.Length = S.Length - len;
		return true;
	}

}

bool StrDel2(SString& S, int pos, int len)//删除子串
{
	int i;
	if (pos<1 || pos>S.Length || len<0 || len>S.Length - pos+1)
		return false;
	else
	{
		for (i = pos + len-1; i < S.Length; i++)
		{
			S.ch[i - len] = S.ch[i];
		}
		S.ch = (char*)realloc(S.ch, (S.Length - len) * sizeof(char));
		if (S.ch == NULL)return false;
		S.Length = S.Length - len;
		return true;
	}

}

int StrLen(SString S)//求串长
{
	return S.Length;
}
bool Print(SString S)//打印
{
	for (int i = 0; i < S.Length; i++)
	{
		cout << S.ch[i];
	}
	cout << endl;
	return true;
}
#include"SString1.h"
int main()
{

	SString S1;
	SString S2;
	StrInit(S1);
	StrInit(S2);
	char a[] = "qwertyabcduiop";
	char b[] = "abcd";
	StrAssign(S1, a);//一个字符串常量赋值给顺序串S
	cout << StrLen(S1) << endl;
	Print(S1);
	StrAssign(S2, b);

	StrCopy(S1, S2);//将T串赋给S
	Print(S1);

	SubString(S1, S2, 1, 4);//取子串,此处pos代表元素的位置
	Print(S1);
	Print(S2);

	StrConcat(S1, S2);//串连接
	Print(S1);

	Insert(S1, 3, S2);//插入子串
	Print(S1);


	int M;
	Index(S1, S2, M);//子串定位
	cout << M << endl;
	Print(S1);


	//删除子串,pos是元素的位置
	SString S3;
	S3.ch = (char*)malloc(15 * sizeof(char));
	int j = 0;
	int i = 14;
	for (j = 0; j < i; j++)
	{
		S3.ch[j] = a[j];
		S3.Length = i;
	}
	Print(S3);
	StrDel2(S3, 3, 4);
	Print(S3);
	return 0;
}

四、完整代码2

#pragma once
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<malloc.h>
using namespace std;
typedef struct {
    char* ch;                  // 先存放非空串的首地址,不分配内存
    int Length;                  // 存放串的当前长度
}SString;                    

bool StrInit(SString& S);//初始化
bool StrAssign(SString& S, char* chars);//一个字符串常量赋值给顺序串S
bool StrCopy(SString& S, SString T);//将T串拷贝给S串
bool SubString(SString S, SString& T, int pos, int len);//取子串,此处pos代表元素下标
bool SubString2(SString S, SString& T, int pos, int len);//取子串,此处pos代表元素的位置
//串S中从第POS个位置开始,取长度为len的子串T
bool Index(SString S, SString T, int& pos);//子串定位
bool Insert(SString& S, int pos, SString T);//插入子串,pos表示下标
int StrLen(SString S);//求串长
bool Print(SString S);//打印

#include"SString.h"
bool StrInit(SString& S)//初始化
{
	S.ch = NULL;
	S.Length = 0;
	return true;
}

bool StrAssign(SString& S, char* chars)//一个字符串常量赋值给顺序串S
{
	int i, j;
	char* c;
	for (i = 0, c = chars; *c; i++, c++);//计算一个字符串常量的长度
	if (i == 0)//说明字符串常量是0,就不用给SString开辟空间
		return false;
	else
	{
		S.ch = (char*)malloc(i * sizeof(char));//申请空间
		if (S.ch == NULL)
		{
			exit(0);
		}
		for (j = 0; j < i; j++)
		{
			S.ch[j] = chars[j];
			S.Length = i;
		}
	}
	return true;
}

bool StrCopy(SString& S, SString T)//将T串拷贝给S串
{
	if (S.ch != NULL)//先释放掉原来的空间
	{
		S.ch = NULL;
		free(S.ch);//注意此处虽然free函数进行了动态内存的释放和回收,但实际中未完全释放,S.ch依然会指向
		//动态开辟的空间,而非指向NULL。当第一次使用完空间,如果未退出继续运行代码,再次赋值就会发生错误,
		//只需在free函数前把S.ch进行赋值NULL操作即可
	}
	if (S.Length != 0)
	{
		StrInit(S);
	}
	for (int i = 0; i < T.Length; i++)
	{
		S.ch = (char*)malloc(T.Length * sizeof(char));
		if (S.ch == NULL)
			return false;
		S.ch[i] = T.ch[i];
		S.Length = T.Length;

	}
	return true;
}


bool SubString(SString S, SString& T, int pos, int len)//取子串,此处pos代表元素下标
{
	if (pos<0 || pos>S.Length - 1 || len<0 || len>S.Length - pos)
		return false;
	else
	{
		if (T.ch != NULL)
		{
			T.ch = NULL;
			free(T.ch);
		}
		if (T.Length != 0)
			StrInit(T);
		int i;
		T.ch = (char*)malloc(len * sizeof(char));
		if (T.ch == NULL)
			return false;
		for (i = 0; i < len; i++)
		{
			T.ch[i] = S.ch[pos + i];
			T.Length = len;
		}
		return true;
	}
	return true;
}



//第二种
bool SubString2(SString S, SString& T, int pos, int len)//取子串,此处pos代表元素的位置
//串S中从第POS个位置开始,取长度为len的子串T
{
	if (pos<1 || pos>S.Length || len<0 || len>S.Length - pos + 1)
		return false;
	else
	{
		if (T.ch != NULL)
		{
			T.ch = NULL;
			free(T.ch);
		}
		if (T.Length != 0)
			StrInit(T);
		int i;
		T.ch = (char*)malloc(len * sizeof(char));
		for (i = 0; i < len; i++)
		{
			if (T.ch == NULL)
				return false;
			T.ch[i] = S.ch[pos - 1 + i];
			T.Length = len;
		}
		return true;
	}
	return true;
}

bool Index(SString S, SString T, int& pos)//子串定位
{
	int i = 0, j = 0;
	while (i < S.Length && j < T.Length)
	{
		if (S.ch[i] == T.ch[j])
		{
			i++;
			j++;
		}
		else
		{
			i = i - j + 1;
				j = 0;
		}
	}
	if (j == T.Length)//子串定位成功后,用m返回T串的第一个字符在S串中的下标
	{
		pos = i - j;//pos=i-T.Length
		return true;
	}
	else
		return false;

}


bool Insert(SString& S, int pos, SString T)//插入子串,pos表示下标
{
	if (pos<0 || pos>S.Length)
		return false;
	if (T.ch != 0)
	{
		S.ch = (char*)realloc(S.ch, (S.Length + T.Length) * sizeof(char));//在S串后增加T.Length个空间
		int i;
		for (i = S.Length - 1; i >= pos; i--)
		{
			S.ch[i + T.Length] = S.ch[i];//从S串的最后一个字符开始,依次向后移动T.Length长度
		}
		//方法二
		//for (i = 0; i < T.Length; i++) //从下标为pos的字符开始,每个字符向后移动T.Length长度
		//{
		//	S.ch[S.Length-1-i+T.Length]=S.ch[S.Length-1-i]
		//}
		for (i = 0; i < T.Length; i++)
		{
			S.ch[pos + i] = T.ch[i];
		}
		S.Length = S.Length + T.Length;
	}
	return true;
}

bool StrConcat(SString& S, SString T)//串连接
{
	int i;
	if (T.Length != 0)
	{
		S.ch = (char*)realloc(S.ch,(S.Length + T.Length) * sizeof(char));
		if (S.ch == NULL)
			return false;
		for (i = 0; i < T.Length; i++)
		{
			S.ch[i + S.Length] = T.ch[i];
		}
		S.Length = S.Length + T.Length;
	}
	return true;

}

int StrLen(SString S)//求串长
{
	return S.Length;
}

bool Print(SString S)//打印
{
	for (int i = 0; i < S.Length; i++)
	{
		cout << S.ch[i];
	}
	cout << endl;
	return true;
}
#include"SString.h"
int main()
{
	SString S1;
	SString S2;
	StrInit(S1);
	StrInit(S2);
	char a[] = "qwertyabcduiop";
	char b[] = "abcd";
	StrAssign(S1, a);//一个字符串常量赋值给顺序串S
	cout << StrLen(S1) << endl;
	Print(S1);

	SubString(S1, S2, 3, 5);
	Print(S2);
	return 0;

}

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值