29.1.05

Comprara dos archivos.

Saludos.

El siguiente programa permite comparar dos archivos de texto binários. Aunque funciona la mayoría de las veces, tiene bastantes errores de diseño y, con ciertas condiciones especiales falla.


#include
#include

#define SIZE 256

// Devuelve 1 si son distintos y 0 si son iguales.
int cmpArrays(char a1[], char a2[], int size);

int main(int argc, char *args[])
{
char buff1[SIZE], buff2[SIZE];
int fd1, fd2;
int readed1, readed2;

fd1 = open(args[1], O_RDONLY);
fd2 = open(args[2], O_RDONLY);

while ( (readed1=read(fd1, buff1, SIZE)) >0) {
readed2=read(fd2, buff2, SIZE);
if (readed1 != readed2) {
printf("\nArchivos de distinto tamaño.\n");
return 0;
}
if (cmpArrays(buff1, buff2, readed1)) {
printf("\nArchivos con distinto contenido.\n");
return 0;
}
}

close(fd1);
close(fd2);

printf("\nArchivos iguales.\n");

return 0;
}


//------------------------------------

int cmpArrays(char a1[],char a2[], int size)
{
int c;

for (c=0; c < size;c++)
if (a1[c] != a2[c])
return 1;

return 0;
}

Guardar la entrada estándar en un fichero.

Saludos.

El siguiente código va leyendo la entrada estándar y guardando lo leido en un archivo buffer.f



#include
#include
#include

int main()
{
int fd;
char *buffer[256];
int b_leidos, b_escritos;

fd = open("buffer.f", O_WRONLY | O_APPEND);
if (fd == -1)
{
printf("\nCreando fichero 'buffer.f'\n");
fd = open("buffer.f", O_WRONLY | O_CREAT, 00600);
if (fd == -1)
{
perror("Error creando 'buffer.f'\n");
return -1;
}
}

b_leidos = read(0, buffer, 256);
while (b_leidos > 0)
{
b_escritos = write(fd, buffer, b_leidos);
if (b_escritos == -1)
{
perror("Error escribiendo.\n");
return -1;
}
b_leidos = read(0, buffer, 256);
}
close(fd);
}

23.1.05

Funciones potencial y factorial

Saludos.

Como recordatorio de la manera de hacer bibliotecas de funciones y de las técnicas recursivas, se propuso como ejercicio implementar una biblioteca de funciones con una función potencial y otra factorial. A continuación se muestra dicha biblioteca con versiones recursivas y no recursivas.

Próximamente más.

pot_fac.h

#ifndef __pot_fac__
#define __pot_fac__

int potencial_nr(int, int);
int potencial_r(int, int);
int factorial_nr(int);
int factorial_r(int);

#endif





pot_fac.c

#include "pot_fac.h"

int potencial_nr(int valor, int potencia)
{
int i, resultado;
resultado = 1;
for (i=0; i 0; i--)
resultado *= i;
return resultado;
}

//---------------------------------------------
int factorial_r(int valor)
{
if (valor == 1)
return 1;
return valor * factorial_r(valor-1);
}





prueba_pot_fac.c

#include "pot_fac.h"

int main() {

int resultado;

resultado=potencial_nr(4, 3);
printf("4 elevado a 3 %i (no resursivo)\n", resultado);

resultado=potencial_r(3, 3);
printf("3 elevado a 3 %i (resursivo)\n", resultado);

resultado=factorial_nr(4);
printf("4 factorial %i (no resursivo)\n", resultado);

resultado=factorial_r(6);
printf("6 factorial %i (resursivo)\n", resultado);

return 0;
}


Contar caracteres de una frase

Saludos.

Este ejercicio se propuso para que los alumnos repasaran sus conocimientos de manejo de cadenas en C. El objetivo es introducir una frase en la línea de comandos. El programa devolverá el número de veces que se repite cada una de las letras en la frase.

Próximamente más.


#include "stdlib.h"
#include "string.h"

// Variables globales;
char caracteres[29];
int car_index = 0;
int repeticiones[29];

// Prototipos
void incCaracter(char caracter)
{
int pos = -1;
int i;

for (i=0; i< car_index; i++)
if (caracteres[i] == caracter)
pos = i;

if (pos == -1) {
//car_index++;
caracteres[car_index] = caracter;
repeticiones[car_index] = 0;
pos = car_index;
car_index++;
}

repeticiones[pos] ++;
}

//-----------------------------------------------------
int main(int argc, char *argv[])
{
char cadena[255];
int i = 0;

if (argc < 2) {
printf("Parámetros insuficientes. \n");
return -1;
}
strcpy(cadena, argv[1]);

while (cadena[i] != '\0')
{
incCaracter(cadena[i]);
i++;
}

printf("Estadísticas de <%s>: \n", cadena);
for (i=0; i < car_index; i++)
printf("%c : %i \n", caracteres[i], repeticiones[i]);

return 0;
}



