详解C++中string类

前言

string是C++标准库的一个重要的部分,主要用于字符串处理。这篇文章主要介绍了C++ string的用法和例子,需要的朋友可以参考下。

首先,做一个总结,string主要用于字符串处理,对于字符串操作,有以下几点需要解决:

  1. 如何创建字符串对象,创建字符串的方法
  2. 如何获取字符串的长度、判断一个字符串是否为空清空字符串
  3. 如何获取字符串内的单个字符
  4. 如何在字符串后添加新的字符串或字符
  5. 如何在字符串中间任何位置插入新的字符串或字符
  6. 如何删除字符串中某一段字符串或字符
  7. 如何用新的字符串或字符替换原字符串中某一段字符串或字符
  8. 如何交换两个字符串的内容
  9. 如何在原字符串中查找是否存在某字符串或某些字符
  10. 如何获得字符串中的某个子字符串或字符
  11. 如何比较两个字符串是否相同
  12. 如何实现对多个字符串的拼接
  13. 如何从用户输入处获得字符串,如何输出字符串
  14. 如何将string类字符串转换为C语言中的字符串数组

解决以上问题对应的函数:

  1. 创建: = () assign
  2. 长度 : length size是否为空: empty清空: clear
  3. 获取单个字符: [] at
  4. 添加: += append
  5. 插入: insert
  6. 删除: erase
  7. 替换: replace
  8. 交换: swap
  9. 查找: find rfind find_first_of find_last_of find_first_not_of find_last_not_of
  10. 子字符串或字符: substr
  11. 比较: relational operators compare
  12. 拼接: +
  13. 输入、输出: << >> getline
  14. c_str data

Member functions

构造字符串对象:

// string constructor
#include <iostream>
#include <string>
using namespace std;

int main ()
{
	string s0 ("Initial string");
	string s1;
	string s2 (s0);
	string s3 (s0, 8, 3);
	string s4 ("A character sequence");
	string s5 ("Another character sequence", 12);
	string s6a (10, 'x');
	string s6b (10, 42);      // 42 is the ASCII code for '*'
	string s7 (s0.begin(), s0.begin()+7);

	cout << "s1: " << s1 << "\ns2: " << s2 << "\ns3: " << s3;
	cout << "\ns4: " << s4 << "\ns5: " << s5 << "\ns6a: " << s6a;
 	cout << "\ns6b: " << s6b << "\ns7: " << s7 << '\n';
  	return 0;
}

▌01. Iterators

FunctionExplanation
begin函数返回一个迭代器,指向字符串的第一个元素
end函数返回一个迭代器,指向字符串的末尾(最后一个字符的下一个位置)
rbegin函数返回一个逆向迭代器,指向字符串的最后一个字符
rend函数返回一个逆向迭代器,指向字符串的开头(第一个字符的前一个位置)
#include <iostream>
#include <string>
using namespace std;

int main()
{
	string str1 ("Test string");
	string str2 ("now step live...");
	string::iterator it;			//定义正向迭代器
	string::reverse_iterator rit;	//定义逆向迭代器
	
	//用正向迭代器遍历容器
	for(it=str1.begin(); it!=str1.end(); it++)	
	{
		cout << *it;		//*it 就是迭代器it指向的元素
	}
	cout << endl;
	
	//用逆向迭代器遍历容器
	for(rit=str2.rbegin(); rit!=str2.rend(); rit++)	
	{
		cout << *rit;		//*rit 就是迭代器rit指向的元素
	}
	cout << endl;
	return 0;
}

输出结果:

Test string
...evil pets won

▌02. Capacity

FunctionExplanation
size or length返回源字符串的长度大小
max_size返回string对象中可存放的最大字符串的长度
capacity返回string分配的存储容量
resize调整源字符串的长度
reserve重新给源字符串分配存储容量
clear删除字符串的内容,该字符串将变为空字符串(长度为0个字符)
empty判断源字符串是否为空
#include <iostream>
#include <string>
using namespace std;

