Programa para detectar palindromos

Iniciado por Error 404:, 3 Septiembre 2014, 13:23 PM

0 Miembros y 1 Visitante están viendo este tema.

Error 404:

Hola a todos, antes de nada, ya se que saqué este hilo hace algún tiempo, pero sigo teniendo un problema al que no consigo darle la solución. El objetivo del programa que estoy intentando crear es que al introducir una cadena de caracteres, éste te diga si esa cadena es o no un palíndromo (que se lee igual de izquierda a derecha y de derecha a izquierda (ejemplo otto)).
He conseguido compilar el código sin que me salga ningún error ni ningún warning, sin embargo cuando lo ejecuto, al introducir la cadena, no hace nada  :huh:
Les dejo el código por si me pudieran ayudar. Gracias de antemano a todos.
Código (cpp) [Seleccionar]


#include <iostream>
#include <cstring>

using namespace std;

bool palindromo(char cadena[100]);

int main(){

    char cadena[100];

    cout << "Introduzca una palabra o cadena de ellas sin utilizar espacios y/o" << endl;

    cout << " mayusculas, minusculas, acentos, etc. El programa le dira si la" << endl;

    cout << " cadena introducida es un palindromo."<< endl;

   

    cin >> cadena;

    cin.get();

    if (palindromo(cadena)) cout<< "Es un palindromo.";

    else cout<< " No es un palindromo.";


cin.get();

return 0;

}

bool palindromo(char cadena[100])
{

     int n;

     int j = sizeof(cadena)/sizeof(cadena[0]);

     int k = 0;

     do{

         if (cadena[k]!=cadena[j])(n=0);

         else {                                     

              k++;

              j--;

              n=1;

              }

         } while(k != j-1 || n!=0);

         if (n==1) return true; else return false;

}

Si se puede imaginar, se puede programar.

ivancea96

Hazlo haciendo que la variable 'j' sea strlen(cadena)-1.

Bueno, eso, y otros cambios que has de hacerle.

eferion

#2
Para las cadenas, usa la clase string en vez de char*:

Código (cpp) [Seleccionar]

#include <string>

// const& implica una referencia constante
bool palindromo( const std::string& cadena );

// ...

std::string cadena;

// ...

std::cin >> cadena;

// ...


Además, te complicas demasiado la forma de recorrer la cadena:

Código (cpp) [Seleccionar]
int j = sizeof(cadena)/sizeof(cadena[0]);

sizeof(cadena) te va a dar 100... realmente tiene 100 caracteres tu cadena???, no verdad??

Código (cpp) [Seleccionar]
int j = strlen(cadena) - 1;

O si estás haciendo uso de la clase string:

Código (cpp) [Seleccionar]
int j = cadena.length( ) - 1;

Por otro lado, haces un uso un tanto complicado de la variable 'n':

* No la inicializas al principio... eso es peligroso
* Solo va a tener dos posibles estados... mejor declararla como bool
* Poner nombres significativos a las variables facilita la lectura y mantenimiento del código.

Código (cpp) [Seleccionar]

bool esPalindromo = true;

do
{
 if ( cadena[ k ] != cadena[ j ] )
   esPalindromo = false;
 else
 {
   k++;
   j--;
 }
} while ( k < j && esPalindromo ); // k != j - 1 ¿¿??


Aún con todo, insisto, hay formas más sencillas de hacer esto. Por ejemplo copiar la cadena invertida en otro buffer (o en otra instancia de tipo string) y comparar ambas cadenas (con strcmp o con el operador == según el caso )... si son iguales entonces hay palíndromo:

Código (cpp) [Seleccionar]

int main( )
{
 std::string cadena;

 std::cout << "Introduce una cadena: " << std::endl;

 std::cin >> cadena;

 std::string cadenaInvertida{ cadena.rbegin( ), cadena.rend( ) };

 if ( cadena == cadenaInvertida )
   std::cout << "Es palíndromo" << std::endl;
 else
   std::cout << "NO es palíndromo" << std::endl;
}





PD.: Este es mi mensaje nº 1.000 yuhuuuu XDDD

vk496

Me ha intrigado tu propuesta, y me puse a hacerlo... pero en Bash (no domino el C/C++)

Código (bash) [Seleccionar]
#!/bin/bash

verde="\033[1;32m"
rojo="\033[1;31m"
rescolor="\e[0m"

