如何在C或C ++中反转string?

如何在C或C ++中反转string而不需要单独的缓冲区来保存反转的string?

邪恶C:

#include <stdio.h> void strrev(char *p) { char *q = p; while(q && *q) ++q; for(--q; p < q; ++p, --q) *p = *p ^ *q, *q = *p ^ *q, *p = *p ^ *q; } int 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; } 

(这是XOR交换的事情,注意你必须避免与自己交换,因为^ a == 0。)


好吧,我们来修复UTF-8字符。

 #include <bits/types.h> #include <stdio.h> #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; } 
  • 为什么,是的,如果input是borked,这将愉快地交换外面的地方。
  • 在UNICODE中破坏时的有用链接: http : //www.macchiato.com/unicode/chart/
  • 另外,0x10000以上的UTF-8是未经testing的(因为我似乎没有任何字体,也不耐心使用hexeditor)

例子:

 $ ./strrev Räksmörgås ░▒▓○◔◑◕● ░▒▓○◔◑◕● ●◕◑◔○▓▒░ Räksmörgås sågrömskäR ./strrev verrts/. 
 #include <algorithm> std::reverse(str.begin(), str.end()); 

这是C ++中最简单的方法。

阅读Kernighan和Ritchie

 #include <string.h> void 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; } } 

反转string(可视化):

反转一个字符串到位

非邪恶的C,假设string是一个空终止的char数组的常见情况:

 #include <stddef.h> #include <string.h> /* 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--; } } 

您可以使用C ++标准库中的std::reversealgorithm。

已经有一段时间了,我不记得哪一本书教给我这个algorithm,但是我认为它非常巧妙和简单:

 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); 

请注意,std :: reverse的美妙之处在于它可以和char *string和std::wstring ,就像std::string s一样

 void strrev(char *str) { if (str == NULL) return; std::reverse(str, str + strlen(str)); } 

使用STL中的std :: reverse方法:

 std::reverse(str.begin(), str.end()); 

你将不得不包括“algorithm”库, #include<algorithm>

如果你正在寻找反向NULL终止缓冲区,这里发布的大多数解决scheme都可以。 但是,正如Tim Farley所指出的那样,这些algorithm只有在假设string在语义上是一个字节数组(即单字节string)的情况下才有效,我认为这是错误的假设。

例如,string“año”(西class牙语年)。

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大端:

原版的:

0x00,0x61,0x00,0xf1,0x00,0x6f,0x00,0x00

第一个字节将被视为NUL终结符。 不会倒转。

UTF-16小端:

原版的:

0x61,0x00,0xf1,0x00,0x6f,0x00,0x00,0x00

第二个字节将被视为NUL终结符。 结果将是0x61,0x00,一个包含'a'字符的string。

为了完整起见,应该指出的是,在各种平台上存在string的表示,其中每个字符的字节数根据字符而变化 。 老派程序员会把它称为DBCS(双字节字符集) 。 现代程序员通常在UTF-8 (以及UTF-16等)中遇到这种情况。 还有其他这样的编码。

在这些可变宽度编码scheme中,这里发布的简单algorithm( 邪恶的 , 非邪恶的或其他 )将不能正常工作! 事实上,他们甚至可能会导致string在该编码scheme中变得难以辨认,甚至是非法string。 请参阅Juan Pablo Califano的一些好例子的答案 。

只要你的平台的标准C ++库的实现(特别是string迭代器)正确地考虑到了这一点,std :: reverse()就可能仍然可以工作。

 #include <cstdio> #include <cstdlib> #include <string> void strrev(char *str) { if( str == NULL ) return; char *end_ptr = &str[strlen(str) - 1]; char temp; while( end_ptr > str ) { temp = *str; *str++ = *end_ptr; *end_ptr-- = temp; } } int main(int argc, char *argv[]) { char buffer[32]; strcpy(buffer, "testing"); strrev(buffer); printf("%s\n", buffer); strcpy(buffer, "a"); strrev(buffer); printf("%s\n", buffer); strcpy(buffer, "abc"); strrev(buffer); printf("%s\n", buffer); strcpy(buffer, ""); strrev(buffer); printf("%s\n", buffer); strrev(NULL); return 0; } 