int main()
{
	string str1 ("Test string");
	
	//1. 返回源字符串的长度大小
	cout << "size: " << str1.size() << "\n";
	cout << "length: " << str1.length() << "\n";
	
	//2. 返回string对象中可存放的最大字符串的长度
	cout << "max_size: " << str1.max_size() << "\n";
	
	//3. 返回string分配的存储容量
	cout << "capacity: " << str1.capacity() << "\n\n";
	
	//4. 调整源字符串的长度
	string str2 ("I like to code in C");
	cout << str2 << "\n";
	//4.1 void resize (size_t n, char c);  调整字符串长度为n,并用字符c填充不足的部分 。
	unsigned sz = str2.size();
	str2.resize (sz+2,'+');
	cout << str2 << "\n";
	//4.2 void resize (size_t n);  调整源字符串的长度为n。
	str2.resize (14);
	cout << str2 << "\n\n\n";
	
	//5. 重新给源字符串分配存储容量
	//   void reserve (size_t n = 0);
	string str ("Test string");
	
    cout<<"调用str.reserve(size_t n=0);之前:"<<endl;
    cout<<"capacity: "<<str.capacity()<<endl;
    cout<<"max_size: "<<str.max_size()<<endl;
    cout<<"size: "<<str.size()<<endl;
    cout<<"length: "<<str.length()<<endl;
    cout<<endl;

    str.reserve(50);//string增加容量时,每次增加16的倍数,
    cout<<"str.reserve(50);之后:str.capacity()=16*4-1"<<endl;
    cout<<"capacity: "<<str.capacity()<<endl;//16*4-1
    cout<<"max_size: "<<str.max_size()<<endl;
    cout<<"size: "<<str.size()<<endl;
    cout<<"length: "<<str.length()<<endl;
    cout<<endl;

    str.reserve(100);//string增加容量时,每次增加16的倍数
    cout<<"str.reserve(100);之后:str.capacity()=16*7-1"<<endl;
    cout<<"capacity: "<<str.capacity()<<endl;
    cout<<"max_size: "<<str.max_size()<<endl;//16*7-1
    cout<<"size: "<<str.size()<<endl;
    cout<<"length: "<<str.length()<<endl;
    cout<<endl;
  
	return 0;
}

输出结果:

size: 11
length: 11
max_size: 1073741820
capacity: 11

I like to code in C
I like to code in C++
I like to code


调用str.reserve(size_t n=0);之前:
capacity: 11
max_size: 1073741820
size: 11
length: 11

str.reserve(50);之后:str.capacity()=16*4-1
capacity: 50
max_size: 1073741820
size: 11
length: 11

str.reserve(100);之后:str.capacity()=16*7-1
capacity: 100
max_size: 1073741820
size: 11
length: 11

▌03. Element access

FunctionExplanation
operator[]返回对字符串中位置pos处的字符的引用
at返回对字符串中位置pos处的字符的引用
#include <iostream>
#include <string>
using namespace std;

int main()
{
	string str ("Test string");
  	for (int i=0; i<str.length(); i++)
  	{
		cout << str[i];
  	}
  	
  	cout << endl;
  	
  	for (unsigned i=0; i<str.length(); ++i)
  	{
		cout << str.at(i);
  	}
  	return 0;
}

输出结果:

Test string
Test string

▌04. Modifiers

FunctionExplanation
operator+=Append to string
appendAppend to string
push_back字符串之后插入一个字符
assign可以理解为先将原字符串清空,然后赋予新的值作替换
insert插入操作
erase删除操作
replace替换操作
swap交换操作

4.1 append & push_back

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

int main ()
{
	string str;
	string str2="Writing ";
	string str3="print 10 and then 5 more";
	
	// used in the same order as described above:
	str.append(str2);                       // "Writing "
	str.append(str3,6,3);                   // "10 "
	str.append("dots are cool",5);          // "dots "
	str.append("here: ");                   // "here: "
	str.append(10u,'.');                    // ".........."
	str.append(str3.begin()+8,str3.end());  // " and then 5 more"
	str.append<int>(5,0x2E);                // "....."
	str.push_back('E')						// 'E'
	
	cout << str << '\n';
	return 0;
}

Output:

Writing 10 dots here: .......... and then 5 more.....E

4.2 assign

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