19.1.05

Operación Limpieza

Aviso a navegantes.

Por estas fechas termino de impartir una serie de clases sobre programación C básica en sistemas Unix/Linux (Fedora y SunOS). Por este motivo voy a ir publicando aquí en los próximos días el código de los ejemplos y problemas extra que he ido proponiendo a mis alumnos.

También pondré de vez en cuando algún otro post como los que hay más abajo para que esto no se convierta en un monográfico C bajo Unix.


16.1.05

Convertir double a caddena

Saludos.

El otro día me preguntaron como pasar un tipo double a cadena con un número determinado de decimales, por ejemplo 2, en Java. Una posible solución se muestra a continuación:



import java.text.DecimalFormat ;

public class Decimal {

public static void main(String args[]) {

double d1 = 123456789.123456789;
double d2 = 1.7976931348623157d;
double d3 = 4415961481999.03D;
DecimalFormat df = new DecimalFormat ("##############.##");

System.out.println ("d1:"+df.format(d1));
System.out.println ("d2:"+df.format(d2));
System.out.println ("d3:"+df.format(d3));

/**
Salida:
>java Decimal
d1:123456789,12
d2:1,8
d3:4415961481999,03
}
}



14.1.05

Pruebas como indicadores del avance de un proyecto.

¿Cuándo finaliza la construcción de un programa?. ¿Cuánto hemos avanzado esta semana?. ¿Vamos más rápidos o más lentos que el mes pasado?.

Todas estas preguntas se refieren a la velocidad con la que se crea o construye un programa y, en muchas ocasiones no son fáciles de responder. Una primera idea podría ser pensar que el avance de un programa tiene relación con las líneas de código escritas o número de clases implementadas, pero nada más lejos de la realidad. Es posible, por ejemplo, escribir 100.000 líneas de código o 50 clases en una semana y que el proyecto no avance ni un ápice, porque, por ejemplo, el código no funcione correctamente y necesite una depuración a fondo, o no pueda incorporarse al resto del programa o tenga que ser reescrito o, simplemente, se haya escrito código para una característica o función que no va a tener el sistema, por lo que no habrá servido de nada.

Una aproximación más fiable, pero aún no perfecta desde mi punto de vista, es relacionar el avance del proyecto con el cumplimiento de los requisitos. Un requisito es una característica que el sistema debe tener o algo que debe permitir hacer. A medida que vayamos escribiendo código, el sistema permitirá hacer cada vez más cosas, hasta que el sistema sea capaz de hacer todo lo que le piden los requisitos, momento en el que estará terminado. Sin embargo a veces es difícil cuantificar, a partir del código, el cumplimiento de requisitos. Por ejemplo, en un sistema típico de gestión comercial, si empleamos dos semanas en construir las bases de datos y las clases de acceso a las bases de datos (algo que será necesario para todos los requisitos), ¿qué grado de cumplimiento de los requisitos hemos conseguido un 1%, un 10%?. ¿Algún requisito habrá avanzado más que otro?. ¿Cuánto nos queda para satisfacer todos los requisitos?.

La mejor aproximación desde mi punto de vista, y que aúna características de las dos anteriores, es medir el avance del proyecto en función de la superación de pruebas. El proyecto estará terminado cuando sea capaz de superar todas las pruebas que lo verifiquen. Una semana se avanzará más que otra si ha sido capaz de superar todas las pruebas de la semana anterior y un número mayor de nuevas pruebas. Esta aproximación nos permite además, medir el desarrollo del código, mediante pruebas unitarias, y medir el cumplimiento de requisitos, mediante pruebas del sistema o pruebas de aceptación. En el momento en que ambas medidas alcancen el máximo, el sistema hará todo o que debe hacer sin errores en su código.

Un motivo más que justifica escribir pruebas para nuestros proyectos: no solo nos garantizan el cumplimiento de requisitos y la ausencia de errores, sino que nos permiten conocer el estado de nuestro proyecto, a que ritmo avanza y cuanto queda para su conclusión.


6.1.05

Límite de procesos en Unix/Linux

Saludos.

Preparando una clase de programación en C Unix/Linux he intentado hacer un ejemplo donde un gran número de procesos accedieran simultáneamente a un trozo de memoria compartida y los resultados no fueran los esperados. Con esto pretendía ilustrar la necesidad de garantizar la exclusión mútua.

No lo he conseguido. Mi Knoppix solo me ha permitido lanzar 487 procesos simultáneamente, mientra que SunOS me dejaba algunos más, hasta 496, 497 más o menos. Por desgracia con este número de procesos todo funcionaba a la perfección y, aunque no garantizara la exclusión mútua, ningún proceso se pisaba a otro.

Tnedré que escribir un programa donde fuerce la situación con unos sleep estratégicamente colocados.

Es una alegría que los Linux/Unix funcionen bien incluso cuando uno quiere que fallen.