如何在C或C++中反转字符串而不需要单独的缓冲区来保存反向字符串?
#includestd::reverse(str.begin(), str.end());
这是C++中最简单的方法.
阅读Kernighan和Ritchie
#includevoid reverse(char s[]) { int length = strlen(s) ; int c, i, j; for (i = 0, j = length - 1; i < j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = c; } }
邪恶的C:
void strrev(char *head) { if (!head) return; char *tail = head; while(*tail) ++tail; // find the 0 terminator, like head+strlen --tail; // tail points to the last real char // head still points to the first for( ; head < tail; ++head, --tail) { // walk pointers inwards until they meet or cross in the middle char h = *head, t = *tail; *head = t; // swapping as we go *tail = h; } }
(这是XOR交换的事情.请注意,你必须避免与self交换,因为a ^ a == 0.)
// test program that reverses its args #includeint main(int argc, char **argv) { do { printf("%s ", argv[argc-1]); strrev(argv[argc-1]); printf("%s\n", argv[argc-1]); } while(--argc); return 0; }
为什么,是的,如果输入是borked,这将愉快地交换到该地方之外.
在UNICODE中破坏时的有用链接:http://www.macchiato.com/unicode/chart/
此外,超过0x10000的UTF-8未经测试(因为我似乎没有任何字体,也没有使用hexeditor的耐心)
例子:
#include#include #define SWP(x,y) (x^=y, y^=x, x^=y) void strrev(char *p) { char *q = p; while(q && *q) ++q; /* find eos */ for(--q; p < q; ++p, --q) SWP(*p, *q); } void strrev_utf8(char *p) { char *q = p; strrev(p); /* call base case */ /* Ok, now fix bass-ackwards UTF chars. */ while(q && *q) ++q; /* find eos */ while(p < --q) switch( (*q & 0xF0) >> 4 ) { case 0xF: /* U+010000-U+10FFFF: four bytes. */ SWP(*(q-0), *(q-3)); SWP(*(q-1), *(q-2)); q -= 3; break; case 0xE: /* U+000800-U+00FFFF: three bytes. */ SWP(*(q-0), *(q-2)); q -= 2; break; case 0xC: /* fall-through */ case 0xD: /* U+000080-U+0007FF: two bytes. */ SWP(*(q-0), *(q-1)); q--; break; } } int main(int argc, char **argv) { do { printf("%s ", argv[argc-1]); strrev_utf8(argv[argc-1]); printf("%s\n", argv[argc-1]); } while(--argc); return 0; }
"你必须避免与自己交换,因为'a ^ a == 0`" - 错了.`a ^ a == 0`,但那不是问题,因为那时你会做`a ^(a ^ a)```a ^ 0`是'a`.因此,即使两个swappees(有这样一个单词)相等,XOR交换也能正常工作.
4> slashdottir..:反转字符串(可视化):
5> Chris Conway..:非邪恶的C,假设字符串是以空终止的
char
数组的常见情况:#include#include /* PRE: str must be either NULL or a pointer to a * (possibly empty) null-terminated string. */ void strrev(char *str) { char temp, *end_ptr; /* If str is NULL or empty, do nothing */ if( str == NULL || !(*str) ) return; end_ptr = str + strlen(str) - 1; /* Swap the chars */ while( end_ptr > str ) { temp = *str; *str = *end_ptr; *end_ptr = temp; str++; end_ptr--; } }
6> Nemanja Trif..:您使用
std::reverse
C++标准库中的算法.
对.我总是想知道为什么这么多人仍然把它称为"STL",尽管这只会让人感到困惑.如果有更多人喜欢你,并且只是将它称为"C++标准库"或STL并说"STandard Library":)会更好
标准模板库是一个预标准术语.C++标准没有提到它,以前的STL组件在C++标准库中.
7> karlphillip..:已经有一段时间了,我不记得哪本书教会了我这个算法,但我认为它非常巧妙且易于理解:
char input[] = "moc.wolfrevokcats"; int length = strlen(input); int last_pos = length-1; for(int i = 0; i < length/2; i++) { char tmp = input[i]; input[i] = input[last_pos - i]; input[last_pos - i] = tmp; } printf("%s\n", input);
8> 小智..:使用STL中的std :: reverse方法:
std::reverse(str.begin(), str.end());你必须包括"算法"库,
#include
.
9> Eclipse..:请注意,std :: reverse的优点在于它适用于
char *
字符串和std::wstring
s以及std::string
svoid strrev(char *str) { if (str == NULL) return; std::reverse(str, str + strlen(str)); }
10> Juan Pablo C..:如果您正在寻找反转NULL终止缓冲区,那么此处发布的大多数解决方案都可以.但是,正如Tim Farley已经指出的那样,这些算法只有在假设字符串在语义上是一个字节数组(即单字节字符串)时才有效,我认为这是一个错误的假设.
例如,字符串"año"(西班牙语年份).
Unicode代码点是0x61,0xf1,0x6f.
考虑一些最常用的编码:
Latin1/iso-8859-1(单字节编码,1个字符是1个字节,反之亦然):
原版的:
0x61,0xf1,0x6f,0x00
相反:
0x6f,0xf1,0x61,0x00
结果还可以
UTF-8:
原版的:
0x61,0xc3,0xb1,0x6f,0x00
相反:
0x6f,0xb1,0xc3,0x61,0x00
结果是乱码和非法的UTF-8序列
UTF-16 Big Endian:
原版的:
0x00,0x61,0x00,0xf1,0x00,0x6f,0x00,0x00
第一个字节将被视为NUL终止符.不会发生逆转.
UTF-16 Little Endian:
原版的:
0x61,0x00,0xf1,0x00,0x6f,0x00,0x00,0x00
第二个字节将被视为NUL终止符.结果将是0x61,0x00,一个包含'a'字符的字符串.
11> Tim Farley..:为了完整性,应该指出在各种平台上存在字符串的表示,其中每个字符的字节数根据字符而变化.老派程序员将此称为DBCS(双字节字符集).现代程序员更常见的是UTF-8(以及UTF-16等).还有其他类似的编码.
在任何这些可变宽度编码方案中,这里发布的简单算法(邪恶,非邪恶或其他)根本无法正常工作!实际上,它们甚至可能导致字符串在该编码方案中变得难以辨认或甚至是非法字符串.有关一些很好的例子,请参阅Juan Pablo Califano的答案.
只要您的平台的标准C++库(特别是字符串迭代器)的实现正确考虑到这一点,std :: reverse()在这种情况下仍然可能仍然有效.
std :: reverse不会考虑到这一点.它反转了value_type的.在std :: string的情况下,它会反转char的.不是人物.
12> pprzemek..:另一种C ++方式(尽管我可能会自己使用std :: reverse():)来提高表现力和速度)
str = std::string(str.rbegin(), str.rend());C方式(或多或少:)),请注意交换的XOR技巧,编译器有时无法对其进行优化。
在这种情况下,通常速度要慢得多。
char* reverse(char* s) { char* beg = s, *end = s, tmp; while (*end) end++; while (end-- > beg) { tmp = *beg; *beg++ = *end; *end = tmp; } return s; } // fixed: check history for details, as those are interesting ones