int main ()
{
	string str;
	string base="The quick brown fox jumps over a lazy dog.";
	
	str.assign(base);
	cout << str << '\n';
	
	str.assign(base,10,9);
	cout << str << '\n';         // "brown fox"
	
	str.assign("pangrams are cool",7);
	cout << str << '\n';         // "pangram"
	
	str.assign("c-string");
	cout << str << '\n';         // "c-string"
	
	str.assign(10,'*');
	cout << str << '\n';         // "**********"
	
	str.assign<int>(10,0x2D);
	cout << str << '\n';         // "----------"
	
	str.assign(base.begin()+16,base.end()-12);
	cout << str << '\n';         // "fox jumps over"
	
	return 0;
}

Output:

The quick brown fox jumps over a lazy dog.
brown fox
pangram
c-string
**********
----------
fox jumps over

4.3 insert

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

int main ()
{
	string str="to be question";
	string str2="the ";
	string str3="or not to be";
	string::iterator it;
	
	str.insert(6,str2);                 // to be (the )question							s.insert(pos,str) 				在s的pos位置插入str
	str.insert(6,str3,3,4);             // to be (not )the question						s.insert(pos,str,a,n)			在s的pos位置插入str中插入位置a到后面的n个字符
	str.insert(10,"that is cool",8);    // to be not (that is )the question				s.insert(pos,cstr,n)			在pos位置插入cstr字符串从开始到后面的n个字符
	str.insert(10,"to be ");            // to be not (to be )that is the question		s.insert(pos,cstr)				在s的pos位置插入cstr
	str.insert(15,1,':');               // to be not to be(:) that is the question		s.insert(pos,n,ch)				在s.pos位置上面插入n个ch
	it = str.insert(str.begin()+5,','); // to be(,) not to be: that is the question		s.insert(s.it,ch)				在s的it指向位置前面插入一个字符ch,返回新插入的位置的迭代器
	str.insert (str.end(),3,'.');       // to be, not to be: that is the question(...)	s.insert(s.it,n,ch)				在s的it所指向位置的前面插入n个ch
	str.insert (it+2,str3.begin(),str3.begin()+3); // (or )								s.insert(it,str.ita,str.itb)	在it所指向的位置的前面插入[ita,itb)的字符串

	cout << str << '\n';
	return 0;
}

Output:

to be, or not to be: that is the question...

4.4 erase

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

int main ()
{
	string str ("This is an example sentence.");
	cout << str << '\n';
                                         		// "This is an example sentence."
	str.erase (10,8);                        	//            ^^^^^^^^				直接指定删除的字符串位置第十个后面的8个字符
	cout << str << '\n';
	                                         	// "This is an sentence."
	str.erase (str.begin()+9);               	//           ^						删除迭代器指向的字符
	cout << str << '\n';
	                                         	// "This is a sentence."
	str.erase (str.begin()+5, str.end()-9);  	//       ^^^^^						删除迭代器范围的字符
	cout << str << '\n';
	                                         	// "This sentence."
	return 0;
}

4.5 replace

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

int main ()
{
	string base="this is a test string.";
	string str2="n example";
	string str3="sample phrase";
	string str4="useful.";
		
	// Using positions:                 0123456789*123456789*12345
	string str=base;           		// "this is a test string."
	str.replace(9,5,str2);          // "this is an example string." (1)
	str.replace(19,6,str3,7,6);     // "this is an example phrase." (2)
	str.replace(8,10,"just a");     // "this is just a phrase."     (3)
	str.replace(8,6,"a shorty",7);  // "this is a short phrase."    (4)
	str.replace(22,1,3,'!');        // "this is a short phrase!!!"  (5)
	
	// Using iterators:                                               0123456789*123456789*
	str.replace(str.begin(),str.end()-3,str3);                    // "sample phrase!!!"      (1)
	str.replace(str.begin(),str.begin()+6,"replace");             // "replace phrase!!!"     (3)
	str.replace(str.begin()+8,str.begin()+14,"is coolness",7);    // "replace is cool!!!"    (4)
	str.replace(str.begin()+12,str.end()-4,4,'o');                // "replace is cooool!!!"  (5)
	str.replace(str.begin()+11,str.end(),str4.begin(),str4.end());// "replace is useful."    (6)
	cout << str << '\n';
	return 0;
}

