Bienvenid@ a Guimi.Net
 
 Cambiar a versión para impresión

Introduccion a C (ANSI)

Creative Commons License Marzo de 2006 Güimi (http://guimi.net)
Está permitido copiar, distribuir y/o modificar los documentos bajo los términos de la licencia
"Reconocimiento-Compartir bajo la misma licencia 3.0 España" de Creative Commons.
Puede ver una copia de esta licencia completa.

Introducción

Esta es una introducción a C a base de ejemplos y orientada a programadores de otros lenguajes.
Si no sabe lo que son variables, funciones, recursividad... busque un buen curso o tutorial, hay algunos muy buenos en internet.
 
Los ejemplos están explicados en el propio código con comentarios.
Lea el código y los comentarios de cada ejemplo, cópielo, compílelo y ejecútelo.
Despu´┐Żs vuelva a leer el c´┐Żdigo y los comentarios.
Casi todos los ejemplos, con pocas modificaciones y mucho comentario, proceden de apuntes de las asignaturas MTP y SO de la UPV y del tutorial "Programming C" de Steve Holmes (antes disponible en Universidad de Strathclyde -enlace original desaparecido-).
 
Recomiendo conseguir una copia de la "C Reference Card (ANSI)".
 

El lenguaje C

Información extraida de la Wikipedia que tiene un excelente artículo sobre C.
El desarrollo inicial de C se realizó a principio de los 70 en los laboratorios Bell-Labs de AT&T, deriv´┐Żndose del lenguaje B, una versión reducida de BCPL realizada por Ken Thompson.
Thompson y Dennis Ritchie querían portar el SO de una PDP-7 a una PDP-11 (según cuenta la leyenda, para poder jugar al Space Travel, del propio Thompson), pero todo el SO estaba escrito en código ensamblador por lo que el coste era alto. Así que se les ocurrió nada menos que crear un nuevo SO portable (UNIX) con un nuevo lenguaje portable (C). En realidad primero hicieron UNIX en ensamblador de PDP-11/20 y después hicieron C con el que reescribieron UNIX (!).
En 1978 Ritchie y Brian Kernighan escribieron un manual de C (The C Programming Language) que sirvió como primera especifición del lenguaje, estandarizando su uso e incluyendo algunas mejoras. Esta especificación se conoce como K&R C.
En 1983 aparece C++. Ese mismo año el ANSI crea un comité para estandarizar el lenguaje C. Dicho estandard, aparecido en 1989, es el ANSI C original, o C89, para distinguirlo.
En 1990 la ISO adopta C89 con algunos pequeños cambios menores. Es el ANSI C90, o simplemente ANSI C.
Existe una revisión conocida como C99, pero C++, que tiene un gran mercado (mucha parte del código de Windows, por ejemplo) es más compatible con C90 que con C99, y algunos compiladores no reconocen las funcionalidades de C99 incompatibles con C++.
 
Todos los ejemplos de esta página se ajustan -o eso pretenden- a ANSI C y han sido probados y compilados con gcc en GNU/Linux. Todos los ejemplos de la primera parte (los que no son específicos de procesos y ficheros en POSIX) se han probado y compilado también en Windows.
 

Ejemplos de código

01-Hola_Mundo.c
// Guimi - 2006-03 http://guimi.net
// Esto es un comentario
/* Esto tambien es un comentario */

/* Linux / UNIX estan programados en C, por lo que las instrucciones de C
 *  se pueden usar como comandos (mas o menos).
 * En todo caso, siempre se puede hacer "man 3 instruccion" para aprender
 *  a usar una instruccion y saber en que libreria se encuentra.
 * */


/* Hay que compilar el codigo con
 *  gcc -o 01-Hola_Mundo 01-Hola_Mundo.c  //Linux
 *  gcc -o 01-Hola_Mundo.exe 01-Hola_Mundo.c  //DOS
 */

// DIRECTIVAS
/* Libreria standar de entrada / salida.
 * Usada para printf.
 * */
#include <stdio.h>

/* Funcion principal, que inicia la ejecucion.
 *  int  - es el tipo de valor que devuelve (integer: numero entero).
 *  main - es el nombre, indica que es la funcion principal.
 *  ()   - indica que no toma ningun argumento.
 * */
int main() {
	//Si quisiesemos limpiar la pantalla al principio
	//system ("clear"); // Para Linux
	//system ("cls"); // Para DOS

	// Mostramos un saludo
	printf("Hola mundo\n");
	/* Mostramos caracteres raros como " o \ */
	printf("Esto es \"extra´┐Żo\"\\raro\n");

	/* Ejemplo de que el tipo char es en realidad un int pequenyo */
	char letra = 'A';
	printf( "El n´┐Żmero ASCII de la letra %c es: %i.\n", letra, letra );
	/* Formato de strings
	 * %d	- Decimal Integer
	 * %f	- Float
	 * %lf	- Long Float (Double)
	 * %e	- Exponential
	 * %i	- Short Integer
	 * %u	- Unsigned Integer
	 * %x	- Hexadecimal Integer
	 * %o	- Octal Integer
	 * %g	- Shorter of %f and %e
	 * %c	- Character
	 * %s	- String (char *)
	 * */

	/* Mostramos el tama´┐Żo de un tipo int */
	int num1;
	printf( "El tipo int ocupa %i bytes\n", sizeof(int) );

	/* Terminamos la funci´┐Żn main devolviendo el valor 0
	 *  que indica 'sin errores'.
	 */
	return 0;
}


[Índice]

02-Interaccion.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
/* Libreria estandar de utilidades generales, necesaria para exit */
#include <stdlib.h>
// Definimos un valor constante
#define KILOS_PER_POUND .45359

/* Descriptores de ficheros especiales:
 *  stdin - standard input
 *  stdout - standard output
 *  stderr - standard error output
 *
 * E/S con ficheros
 *  putc(c, stdout) - equivale a putchar(c)
 *  getc(stdin) - equivale a getchar()
 *
 * E/S formateada
 *  fprintf y fscanf - equivalen a printf y scanf
 *
 * E/S de strings formateada
 *  sprintf - pone informacion formateada en un string (controla overbuffer)
 *  sscanf - lee informacion de un string y la devuelve formateada en variables
 *
 * E/S de lineas
 *  fgets(string, 80, stdin);
 *  fputs(string, stdout);
 * */

/* Funcion que no devuelve ningun valor (void)
 *  y toma un argumento de tipo int (pounds).
 * */
void print_converted(int pounds) {
/* Convert U.S. Weight to Imperial and International
 *  Units. Print the results
 * */
	int stones = pounds / 14;
	int uklbs = pounds % 14;
	float kilos = pounds * KILOS_PER_POUND;

	// Indicamos cuantos digitos debe tener cada valor
	// al mostrarse
	printf("   %3d          %2d  %2d        %6.2f\n",
			pounds, stones, uklbs, kilos);
}


/* Funcion principal, esta vez con dos argumentos.
 *  argc    - es el numero de argumentos con que se ha llamado al programa.
 *  *argv[] - es un puntero (*) al array de argumentos (argv[]).
 * */
int main(int argc, char *argv[]) {
	int us_pounds;

	if (argc == 2) { // Si tenemos dos argumentos
		/* sscanf convierte una entrada (argv[1]) consistente en un integer (%d)
		 *  y lo escribe en la direccion de memoria (&) de us_pounds.
		 * */
		sscanf(argv[1], "%d", &us_pounds);
		/* No hacemos ningun control, si el argumento es una cadena
		 *  el programa tomara el valor numerico de la misma
		 *  */
	} else if (argc == 1) { // Si tenemos un solo argumento (la llamada al programa)
		printf("Give an integer weight in Pounds : ");
		/* scanf convierte una cadena de la entrada estandar
		 *  consistente en un integer (%d) y lo guarda en la
		 *  direccion de memoria (&) de us_pounds.
		 * */
		scanf("%d", &us_pounds);
		/* No hacemos ningun control, si el argumento es una cadena
		 *  el programa tomara el valor numerico de la misma
		 *  */
	} else { // Si tenemos mas de dos argumentos
		printf("Uso: Interaccion peso_en_libras\n");
		// Terminamos con un valor distinto de 0 (error)
		exit (1);
	}

	printf(" US lbs      UK st. lbs       INT Kg\n\n");
	// Llamamos a nuestra funcion
	print_converted(us_pounds);

	// Bucle para mostrar varias conversiones
	for(us_pounds=10; us_pounds < 100; us_pounds+=10)
			                print_converted(us_pounds);

	// Uso de getchar / putchar - e/s de caracteres
	// Generamos dos int e iniciamos el segundo a 0
	int ch, i=0;
	printf("\nEscriba cuanto desee. Pulse Ctrl+D para terminar\n");
	// Ctrl+D genera el codigo EOF
	while((ch = getchar()) != EOF) {
		/* La funcion toupper convierte un caracter en mayusculas.
		 * Podemos ver que la salida es asincrona, ya que funciona
		 *  -por optimizacion- mediante buffers, asi
		 *  el efecto de putchar solo es visible al pulsar enter
		 *  o Ctrl+D.
		 * */
		putchar(toupper(ch));
		i++;
	}
	printf("\nA tecleado %d veces\n", i);
	/* Para conseguir una salida sincrona podemos usar:
	 * stderr              - es generalmente unbuffered, pero usamo la salida de errores
	 * fflush(stdout)      - vuelca el contenido del buffer de salida
	 * setbuf(stdout,NULL) - elimina el buffer de la salida
	 * */

	printf("\nDe nuevo escriba cuanto desee. Pulse EOF para terminar\n");
	// Uso de gets / puts - e/s de lineas
	char line[256]; /* Define string sufficiently large to
                            store a line of input */
	/* Read line        */
	/* El uso de gets esta altamente desaconsejado
	 * Hay que asegurar que no se produce desbordamiento
	 *  de pila.
	 * */
	while(gets(line) != NULL) {
		puts(line);        /* Print line       */
		printf("\n");      /* Print blank line */
	}

	// Uso de scanf
	char nombre[50];
	char apellido[50];
	int edad;
	int retorno;
	while (1) {
		printf("\nEscriba nombre apellido edad:\n");
		retorno=scanf("%s %s %d", nombre, apellido, &edad);
		if (retorno == 3) // Si hemos obtenido las 3 conversiones pedidas
			break;
		else
			printf("Incorrecto, pruebe de nuevo");
	}
	printf("Hola, %s %s de %d\n", nombre, apellido, edad);
	/* Si scanf encuentra algo distinto a lo que espera sigue leyendo hasta
	 *  completar lo que espera o encontrar un EOF.
	 * Un retorno de carro es como un espacio.
	 * Asi en un caso como el anterior si ponemos:
	 *  a 1 a - dara error
	 *  a 1 a (de nuevo) - esta vez es correcto, porque ha tomado
	 *  "a 1 a a 1 a", donde la secuencia "a a 1" es correcta.
	 * Esto es bastante frustrante para el usuario, porque hace cosas
	 *  muy "raras".
	 * Lo mejor es tomar la cadena en un solo string y tratarla con sscanf.
	 * */


	// Terminamos
	return 0;
}

[Índice]

03-Fibonacci.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>

/* Este programa muestra el uso de arrays */

// Funcion principal
int main() {
	// Creamos un array de 24 integers [0,23]
	int fib[24];
	// Creamos un integer
	int i;

	// Asignamos valores a los dos primeros int
	fib[0] = 0;
	fib[1] = 1;

	/* Rellenamos el resto de valores de la
	 * secuencia de Fibonacci
	 * */
	for(i = 2; i < 24; i++)
		fib[i] = fib[i-1] + fib[i-2];

	// Mostramos toda la serie
	for (i = 0; i < 24; i++)
		printf("%3d   %6d\n", i, fib[i]);

	// Terminamos
	return 0;
}

[Índice]

04-Punteros.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>

// Definimos la struct persona
typedef struct {
	int edad;
	int altura;
	char nombre[25];
} persona;


/* La funcion recibe un entero y un puntero a otro entero
 * */
void fiddle(int x, int *y) {
	printf(" Starting fiddle: x = %d, y = %d\n", x, *y);
	x ++;
	/* Como *y es un puntero, para incrementar y
	 * primero debemos de-referenciarlo
	 * */
	(*y)++;
	printf("Finishing fiddle: x = %d, y = %d\n", x, *y);
}

/* Funcion que maneja structs */
int suma_edades(persona *per1, persona *per2) {
	int suma;
	suma = (*per1).edad + (*per2).edad;
	/* Habitualmente escribimos per1->edad, pero la
	 * nomenclatura anterior es mas didactica
	 * */
	return suma;
}

// Funcion principal
int main() {
	// Inicializamos un par de enteros
	int i = 0;
	int j = 0;

	/* Generamos un puntero tipo int
	 * Asignamos al puntero la direccion de memoria de i
	 * */
	int *puntero_a_i;
	puntero_a_i = &i;
	// Modificamos el espacio apuntado por el puntero...
	*puntero_a_i = 5;
	// ...y modificamos i
	printf("i = %d\n", i);

	// Probamos nuestra funcion de punteros
	printf(" Starting main  : i = %d, j = %d\n", i, j);
	printf("Calling fiddle now\n");
	/* Para que una funcion modifique una variable debemos
	 * pasarla por referencia (con &),
	 * es decir pasando la direccion de memoria donde se encuentra
	 * almacenada la variable.
	 * Despues en la funcion debemos indicar que el argumento es
	 * un puntero (*) y despues de-referenciarlo para
	 * poder utilizar y modificar el valor contenido en la
	 * variable.
	 * */
	/* Pasamos la variable i
	 * y la direccion de memoria (&) de j
	 */
	fiddle(i, &j);
	/* El valor de i no ha cambiado
	 * pero el valor de j si ha cambiado
	 * */
	printf("Returned from fiddle\n");
	printf("Finishing main  : i = %d, j = %d\n", i, j);

	/* Un array es un puntero al elemento 0 del propio array
	 * Asi mi_array[0] equivale a *mi_array
	 *     mi_array[4] equivale a *(mi_array + 4)
	 * Sin embargo un array es estatico en el ambito declarado,
	 * es decir, no se puede ampliar el array, solo modificar
	 * los datos que contiene.
	 * Por tanto mi_array++ es ilegal, pero mi_array[1]++ es correcto
	 * (incrementa el valor del elemento mi_array[1])
	 *
	 * Sin embargo si creamos un puntero que apunte a un array,
	 * gracias a que el puntero tiene tipo definido (conoce el tamanyo
	 * en memoria), si que podemos usar puntero++, pero para
	 * pasar al siguiente elemento del array, no para incrementar
	 * el valor del elemento
	 * */
	int numeros[10];
	int *ptr_num;

	numeros[0]=0;
	numeros[1]=1;
	numeros[2]=2;

	// Apuntamos ptr_num al primer elemento de numeros
	ptr_num = &numeros[0];
	for (i=0; i<3; i++) {
		printf("*ptr_num = %d\n", *ptr_num);
		ptr_num++;
	}

	/* Los punteros son especialmente utiles cuando se utilizan
	 * funciones que operan sobre estructuras. Al usar los punteros
	 * evitamos copiar grandes cantidades de datos
	 * */
	persona mujer, marido;

	mujer.edad=29;
	marido.edad=29;
	i=suma_edades(&mujer, &marido);
	printf("suma_edades = %d\n", i);

	// Terminamos
	return 0;
}


[Índice]

05-Fibonacci_recursivo.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>

// Funcion que recursivamente calcula el valor
// de la serie Fibonacci
int fib(int num) {
	switch(num) {
	case 0:
		return(0);
		break;
	case 1:
		return(1);
		break;
	default:  /* Including recursive calls */
		/* Cada vez se llama recursivamente dos veces a la funcion
		 * lo que significa que tiene un costo bastante alto
		 * La recursividad aporta a veces soluciones sencillas y elegantes
		 * pero hay que tener mucho cuidado con los costes
		 * Ver las notas sobre time mas abajo
		 * */
		return(fib(num - 1) + fib(num - 2));
		break;
	}
}

/* Para comprobar el uso de recursos se puede utilizar el
 * comando time de unix:
 * time ./5-Fibonacci_recursivo 40
 * 102334155    <-- Respuesta de este programa
 *
 * real    0m4.190s  <-- Tiempo real que ha tardado
 * user    0m4.136s  <-- Tiempo utilizando CPU como usuario
 * sys     0m0.001s  <-- Tiempo utilizando CPU como sistema
 *
 * */


/* Funcion principal */
int main(int argc, char *argv[]) {
	// Declaramos variables locales
	int numero, valor;

	if (argc == 2) { // Si tenemos dos argumentos
		// Tomamos el segundo argumento como valor
		sscanf(argv[1], "%d", &valor);
	} else if (argc == 1) { // Si tenemos un solo argumento (la llamada al programa)
		printf("Introduzca un valor: ");
		// Tomamos la entrada como valor
		scanf("%d", &valor);
	} else { // Si tenemos mas de dos argumentos
		printf("Uso: %s [valor]\n", argv[0]);
		// Terminamos con un valor distinto de 0 (error)
		exit (1);
	}

	// Llamamos a la funcion
	numero=fib(valor);
	// Mostramos el resultado
	printf("%6d\n", numero);

	// Terminamos
	return 0;
}

[Índice]

06-Cadenas.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>
/* Funciones de cadenas */
#include <string.h>

/* Un string es un array de caracteres
 * tras el ultimo caracter con informacion hay un \0
 * */
char str1[10]; // Reserva espacio para 10 chars
char str2[10];
char str3[]="Prueba";
char *ptr_str; // Declaramos un puntero sin inicializarlo
unsigned int longitud;


/* Funcion principal */
int main(int argc, char *argv[]) {
	printf("Pruebe a pasar como argumento 'Prueba' o una cadena de mas de 10 caracteres\n");
	if (argc == 2) { // Si tenemos dos argumentos
		/* Tomamos el segundo argumento como cadena
		 * Atencion al tratamiento de str1 (sin &)
		 * */
		sscanf(argv[1], "%s", str1);
		/* Si str1 no es suficientemente grande, mala suerte */
	} else if (argc == 1) { // Si tenemos un solo argumento (la llamada al programa)
		printf("Introduzca un valor: ");
		/* Tomamos la entrada como cadena
		 * Atencion al tratamiento de str1 (sin &)
		 * */
		scanf("%s", str1);
		/* Si str1 no es suficientemente grande, mala suerte */
	} else { // Si tenemos mas de dos argumentos
		printf("Uso: %s [valor]\n", argv[0]);
		// Terminamos con un valor distinto de 0 (error)
		exit (1);
	}

	longitud = strlen(str1);
	printf("Longitud de <%s> es %d\n", str1, longitud);

	/* strcpy(str1, str2) - pone en str1 el contenido de str2
	 * strcmp(str1, str2) - devuelve 0 si str1 y str2 tienen el mismo contenido
	 * */
	/* Copiamos la cadena H-o-l-a al atring str2
	 * De nuevo, si str2 es demasiado pequenyo, mala suerte
	 * */
	strcpy(str2,"Hola");
	// Concatenamos
	strcat(str2," mundo");
	// Ahora str2 tiene H-o-l-a- -m-u-n-d-o-\0
	longitud = strlen(str2);
	printf("Longitud de <%s> es %d\n", str2, longitud);
	longitud = strlen(str1);
	printf("Longitud de <%s> es %d\n", str1, longitud);
	// Comparamos cadenas
	if(strcmp(str1, str3)) {
		printf("<%s> y <%s> son diferentes\n",str1, str3);
	} else {
		printf("<%s> y <%s> son iguales\n",str1, str3);
	}
	// Realizamos busquedas
	if (strstr(str1, "rue") == (char*) NULL) {
		printf("\"rue\" no esta en <%s> \n",str1);
	} else {
		printf("\"rue\" esta en <%s> \n",str1);
	}
	// Buscamos la primera 'o' de str1
	ptr_str=strchr(str1, 'o');
	if (ptr_str == (char*) NULL) {
		printf("No hay ninguna 'o' en <%s> \n",str1);
	} else {
		printf("<%s> a partir de la primera o es <%s>\n",str1, ptr_str);
	}

	// Terminamos
	return 0;
}

[Índice]

07-Ficheros_UNIX.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
// Definiciones
#define MAXLONGNAME 50
typedef struct {
	char c1;
	int c2;
	char c3[20];
	float c4;
} registro;

// Variables GLOBALES
FILE *fp; // Puntero a nombre de fichero

/* Alta de registros */
void alta() {
	char opcion;
	registro reg;
	FILE *f;

	/* Los fichero se pueden abrir en modo
	 * r - read only
	 * w - write
	 * a - append
	 * */
	f=fopen("datos.dat", "a");
	do {
		// Tomamos datos en el registro reg
		printf ("\nc1 (char): ");
		scanf ("%c", &reg.c1);
		printf ("\nc2 (int): ");
		scanf ("%d", &reg.c2);
		printf ("\nc3 (string): ");
		scanf ("%s", reg.c3);
		printf ("\nc4 (float): ");
		scanf ("%f", &reg.c4);
		//fflush(stdin);
		// Escribimos en el fichero
		fwrite(&reg,sizeof(registro),1,f);

		// Continuamos?
		printf("\nDesea dar de alta otro registro (S/n): ");
		scanf("%c",&opcion);
		//fflush(stdin);
	} while (opcion!='n');
	// Cerramos el fichero
	fclose(f);
}


/* Modificacion de registros */
void modificar() {
	char opcion;
	int noreg;
	long max;
	registro reg;
	FILE *f;

	f=fopen("datos.dat", "r+");
	fseek(f,0,SEEK_END);
	max = ftell(f)/sizeof(registro);
	do {
		printf("\nQue registro desea modificar? ");
		scanf("%d",&noreg);
		//fflush(stdin);
		if ((noreg>=1) && (noreg<=max)) {
			// Nos situamos en la posicion indicada
			fseek(f,(noreg-1)*sizeof(registro),0);
			// Leemos el registro
			fread(&reg,sizeof(registro),1,f);
			// Tomamos datos en el registro reg
			printf ("\nc1 (char) <%c>: ", reg.c1);
			scanf ("%c", &reg.c1);
			printf ("\nc2 (int) <%d>: ", reg.c2);
			scanf ("%d", &reg.c2);
			printf ("\nc3 (string) <%s>: ", reg.c3);
			scanf ("%s", reg.c3);
			printf ("\nc4 (float) <%f>: ", reg.c4);
			scanf ("%f", &reg.c4);
			//fflush(stdin);

			// Nos volvemos a situar en la posicion indicada
			fseek(f,(noreg-1)*sizeof(registro),0);
			// Escribimos el registro
			fwrite(&reg,sizeof(registro),1,f);
		} else {
			printf("\nError. Elija un registro entre el 1 y el %ld\n", max);
		}

		// Continuamos?
		printf("\nDesea modificar otro registro (S/n): ");
		scanf("%c",&opcion);
		//fflush(stdin);
	} while (opcion!='n');
}


/* Eliminacion de registros */
void baja() {
	char opcion;
	int noreg, regact;
	long max;
	registro reg;
	FILE *fo, *fn;

	do {
		fo=fopen("datos.dat", "r");
		fseek(fo,0,SEEK_END);
		max = ftell(fo)/sizeof(registro);
		fn=fopen("datos.tmp", "w");
		printf("\nQue registro desea eliminar? ");
		scanf("%d",&noreg);
		//fflush(stdin);
		if ((noreg>=1) && (noreg<=max)) {
			regact=0;
			fseek(fo,0,SEEK_SET);
			if (fread(&reg,sizeof(registro),1,fo)==1) {
				while (!feof(fo)) {
					if (regact!=(noreg-1))
						fwrite(&reg,sizeof(registro),1,fn);
					regact++;
					fread(&reg,sizeof(registro),1,fo);
				}
				fclose(fo);
				remove("datos.dat");
				fclose(fn);
				rename("datos.tmp", "datos.dat");
			}
		} else {
			printf("\nError. Elija un registro entre el 1 y el %ld\n", max);
		}

		// Continuamos?
		printf("\nDesea eliminar otro registro (S/n): ");
		scanf("%c",&opcion);
		//fflush(stdin);
	} while (opcion!='n');
}


/* Lista de registros */
void listar() {
	registro reg;
	FILE *f;

	if ((f=fopen("datos.dat", "r"))!=NULL) {
		printf("\nRegistros:\n");
		if (fread(&reg,sizeof(registro),1,f)==1)
			while (!feof(f)) {
				printf("%10c%10d%20s%10.2f\n",reg.c1,reg.c2,reg.c3,reg.c4);
				fread(&reg,sizeof(registro),1,f);
			}
		fclose(f);
	} else {
		printf ("\nNo existe el fichero\n");
	}
}




/* Funcion principal */
int main() {
	char opcion;

	do {
		// Mostramos el menu
		printf("\n\n   Menu principal\n");
		printf("===================\n\n");
		printf("1.- Alta registro\n");
		printf("2.- Baja registro\n");
		printf("3.- Modif. registro\n");
		printf("4.- Listar fichero\n");
		printf("\n0.- Terminar\n\n");
		printf("Opcion: ");
		// Tomamos la opcion
		scanf("%c", &opcion);
		// Volvemos a leer para que tome el Intro tras la opci´┐Żn
		scanf("%c", &intro);
		// Vaciamos el buffer de entrada
		setbuf(stdin,NULL);

		// Realizamos la opcion solicitada
		switch (opcion) {
		case '1': alta();
				  break;
		case '2': baja();
				  break;
		case '3': modificar();
				  break;
		case '4': listar();
				  break;
		case '0': printf("\nFin de programa\n");
				  break;
		default: printf("error: opcion invalida\n");
				  break;
		}
	} while (opcion!='0');

	// Terminamos
	return 0;
}

[Índice]

08-cp.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>

/* En este ejemplo distribuimos el codigo en dos ficheros
 *  8-cp.c      - es el principal, ya que contiene la funcion main
 *  8-cp_copy.c - contiene una funcion que necesita 8-cp.c
 * Se compila con
 *  gcc -o 8-cp 8-cp.c 8-cp_copy.c
 */

// Funcion principal
int main (int argc, char *argv[]) {
	// Comprobamos si tenemos los argumentos necesaios
	if (argc!=3) {
		fprintf(stderr,"Uso: %s forigen fdestino\n", argv[0]);
		exit (1);
	}
	// Llamamos a nuestra funcion de copia que esta en otro fichero
	copy(argv[1], argv[2]);

	// Terminamos
	return 0;
}


08-cp_copy.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
// Definiciones
#define BUFSIZE 1024

// Nuestra funcion copy
void copy(char *from, char *to) {
	int fromfd, tofd, nread;
	char buf[BUFSIZE];

	if ((fromfd = open(from, O_RDONLY)) == -1) {
		perror(from);
		exit(1);
	}

	if ((tofd = creat(to, 0666)) == -1) {
		perror(to);
		exit(1);
	}

	while ((nread = read(fromfd, buf, sizeof (buf))) > 0)
		if (write(tofd, buf, nread) != nread) {
			perror("write");
			exit(1);
		}

	if (nread == -1) perror ("read");

	if (close(fromfd) == -1 || close(tofd) == -1) perror ("close");
}


[Índice]

09-Otros_recursos.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>
// Funciones de reloj
#include <time.h>
// Definiciones
#define NUM 10

/* Funcion que queremos probar
 * */
int comp(const void *a, const void *b) {
	return *(int*)a - *(int*)b;
}


/* Funcion principal */
int main() {
	// Declaramos variables locales
	int numeros[NUM];
	int i;

	// Pedimos al sistema que ejecute el comando date
	system("date");

	/* Establecemos para rand una semilla que es de tipo long
	 * para ello llamamos a time
	 * time devuelve el valor en segundos desde el 1 de enero de 1970
	 * y ademas lo almacena en (NULL) (no lo almacena en este caso)
	 * */
	srand((long)time(NULL));

	printf("Los numeros desordenados son:\n");
	for (i=0; i<NUM; i++) {
		/* A cada numero le asignamos un valor random de 48 bits [0,2^31]
		 * Para obtener un numero random igual pero entre [0 y 1]
		 * podemos usar drand48, pero tendriamos que almacenar la respuesta
		 * en floats no en integers
		 * */
		numeros[i]=lrand48();
		printf("%d: %3d\n", i, numeros[i]);
	}

	/* qsort ordena un vector
	 * (puntero al vector, numero de miembros,
	 * tamanyo de cada miembro, funcion de comparacion)
	 * */
	qsort((void*)numeros,(size_t)NUM,sizeof(int),comp);
	printf("Los numeros ordenados son:\n");
	for (i=0; i<NUM; i++) {
		printf("%d: %3d\n", i, numeros[i]);
	}

	/* Recogemos la salida de un comando de sistema
	 * a traves de una tuberia usando punteros de fichero
	 * */
	FILE *fp; 		// Fichero
	char string[150];
	// El fichero abre una tuberia de lectura con el comando date
	fp = popen("date", "r");
	if (fp==NULL) { // Si el fichero no recoge informacion
		printf("Error al ejecutar date\n");
	} else { // Si el fichero recoge informacion
		// Leemos el contenido del fichero fp
		fgets(string, 32, fp);
		printf("El comando date ha devuelto <%s>\n", string);
		// Cerramos la tuberia
		pclose(fp);
	}


	// Terminamos
	return 0;
}

[Índice]

10-Procesos_1.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
/* Utilidades generales, ahora tambien para gestion de PIDs */
#include <stdlib.h>

// Funcion principal
int main() {
	printf("Ejecute este programa con '&' y vaya comprobando los procesos ");
	printf("que se crean, quedan zombies y terminan.\n\n");

	pid_t ident;
	/* Creamos un proceso hijo. fork() genera un proceso hijo que hereda todo
	 *  el estado del padre, incluyendo el valor de las variables
	 * fork() devuelve:
	 *  -1 	- en caso de error
	 *   0 	- al hijo
	 * el PID del hijo 	- al padre
	 *  */
	ident = fork ();

	// Comprobamos quienes somos
	switch (ident) {
		case -1:
		printf ("No he podido crear el proceso hijo\n");
		break;
	case 0:
		printf ("Soy el hijo, mi PID es %d y mi PPID es %d\n", getpid(), getppid());
		sleep (15);
		break;
	default:
		printf ("Soy el padre, mi PID es %d y el PID de mi hijo es %d\n", getpid(), ident);
		sleep (25);
	}

	printf ("Final de ejecucion de %d\n", getpid());

	// Terminamos
	return 0;
}


[Índice]

10-Procesos_1w.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
/* Utilidades generales, ahora tambien para gestion de PIDs */
#include <stdlib.h>

// Funcion principal
int main() {
    pid_t ident;
    int status, x, i;

    /* Creamos un hijo */
    ident = fork();
    // Comprobamos quienes somos
    switch (ident) {
        case -1:
            printf ("No he podido crear el proceso hijo %i\n", i);
            break;
        case 0:
            printf ("Soy el primer hijo, mi PID es %d y mi PPID es %d\n", getpid(), getppid());
            sleep (5);
            printf ("[%i] Termino\n", getpid());
            /* Terminamos el primer hijo */
            return (0);
            break;
        default:
            if ((x=wait(&status)) != ident)
                fprintf (stderr, "PADRE: wait interrumpido por una se´┐Żal\n");
            else
                printf ("Soy el padre [%d], wait ha devuelto %d\n", getpid(), x);
            break;
    }

    printf ("Creando varios hijos...\n");
    /* El padre, solo el padre, crea varios hijos */
    for (i=0; i<5; i++)
        if (!(ident = fork())) break;

    if (ident == 0) {
        printf ("Soy hijo, mi PID es %d y mi PPID es %d\n", getpid(), getppid());
        sleep (5);
    }

    /* Wait dara error (-1) a los hijos, que no esperan a nadie */
    while ((x=wait(NULL)) != -1) {
        printf ("Soy el padre [%d], wait ha devuelto %d\n", getpid(), x);
    }

    printf ("Final de ejecucion de %d\n", getpid());

    /* Terminamos la funci´┐Żn main devolviendo el valor 0
     * que indica 'sin errores' */
    return 0;
}


[Índice]

10-Procesos_2.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>

/* Funcion principal */
int main() {
	int i, n;
	n = 4;
	fprintf(stderr,"Este es el proceso %ld\n", (long)getpid());
	fprintf(stderr,"Preste atencion al orden en que empiezan y acaban los hijos\n\n");

	for (i=1;i<n;i++) {
		fprintf(stderr,"Este es el proceso %ld cuando i vale %d\n", (long)getpid(), i);
		// Si somos el padre salimos del bucle
		if (fork()>0) break;
		// Observe que el hijo hereda el valor de i
	}
	fprintf(stderr,"Este es el proceso %ld con padre %ld\n", (long)getpid(), (long)getppid());

	// Terminamos
	return 0;
}


[Índice]

10-Procesos_3.c
// Guimi - 2006-03 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[]) {
	printf ("Pruebe a ejecutar este programa como 'programa ls -l'\n");
	int i;
	printf ("\n Ejecutando el programa (%s). Sus argumentos son: \n", argv[0]);

	for (i=0; i<argc; i++)
		printf ("  argv[%d]: %s \n",i,argv[i]);

	sleep (2);

	/* La  familia de funciones exec reemplaza la imagen del proceso
	 * en curso con una nueva. Si cualquiera de las funciones exec
	 * regresa, es que ha ocurrido  un  error.
	 * Por legibilidad ponemos el c´┐Żdigo en una cla´┐Żsula if
	 * pero bastar´┐Ża:
	 * 	execvp (orden, params, 0);
	 * 	printf("Error\n");
	 * 	exit (1);
	 * Ya que si llegamos a printf es porque execvp no ha conseguido
	 * cambiar la imagen de memoria
	 * */
	if (execvp (argv[1],&argv[1])<0) {
		printf("Error en la invocacion\n");
		exit (1);
	}

	// Terminamos
	return 0;
}


