•Toshiba Preferred User Entrada/Salida • El apuntador del tipo FILE se incrementa automáticamente con las funciones de lectura y escritura. char *string[80] FILE *stream, *fopen(); if ( (stream = fopen(...)) != NULL) fscanf(stream,``%s'', string); Entrada/Salida • Leer y escribir archivos Las funciones fprintf y fscanf se usan para acceder a los archivos. int fprintf(FILE *stream, char *format, args..) int fscanf(FILE *stream, char *format, args..) Entrada/Salida • Otras funciones para acceder archivos: int getc(FILE *stream) int fgetc(FILE *stream) int putc(char ch, FILE *s) int fputc(char ch, FILE *s) •Escriba el título aquí •1 •Toshiba Preferred User Entrada/Salida • sprintf and sscanf Son similares a fprintf y fscanf excepto que leen/escriben de/a un string. int sprintf(char *string, char *format, args..) int sscanf(char *string, char *format, args..) Entrada/Salida float full_tank = 47.0; /*litros */ float millas = 300; char millas_por_litro[80]; sprintf(millas_por_litro, ``Millas por litro = %2.3f'', millas/full_tank); Entrada/Salida • Funciones para preguntar por el status de las operaciones int feof(FILE *stream); int ferror(FILE *stream); void clearerr(FILE *stream); int fileno(FILE *stream); •Escriba el título aquí •2 •Toshiba Preferred User Entrada/Salida feof(): retorna true si se ha llegado a fin de archivo. while ( !feof(fp) ) fscanf(fp,"%s",line); ferror(): retorna true si ha ocurrido un error en la operación clearerr(): re-inicializa la indicación de error actual. fileno(): retorna el descriptor de archivo asociado al FILE *. Entrada/Salida fread () y fwrite(): permiten la lectura y escritura de bloques de cualquier tipo de datos. fread(void *buffer, size_t numbytes, size_t cuantos, FILE *fp); /* devuelve el número de elementos leídos */ fwrite (void *buffer, size_t numbytes, size_t cuantos, FILE *fp); /* devuelve el número de elementos escritos */ void main() { FILE *fp; double d = 12.23; int i = 101; long l =123023L; if (fp = fopen(“prueb”, “WB+”)) == Null) { printf(“error”); exit(1); } •Escriba el título aquí fwrite(&d, sizeof(double) 1, fp); fwrite(&i, sizeof(int), 1, fp); fwrite(&l, sizeof(long), 1, fp); rewind(fp); fread(&d, sizeof(double), 1, fp); fread(&i, sizeof(int), 1, fp); fread(&l, sizeof(long), 1, fp); •3 •Toshiba Preferred User Otro ejemplo ... struct tipo_struct { float balance; char nombre[80]; } cliente; La siguiente proposición escribe el contenido de cliente en un archivo apuntado por fp: fwrite(&cliente, sizeof(struct tipo_struct), 1, fp); Entrada/Salida E/S de bajo nivel • Esta forma de E/S no es a través de buffers. • No hay facilidades para formatear la entrada o la salida. • Se trabaja con archivos en forma binaria no en modo texto. • Se usan descriptores de archivo en lugar de FILE *. Entrada/Salida int open(char *filename, int flag, int perms) -- retorna un descriptor de archivo o -1 si falla. flag controla el tipo de acceso al archivo y algunos de sus valores son: • O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_WRONLY •Escriba el título aquí •4 •Toshiba Preferred User Entrada/Salida • creat(char *filename, int perms) • int close(int handle) • int read(int handle, char *buffer, unsigned length) • int write(int handle, char *buffer, unsigned length) #include<stdio.h> #include<fcntl.h> float bigbuff[1000]; main(int argc, char **argv) { int fd, bytes_read, file_length; if ((fd = open(argv[1],O_RDONLY)) = -1) { /* error */ } if ((bytes_read = read(fd,&file_length, sizeof(int))) == -1) { /* error reading file */ } if ((bytes_read = read(fd,bigbuff, file_length*sizeof(float))) == -1) { /* error reading open */ } El Pre-procesador de C •Escriba el título aquí •5 •Toshiba Preferred User El Pre-procesador de C • El preprocesamiento es el primer paso durante el ciclo de compilación de un programa en C. • Las directivas comienzan con un #. • Entre las ventajas del preprocesamiento se encuentran: • Los programas son más fáciles de desarrollar. • Mas fáciles de leer y modificar • El código C es más portable. El Pre-procesador de C Nos permite adaptar el lenguaje a nuestras necesidades. Por ejemplo, podemos reemplazar las { ... } por los delimitadores PASCAL begin ... end #define begin { #define end } El Pre-procesador de C #define Se usa para definir constantes o MACROS. #define <macro> <replacement name> Por ejemplo: #define FALSE 0 #define TRUE !FALSE •Escriba el título aquí •6 •Toshiba Preferred User El Pre-procesador de C MACROS #define max(A,B) ( (A) > (B) ? (A):(B)) Si en nuestro programa colocamos: x = max(q+r,s+t); después del preprocesamiento quedaría: x = ((q+r)>(r+s)?(q+r):(s+t)); El Pre-procesador de C • #undef : elimina la definición previamente realizada del nombre de la macro que le sigue. #undef nombre_de_macro Ejemplo: #define LONG 100 #define ANCHO 100 char array[LONG][ANCHO] #undef LONG #undef ANCHO El Pre-procesador de C • #include: permite incluir un archivo en el código. Son válidas dos formas: #include <file>: le dice al compilador que busque en determinado directorio del sistema operativo. #include ``file'’: el archivo está en el directorio actual •Escriba el título aquí •7 •Toshiba Preferred User El Pre-procesador de C #if -- inclusion condicional • #if evalúa una expresión entera constante. • Siempre se necesita #endif para delimitar el final de la instrucción. • Podemos también usar else, #else y #elif -- else if. El Pre-procesador de C • Otro uso común de #if es con: • #ifdef – -- Si está definido • #ifndef – -- Si no está definido Es útil para chequear si ciertas MACROS han sido ya definidas. El Pre-procesador de C • Por ejemplo para asignar el tamaño de un entero en un programa que debe ser portable entre borland C y UNIX u otro OS. #ifdef TURBOC #define INT_SIZE 16 #else #define INT_SIZE 32 #endif •Escriba el título aquí •8 •Toshiba Preferred User El Pre-procesador de C • Otro ejemplo: si vamos a correr un programa en MSDOS se debe incluir el archivo msdos.h, de lo contrario se incluye el archivo default.h. #if SYSTEM == MSDOS #include <msdos.h> #else #include ``default.h'' #endif El Pre-procesador de C • Como las directivas del preprocesador pueden escribirse en cualquier lugar dentro del programa, se pueden filtrar algunas instrucciones. x = y *3; #ifdef DEBUG print("Debugging: Variables (%d,%d) = \n",x,y); #endif El Pre-procesador de C • #error: genera un mensaje de error y fuerza al compilador a detener la compilación. #ifdef OS_MSDOS #include <msdos.h> #elifdef OS_UNIX #include ``default.h'' #else #error Wrong OS!! #endif •Escriba el título aquí •9 •Toshiba Preferred User El Pre-procesador de C • # line: hace que las líneas del código fuente subsecuentes se renumeren, iniciándose con el valor entero constante especificado. #line 100 /* inicia la numeración de líneas a partir de 100, empezando con la siguiente línea de código fuente */ El Pre-procesador de C • En la directiva #line puede incluirse el nombre del archivo. #line 100 “file1.c” indica que las líneas están numeradas a partir de 100, empezando desde la siguiente línea de código y el nombre del archivo es file1.c El Pre-procesador de C #include <stdio.h> #line 100 /* reinicializa el contador de líneas */ void main(void) { /* linea 100 */ printf(“%d\n”, __LINE__); /* 101 */ } •Escriba el título aquí •10 •Toshiba Preferred User El Pre-procesador de C • El operador #: convierte el argumento al que precede en una cadena entrecomillada. Ejemplo: #include <stdio.h> #define hazcad(s) # s void main(void) { printf(hazcad(Me gusta C)); } El Pre-procesador de C void main(void) { printf(hazcad(Me gusta C)); } El pre-procesador de C convierte la línea: printf(hazcad(Me gusta C)); en: printf(“Me gusta C”); Desarrollo en Varios Archivos •Escriba el título aquí •11 •Toshiba Preferred User Desarrollo en Varios Archivos (Ventajas) • Varios programadores pueden trabajar sobre varios módulos de un mismo programa. • Se puede usar un estilo orientado por objetos: Cada archivo define un tipo de datos particular y sus operaciones. La implementación del objeto se mantiene privada para el resto. Desarrollo en Varios Archivos (Ventajas) • Los objetos bien implementados pueden usarse en otros programas reduciendo así el tiempo de desarrollo. Desarrollo en Varios Archivos (Cómo hacer la división) • De todos los archivos, uno solo contendrá el main, y los otros contendrán funciones auxiliares que serán tratadas como funciones de librería. •Escriba el título aquí •12 •Toshiba Preferred User Desarrollo en Varios Archivos (Como hacer la división) • Si los objetos se implementan con estructuras, es recomendable mantener todas las funciones que acceden al objeto dentro del mismo archivo. Las ventajas son: • el objeto se puede reusar fácilmente en otros programas. • Todas las funciones relacionadas están juntas. • Si hay cambios a la estructura, sólo un archivo se modifica. Desarrollo en Varios Archivos (Como hacer la división) • Los prototipos de las funciones que queremos que sean visibles a otros programas se escriben en un archivo de encabezado (.h). • Cada vez que un programa desea usar una función de nuestro archivo .C debe incluir el encabezado donde están definidos los prototipos. (#include del .h). Desarrollo en Varios Archivos Cada archivo se organiza típicamente de la siguiente forma: • Un preambulo que consiste en constantes (#define), archivos de encabezado, y definiciones de tipos importantes. • Declaración de variables globales y externas. • Una o más funciones. •Escriba el título aquí •13 •Toshiba Preferred User Desarrollo en Varios Archivos • El orden de los items es importante: cada objeto debe definirse antes de declararse. Las funciones que retornan valores también deben definirse antes de su llamada. La definición se hace de una de las siguiente forma: • Si la función es definida y usada en el mismo archivo, una declaración completa de la misma se coloca antes de usarla. • Si la función es invocada en un archivo donde no está definida, el prototipo debe aparecer antes de la llamada a la función. Desarrollo en Varios Archivos Una función definida como: float find_max(float a, float b, float c) { /* etc ... ... */ Tiene el siguiente prototipo: float find_max(float, float, float); •Escriba el título aquí •14