4.6 swap

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

main ()
{
	string buyer ("money");
	string seller ("goods");
	
	cout << "Before the swap, buyer has " << buyer;
	cout << " and seller has " << seller << '\n';
	
	seller.swap (buyer);
	
	cout << " After the swap, buyer has " << buyer;
	cout << " and seller has " << seller << '\n';
	
	return 0;
}

Output:

Before the swap, buyer has money and seller has goods
 After the swap, buyer has goods and seller has money

▌05. String operations

FunctionExplanation
get_allocator返回本字符串的配置器
c_str or data返回一个指向正规C字符串的指针常量, 内容与本string串相同
copy将string对象的当前值的子字符串复制到s所指的数组中
find查找字符串中的内容
rfind查找字符串中最后出现的内容, 返回的位置仍然是从前往后数的
find_first_of在字符串中搜索与参数中指定的任何字符匹配的第一个字符
find_last_of从字符串末尾查找字符
find_first_not_of查找字符串中缺少字符
find_last_not_of从字符串末尾查找不匹配的字符
substr生成子字符串
compare比较字符串

5.1 c_str & data

const char* c_str() const;
const char* data() const;

  c_str()函数返回一个指向正规C字符串的指针常量, 内容与本string串相同。这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把 string 对象转换成c中的字符串样式。
注意: 一定要使用strcpy()函数 等来操作方法c_str()返回的指针
不要这样:

char* c; 
string s="1234"; 
c = s.c_str(); 

这样操作:

char c[20]; 
string s="1234"; 
strcpy(c, s.c_str()); 

c_str()data() 的区别:
 1. 从C++标准上的解释来看,只有一点区别
  c_str() 返回一个指向正规C字符串的指针常量,该指针保证指向一个 size() + 1 长度的空间,而且最后一个字符肯定是 \0
  而 data() 返回的指针则保证指向一个size()长度的空间,不保证有没有null-terminate,可能有,可能没有,看库的实现了。
 2. 有的STL的实现中,二者是完全一样的,如vs7.1,两个函数的源码中,data()函数内部调用的是c_str()

5.2 copy

size_t copy (char* s, size_t len, size_t pos = 0) const;

  将string对象的当前值的子字符串复制到s所指的数组中。此子字符串包含从位置pos开始的len字符。函数不会在复制内容的末尾附加空字符

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

int main ()
{
	char buffer[20];
	string str ("Test string...");
	size_t length = str.copy(buffer,6,5);
	buffer[length]='\0';
	cout << "buffer contains: " << buffer << '\n';
	return 0;
}

Output:

buffer contains: string

5.3 find & rfind

  find函数主要是查找一个字符串是否在调用的字符串中出现过,大小写敏感rfind函数就是找最后一个出现的匹配字符串,返回的位置仍然是从前往后数的。下面以find为例:

size_t find (const string& str, size_t pos = 0) const;
size_t find (const char* s, size_t pos = 0) const;
size_t find (const char* s, size_t pos, size_t n) const;
size_t find (char c, size_t pos = 0) const;

size_t rfind (const string& str, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos, size_t n) const;
size_t rfind (char c, size_t pos = npos) const;

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

int main()
{
	string str ("There are two needles in this haystack with needles.");
	string str2 ("needle");

	//1. 在str当中查找第一个出现的needle,找到则返回出现的位置,否则返回结尾	size_t find (const string& str, size_t pos = 0) const;
	size_t found = str.find(str2);
	if (found != string::npos)
	cout << "first 'needle' found at: " << found << '\n';
	
	//2. 在str当中,从第found+1的位置开始查找参数字符串的前6个字符			size_t find (const char* s, size_t pos, size_t n) const;
	found=str.find("needles are small",found+1,6);
	if (found != string::npos)
	cout << "second 'needle' found at: " << found << '\n';
	
	//3. 在str当中查找参数中的字符串											size_t find (const char* s, size_t pos = 0) const;
	found=str.find("haystack");
	if (found != string::npos)
	cout << "'haystack' also found at: " << found << '\n';
	
	//4. 查找一个字符														size_t find (char c, size_t pos = 0) const;
	found=str.find('.');
	if (found != string::npos)
	cout << "Period found at: " << found << '\n';
	
	//5. 组合使用,把str2用参数表中的字符串代替, let's replace the first needle:
	str.replace(str.find(str2),str2.length(),"preposition");
	cout << str << '\n';
	
	return 0;
}