[Índice]

11-Dup.c
// Guimi - 2006-07 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>
// Para los flags de open (O_WRONLY...)
#include <fcntl.h>
// Para los modos de open (S_IRUSR...)
#include <sys/stat.h>
// Para las definiciones de I/O/E std (STDOUT_FILENO...)
#include <unistd.h>

// Definimos constantes con los modos que deseamos utilizar
#define NEWFILE (O_WRONLY | O_CREAT | O_EXCL)
#define MODE644 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

// Funcion que modifica la salida estandar
int redirect_output(const char *file) {
	// Variable que usaremos como descriptor de fichero
	int fd;

	// Intentamos abrir el fichero recibido como argumento
	if ((fd=open(file, NEWFILE, MODE644)) == -1) return -1;

	// Intentamos duplicar el descriptor en el registro de salida estandar
	if (dup2(fd, STDOUT_FILENO) == -1) return -1;
	// Cerramos el descriptor original
	close(fd);

	return 0;
} // redirect_output

/* Funcion principal, con dos argumentos.
 *  argc    - es el numero de argumentos con que se ha llamado al programa.
 *  *argv[] - es un puntero (*) al array de argumentos (argv[]).
 * */
int main(int argc, char *argv[]) {
	int form_fd, to_fd;

	// Comprobamos que tenemos los argumentos necesarios
	if (argc < 3) {
		fprintf(stderr, "uso: %s fichero_salida comando args\n", argv[0]);
		exit(1);
	}

	// Redirigimos la salida
	if (redirect_output(argv[1]) == -1) {
		fprintf(stderr, "No se pudo redirigir la salida a %s\n", argv[1]);
		exit(1);
	}

	// Ejecutamos el comando
	if (execvp(argv[2], &argv[2]) <0) {
		fprintf(stderr, "No se pudo ejecutar %s\n", argv[2]);
		exit(1);
	}

	return 0;
} //main


