Mostrando entradas con la etiqueta Programacion. Mostrar todas las entradas
Mostrando entradas con la etiqueta Programacion. Mostrar todas las entradas

martes, 2 de abril de 2013

Limpiar la entrada estándar en C en Linux, fflush(stdin)

Uno de los problemas que surgen a la hora de programar en C en Linux es que no podemos limpiar los caracteres no deseados que quedan almacenados en ocasiones en la entrada estándar, ya que al ejecutar la función fflush(stdin) no tiene efecto al usarse sobre el flujo de entrada.

Podemos solucionar este problema usando una función como la siguiente:


void fflushin()
{

 int d, i=0;

 d = stdin->_IO_read_end - stdin->_IO_read_ptr;

 for(i=0; i<d; i++)
  getchar();
}


La operación stdin->_IO_read_end - stdin->_IO_read_ptr nos permite calcular el número de caracteres que quedan almacenados en la entrada estándar a partir de la posición actual del puntero (osea, los caracteres sobrantes), después solo tenemos que ejecutar la función getchar() tantas veces como caracteres haya, para limpiar así la entrada estándar y deshacernos de esos caracteres no deseados.


EJEMPLO DE USO

Una situación muy habitual en la que es necesario usar una función como la anterior es la siguiente:

#include <stdio.h>

main()
{

 int num;

 printf("\nInserta un numero: ");
 
 scanf("%d", &num);

 printf("numero insertado: %d", num);

 printf("\n\nPulsa enter para continuar\n\n");

 getchar();
}


En el programa anterior tenemos la intención de usar la función getchar() para pausar la ejecución del programa hasta que el usuario pulse la tecla enter, pero debido a la función scanf se queda un caracter sin leer en la entrada estándar (el caracter de nueva linea), caracter que leerá la función getchar() sin detenerse como teníamos previsto.

Para solucionarlo lo único que tenemos que hacer es limpiar los caracteres no deseados que se han quedado en la entrada estándar usando la función fflushin() que hemos definido:



#include <stdio.h>

void fflushin()
{

 int d, i=0;

 d = stdin->_IO_read_end - stdin->_IO_read_ptr;

 for(i=0; i<d; i++)
  getchar();
}

main()
{

 int num;

 printf("\nInserta un numero: ");
 
 scanf("%d", &num);

 printf("numero insertado: %d", num);

 printf("\n\nPulsa enter para continuar\n\n");

 fflushin();

 getchar();
}




Y de esta manera el programa funciona tal y como habíamos planeado ya que la función fflushin() ha limpiado esos caracteres no deseados de la entrada estándar y por lo tanto la función getchar() detiene la ejecución del programa hasta que el usuario pulse la tecla enter.

Saludos =)


domingo, 27 de enero de 2013

Visor hexadecimal

Buenas, en esta entrada os traigo algo que tenía ganas de hacer hace tiempo, un programa para ver los datos de un archivo en formato hexadecimal.

Este tipo de programas es algo que suelo usar bastante, así que ademas de servirme como práctica de programación también es algo a lo que le voy a dar bastante uso.

La verdad es que me gusta la simplicidad con la que he diseñado el programa. De momento el programa solo visualiza los datos, pero probablemente modifique el programa para que también permita editarlos.

Cuando ejecutéis el programa os saldrán dos columnas, a la izquierda os aparecerán los datos en hexadecimal y a la derecha los caracteres ASCII imprimibles.

En la columna de la derecha, donde se visualizan los caracteres imprimibles, he decidido poner solo los caracteres básicos, del ASCII 33 al 126, y no los extendidos, ya que varían según la codificación que se use.

Os dejo el código a continuación:

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[])
{
 FILE *arc;

 int i=0, k=0, h=0, j=0, m=0, x=0;
 int **car = NULL;


 if(argc<2)
 {
  printf("\nFaltan un argumento\n\nModo de uso: %s \n\n", argv[0]);
 
  exit(-1);
 }


 if((arc = fopen(argv[1], "r")) == NULL)
 {
  printf("\nError al abrir el archivo\n\n");
 
  exit(-1);
 }


 while(!ferror(arc) && !feof(arc))
 {

  if ((car = (int **)realloc(car, (i+1) * sizeof(int *))) == NULL)
  {
   printf("\nError al asignar memoria\n\n");
   exit(-1);
  }


  if((car[i] = (int *)malloc(16 * sizeof(int))) == NULL)
  {
   printf("\nError al asignar memoria\n\n");

   exit(-1);
  }


  for(k=0; k<16; k++)
  {
  
   car[i][k] = fgetc(arc);

  }

  i++;

 }

 if(ferror(arc))
 {
  perror("\nSe ha producido un error durante la lectura\n\n");
 }


 printf("\n\n");


 for(h=0; h<i; h++)
 {
  for(j=0; j<16; j++)
  {
  
   if(car[h][j]==-1)
   {
    for(x=0; x < (16-j); x++)
     printf("   ");

    break;
   }
   else
   {
    if(car[h][j]<16)
    {
     printf("0%X ",car[h][j]);
    }
    else
    {
   
     printf("%X ", car[h][j]);
    }
   
   
   }

  }

  printf("\t");

  for(j=0; j<16; j++)
  {
 
   if(car[h][j]==-1)
   {
    break;
   }
   else
   {
   
    if((car[h][j] > 32) && (car[h][j] < 127))
    {
    
     printf("%c",car[h][j]);
   
    }
    else
    {
    
     printf(".");

    }
   }
  }


 printf("\n");
 
 }

 printf("\n\n");


 for(m=0; m<i; m++)
  free(car[m]);


 free(car);

 fclose(arc);


 return 0;

}
 


lo compilamos con:


cc hexa.c -o hexa


Para ejecutarlo solo tenemos que indicar como argumento el nombre de archivo que queremos visualizar:


./hexa <nombre_archivo>


Si el archivo a visualizar es demasiado grande probablemente el shell os trunque el principio de los datos, en esos casos os recomiendo redireccionar la salida del programa a un archivo tal que así:


./hexa archivo.jpg > prueba


y a continuación visualizar el archivo resultante desde un editor de texto.

espero que os haya gustado

Saludos =)