Output:

first 'needle' found at: 14
second 'needle' found at: 44
'haystack' also found at: 30
Period found at: 51
There are two prepositions in this haystack with needles.

5.4 find_first_of   find_last_of   find_first_not_of   find_last_not_of

  在字符串中搜索与参数中指定的任何字符(不)匹配的第一个(或最后一个)字符调用格式find or rfind(四种调用格式)。

1) find_first_of

// string::find_first_of
#include <iostream>       // std::cout
#include <string>         // std::string
#include <cstddef>        // std::size_t
using namespace std;

int main ()
{
	string str ("Please, replace the vowels in this sentence by asterisks.");
	size_t found = str.find_first_of("aeiou");
	while (found != string::npos)
	{
		str[found]='*';
		found=str.find_first_of("aeiou",found+1);
	}
	
	cout << str << '\n';

	return 0;
}
//输出:Pl**s*, r*pl*c* th* v*w*ls *n th*s s*nt*nc* by *st*r*sks.

2) find_last_of : 分离文件路径与文件名称

// string::find_last_of
#include <iostream>       // std::cout
#include <string>         // std::string
#include <cstddef>         // std::size_t
using namespace std;

void SplitFilename (const string& str)
{
	cout << "Splitting: " << str << '\n';
	size_t found = str.find_last_of("/\\");
	cout << " path: " << str.substr(0,found) << '\n';
	cout << " file: " << str.substr(found+1) << '\n';
}

int main ()
{
	string str1 ("/usr/bin/man");
	string str2 ("c:\\windows\\winhelp.exe");
	
	SplitFilename (str1);
	SplitFilename (str2);
	
	return 0;
}

/*output:
Splitting: /usr/bin/man
 path: /usr/bin
 file: man
Splitting: c:\windows\winhelp.exe
 path: c:\windows
 file: winhelp.exe
 */

3) find_first_not_of

// string::find_first_not_of
#include <iostream>       // std::cout
#include <string>         // std::string
#include <cstddef>        // std::size_t
using namespace std;

int main ()
{
	string str ("look for non-alphabetic characters...");
	
	size_t found = str.find_first_not_of("abcdefghijklmnopqrstuvwxyz ");
	
	if (found != string::npos)
	{
		cout << "The first non-alphabetic character is " << str[found];
		cout << " at position " << found << '\n';
	}
	
	return 0;
}

//The first non-alphabetic character is - at position 12

4) find_first_not_of: 去除一段话末尾的回车、空格等字符。

// string::find_last_not_of
#include <iostream>       // std::cout
#include <string>         // std::string
#include <cstddef>        // std::size_t
using namespace std;

int main ()
{
	string str ("Please, erase trailing white-spaces   \n");
	string whitespaces (" \t\f\v\n\r");

	size_t found = str.find_last_not_of(whitespaces);
	if (found != string::npos)
		str.erase(found+1);
	else
		str.clear();            // str is all whitespace

	cout << '[' << str << "]\n";

	return 0;
}

// [Please, erase trailing white-spaces]

5.5 substr

string substr (size_t pos = 0, size_t len = npos) const;

注意: substr没有迭代器作为参数的操作,如果输入的位置超过字符的长度,会抛出一个out_of_range的异常。

// string::substr
#include <iostream>
#include <string>
using namespace std;

int main ()
{
	string str="We think in generalities, but we live in details.";
	string str2 = str.substr (3,5);     // "think"
	size_t pos = str.find("live");      // position of "live" in str
	string str3 = str.substr (pos);     // get from "live" to the end
	cout << str2 << ' ' << str3 << '\n';
	
	return 0;
}
// think live in details.