[Índice]

12-Pipe_1.c
// Guimi - 2006-07 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>
// Para las definiciones de I/O/E std (STDOUT_FILENO...)
#include <unistd.h>
// Gestion de cadenas
#include <string.h>
// Definicion de errores
#include <errno.h>

// Definimos constantes
#define BUFSIZE 256

/* Funcion principal, con dos argumentos.
 *  argc    - es el numero de argumentos con que se ha llamado al programa.
 *  *argv[] - es un puntero (*) al array de argumentos (argv[]).
 * */
int main(int argc, char *argv[]) {
	int fd[2], status;
	char buf[BUFSIZE];
	unsigned strsize;

	// Comprobamos que tenemos los argumentos necesarios
	if (argc != 1) {
		fprintf(stderr, "uso: %s \n", argv[0]);
		exit(1);
	}

	/* pipe(fd) crea una tuberia y dos descriptores de ficheros
	 * apuntando a ella, uno (fd[0]) en modo solo lectura y otro (fd[1])
	 * en modo solo escritura.
	 * Creamos la tuberia ANTES de hacer fork() para que el hijo herede los fd.
	 * */
	// Creamos una tuberia
	pipe(fd);
	// Creamos un hijo
	switch(fork()) {
        case -1:
			fprintf(stderr, "No he podido crear el proceso hijo\n");
			exit(1);
        case 0: // Hijo
			// Redirigimos la salida del hijo a la tuberia
			dup2(fd[1], STDOUT_FILENO);
			/* Cerramos los descriptores originales de la tuberia
			* para permitir gestionar automaticamente el final de la 
			* comunicacion.
			* */
			close(fd[0]);
			close(fd[1]);

			fprintf(stderr, "[%d] Hijo: Voy a escribir en la tuberia\n", getpid());
			// Preparamos el buffer a escribir
			sprintf(buf, "[%d] Esto se escribira en la tuberia", getpid());
			strsize=strlen(buf)+1;
			// Escribimos en la tuberia
			if (write(STDOUT_FILENO, buf, strsize) != strsize) {
				fprintf(stderr, "Fallo al escribir en la tuberia\n");
				exit(1);
			}
			fprintf(stderr, "[%d] Hijo: Fin\n", getpid());

			break;
        default: // Padre
			// Redirigimos la entrada del padre a la tuberia
			dup2(fd[0], STDIN_FILENO);
			/* Cerramos los descriptores originales de la tuberia
			* para permitir gestionar automaticamente el final de la 
			* comunicacion.
			* */
			close(fd[0]);
			close(fd[1]);

			fprintf(stderr, "[%d] Padre: Voy a leer de la tuberia\n", getpid());
			// Esperamos la correcta finalizacion del hijo
			while ((wait(&status) == -1) && (errno == EINTR));
			// Leemos de la tuberia
			if (read(STDIN_FILENO, buf, BUFSIZE) <= 0) {
				fprintf(stderr, "Fallo al leer de la tuberia\n");
				exit(1);
			}
			fprintf(stderr, "[%d] Padre: Fin\n", getpid());
			fprintf(stderr, "[%d] Padre: Leido \"%s\"\n", getpid(), buf);

			break;
	}

	return 0;
} //main



