float - Invertir una cadena en C
strtol c (23)
¿Ya nadie usa punteros?
void inplace_rev( char * s ) {
char t, *e = s + strlen(s);
while ( --e > s ) { t = *s;*s++=*e;*e=t; }
}
EDITAR: Perdón, solo noté el ejemplo XOR anterior ...
Desarrollé un programa de cadena inversa. Me pregunto si hay una mejor manera de hacerlo, y si mi código tiene algún problema potencial. Estoy buscando practicar algunas características avanzadas de C.
char* reverse_string(char *str)
{
char temp;
size_t len = strlen(str) - 1;
size_t i;
size_t k = len;
for(i = 0; i < len; i++)
{
temp = str[k];
str[k] = str[i];
str[i] = temp;
k--;
/* As 2 characters are changing place for each cycle of the loop
only traverse half the array of characters */
if(k == (len / 2))
{
break;
}
}
}
Aquí está mi oportunidad. Evito intercambiar solo usando el patrón strcpy
estándar:
char *string_reverse(char *dst, const char *src)
{
if (src == NULL) return NULL;
const char *src_start = src;
char *dst_end = dst + strlen(src);
*dst_end = ''/0'';
while ((*--dst_end = *src_start++)) { ; }
return dst;
}
Como dices que quieres ser elegante, quizás quieras intercambiar tus personajes usando un intercambio XOR .
El código parece innecesariamente complicado. Aquí está mi versión:
void strrev(char* str) {
size_t len = strlen(str);
char buf[len];
for (size_t i = 0; i < len; i++) {
buf[i] = str[len - 1 - i];
};
for (size_t i = 0; i < len; i++) {
str[i] = buf[i];
}
}
En lugar de romper a la mitad, simplemente debes acortar el ciclo.
size_t length = strlen(str);
size_t i;
for (i = 0; i < (length / 2); i++)
{
char temp = str[length - i - 1];
str[length - i - 1] = str[i];
str[i] = temp;
}
Esa es una buena pregunta . Puede usar una función independiente para invertir la cadena. El código es ...
#include <stdio.h>
#define MAX_CHARACTERS 99
int main( void );
int strlen( char __str );
int main() {
char *str[ MAX_CHARACTERS ];
char *new_string[ MAX_CHARACTERS ];
int i, j;
printf( "enter string: " );
gets( *str );
for( i = 0; j = ( strlen( *str ) - 1 ); i < strlen( *str ), j > -1; i++, j-- ) {
*str[ i ] = *new_string[ j ];
}
printf( "Reverse string is: %s", *new_string" );
return ( 0 );
}
int strlen( char __str[] ) {
int count;
for( int i = 0; __str[ i ] != ''/0''; i++ ) {
++count;
}
return ( count );
}
Este programa completo muestra cómo lo haría. Tenga en cuenta que estaba escribiendo C cuando la mayoría de ustedes, tragamonedas, eran un destello en los ojos de su madre, así que es de la vieja escuela, hacen el trabajo, son muchos nombres diferentes para los débiles. Soluciona eso si lo deseas, estoy más interesado en la corrección del código.
Maneja NULLs, cadenas vacías y todos los tamaños de cadena. No lo he probado con cadenas de tamaño máximo (max (size_t)) pero debería funcionar, y si estás manejando cadenas tan grandes, de todos modos estás loco :-)
#include <stdio.h>
#include <string.h>
char *revStr (char *str) {
char tmp, *src, *dst;
size_t len;
if (str != NULL)
{
len = strlen (str);
if (len > 1) {
src = str;
dst = src + len - 1;
while (src < dst) {
tmp = *src;
*src++ = *dst;
*dst-- = tmp;
}
}
}
return str;
}
char *str[] = {"", "a", "ab", "abc", "abcd", "abcde"};
int main(int argc, char *argv[]) {
int i;
char s[10000];
for (i=0; i < sizeof(str)/sizeof(str[0]); i++) {
strcpy (s, str[i]);
printf ("''%s'' -> ''%s''/n", str[i], revStr(s));
}
return 0;
}
El resultado de eso es:
'''' -> ''''
''a'' -> ''a''
''ab'' -> ''ba''
''abc'' -> ''cba''
''abcd'' -> ''dcba''
''abcde'' -> ''edcba''
Mis dos centavos:
/* Reverses n characters of a string and adds a ''/0'' at the end */
void strnrev (char *txt, size_t len) {
size_t idx;
for (idx = len >> 1; idx > 0; idx--) {
txt[len] = txt[idx - 1];
txt[idx - 1] = txt[len - idx];
txt[len - idx] = txt[len];
}
txt[len] = ''/0'';
}
/* Reverses a null-terminated string */
void strrev (char *txt) {
size_t len = 0;
while (txt[len++]);
strnrev(txt, --len);
}
Prueba n. ° 1 - strrev()
:
char string[] = "Hello world!";
strrev(string);
printf("%s/n", string); // Displays "!dlrow olleH"
Prueba n. ° 2 - strnrev()
:
char string[] = "Hello world!";
strnrev(string, 5);
printf("%s/n", string); // Displays "olleH"
No veo una declaración de devolución, y está cambiando la cadena de entrada, lo que puede ser un problema para el programador. Puede querer que la cadena de entrada sea inmutable.
Además, esto puede ser quisquilloso, pero len / 2 debe calcularse solo una vez, IMO.
Aparte de eso, funcionará, siempre y cuando se ocupe de los casos problemáticos mencionados por rossfabricant.
Prueba esto:
reverse_string(NULL);
reverse_string("");
Puede cambiar su declaración de bucle for para acortar el código:
char* reverse_string(char *str)
{
char temp;
size_t len = strlen(str) - 1;
size_t stop = len/2;
size_t i,k;
for(i = 0, k = len; i < stop; i++, k--)
{
temp = str[k];
str[k] = str[i];
str[i] = temp;
}
return str;
}
Puede poner su prueba (len/2)
en el ciclo for:
for(i = 0,k=len-1 ; i < (len/2); i++,k--)
{
temp = str[k];
str[k] = str[i];
str[i] = temp;
}
Puede probar esta aritmética de puntero:
void revString(char *s)
{
char *e = s; while(*e){ e++; } e--;
while(e > s){ *s ^= *e; *e ^= *s; *s++ ^= *e--; }
}
Si desea practicar funciones avanzadas de C, ¿qué le parecen los punteros? ¡También podemos usar macros y xor-swap para divertirnos!
#include <string.h> // for strlen()
// reverse the given null-terminated string in place
void inplace_reverse(char * str)
{
if (str)
{
char * end = str + strlen(str) - 1;
// swap the values in the two given variables
// XXX: fails when a and b refer to same memory location
# define XOR_SWAP(a,b) do/
{/
a ^= b;/
b ^= a;/
a ^= b;/
} while (0)
// walk inwards from both ends of the string,
// swapping until we get to the middle
while (str < end)
{
XOR_SWAP(*str, *end);
str++;
end--;
}
# undef XOR_SWAP
}
}
Un puntero (por ejemplo, char *
, leído de derecha a izquierda como un puntero a un char
) es un tipo de datos en C que se utiliza para referirse a la ubicación en la memoria de otro valor. En este caso, la ubicación donde se almacena un char
. Podemos quitar punteros de referencia prefijándolos con un *
, que nos da el valor almacenado en esa ubicación. Entonces el valor almacenado en str
es *str
.
Podemos hacer aritmética simple con punteros. Cuando incrementamos (o disminuimos) un puntero, simplemente lo movemos para referirnos a la siguiente (o anterior) ubicación de memoria para ese tipo de valor. El aumento de punteros de diferentes tipos puede mover el puntero en un número diferente de bytes porque los diferentes valores tienen diferentes tamaños de bytes en C.
Aquí, usamos un puntero para referirnos al primer char
no procesado de la cadena ( str
) y otro para referirnos al último ( end
). Intercambiamos sus valores ( *str
y *end
) y movemos los punteros hacia adentro hasta el centro de la cadena. Una vez str >= end
, o ambos apuntan al mismo char
, lo que significa que nuestra secuencia original tenía una longitud impar (y el char
medio no necesita ser revertido), o hemos procesado todo.
Para hacer el intercambio, he definido una macro . Las macros son una sustitución de texto realizada por el preprocesador C. Son muy diferentes de las funciones, y es importante saber la diferencia. Cuando llama a una función, la función opera en una copia de los valores que le da. Cuando llamas a una macro, simplemente hace una sustitución textual, por lo que los argumentos que le das se usan directamente.
Como solo usé la macro XOR_SWAP
una vez, probablemente fue excesivo definirla, pero dejó más claro lo que estaba haciendo. Después de que el preprocesador C expande la macro, el ciclo while se ve así:
while (str < end)
{
do { *str ^= *end; *end ^= *str; *str ^= *end; } while (0);
str++;
end--;
}
Tenga en cuenta que los argumentos de macro aparecen una vez por cada vez que se usan en la definición de macro. Esto puede ser muy útil, pero también puede romper su código si se usa incorrectamente. Por ejemplo, si hubiera comprimido las instrucciones de incremento / decremento y la macro llamada en una sola línea, como
XOR_SWAP(*str++, *end--);
Entonces esto se expandiría a
do { *str++ ^= *end--; *end-- ^= *str++; *str++ ^= *end--; } while (0);
Que tiene el triple de las operaciones de incremento / decremento, y en realidad no hace el intercambio que se supone que tiene que hacer.
Mientras hablamos del tema, debes saber qué significa xor ( ^
). Es una operación aritmética básica, como sumar, restar, multiplicar, dividir, excepto que generalmente no se enseña en la escuela primaria. Combina dos enteros poco a poco, como la suma, pero no nos importan los traspasos. 1^1 = 0
, 1^0 = 1
, 0^1 = 1
, 0^0 = 0
.
Un truco bien conocido es usar xor para intercambiar dos valores. Esto funciona debido a tres propiedades básicas de xor: x ^ 0 = x
, x ^ x = 0
y x ^ y = y ^ x
para todos los valores x
e y
. Entonces, digamos que tenemos dos variables a
y b
que inicialmente almacenan dos valores v a
y v b
.
// initially: // a == va // b == vb a ^= b; // now: a == va ^ vb b ^= a; // now: b == vb ^ (va ^ vb) // == va ^ (vb ^ vb) // == va ^ 0 // == va a ^= b; // now: a == (va ^ vb) ^ va // == (va ^ va) ^ vb // == 0 ^ vb // == vb
Entonces los valores son intercambiados. Esto tiene un error, cuando a
y b
son la misma variable:
// initially: // a == va a ^= a; // now: a == va ^ va // == 0 a ^= a; // now: a == 0 ^ 0 // == 0 a ^= a; // now: a == 0 ^ 0 // == 0
Desde que terminamos, esto nunca ocurre en el código anterior, así que estamos bien.
Si bien nos preocupa la corrección, deberíamos revisar nuestros casos extremos. La línea if (str)
debería asegurarse de que no se nos haya dado un puntero NULL
para la cadena. ¿Qué pasa con la cadena vacía ""
? Bien strlen("") == 0
, por lo que inicializaremos el end
como str - 1
, lo que significa que la condición while (str < end)
nunca es verdadera, por lo que no hacemos nada. Cual es correcta.
Hay un montón de C para explorar. ¡Diviértete con eso!
Actualización: mmw plantea un buen punto, que es necesario tener un poco de cuidado al invocar esto, ya que opera en el lugar.
char stack_string[] = "This string is copied onto the stack.";
inplace_reverse(stack_string);
Esto funciona bien, ya que stack_string
es una matriz, cuyos contenidos se inicializan a la constante de cadena dada. sin embargo
char * string_literal = "This string is part of the executable.";
inplace_reverse(string_literal);
Hará que tu código se encienda y muera en el tiempo de ejecución. Eso es porque string_literal
simplemente apunta a la cadena que está almacenada como parte de su ejecutable, que normalmente es una memoria que el sistema operativo no le permite editar. En un mundo más feliz, su compilador sabrá esto y toserá un error cuando intente compilar, diciéndole que string_literal
necesita ser del tipo char const *
ya que no puede modificar los contenidos. Sin embargo, este no es el mundo en el que vive mi compilador.
Hay algunos hacks que puedes intentar para asegurarte de que parte de la memoria está en la pila o en el montón (y por lo tanto es editable), pero no son necesariamente portátiles, y podría ser bastante feo. Sin embargo, estoy más que feliz de echar la responsabilidad de esto al invocador de funciones. Les dije que esta función tiene lugar en la manipulación de la memoria, es su responsabilidad darme un argumento que permita eso.
Solo una reorganización y un control de seguridad. También eliminé su tipo de devolución no utilizada. Creo que es un lugar seguro y limpio:
#include <stdio.h>
#include <string.h>
void reverse_string(char *str)
{
/* skip null */
if (str == 0)
{
return;
}
/* skip empty string */
if (*str == 0)
{
return;
}
/* get range */
char *start = str;
char *end = start + strlen(str) - 1; /* -1 for /0 */
char temp;
/* reverse */
while (end > start)
{
/* swap */
temp = *start;
*start = *end;
*end = temp;
/* move */
++start;
--end;
}
}
int main(void)
{
char s1[] = "Reverse me!";
char s2[] = "abc";
char s3[] = "ab";
char s4[] = "a";
char s5[] = "";
reverse_string(0);
reverse_string(s1);
reverse_string(s2);
reverse_string(s3);
reverse_string(s4);
reverse_string(s5);
printf("%s/n", s1);
printf("%s/n", s2);
printf("%s/n", s3);
printf("%s/n", s4);
printf("%s/n", s5);
return 0;
}
Editado para que el final no apunte a una ubicación de memoria posiblemente mala cuando strlen es 0.
código fácil y simple xD
void strrev (char s[]) {
int i;
int dim = strlen (s);
char l;
for (i = 0; i < dim / 2; i++) {
l = s[i];
s[i] = s[dim-i-1];
s[dim-i-1] = l;
}
}
#include <stdio.h>
int main()
{
char string[100];
int i;
printf("Enter a string:/n");
gets(string);
printf("/n");
for(i=strlen(string)-1;i>-1;i--)
printf("%c",string[i]);
}
#include <stdio.h>
#include <string.h>
int main()
{
char *data = "hello world";
int length=strlen(data);
char bytes[length];
int n=0;
while(n<=length)
{
bytes[n] = data[length-n-1];
n++;
}
printf("%s/n", bytes);
return 0;
}
/* Author: Siken Dongol */
#include <stdio.h>
int strLength(char *input) {
int i = 0;
while(input[i++]!=''/0'');
return --i;
}
int main()
{
char input[] = "Siken Man Singh Dongol";
int len = strLength(input);
char output[len];
int index = 0;
while(len >= 0) {
output[index++] = input[--len];
}
printf("%s/n",input);
printf("%s/n",output);
return 0;
}
Here is my shot which will handle all the cases
char *p ="KDLAKDADKADAD"
char p[] = "lammdlamldaldladadada"
also empty string
#include<stdio.h>
#include<string.h>enter code here
#include<stdlib.h>
char *string_reverse(char *p);
int main()
{
char *p = " Deepak@klkaldkaldkakdoroorerr";
char *temp = string_reverse(p);
printf("%s", temp);
}
char * string_reverse( char *p )
{
if(*p == ''/0'')
{
printf("No charecters are present /n");
return 0;
}
int count = strlen(p)+1;
int mid = strlen(p)/2;
char *q = (char *)malloc(count * sizeof(char));
if( q )
{
strcpy(q,p);
char *begin,*end,temp;
begin = q ;
end = q+strlen(p)-1 ;
int i = 0;
while( i < mid/2 )
{
temp = *end;
*end = *begin;
*begin = temp;
begin++;
end--;
i++;
}
return q;
}
else
{
printf("Memory Not allocated ");
}
free(q);
}
bool reverse_string(char* str)
{
// Make sure str is reversible
if (!str || strlen(str) < 2)
return false;
char* first = str;
char* last = str + strlen(str) - 1; // Minus 1 accounts for Index offset
char temp;
do{
temp = *first;
*first = *last;
*last = temp;
}
while (++first < --last); // Update Pointer Addresses and check for equality
return true;
}
Esta solución se basa en la publicación de GManNickG con algunas modificaciones. La declaración lógica inicial puede ser peligrosa si! Str no se evalúa antes de la operación strlen (para un ptr nulo). Este no fue el caso con mi compilador. Pensé que agregaría este código porque es un buen ejemplo de un ciclo do-while.
rev {
int len = strlen(str)-1;
for ( int i =0; i< len/2 ; i++ ) {
char t = str[i];
str[i] = str[len-i];
str[len-i] = t;
}
}
void reverse(char *s)
{
char *end,temp;
end = s;
while(*end != ''/0''){
end++;
}
end--; //end points to last letter now
for(;s<end;s++,end--){
temp = *end;
*end = *s;
*s = temp;
}
}