Problema con un programa en C (string.h y funciones)

Iniciado por loriik, 11 Marzo 2014, 01:00 AM

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

leosansan

#10
Cita de: yoel_alejandro en 11 Marzo 2014, 08:33 AM
Totalmente de acuerdo engelx, pero también hay considerar a veces que no sólo el código fuente sea más breve, sino que realmente se ejecute más rápido.

Por ejemplo, usas tres veces el strlen(text) es decir una sobrecarga por llamadas a función. Sería mejor definir una constante y asignarle el valor N = strlen(text), luego usas N. Esto quizá lleve más líneas de código fuente pero se ejecutará más rápido.

Aunque aparentemente sea así, por lo que tengo entendido el compilador se encargará de eso de  forma automática

Ya he comprobado que en otras ocasiones el definir una función como inline no produce las mejoras que se esperan de ello ya que al parecer, aunque no la declares como inline, en ocasiones el compilador hace la misma tarea que al declararla inline.


¡¡¡¡ Saluditos! ..... !!!!




eferion

Cita de: leosansan en 11 Marzo 2014, 11:13 AM
Aunque aparentemente sea saí, por lo que tengo entendido el compilador se encargará de eso de  forma automática

Ya he comprobado que en otras ocasiones el definir una función como inline noproduce las mejoras que se esperan de ello ya que al parecer, aunque no la declares como inline, en ocasiones el compilador hace la misma tarea que al declararla inline.


¡¡¡¡ Saluditos! ..... !!!!




Efectivamente, los compiladores de hoy en día hacen maravillas en cuanto a optimizaciones. De hecho muchos compiladores ignoran el uso de inline y lo aplican a discreción según el código que se encuentren (aunque éste esté en el cpp).

En cualquier caso, si un mismo resultado se va a utilizar varias veces en una misma función siempre queda mejor almacenarlo en una variable que volver a insertar la llamada a la función. De esa forma te aseguras que el código sea más óptimo independientemente de que el compilador optimice de una forma o de otra.

rir3760

Cita de: yoel_alejandro en 11 Marzo 2014, 03:43 AMPor último un detalle sutil. Cuando la longitud N de la palabra sea impar, el cociente N/2 será decimal, pero los tipos de las variables i, N son enteros, por eso la comparación i < N/2 no será válida. Es necesario convertir N a float para que admita los decimales y por eso ponemos i < (float)N / 2.
La conversión al tipo float no es necesaria ya que la división entre dos números enteros resulta en un valor también entero (los decimales se descartan).

----

Una forma ligeramente distinta a las expuestas es:
#include <string.h>

int es_palindromo(char const *cad)
{
   int i;
   int j = strlen(cad) - 1;
   
   for (i = 0; i < j && cad[i] == cad[j]; i++, j--)
      ;
   
   return i >= j;
}


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

leosansan

#13

Por cierto amigo engelx, en mi caída te arrastré antes y ninguno pusimos los include de cabecera, lo que nos dice que con la emoción no pusimos atención a los warnings que nos lazaba el compilador. Y es que donde esté un "pique" sanote que se quite todo lo demás.


Código (cpp) [Seleccionar]

#include <stdio.h>
int main (){
   char text[100];
   int i=0,j=0;
   printf("\n Introduce un texto ");
   gets(text);
   while (text[j++]!='\0');
   for(;text[i]==text[j-i-2] && j/2>i++;);
   printf (i>j/2 ? "\n Es un palindromo ": "\n No es un palindromo ");
   return 0;
}


Aunque tengo un while de más, me ahorro la librería string.h y el repetir strlen en tres ocasiones y además, como ya comentaron anteriormente, el código está más optimizado sin calcular tantas veces strlen.

¡¡¡¡ Saluditos! ..... !!!!



do-while

#14
¡Buenas!

Estaba corrigiendo el código para que tuviese en cuenta los espacios y las eñes, y la parte de los espacios va sobre ruedas, pero por lo menos en Debian no reconoce las eñes, ni introduciendolas como caracteres ni introduciendo sus valores, ni con signo ni sin signo...

¿Alguien puede confirmarmelo?