[Índice]

13-Senyales.c
// Guimi - 2006-07 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>
// Libreria de senyales
#include <signal.h>

// Funcion manejador de senyal
void manejador_ctrl_c() {
	fprintf(stderr,"Ctrl-c recibido\n");
}

// Funcion principal del programa
int main() {
	// Conjunto de senyales
	sigset_t mimascara;
	// Estructura sigaction
	struct sigaction st_accion;
	// Variables auxiliares
	int i;
	double y;

	// Preparamos la estructura del manejador
	st_accion.sa_handler = manejador_ctrl_c;
	sigemptyset(&st_accion.sa_mask);
	st_accion.sa_flags = 0;

	// Capturamos la senyal SIGINT
	// y NO guardamos la estructura de accion anterior
	sigaction(SIGINT, &st_accion, NULL);
	fprintf(stderr,"Senyal SIGINT capturada\n");
	sleep (10);

	// Preparamos la estructura del manejador
	// para que ignore la senyal
	st_accion.sa_handler = SIG_IGN;
	// Ignoramos SIGINT
	sigaction(SIGINT, &st_accion, NULL);
	fprintf(stderr,"Senyal SIGINT ignorada\n");
	sleep (10);

	// Preparamos la estructura del manejador
	// para que realice la accion por defecto
	st_accion.sa_handler = SIG_DFL;
	// Ignoramos SIGINT
	sigaction(SIGINT, &st_accion, NULL);
	fprintf(stderr,"Senyal SIGINT accion por defecto\n");

	// Establecemos el conjunto vacio de senyales
	sigemptyset(&mimascara);
	// Anyadimos al conjunto la senyal SIGINT
	sigaddset(&mimascara, SIGINT);

	// Bloqueamos todas las senyales del conjunto
	// y NO guardamos la mascara anterior (NULL)
	sigprocmask(SIG_BLOCK, &mimascara, NULL);
	fprintf(stderr,"Senyal SIGINT bloqueada\n");
	sleep (10);

	// DESbloqueamos todas las senyales del conjunto
	// y NO guardamos la mascara anterior (NULL)
	sigprocmask(SIG_UNBLOCK, &mimascara, NULL);
	fprintf(stderr,"Senyal SIGINT DESbloqueada\n");
	sleep (10);

	return 0;
} // main


