如果字符串,"vwxyz",在新的顺序中被复制为,"zyxwv"。
那么这个字符串就被逆转了。不幸的是,这种直接可逆性在C++中是不可能的。然而,在C++中,有一个经典的变通方法来反转字符串。请继续阅读这篇文章,了解其中的诀窍。
在C++中,可以通过两种主要方式创建字符串。字符串可以作为一个字符序列的常数指针来创建。字符串也可以通过从字符串类中实例化一个字符串对象来创建。本文讨论的是从字符串类中实例化的字符串对象。这意味着必须包含字符串库才能执行本文的代码样本。
字符串对象是一个数据结构,其中字符串字面是一个列表。每个字符都是列表中的一个元素。因此,字符串的字面意义可以像一个元素数组一样被处理。
本文解释了C++中逆转字符串的经典工作方法。这实质上是对字符串字面的逆向迭代。有了对正向迭代的简要了解,读者就能更好地理解反向迭代。本文涉及从字符串类实例化的字符串对象。
除非另有说明,本教程的所有字符串代码都写在C++的main()函数中。
文章内容
正向迭代
迭代器是一个指针类,可以从中实例化出迭代器对象。迭代器对象可以用来扫描字符串元素,从字符串列表的开始到字符串列表的结束。字符串成员函数,begin(),返回一个指向字符串字面第一个元素的迭代器。它可以被递增,直到它到达,就在字符串的最后一个元素之后。字符串成员函数end()返回一个迭代器,指向字符串字面的最后一个元素之后。它可以被递减,直到它达到字符串的最后一个元素。这两个迭代器被认为是前向迭代器,尽管第二个迭代器是后向迭代。
对于一个变量名为str的字符串对象,下面的语句将返回一个开始迭代器。
string::iterator p = str.begin();
这里,p是一个开始迭代器。一个结束迭代器可以通过下面的语句返回。
string::iterator q = str.end();
这里,q是一个结束迭代器。上面的p和q是同一类型的,甚至可以互换。
下面的代码打印出了字符串的所有字符,从开始到结束。
string str = {'v', 'w', 'x', 'y', 'z', '\0'};
for (string::iterator p = str.begin(); p != str.end(); p++) {
cout << *p << ' ';
}
cout << endl;
输出的结果是
v w x y z
'\0'不应该被打印出来。它应该是用来标记字符串字面的结束。注意开始迭代器是如何获得的。迭代从头到尾扫描sting列表,将每个元素的迭代器与str.begin();递增后返回的迭代器进行比较。当返回的迭代器是最后一个元素之后的迭代器时,迭代停止。迭代器的递增或递减方式与索引的递增或递减方式相同。表达式*p返回由迭代器p指向的值。
下面的代码使用结束迭代器打印出字符串中从最后一个字符到第一个字符的值。
string str = "vwxyz";
string::iterator q = str.end();
for (q = --q; q >= str.begin(); q--) {
cout << *q << ' ';
}
cout << endl;
输出的结果是
z y x w v
这是一个字符串的间接反转。末端迭代器正好指向字符串字面的末端,而这样的点不是一个元素。为了让它指向最后一个元素,它必须被递减。从那里开始,迭代可以向后进行。
正因为如此,结束迭代器被声明在for-loop之外。在for-loop中迭代器的初始值是一次递减。迭代器按步骤递减,直到到达 "str.begin() "所指示的第一个元素。这是一种非正式的向后迭代的方式。也就是说,这是一种非正式的反转向量的方法(间接地)。
改变一个元素的字符
字符串对象是一个数据结构,其中的字符串字面是一个列表。列表由元素组成。每个元素都有一个字符,该字符是该元素的值。这些字符也是字符串的值。完整的字符串字面意义就是字符串对象的值。
当字符串对象的声明前面没有const(表示常量)时,字符串中任何元素的值都可以被改变。举例说明。
string str = "vwxyz";
string::iterator q = str.end();
q--; q--; q--;
*q = 'a';
string::iterator B = str.end();
for (B = --B; B >= str.begin(); B--) {
cout << *B << ' ';
}
cout << endl;
输出的结果是
z y a w v
"q-; q-; q-;" 将终端迭代器递减3次,指向'C'。
当字符串对象声明前面有const时,字符是只读的。对于这样的代码,返回的迭代器必须是const_iterator。在这种情况下,代码不会被编译。下面的代码将发出一个错误信息。
const string str = "vwxyz";
string::const_iterator q = str.end();
q--; q--; q--;
*q = 'a';
反向迭代
用于反向迭代的迭代器是reverse_iterator。字符串类的另一个成员函数是rend(),它返回一个正好指向字符串对象的第一个元素的迭代器。还有,字符串类的另一个成员函数是rbegin(),它返回一个指向字符串对象最后一个元素的迭代器。下面的代码说明了返回的reverse_iterator的使用,从第一个元素读到最后一个元素的正向方向。
string str = "vwxyz";
string::reverse_iterator p = str.rend();
for (p = --p; p >= str.rbegin(); p--) {
cout << *p << ' ';
}
cout << endl;
输出的结果是
v w x y z
注意,在while条件下,使用reverse_iterator,++是-,<=是>=。
下面的代码向后迭代,使用rbegin()的迭代器。
string str = "vwxyz";
for (string::reverse_iterator q = str.rbegin(); q <= str.rend(); q++) {
cout << *q << ' ';
}
cout << endl;
输出的结果是
z y x w v
同样,用++代替了-,用<=代替了>=。
改变一个元素的字符
当字符串对象的声明前面没有const(表示常量)时,字符串中任何元素的值都可以被改变。举例说明。
string str = "vwxyz";
string::reverse_iterator q = str.rbegin();
q++; q++;
*q = 'a';
for (string::reverse_iterator B = str.rbegin(); B <= str.rend(); B++) {
cout << *B << ' ';
}
cout << endl;
输出的结果是
z y a w v
rbegin()的迭代器q被 "q++; q++; "递减了两次,指向'C',因为它最初指向最后一个元素。
如果一个字符串对象前面有const,那么就不能用任何种类的迭代器来改变其中的字符。编译器将对以下代码发出错误信息,因为该代码试图修改'C'的值。
const string str = "vwxyz";
string::const_reverse_iterator q = str.rbegin();
q++; q++;
*q = 'a';
字符串常量逆向迭代
const_reverse_iterator由成员函数crbegin()返回。crbegin()与rbegin()相似,但是其迭代器所指向的值不能改变。const_reverse_iterator也由另一个成员函数crend()返回。crend()与rend()相似,但其迭代器所指向的值不能被改变。
下面的代码显示了字符串对象的所有值,使用const_reverse_iterator,从最后一个元素开始。
const string str = "vwxyz";
for (string::const_reverse_iterator q = str.crbegin(); q <= str.crend(); q++) {
cout << *q << ' ';
}
cout << endl;
输出的结果是
z y x w v
尽管字符串对象的声明前面没有const,但下面的代码将无法编译。这是因为使用了const_reverse_iterator的缘故。即使声明前面有const,也会因为同样的原因而不能编译。这段代码是
const string str = "vwxyz";
string::const_reverse_iterator q = str.crbegin();
q++; q++;
*q = 'a';
结论
字符串类没有一个成员函数来反转一个字符串。然而,通过从后往前迭代,可以间接地反转一个字符串。涉及的成员函数有:end(), begin(), rend(), rbegin(), crend() 和 crbegin()。涉及的迭代器是iterator、reverse_iterator和const_reverse_iterator。这些特性结合起来产生了一个间接但仍然有效的对字符串对象的字面意义的反转。