¿Cómo invertir una cadena en C o C ++?

¿Cómo invertir una cadena en C o C ++ sin requerir un buffer separado para mantener la cadena invertida?

Evil C:

#include  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; } 

(Esto es algo de XOR-swap. Tenga en cuenta que debe evitar intercambiarse consigo mismo, porque a ^ a == 0).


Bien, bien, arreglemos los caracteres UTF-8 ...

 #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; } 
  • Por qué, sí, si la entrada está modificada, esto se intercambiará alegremente fuera del lugar.
  • Enlace útil al vandalizar en UNICODE: http://www.macchiato.com/unicode/chart/
  • Además, UTF-8 más de 0x10000 no se ha probado (ya que no parece tener ninguna fuente, ni la paciencia para usar un editor hexadecimal)

Ejemplos:

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

Esta es la forma más simple en C ++.

Lea Kernighan y Ritchie

 #include  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; } } 

Invierta una cadena en su lugar (visualización):

Invierta una cuerda en su lugar

C no maligno, suponiendo el caso común en el que la cadena es una matriz char terminada en nulo:

 #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--; } } 

Utiliza el algoritmo std::reverse de la biblioteca estándar de C ++.

Ha pasado un tiempo y no recuerdo qué libro me enseñó este algoritmo, pero pensé que era bastante ingenioso y simple de entender:

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

Use el método std :: reverse de STL :

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

Deberá incluir la biblioteca “algorithm”, #include .

Tenga en cuenta que la belleza de std :: reverse es que funciona con char * strings y std::wstring s tan bien como std::string s

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

Si está buscando revertir los búfers terminados en NULL, la mayoría de las soluciones publicadas aquí están bien. Pero, como Tim Farley ya señaló, estos algoritmos funcionarán solo si es válido suponer que una cadena es semánticamente una matriz de bytes (es decir, cadenas de un solo byte), lo cual es una suposición errónea, creo.

Tomemos, por ejemplo, la cadena “año” (año en español).

Los puntos de código Unicode son 0x61, 0xf1, 0x6f.

Considere algunas de las codificaciones más utilizadas:

Latin1 / iso-8859-1 (encoding de un solo byte, 1 carácter es 1 byte y viceversa):

Original:

0x61, 0xf1, 0x6f, 0x00

Marcha atrás:

0x6f, 0xf1, 0x61, 0x00

El resultado está bien

UTF-8:

Original:

0x61, 0xc3, 0xb1, 0x6f, 0x00

Marcha atrás:

0x6f, 0xb1, 0xc3, 0x61, 0x00

El resultado es un galimatías y una secuencia UTF-8 ilegal

UTF-16 Big Endian:

Original:

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

El primer byte se tratará como un terminador NUL. No se llevará a cabo ninguna inversión.

UTF-16 Little Endian:

Original:

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

El segundo byte se tratará como un NUL-terminator. El resultado será 0x61, 0x00, una cadena que contiene el carácter ‘a’.

En aras de la integridad, se debe señalar que hay representaciones de cadenas en varias plataformas en las que el número de bytes por carácter varía según el personaje. Los progtwigdores de la vieja escuela se refieren a esto como DBCS (Juego de caracteres de doble byte) . Los progtwigdores modernos encuentran esto más comúnmente en UTF-8 (así como en UTF-16 y otros). Hay otras codificaciones similares también.

En cualquiera de estos esquemas de encoding de ancho variable, los algoritmos simples publicados aquí ( malvados , no malvados o no ) no funcionarían correctamente. De hecho, incluso podrían hacer que la cadena se vuelva ilegible o incluso una cadena ilegal en ese esquema de encoding. Vea la respuesta de Juan Pablo Califano para algunos buenos ejemplos.

std :: reverse () potencialmente seguiría funcionando en este caso, siempre y cuando la implementación de su plataforma de la biblioteca estándar de C ++ (en particular, los iteradores de cadena) tenga esto en cuenta.

 #include  #include  #include  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; } 

Este código produce esta salida:

 gnitset a cba 

En caso de que esté utilizando GLib, tiene dos funciones para eso, g_strreverse () y g_utf8_strreverse ()

Otra forma C ++ (aunque probablemente usaría std :: reverse () 🙂 como más expresivo y más rápido.

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

La forma C (más o menos :)) y por favor, tenga cuidado con el truco XOR para el intercambio, los comstackdores generalmente no pueden optimizar eso.

En tal caso, generalmente es mucho más lento.

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

Me gusta la respuesta de Evgeny K & R. Sin embargo, es bueno ver una versión con punteros. De lo contrario, es esencialmente lo mismo:

 #include  #include  #include  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; } 

Función recursiva para invertir una cadena en su lugar (sin búfer adicional, malloc).

Código corto y sexy. Malo, mal uso de la stack.

 #include  /* 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 \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; } 

Comparte mi código Como aprendiz de C ++, como una opción para usar swap (), humildemente estoy pidiendo comentarios.

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

Si está utilizando ATL / MFC CString , simplemente llame a CString::MakeReverse() .

Aún otra:

 #include  #include  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  #include  #include  #include  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"); } 

Si no necesita almacenarlo, puede reducir el tiempo empleado de esta manera:

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

Con 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; }; 

Mi respuesta sería similar a la mayoría de ellos, pero encuentra mi código aquí.

 //Method signature to reverse string string reverseString(string str); int main(void){ string str; getline(cin, str); str = reverseString(str); cout << "The reveresed string is : " << str; return 0; } ///  /// Reverses the input string. ///  ///  /// This is the input string which needs to be reversed. ///  ///  /// This method would return the reversed string ///  string reverseString(string str){ int length = str.size()-1; char temp; for( int i=0 ;i<(length/2);i++) { temp = str[i]; str[i] = str[length-i]; str[length-i] = temp; } return str; } 

Use std::reverse()

reverse(begin(str), end(str));

Y eso es.

Creo que hay otra forma de invertir la cadena. obtener la entrada del usuario y revertirla.

 void Rev() { char ch; cin.get(ch); if (ch != '\n') { Rev(); cout.put(ch); } 

}

Este es mi punto de vista en C. Lo hice para practicar e intenté ser lo más conciso posible. Usted ingresa una cadena a través de la línea de comando, es decir ./program_name “enter string here”

 #include  #include  void reverse(int s,int e,int len,char t,char* arg) { for(;s 

Pero creo que el algoritmo de intercambio XOR es el mejor …

 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 #include 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; } 

Este es un código optimizado en el lenguaje C para invertir una cadena … Y es simple; solo usa un puntero simple para hacer el trabajo …

Esta es la forma más limpia, segura y fácil de invertir una cadena en C ++ (en mi opinión):

 #include  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); } 

Una alternativa es usar std::swap , pero me gusta definir mis propias funciones: es un ejercicio interesante y no necesita include nada extra.

 /** 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; }