[Índice]

14-Directorios.c
// Guimi - 2006-07 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>

// Funcion principal del programa
int main() {
	// Directorio
	DIR *midir;
	// Entrada de directorio
	struct dirent *midirent;

	// Abrimos el directorio en que nos encontramos
	if ((midir = opendir(".")) == NULL) {
		fprintf(stderr,"Error al leer el directorio\n");
		exit (1);
	}

	// Leemos el contenido
	while ((midirent=readdir(midir)) != NULL) {
		if (!strcmp(midirent->d_name, "kk")) {
			link(midirent->d_name, "kk_old");
			printf("CREADO kk_old\n");
			sleep(10);
			unlink(midirent->d_name);
			printf("BORRADO ");
			printf("%d - %c - %s\n", midirent->d_ino, midirent->d_type, midirent->d_name);
			sleep(10);
		} else {
			printf("%d - %c - %s\n", midirent->d_ino, midirent->d_type, midirent->d_name);
		}
	}

	// Cerramos el directorio
	closedir(midir);

	// Terminamos
	return 0;
} // main



[Índice]

15-Permisos.c
// Guimi - 2006-07 http://guimi.net
// DIRECTIVAS
#include <stdio.h>
#include <stdlib.h>
// Para los flags de open (O_WRONLY...)
#include <fcntl.h>
// Para los modos de open (S_IRUSR...)
#include <sys/stat.h>
// Para las definiciones de I/O/E std (STDOUT_FILENO...)
#include <unistd.h>