#include <stdio.h>
#include <ctype.h>
#include <string.h>

char mayus(char c)
{
   if(c == 'ñ')
       return 'Ñ';

   return toupper(c);
}

int palindromo(char *s)
{
   int ini = 0 , fin = strlen(s) - 1;

   while(ini < fin)
   {
       while(isspace(s[ini]) && s[ini])
           ini++;

       while(isspace(s[fin]) && fin > 0)
           fin--;

       if(ini < fin && mayus(s[ini]) != mayus(s[fin]))
           return 0;

       ini++;
       fin--;
   }

   return 1;
}

int main ()
{
   char text[100]="dabale\n \t Arroz a      la zorra el abad";
   char texto[100]="   aMa \n ña ÑamA";
   int i=0;

   printf("%d %d\n", (unsigned char)'ñ' , (unsigned char) 'Ñ');

   printf("%s",text);
   for(;text[i]==text[strlen(text)-i-1] && strlen(text)/2>i++;);

   printf (i>strlen(text)/2 ? "\n Es un palindromo ": "\n No es un palindromo ");
   printf(palindromo(text) ? "\n Es un palindromo ": "\n No es un palindromo ");
   printf(palindromo(texto) ? "\n Es un palindromo ": "\n No es un palindromo ");

   return 0;
}


¡Saludos!
________________________________________________________________________________________________________

PD: Cambiando la condición isspace por !isalnum ignoraréis cualguier cosa que no sea un caracter o un número (incluida la ñ...). Por ejemplo:

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int mayus(int c)
{
    if(c == 'ñ')
        return 'Ñ';

    return toupper(c);
}

int palindromo(char *s)
{
    int ini = 0 , fin = strlen(s) - 1;

    while(ini < fin)
    {
        while(!isalnum(s[ini]) && s[ini++]);

        while(!isalnum(s[fin]) && fin-- > 0);

        if(ini < fin && mayus(s[ini++]) != mayus(s[fin--]))
            return 0;
    }

    return 1;
}

int main ()
{
    char texto[100]="a man, \n a p\tlan, a canal, panama";
    int i;

    printf("%s",texto);

    for(;texto[i]==texto[strlen(texto)-i-1] && strlen(texto)/2>i++;);

    printf (i>strlen(texto)/2 ? "\n Es un palindromo ": "\n No es un palindromo ");
    printf(palindromo(texto) ? "\n Es un palindromo ": "\n No es un palindromo ");

    return 0;
}


Lo de la ñ debe ser porque lo considera un caracter multibyte..., ahora investigo un poco mas.

Con la última modificación ha quedado un poco mas compacto pero un poco menos legible XD.

¡Saludos!
________________________________________________________________________________________________________

sizeof('ñ') en Debian, me está diciendo que son 4 bytes...
- Doctor, confundo los números y los colores.
- Vaya marrón.
- ¿Marrón? ¡Por el culo te la hinco!

Yoel Alejandro

rir3760, no era exactamente eso lo que quería decir. Mi intención era precisamente que sí reconociera los decimales, por ejemplo, si la longitud es N=5 se consideraran los valores i = 0, i = 1, i = 2. O sea todos los valores enteros de i no mayores a 5/2 = 2.5, en cuyo caso debemos convertir a float o double, pues de otro modo la sentencia i < N/2 llegaría sólo hasta i=1.

Claro, ahondando en el fondo vemos que i = 2 no es necesario porque no necesitamos comparar el elemento del medio de la cadena. O sea que al final el (float) sí es redundante.

Pero lo que quiero decir es que en un problema donde se requiriera llegar hasta el elemento del medio i = 2, habría que poner el (float), ya que de otro modo la sentencia i < N/2 con N = 5, llegaría hasta i = 1. Y si se nos ocurre poner i <= N/2 también estaría mal porque en el caso que N sea par, ejemplo N = 6, llegaría hasta i = 3 cuando debería ser hasta i = 2. En un caso como ese creo que no queda otro remedio que i < (float)N/2

Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)

rir3760