这段代码产生这个输出:

 gnitset a cba 

如果你使用GLib,它有两个函数, g_strreverse()和g_utf8_strreverse()

另一个C ++的方式(虽然我可能会使用std :: reverse()我:)作为更具有performance力和更快)

 str = std::string(str.rbegin(), str.rend()); 

C的方式(或多或less:)),请注意XOR交换技巧,编译器通常无法优化。

在这种情况下,通常要慢得多。

 char* reverse(char* s) { char* beg = s-1, *end = s, tmp; while (*++end); while (end-- > ++beg) { tmp = *beg; *beg = *end; *end = tmp; } return s; } 

我喜欢Evgeny的K&R答案。 不过,看到使用指针的版本是很好的。 否则,它本质上是一样的:

 #include <stdio.h> #include <string.h> #include <stdlib.h> char *reverse(char *str) { if( str == NULL || !(*str) ) return NULL; int i, j = strlen(str)-1; char *sallocd; sallocd = malloc(sizeof(char) * (j+1)); for(i=0; j>=0; i++, j--) { *(sallocd+i) = *(str+j); } return sallocd; } int main(void) { char *s = "a man a plan a canal panama"; char *sret = reverse(s); printf("%s\n", reverse(sret)); free(sret); return 0; } 

recursion函数来反转一个string到位(没有额外的缓冲区,malloc)。

简短,性感的代码。 糟糕的,糟糕的堆栈使用。

 #include <stdio.h> /* Store the each value and move to next char going down * the stack. Assign value to start ptr and increment * when coming back up the stack (return). * Neat code, horrible stack usage. * * val - value of current pointer. * s - start pointer * n - next char pointer in string. */ char *reverse_r(char val, char *s, char *n) { if (*n) s = reverse_r(*n, s, n+1); *s = val; return s+1; } /* * expect the string to be passed as argv[1] */ int main(int argc, char *argv[]) { char *aString; if (argc < 2) { printf("Usage: RSIP <string>\n"); return 0; } aString = argv[1]; printf("String to reverse: %s\n", aString ); reverse_r(*aString, aString, aString+1); printf("Reversed String: %s\n", aString ); return 0; } 

分享我的代码。 作为一名C ++学习者,作为使用swap()的选项,我虚心地征求意见。

 void reverse(char* str) { int length = strlen(str); char* str_head = str; char* str_tail = &str[length-1]; while (str_head < str_tail) swap(*str_head++, *str_tail--); } 

如果您使用ATL / MFC CString ,只需调用CString::MakeReverse()

完后还有:

 #include <stdio.h> #include <strings.h> int main(int argc, char **argv) { char *reverse = argv[argc-1]; char *left = reverse; int length = strlen(reverse); char *right = reverse+length-1; char temp; while(right-left>=1){ temp=*left; *left=*right; *right=temp; ++left; --right; } printf("%s\n", reverse); } 
 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> unsigned char * utf8_reverse(const unsigned char *, int); void assert_true(bool); int main(void) { unsigned char str[] = "mañana mañana"; unsigned char *ret = utf8_reverse(str, strlen((const char *) str) + 1); printf("%s\n", ret); assert_true(0 == strncmp((const char *) ret, "anãnam anañam", strlen("anãnam anañam") + 1)); free(ret); return EXIT_SUCCESS; } unsigned char * utf8_reverse(const unsigned char *str, int size) { unsigned char *ret = calloc(size, sizeof(unsigned char*)); int ret_size = 0; int pos = size - 2; int char_size = 0; if (str == NULL) { fprintf(stderr, "failed to allocate memory.\n"); exit(EXIT_FAILURE); } while (pos > -1) { if (str[pos] < 0x80) { char_size = 1; } else if (pos > 0 && str[pos - 1] > 0xC1 && str[pos - 1] < 0xE0) { char_size = 2; } else if (pos > 1 && str[pos - 2] > 0xDF && str[pos - 2] < 0xF0) { char_size = 3; } else if (pos > 2 && str[pos - 3] > 0xEF && str[pos - 3] < 0xF5) { char_size = 4; } else { char_size = 1; } pos -= char_size; memcpy(ret + ret_size, str + pos + 1, char_size); ret_size += char_size; } ret[ret_size] = '\0'; return ret; } void assert_true(bool boolean) { puts(boolean == true ? "true" : "false"); } 