// Definimos constantes con los modos que deseamos utilizar
#define NEWFILE (O_WRONLY | O_CREAT | O_EXCL)
#define MODE777 (S_IRWXU | S_IRWXG | S_IRWXO)
#define MODE664 (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH )
#define MODE600 (S_IRUSR | S_IWUSR)
#define MODE760 (S_IRWXU | S_IRGRP | S_IWGRP)
#define MODE121 (S_IXUSR | S_IWGRP | S_IXOTH)

int main() {
	// Intentamos crear un fichero
	if ((open("kk1", NEWFILE, MODE777)) == -1) {
		fprintf(stderr, "El fichero no se pudo crear\n");
		exit (1);
	}

	// Intentamos crear un fichero
	if ((open("kk2", NEWFILE, MODE664)) == -1) {
		fprintf(stderr, "El fichero no se pudo crear\n");
		exit (1);
	}

	// Intentamos crear un fichero
	if ((open("kk3", NEWFILE, MODE600)) == -1) {
		fprintf(stderr, "El fichero no se pudo crear\n");
		exit (1);
	}

	// Modificamos la mascara
	umask(MODE121);

	// Intentamos crear un fichero
	if ((open("kk4", NEWFILE, MODE760)) == -1) {
		fprintf(stderr, "El fichero no se pudo crear\n");
		exit (1);
	}

	// Terminamos
	return 0;
} //main



[Índice]

16-Hilos.c
// Guimi - 2006-07 http://guimi.net
// Este programa debe ser compilado con -pthread
//+ gcc -pthread -o 16-Hilos 16-Hilos.c
// DIRECTIVAS
#include <stdio.h>
#include <pthread.h>

#define NUM_IT 100

// Variable global iniciada a 0
int a=0;