Cita de: yoel_alejandro en 11 Marzo 2014, 23:05 PMPero lo que quiero decir es que en un problema donde se requiriera llegar hasta el elemento del medio i = 2, habría que poner el (float), ya que de otro modo la sentencia i < N/2 con N = 5, llegaría hasta i = 1. Y si se nos ocurre poner i <= N/2 también estaría mal porque en el caso que N sea par, ejemplo N = 6, llegaría hasta i = 3 cuando debería ser hasta i = 2. En un caso como ese creo que no queda otro remedio que i < (float)N/2.
Si la intención es procesar la primera mitad de un array incluyendo el elemento pivote (si existe) me parece mas sencillo utilizar la expresión "i < (N + 1) / 2" para controlar el bucle.

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

leosansan

Cita de: yoel_alejandro en 11 Marzo 2014, 23:05 PM
......................................................................................

Pero lo que quiero decir es que en un problema donde se requiriera llegar hasta el elemento del medio i = 2, habría que poner el (float), ya que de otro modo la sentencia i < N/2 con N = 5, llegaría hasta i = 1. Y si se nos ocurre poner i <= N/2 también estaría mal porque en el caso que N sea par, ejemplo N = 6, llegaría hasta i = 3 cuando debería ser hasta i = 2. En un caso como ese creo que no queda otro remedio que i < (float)N/2



No, no y no. El término central en un array de cindo elementos no es el 2.5 sino el tercero.

Paree que olvidas que los elemento de un array es un caso particular de los términos de una sucesión, que no es más que una aplicación biyectiva entre los números naturales y los elementos de la sucesión .. y entre los números naturales no están los decimales.

El problema se reduce a comparar la sucesión de los elementos de la de parte izquierda con los de la parte derecha y:

* si se trata de un número par se compara exactamente la mitad.

*  si se trata de un número impar se compara la mitad menos uno de cada parte, quedando el central sin nadie con quien compara, por lo que se pasa de él.

De ahí que la expresión N/2 sea la apropiada a emplear.


¡¡¡¡ Saluditos! ..... !!!!




do-while

Ese algoritmo tiene grades fallos lógicos:

O bien la cadena tiene que ser simétrica con respecto al centro o no puede contener espacios.

Dado que hay palíndromos que contienen espacios y que no son simétricos os dirá que textos que realmente son palíndromos no lo son (ej: Anita lava la tina).  Lo de los espacios lo podéis arreglar añadiendo una función que los elimine. De todas todas tenéis que corregir el código.

¡Saludos!
- Doctor, confundo los números y los colores.
- Vaya marrón.
- ¿Marrón? ¡Por el culo te la hinco!

Yoel Alejandro

Cita de: rir3760 en 12 Marzo 2014, 03:38 AM
Si la intención es procesar la primera mitad de un array incluyendo el elemento pivote (si existe) me parece mas sencillo utilizar la expresión "i < (N + 1) / 2" para controlar el bucle.

Es otra manera, gracias.

Para do-while, la solución que presenté considera que la palabra no contiene espacios, y fue así para mantenerme fiel al enfoque dado inicialmente al tema por parte de su autor. Luego él mencionó el problema de los espacios, y creo que después presentó en un programa capaz de manejar ese problema.

Leosansan ya va tranquilo, calma. Por supuesto que el elemento central de una sucesión de cinco elementos no es el 2.5, sino el 2 (o sea, de índice 2). Se trataba de una condición que pudiera discernir los valores correctos de i a tomar. Al redondear a enteros, la condición i < 2.5 se reduce a i = 0, 1, 2, como queríamos.

O más precisamente, tal como rir3760 y tú dicen la condición i< N/2 es la apropiada si para el caso impar no se toma el elemento central (el caso nuestro), y la condición i < (float)N / 2, o bien i < (N+1)/2 si el elemento central fuera tomado (que no es nuestro caso).

Pero yo tuve un lapsus y por alguna razón incluí el elemento central o pivote, de donde surgió toda la discusión. Conste que incluir este pivote no afecta el resultado del programa, por cuánto estaría comparando dicho elemento consigo mismo y a lo peor incurre en una pequeña falta de eficiencia.
Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)