5.6 compare

  和strcmp函数一样,如果两个字符串相等,那么返回0,调用对象大于参数返回>0,小于返回<0。在compare当中还支持部分比较,里面有6个参数可以设置,6个参数的配置见cplusplus.com

valuestr1.compare(str2)
0两个字符串相等
<0在比较字符串中,str1 < str2 (第一个不匹配的字符的值较小,或者所有比较字符都匹配,但比较字符串较短)
>0在比较字符串中,str1 > str2 (第一个不匹配字符的值较较大,或者所有比较字符都匹配,但比较字符串较长)
#include <iostream>
#include <string>
using namespace std;

int main ()
{
	string str1 ("green apple");
	string str2 ("red apple");
	
	cout << str1.compare("green") << endl;				//6,  >0
	cout << str1.compare("green apple 0") << endl;		//-2, <0
	cout << str1.compare("green apple") << endl;		//0,  =0

	if (str1.compare(str2) != 0)
		cout << str1 << " is not " << str2 << '\n';
	
	if (str1.compare(6,5,"apple") == 0)
		cout << "still, " << str1 << " is an apple\n";
	
	if (str2.compare(str2.size()-5,5,"apple") == 0)
		cout << "and " << str2 << " is also an apple\n";
	
	if (str1.compare(6,5,str2,4,5) == 0)
		cout << "therefore, both are apples\n";
	
	return 0;
}

output:

6
-2
0
green apple is not red apple
still, green apple is an apple
and red apple is also an apple
therefore, both are apples

Member constants

▌01. npos

表示size_t的最大值(Maximum value for size_t
static const size_t npos = -1;

  1. 如果作为一个返回值(return value)表示没有找到匹配项
  2. 但是string::npos作为string的成员函数的一个长度参数时,表示“直到字符串结束(until the end of the string)”。

详见:string::npos的一些说明


Non-member function overloads

FunctionExplanation
operator+Concatenate strings (function )
relational operatorsRelational operators for string (function )
swapExchanges the values of two strings (function )
operator>>Extract string from stream (function )
operator<<Insert string into stream (function )
getlineGet line from stream into string (function )

▌01. operator+

// concatenating strings
#include <iostream>
#include <string>
using namespace std;

int main ()
{
	string firstlevel ("com");
	string secondlevel ("cplusplus");
	string scheme ("http://");
	string hostname;
	string url;

	hostname = "www." + secondlevel + '.' + firstlevel;
	url = scheme + hostname;

	cout << url << '\n';

	return 0;
}
// http://www.cplusplus.com

▌02. relational operators

// string comparisons
#include <iostream>
#include <string>
using namespace std;

int main ()
{
	string foo = "alpha";
	string bar = "beta";

	if (foo==bar) std::cout << "foo and bar are equal\n";
	if (foo!=bar) std::cout << "foo and bar are not equal\n";
	if (foo< bar) std::cout << "foo is less than bar\n";
	if (foo> bar) std::cout << "foo is greater than bar\n";
	if (foo<=bar) std::cout << "foo is less than or equal to bar\n";
	if (foo>=bar) std::cout << "foo is greater than or equal to bar\n";
	
	return 0;
}

/*output:
foo and bar are not equal
foo is less than bar
foo is less than or equal to bar
*/

▌03. swap

// swap strings
#include <iostream>
#include <string>
using namespace std;

int main ()
{
	string buyer ("money");
	string seller ("goods");
	
	cout << "Before the swap, buyer has " << buyer;
	cout << " and seller has " << seller << '\n';
	
	swap (buyer,seller);
	
	cout << " After the swap, buyer has " << buyer;
	cout << " and seller has " << seller << '\n';
	
	return 0;
}

▌04. operator>>   operator<<

// extract to string
#include <iostream>
#include <string>
using namespace std;

int main ()
{
	string name;
	
	cout << "Please, enter your name: ";
	cin  >> name;
	cout << "Hello, " << name << "!\n";
	
	return 0;
}

▌05. getline

// extract to string
#include <iostream>
#include <string>
using namespace std;

int main ()
{
	string name;

	cout << "Please, enter your full name: ";
	getline (cin, name);
	cout << "Hello, " << name << "!\n";

	return 0;
}

参考资料:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_43964993

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值