void * hilo (void *arg) {
	int id,i,aux;

	// Tomamos el argumento como identificador del hilo
	id = (int) arg;
	printf("Soy el hilo %d con identificador %d.\n", id, pthread_self() );

	// El hilo 0 aumenta el valor de a,
	//+ el resto lo decrementa
	for (i=0; i<NUM_IT; i++)
		if (id == 0) {
			aux = a; aux++; a = aux;
		} else {
			aux = a; aux--; a = aux;
		}

	// No es estrictamente necesario
	pthread_exit(0);
}

int main(void) {
  // Creamos variables hilo
  pthread_t t1, t2, t3;

  // Creamos tres hilos
  printf("Creamos los hilos. Valor inicial de a: %d.\n", a );
  pthread_create(&t1, NULL, hilo, (void *)0);
  pthread_create(&t2, NULL, hilo, (void *)1);
  pthread_create(&t3, NULL, hilo, (void *)2);

  // Esperamos a que acaben los hilos
  printf("Esperando que terminen los hilos. Valor de a: %d.\n", a);
  pthread_join(t1, NULL);
  printf("--Hilo terminado. Valor de a: %d.\n", a);
  pthread_join(t2, NULL);
  printf("--Hilo terminado. Valor de a: %d.\n", a);
  pthread_join(t3, NULL);
  printf("--Hilo terminado. Valor de a: %d.\n", a);

  // Terminamos
  printf( "\nHilos terminados. Valor de a: %d.\n", a );
  return 0;
} // main



[Índice]

16-Hilos_mutex.c
// Guimi - 2006-08 http://guimi.net
// Este programa debe ser compilado con -pthread
// DIRECTIVAS
#include <stdio.h>
#include <pthread.h>

#define NUM_IT 1000

pthread_mutex_t mimutex = PTHREAD_MUTEX_INITIALIZER;

// Variable global iniciada a 0
int a=0;

void *f_hilo1 (void *arg) {
	int i;

	for (i=0; i<NUM_IT; i++) {
		pthread_mutex_lock(&mimutex);
		a++;
		//printf("Hilo1: %i\n", a);
		pthread_mutex_unlock(&mimutex);
	}

	// No es estrictamente necesario
	pthread_exit(0);
}

void *f_hilo2 (void *arg) {
	int i;

	for (i=0; i<NUM_IT; i++) {
		pthread_mutex_lock(&mimutex);
		a--;
		//printf("Hilo2: %i\n", a);
		pthread_mutex_unlock(&mimutex);
	}

	// No es estrictamente necesario
	pthread_exit(0);
}

int main(void) {
  // Creamos variables hilo
  pthread_t hilo1, hilo2;

  // Creamos tres hilos
  printf("Creamos los hilos. Valor inicial de a: %d.\n", a );
  pthread_create(&hilo1, NULL, f_hilo1, NULL);
  pthread_create(&hilo2, NULL, f_hilo2, NULL);

  // Esperamos a que acaben los hilos
  pthread_join(hilo1, NULL);
  pthread_join(hilo2, NULL);

  // Terminamos
  printf( "Hilos terminados. Valor de a: %d.\n", a );
  return 0;
} // main


[Índice]

17-Prod_Cons.c
// Guimi - 2006-08 http://guimi.net
// Este programa debe ser compilado con -pthread
// DIRECTIVAS
#include <stdio.h>
#include <pthread.h>

#define NUM_IT 100

// Variables globales
int p_productor, p_consumidor, contador;
int N=10;
int espera_cons, espera_prod;
pthread_mutex_t mimutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t lleno = PTHREAD_COND_INITIALIZER;
pthread_cond_t vacio = PTHREAD_COND_INITIALIZER;

// Funcion productora
void producir () {
	// Entrada a seccion critica
	pthread_mutex_lock(&mimutex);

	// Espera NO activa
	while (contador == N) {
		pthread_cond_wait(&lleno, &mimutex);
		espera_prod++;
	};

    // Producimos (incrementamos contador)
	contador++;
	if ((contador < 0) || (contador > N)) printf("Error: %i\n", contador);

	// Avisamos a quienes esten esperando
	pthread_cond_broadcast(&vacio);

	// Salida de seccion critica
	pthread_mutex_unlock(&mimutex);
}

// Funcion consumidora
void consumir () {
	// Entrada a seccion critica
	pthread_mutex_lock(&mimutex);

	// Espera NO activa
	while (contador == 0) {
		pthread_cond_wait(&vacio, &mimutex);
		espera_cons++;
	};

    // Consumimos (decrementamos contador)
	contador--;
	if ((contador < 0) || (contador > N)) printf("Error: %i\n", contador);

	// Avisamos a quienes esten esperando
	pthread_cond_broadcast(&lleno);

	// Salida de seccion critica
	pthread_mutex_unlock(&mimutex);
}

