Monthly Archives: January 2011

Cuando inicializar las variables en cero y cuando no

Cuando empecé a aprender a programar en c++ (creo que uno nunca acaba) me enseñaron que siempre hay que inicializar en cero o en algún otro valor las variables, porque si no, pueden tomar valores raros que podrían arruinar nuestro programa.

Vamos a ver si la leyenda es cierta:

#include
using namespace std;

int main()
{
    int var1;
    cout << var1;
}

Pues con mi compilador sí lo es, una variable sin inicializar toma valores raros. Pero si se han fijado en mis programas, yo no siempre inicializo mis variables, ¿por qué? Pues porque no siempre es necesario.

La regla es bastante simple: “Si la primera instrucción en la que usamos nuestra variable es de asignación, no es necesario inicializarla.” Por ejemplo:

cin >> var1; // no es necesario inicializarla
var2 = 14; // no es necesario inicializarla
cout << var3; // es necesario inicializarla
var4 = cos(45); // no es necesario inicializarla
var5++; // es necesario inicializarla
if(var6 != 7) // es necesario inicializarla
cin.getline(var7); // no es necesario inicializarla

Podemos seguir inicializando todas las variables que usemos, pero si únicamente inicializamos las necesarias vamos a dar la impresión de que sabemos lo que estamos haciendo XD

Advertisements

Simular una Progress Bar en C++

Una progress bar es la barrita, generalmente verde, que aparece en sistemas operativos e infinidad de programas cuando algo se está cargando. Hoy no nos vamos a meter en asuntos de cargar archivos o algo, únicamente vamos a ver el principio básico sobre el que operan estas barras.

Nuestro programa sólo pedirá una cantidad en segundos, que será el tiempo que durará en llenarse nuestra progress bar. A la ventana donde se ejecutan nuestros programas le caben 80 caracteres de largo, así que vamos a decir que nuestra progress bar tiene una resolución de 80. El único problema es saber cuánto durará cada unidad de esas 80 para que en total se acumule el tiempo indicado.

La función delay() o Sleep()

Si en su IDE pueden usar la librería conio.h, entonces van a usar la función delay(). Si no, vamos a tener que agregar la librería windows.h y usar la función Sleep() (así con mayúscula).

Ambas funciones hacen exactamente lo mismo: paran el programa durante una cierta cantidad de tiempo en milisegundos. Por ejemplo:
cout << "Hola" << endl;
Sleep(2000);
cout << "Hace dos segundos te saludé!";

Se muestra ‘Hola’, se pausa 2 segundos y se muestra ‘Hace dos segundos te saludé!’

Para los que usan conio.h, sería algo así:
printf("Holan");
delay(2000);
printf("Hace dos segundos te saludé!");

Ahora sí, para saber cuanto tiempo durará cada unidad de nuestra barra tenemos primero que convertir los segundos a milisegundos (s*1000), luego dividirlos entre la resolución de la barra (s*1000/80). Así que nuestro programa queda así:

#include
#include
using namespace std;

int main()
{
    int s;
    cout <> s;
    for(int i=0; i<=79; i++)
        cout << "_";
    for(int i=0; i<=79; i++)
    {
        cout << "=";
        Sleep(s*1000/80);
    }
}

El primer ciclo es solo por estética, para ver hasta donde va a llenar la barra. El segundo es el que imprime la barra con sus respectivas pausas.

Saber si es palíndromo o no, de forma recursiva 2da parte

Pues la idea que se me ocurrió en el otro post resultó ser más sencilla de lo que me imaginé, y ahora sí la función recursiva se ve mucho mejor, ya es mucho más que un ciclo disfrazado.

Comenté extensivamente el código, así que aquí está:

#include
#include
using namespace std;
int len, n=0;

string chk4palindrosity(string thestr)
{
    if(thestr[0] == thestr[thestr.length() - 1]) // comparar primer caracter con ultimo
    {
        n++;
        if(n == len / 2) // si el numero de veces que la comparación ha sido cierta es...
            return "Si es palindromo!"; // igual a la mitad de los caracters, es palindromo
        thestr.erase(0, 1); // borramos primer caracter
        thestr.erase(thestr.length() - 1, 1); // borramos ultimo
        return chk4palindrosity(thestr); // llamamos a la función con el string recortado
    }
    else // si una de las comparaciones no es cierta, no es palíndromo
        return "No es palindromo";
}

int main()
{
    char inputf[50]={0}, input[50], *parte;
    cout<<"Introduce un palindromo: "; cin.getline(input, 'n');

    parte = strtok(input, " ");                 //
    strcat(inputf, parte);                     //
    while((parte = strtok(NULL, " ")) != NULL) //
        strcat(inputf, parte);               // quitar espacios del array

    string thestr(inputf); // convertir array en string para facilitar operaciones
    len = thestr.length(); // obtener longuitud del string
    if(len == 1)
        cout << "Si es palindromo!";
    else
        cout << chk4palindrosity(thestr); // llamar a la funcion e imprimir lo que retorne
    cin.get();
}

Lo que hace la función recursiva es comparar el primer caracter con el último, si son iguales recortarlos y llamarse; si no, no es palíndromo. Cualquier duda ya saben que los comentarios están abiertos.

Saber si es palíndromo o no, de forma recursiva

Hace unos días me pidieron por correo un programa que nos dijera si un string es palíndromo o no, pero usando una función recursiva. Me pareció interesante aunque raro que pidieran hacerlo de forma recursiva.

Tal vez recuerden que ya había publicado aquí una forma de saber si un string es palíndromo o no, el cual he descubierto (ahora que hice este otro) que no es muy eficiente.

Bueno pues el código es este:

#include
#include
using namespace std;
char cadenaf[50]={0}; int len, n=0;

string chk4palindrosity(int c)
{
    if(cadenaf[c] == cadenaf[len-1-c])
    {
        n++;
        if(n == len/2)
            return "Si es palindromo!";
        return chk4palindrosity(c+1);
    }
    else
        return "No es palindromo";
}

int main()
{
    char cadena[50],*parte;
    cout<<"Introduce un palindromo: "; cin.getline(cadena,50,'n');

    parte = strtok(cadena," ");                 //
    strcat(cadenaf,parte);                     //
    while((parte = strtok(NULL," ")) != NULL) //
        strcat(cadenaf,parte);               // quitar espacios del string

    len = strlen(cadenaf);
    cout << chk4palindrosity(0);
    cin.get();
}

La verdad es que es la función es recursiva de puro milagro. Lo que hice fue transformar el ciclo que checaba que los caracteres fueran iguales en una función en la que se aumenta una variable cada vez que se llama a sí misma.

El código ahora es más eficiente por dos simples razones:

  1. Se detiene y da el resultado a la primera comparación de caracteres que no sean iguales. Si el primer y el último caracter no son iguales, no es palíndromo y ya no sigue analizando los demás.
  2. Sólo checa la mitad de los caracteres. Si la mitad de los caracteres corresponden a la configuración de un palíndromo, ya no hay porqué seguir analizando la otra mitad.

Tal vez una mejor manera de hacerlo sería con una función que recibiera el string a analizar, comparar el primer y último caracter: si no, no es; si si, eliminar el primer y último caracter y volver a llamar a la función. Esto hasta que el numero de comparaciones ciertas sea igual a la mitad de la longitud inicial del string. ¿Alguien se anima a hacerlo?