frase=$(echo $@ | sed 's/ //g' | iconv -t ASCII//TRANSLIT | tr [:upper:] [:lower:])
ifrase=$(echo $frase | rev)

if [ -z "$frase" ]; then
echo Introduzca una palabra/frase como parámetro:
echo
echo -e $0 ${rojo}dábale arroz a la zorra el Abad$rescolor
exit 1
fi


if [ "$frase" = "$ifrase" ]; then
echo -e $verde$@$rescolor es un POLINDROMO
echo
echo ":)"
else
echo -e "$rojo$@$rescolor no es un polindromo :("
fi


Espero que te sirva

Salu2

rir3760

Cita de: eferion en  3 Septiembre 2014, 15:02 PMAdemás, te complicas demasiado la forma de recorrer la cadena:

Código (cpp) [Seleccionar]
int j = sizeof(cadena)/sizeof(cadena[0]);

sizeof(cadena) te va a dar 100
Ya que todo parámetro declarado como "T [N]" se procesa en realidad como "T *" el resultado de "sizeof(cadena)" sera igual a "sizeof(char *)". Por supuesto no deja de ser un error y hay que cambiar la aproximación a, como sugieres, el uso de la función strlen.

En el caso de cadenas "a la C" una aproximación en la misma linea mas propia de C que de C++ es:
Código (cpp) [Seleccionar]
bool palindromo(char const *str)
{
   size_t i;
   size_t j = strlen(str) - 1;
   
   for (i = 0; i < j && str[i] == str[j]; i++, j--)
      ;
   
   return i >= j;
}


Un detalle a tener en cuenta es que no hay protección en caso de una cadena vacía (solo el cero), en ese caso daría resultados incorrectos.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

Error 404:

#5
vk496 me temo que no se absolutamente nada de Bash :-\ pero gracias por la respuesta y me alegro que te resulte interesante mi propuesta  :rolleyes:

Eferion, he seguido algunos de tus consejos, y ahora me avisa de cuando es un palíndromo, pero si pongo una cadena/palabra que no lo es no me dice nada. He conseguido avanzar a que me diga cuando sí lo es, pero no consigo hacer que me diga cuando no.
Antes de ponerte el código actual, decirte que estoy siguiendo un manual pues aún no se mucho (como habrás notado), por eso no he usado el último consejo que me has dicho, pues aún no he llegado a eso, y la clase string, me temo que tampoco la he dado aún.
Bueno, dejo el código actual, para ver si alguien ve mi fallo, agradezco mucho las respuestas de verdad, aunque me gustaría que no solo me digáis lo que debo poner o quitar, sino que me intentéis explicar más o menos. el por qué falla como lo tengo, para así saber porque no funciona y evitar que ese fallo me suceda en más ocasiones.

rir3760 la verdad es que no se qué es size_t,´soy bastante nuevo y solo sé lo que he estudiado en el manual que leo, y no he visto nada de eso, por lo que no he entendido nada  :huh: :huh: :huh:

Dicho esto..


Código (cpp) [Seleccionar]


#include <iostream>
#include <cstring>

using namespace std;

bool palindromo(char cadena[100]);

int main(){

   char cadena[100];

   cout << "Introduzca una palabra o cadena de ellas sin utilizar espacios y/o" << endl;

   cout << " mayusculas, minusculas, acentos, etc. El programa le dira si la" << endl;

   cout << " cadena introducida es un palindromo."<< endl;

   

   cin >> cadena;

   cin.get();

   if (palindromo(cadena)) cout<< "Es un palindromo.";

   else cout<< " No es un palindromo.";


cin.get();

return 0;

}

bool palindromo(char cadena[100])
{

   
    bool esPalindromo = true;
    int j = strlen(cadena)-1;
    int k = 0;

    do{

        if (cadena[k]!=cadena[j]){
        esPalindromo = false;
}
else {                                      

             k++;

             j--;

             }

        } while(k < j && palindromo);
    if (esPalindromo) return true;
    else return false;
       

}






Vale, ya me he dado cuenta del error, el fallo estaba en la línea 57
Código (cpp) [Seleccionar]

} while(k < j && palindromo);


No es eso lo que debo poner, sino

Código (cpp) [Seleccionar]

} while(k < j && esPalindromo);


Al hacer ese pequeño cambio ya funciona todo correctamente, aunque si alguien me pudiera explicar por qué no hacía nada, porque entiendo que diera fallo, pero no que no saliera nada  :huh:
Si se puede imaginar, se puede programar.

rir3760

Porque "palindromo" es un puntero y cuando estos se convierten a booleanos los distintos de NULL resultan en true y los iguales en false, tu bucle se procesa de esta forma:
Código (cpp) [Seleccionar]
do {
   if (cadena[k] != cadena[j]){
      esPalindromo = false;
   }else {
      k++;
      j--;
   }
}while (k < j && true); // palindromo != NULL ==> true


Los resultados del operador && en los dos casos que nos importan son:
false && true ==> false
true && true ==> true


Como puedes ver (en este caso en particular) el segundo operando no importa, el resultado solo lo decide el primero, tenemos:
Código (cpp) [Seleccionar]
do {
   if (cadena[k] != cadena[j]){
      esPalindromo = false;
   }else {
      k++;
      j--;
   }
}while (k < j);


Por eso, si los caracteres a comparar en cualquier momento son distintos, se entra en un bucle infinito: para terminar se debe modificar el valor de los contadores "i" y "j" pero la rama de ejecución donde ello se realiza nunca se ejecuta.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

Error 404:

ah, creo que lo he entendido, gracias rir3760, y a todos por la ayuda ;-)
Si se puede imaginar, se puede programar.