// Funcion productor
void *f_productor (void *arg) {
	int i;

	// Producimos NUM_IT veces
	for (i=0; i// No es estrictamente necesario
	pthread_exit(0);
}

// Funcion consumidor
void *f_consumidor (void *arg) {
	int i;

	// Consumimos NUM_IT veces
	for (i=0; i// No es estrictamente necesario
	pthread_exit(0);
}

// Funcion principal
int main(void) {
  // Creamos variables hilo
  pthread_t hilo1, hilo2;

  // Creamos los hilos
  pthread_create(&hilo1, NULL, f_productor, NULL);
  pthread_create(&hilo2, NULL, f_consumidor, NULL);

  // Esperamos a que acaben los hilos
  pthread_join(hilo1, NULL);
  pthread_join(hilo2, NULL);

  printf("El productor a esperado %i veces, el consumidor %i\n", espera_prod, espera_cons);

  // Terminamos
  return 0;
} // main


[Índice]

qsort.c
// Guimi - 2006-03 http://guimi.net
// Implementacion de algoritmo de ordenacion Quick Sort - Hoare 1960

/* C ya implementa este algoritmo, con 
 *  qsort(puntero al vector, numero de elementos, tamanyo de elemento, funcion de comparacion)
 * Ver ejemplo de uso en 09-Otros_recursos.c
 * */

// DIRECTIVAS

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

// Definiciones
#define NUM_ELEMENTOS_VECTOR 100
// Con DEBUG 1 mostramos mensajes de debug
#define DEBUG 0

// FUNCIONES

/* Declaramos la funci´┐Żn que utilizaremos despu´┐Żs */
void ordenar (int vect[], int ind_izq, int ind_der);

// CUERPO DE PROGRAMA

/* Funcion principal */
int main () {
	// Declaramos el vector de elementos
	int vector [NUM_ELEMENTOS_VECTOR];

	// Contador para bucles for
	int i;

	// Mostramos informacion
	printf ("\nAlgoritmo qsort con dos punteros (izq y der)\n");

	// Generamos la semilla aleatoria
	srand(time(NULL));
	// Rellenamos el vector con n´┐Żmeros aleatorios
	for (i = 0; i < NUM_ELEMENTOS_VECTOR; i++)
		vector[i] = rand () % 1000;

	// Mostramos el vector obtenido
	printf ("\nVector desordenado:\n");
	for (i = 0; i < NUM_ELEMENTOS_VECTOR; i++)
		printf ("%d\t", vector[i]);

	// Ordenamos el vector
	ordenar (vector, 0, NUM_ELEMENTOS_VECTOR-1);

	// Mostramos el vector ordenado
	printf ("\nVector ordenado:\n");
	for (i = 0; i < NUM_ELEMENTOS_VECTOR; i++)
		printf ("%d\t", vector[i]);

	// Terminamos
	printf ("\n");
	return 0;
} // main()


/* Funci´┐Żn recursiva ordenar tipo QSORT */
void ordenar (int vect[], int ind_izq, int ind_der) { 
	// Indices (izq, der, pivote) y valor auxiliar para los intercambios
	register int i, j, p, aux;
	// Elemento pivote
	int pivote;

	// Asignamos valores
	i = ind_izq;
	j = ind_der;
	p = (ind_izq+ind_der)/2;
	pivote = vect[p];

	// Informacion de DEBUG
	if (DEBUG) {
		int c1;
		printf ("\n--------------------------------------------\n");
		printf ("Vector por ordenar [%i,%i,%i]:\n", i,j,p);
		for (c1 = i; c1 <= j; c1++)
			printf ("%d\t", vect[c1]);
		printf ("\n");
	}

	// RECORREMOS EL VECTOR
	// Recorremos el vector con dos punteros y vamos cambiando
	//+ los valores para dejar a la izquierda los que sean
	//+ menores que el pivote y a la derecha los que sean mayores
	do {
		// Avanzamos de izq a der hasta encontrar un valor mayor que el pivote
		while ((vect[i] <= pivote) && (i < ind_der)) i++;

		// Avanzamos de der a izq hasta encontrar un valor menor que el pivote
		while ((vect[j] >= pivote) && (j > ind_izq)) j--;

		// Intercambiamos los valores y avanzamos los punteros
		if (i < j) {
			if (DEBUG) printf ("%i-%i;", vect[i], vect[j]);

			aux = vect[i];
			vect[i] = vect[j];
			vect[j] = aux;
		}

	} while (i < j);

	// ORDENAMOS LOS SUBVECTORES RECURSIVAMENTE
	// En el punto donde se cruzan los punteros, todos los valores de la izquierda
	//+ son menores que el pivote y todos los de la derecha son mayores
	//+ Ese es el lugar de orden que le corresponde al pivote
	if (DEBUG) printf ("\nvect[%i]:%i, vect[%i]:%i, pivote[%i]:%i", i, vect[i], j, vect[j], p, vect[p]);

	// Si el cruce es a la izquierda del pivote
	if (p > i) {
		// Cambiamos el pivote con vect[i]
		if (DEBUG) printf ("\n%i-%i", vect[p], vect[i]);
		aux = vect[p];
		vect[p] = vect[i];
		vect[i] = aux;

	// Si el cruce es a la derecha del pivote
	} else if (p < j) {
		// Cambiamos el pivote con vect[j]
		if (DEBUG) printf ("\n%i-%i", vect[p], vect[j]);
		aux = vect[p];
		vect[p] = vect[j];
		vect[j] = aux;
	}

	// Si el cruce es con el pivote en medio o en el mismo punto
	//+ no cambiamos valores

	// Informacion de DEBUG
	if (DEBUG) {
		int c1;
		printf ("\n-izq-> ");
		for (c1 = ind_izq; c1 <= j; c1++)
			printf ("%d\t", vect[c1]);
		printf ("\n-der-> ");
		for (c1 = i; c1 <= ind_der; c1++)
			printf ("%d\t", vect[c1]);
	}

	// Ordenamos el vector de la izq (incluyendo el indice j)
	if (ind_izq < j) ordenar (vect, ind_izq, j);
	// Ordenamos el vector de la der (incluyendo el indice i)
	if (i < ind_der) ordenar (vect, i, ind_der);

	/* Mejoras posibles:
	 *  Al ordenar subvector izq y subvector der, no incluir el pivote.
	 *
	 *  Elegir un buen pivote, por ejemplo tomar los elementos 
	 *   inicial, final y medio y seleccionar de pivote aquel cuyo 
	 *   valor este entre los otros dos.
	 *
	 *  El caso en que se comporta peor el algoritmo es el de una lista
	 *   ya ordenada (o casi).
	 *  Cuando el algoritmo est´┐Ż terminando, los subvectores 
	 *   tienden a ello, por eso se puede hacer una transaccion a otro
	 *   algoritmo cuando los vectores tienen pocos elementos.
	 *  Por ejemplo, si el vector tiene menos de 10 o 15 elementos
	 *   utilizar algoritmo de insercci´┐Żn en vez de quick sort.
	 *
	 *  Introsort cambia a heapsort en caso de que las iteracciones de
	 *   de quicksort alcancen un n´┐Żmero muy alto.
	 * */

} // ordenar()


[Índice]

endian.c
// Guimi - 2009-01 http://guimi.net
// Tomado de la wikipedia (http://www.wikipedia.org)
/* Este programa nos indica si la m´┐Żquina trabaja en modo big-endian (típico de Motorola)
 o little-endian (típico de Intel) */

/* Hay que compilar el codigo con
 *  gcc -o endian endian.c  //Linux
 *  gcc -o endian.exe endian.c  //DOS
 */

// DIRECTIVAS
#include <stdio.h>

// Funcion principal
int main(void)
{
	// Generamos un valor conocido
	int i = 1;
	char *p = (char *) &i;
	// Comprobamos si el uno está en la primera posición
	if ( p[0] == 1 )
		printf("Little Endian\n");
	else
		printf("Big Endian\n");

  // Terminamos
  return 0;
} // main

[Índice]

ANEXO

// Guimi - 2006-03 http://guimi.net
// Librerias estandar
#include <assert.h>	// Assertions
#include <ctype.h>	// Character identification
#include <errno.h>	// Error handling
#include <float.h>	// Max and Min values for floats
#include <limits.h>	// Limits for integral types
#include <locale.h>	// Internationalisation info
#include <math.h>	// Advanced math functions
#include <setjmp.h>	// Non-local jump
#include <signal.h>	// Exception handling
#include <stdarg.h>	// Variable numbers of arguments
#include <stddef.h>	// Standard definitions
#include <stdio.h>	// Input/Output
#include <stdlib.h>	// General Utilities
#include <string.h>	// String Manipulation
#include <time.h>	// Date and Time functions

// Compilacion condicional
//#ifdef __STDC__
/* codigo ANSI C a compilar */
//#else
/* codigo K&R C a compilar */
//#endif

/* Caracteres especiales
 * \014 - Bit pattern for Form Feed
 * \n	- New line
 * \t	- Tab
 * \\	- \
 * \'	- '
 * \"	- "
 * \b	- BackSpace
 * \r	- Carriage Return
 * \f	- Form Feed
 * \0	- NULL (String Terminator)
 * */

[Índice]

Warning: include(): Unable to access licencia/cc-by-sa-30-es.html in /usr/home/guimi.net/web/datos/tec-docs/cursoC.html on line 2049 Warning: include(licencia/cc-by-sa-30-es.html): failed to open stream: No such file or directory in /usr/home/guimi.net/web/datos/tec-docs/cursoC.html on line 2049 Warning: include(): Unable to access licencia/cc-by-sa-30-es.html in /usr/home/guimi.net/web/datos/tec-docs/cursoC.html on line 2049 Warning: include(licencia/cc-by-sa-30-es.html): failed to open stream: No such file or directory in /usr/home/guimi.net/web/datos/tec-docs/cursoC.html on line 2049 Warning: include(): Failed opening 'licencia/cc-by-sa-30-es.html' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /usr/home/guimi.net/web/datos/tec-docs/cursoC.html on line 2049
Para contactar con nosotros escríbe a contacto_ARROBA_guimi.net
Esta página está optimizada para todos los navegadores ;)
Esta página ha sido realizada utilizando CMSXP Valid HTML 4.01!
Estadísticas