如果你不需要存储它,你可以减less这样的时间:

 void showReverse(char s[], int length) { printf("Reversed String without storing is "); //could use another variable to test for length, keeping length whole. //assumes contiguous memory for (; length > 0; length--) { printf("%c", *(s+ length-1) ); } printf("\n"); } 

用C ++ lambda:

  auto reverse = [](std::string& s) -> std::string { size_t start = 0, end = s.length() -1; char temp; while (start < end) { temp = s[start]; s[start++] = s[end]; s[end--] = temp; } return s; }; 

这是我在C上的练习。是否练习,尽量简洁! 你通过命令行input一个string,即./program_name“在这里inputstring”

 #include <stdio.h> #include <string.h> void reverse(int s,int e,int len,char t,char* arg) { for(;s<len/2;t=arg[s],arg[s++]=arg[e],arg[e--]=t); } int main(int argc,char* argv[]) { int s=0,len=strlen(argv[1]),e=len-1; char t,*arg=argv[1]; reverse(s,e,len,t,arg); for(s=0,e=0;e<=len;arg[e]==' '||arg[e]=='\0'?reverse(s,e-1,e+s,t,arg),s=++e:e++); printf("%s\n",arg); } 

但我认为XOR交换algorithm是最好的…

 char str[]= {"I am doing reverse string"}; char* pStr = str; for(int i = 0; i != ((int)strlen(str)-1)/2; i++) { char b = *(pStr+i); *(pStr+i) = *(pStr+strlen(str)-1-i); *(pStr+strlen(str)-1-i) = b; } 
 #include<stdio.h> #include<conio.h> int main() { char *my_string = "THIS_IS_MY_STRING"; char *rev_my_string = my_string; while (*++rev_my_string != '\0') ; while (rev_my_string-- != (my_string-1)) { printf("%c", *rev_my_string); } getchar(); return 0; } 

这是C语言中用于反转string的优化代码…而且很简单; 只需使用一个简单的指针来完成这项工作…

这是在C ++中反转string的最简洁,最安全,最简单的方法(在我看来):

 #include <string> void swap(std::string& str, int index1, int index2) { char temp = str[index1]; str[index1] = str[index2]; str[index2] = temp; } void reverse(std::string& str) { for (int i = 0; i < str.size() / 2; i++) swap(str, i, str.size() - i - 1); } 

另一种方法是使用std::swap ,但我喜欢定义我自己的函数 – 这是一个有趣的练习,你不需要include任何额外的东西。

 /** I am a boy -> boy a am I */ int main() { int i, j, n, temp, temp_i, cnt; //char *array = "Samsung"; char array[1000]; char newarr[strlen(array)]; printf("Enter The String: \n"); gets(array); for(i = (strlen(array)-1), n = 0, j = 0; i >= 0; i--) { if( array[i] != ' ') { n++; } else { temp = n; temp_i = i; for(n = 0; n <= temp; n++) { // i = i + 1; newarr[j++] = array[i++]; } i = temp_i; n = 0; } if(i == 0) { newarr[j++] = ' '; temp = n; temp_i = i; for(n = 0; n <= temp; n++) { // i = i + 1; newarr[j++] = array[i++]; } i = temp_i; n = 0; } //newarr[j++] = array[i]; } newarr[j] = '\0'; cnt = 0; for(j = 0; j <= (strlen(newarr)-1); j++)//This is not required just do some R n D { newarr[j] = newarr[++cnt]; } // printf("The first element is %c \n", newarr[1]); puts(newarr); return 0; }