miércoles, 20 de enero de 2010

Uniones

Una uniòn consiste eb una variable que puede contener valores "normales". Las uniones son una de las alternativas para solventar la falta de comprobaciones de tipo del lenguaje C en tiempo de ejecución.

La sintaxis de la declaraciòn de una unión es semejante a la declaración de una estructura sin más que cambiar la palabra estructura por unión.

struct { /* entrada en la tabla de símbolos */

char *name;
int type;
union {
int u_ival;
float u_fval;
char *_sval;
} uval;
}symtab [NSYMJ;

Las variables symtab[i].uval tienen capacidad suficiente para contener variables de cualquiera de los tipos int, float o char, siendo responsabilidad del programador tener el cuidado necesario para controlar los tipos adecuados de las variables contenidas en una unión.

La unión definida anteriormente permitiría el acceso a susjdis-tintos elementos como:

switch (symtab[i].type) {

case INT:

printf ("%d\n", symtab[i].uval.u_ival);

break;

case STRING:

printf ("%s\n", symtab[i].uval_sval);

break

case FLOAT

printf ("%s\n", symtab[i].uval_fval);

break;

}

siendo similar al programa en Pascal:

type symtab =

record

name ; array[1..10] of char;

case stype : integer of

int : ( ival : integer );

float: (fval : real );

string : (svai . array[1..20] of char );

end;

var

symtab : array [1..nsymbols] of symtab;

...

case symtab[i].stype of

int : writeln(symtab[i].ival);

float : writeln(symtab[i].fval);

string : writeln(symtab[i].sval);

end


La enorme similitud entre ambos programas puede aún aumentarse mediante el empleo del preprocesador de C, empleando #defines que hagan más manejables los nombres de variables:

#define ival uval.u_ival
#define ival uval.u_fval
#define ival uval.u_sval

Las operaciones que pueden realizarse sobre las uniones las mismas que las permitidas sobre las estructuras, acceder a uno de sus miembros y acceder a la dirección de la unión.

miércoles, 6 de enero de 2010

Entrada/Salida en lenguaje C

El lenguaje C no incorpora directamente instrucciones para la realización de las operaciones de Entrada/Salida, implementándola a través de librerías y funciones.

Existe un conjunto de funciones de E/S que es portable a un gran número de sistemas operativos (UNIX, VMS, MS-DOS, CP/M, ...), imple-mentadas en la denominada librería de E/S estándar. Cualquier programador de C debe conocer los nombres y argumentos de estas funciones, considerando que van a ser las mismas en cualquiera de los sistemas operativos mencionados.

Además se incluyen funciones para permitir el interface directo con las propias funciones de E/S del sistema operativo.


Los ficheros en la librería estándar de E/S:

Las declaraciones necesarias para el manejo de la librerìa estàndar de E/S son accesibles mediante el empleo de un #include;

#include

En algunos sistemas puede llegar a ser necesario notificar expresamente al compilador la inclusión de la librería estándar. Por ejemplo, en los antiguos sistemas Unix Versión 6 se requería la inclusión de la opción "-1S" al compilar. Esto ya no es necesario en los sistemas Unix Versión 7 actuales o en sus derivados.

Internamente, la librería estándar de E/S almacena la información correspondiente a cada fichero abierto en una estructura, identificando a los ficheros por medio de punteros a estructuras. El fichero define FILE como una de estas estructuras.

martes, 15 de diciembre de 2009

Apertura de Ficheros

Antes de que se pueda acceder a un fichero èste debe ser abierto mediante la funciòn fopen:

FILE *fopen (name mode) /* Abre un -fichero */

char name; /* Nombre del -fichero a abrir */

char *mode; /* Modo de acceso al -fichero */

El primer argumento de fopen es el nombre del fichero, enviado como una cadena de caracteres. El formato del nombre de fichero es dependiente del sistema operativo. Sin embargo, muchas (no todas) las implementaciones de la librería C estándar de E/S trasladan los nombres de ficheros especificados como en Unix al formato requerido por el sistema operativo.

Por ejemplo, el formato de un nombre de fichero en Unix es:

/directorio l/directorio2/ ... /fichero

Cada uno de los componentes del nombre del fichero (directorio 1, directorio2, fichero) pueden estar formados por cualquier secuencia de caracteres excepto por un slash "A Sólo son significativos los catorce primeros caracteres. No hay un límite para el número de directorios que se pueden especificar.

El "mode" (modo) puede ser de tres tipos:

• modo de acceso "r" indica que el fichero se va a abrir para lectura. Si el fichero no existe, se devolverá un error.
• modo "w" especifica que el fichero se va a abrir para escritura. Si el fichero ya existe no se tendrá en consideración el contenido anterior, perdiéndose por corajoleto. Si el fichero no existiese, entonces lo creará la propia Tunción fopen.
• modo "a"especifica que el fichero se va a abrir para añadirle texto (append). Si el fichero ya existe, los nuevos datos se grabarán al final del mismo, y si no existiese será creado por la función.

En caso de que se produzca un error, fopen devuelve el valor NULL, definido en como (char *)0.

jueves, 10 de diciembre de 2009

E/S básica

Las operaciones más sencillas que se pueden realizar sobre un fichero que ya esté abierto son getc y putc.

int getc(fp)

FILE *fp;

getc devuelve el siguiente caràcter del fichero especificado for fp, o EOF (definida en ). EOF se devuelve cuando se produce algún error o se alcanza el final de fichero.

Análogamente:

int putc(fp)

FILE *fp;

putc escribe el caràcter dado en el fichero fp, y retorna "c" o EOF (en caso de error).

feof(fp)

FILE *fp;

feof devuelve un valor distinto de cero si se ha llegado al final del fichero fp.

ferror(fp)

FILE *fp;

ferror devuelve un valor distinto de cero si se ha encontrado algùn error durante la lectura o escritura del fichero fp

fclose(fp)

FILE *fp;

fclose cierra el fichero fP' devolviendo un EOF si se produce algún error (por ejemplo, si el fichero fp no fue abierto previamente).

La funciòn freopen

FILE *freopen(name, mode, fp)

char *name;

char *mode;

FILE *fp;

en primer lugar cierra el fichero especificado por fp y abre un nuevo fichero, de modo que el fichero recién abierto reutiliza la estructura FILE apuntada por fp. Freopen devuelve fp si la apertura se ha realizado sin problemas, o NULL en caso contrario.

ungetc(c, fp)

char c;

FILE *fp;


ungetc provoca que la siguiente llamada a getc(fd) (así como scanf, getw, gets, y las restantes funciones de lectura) lea el carácter "c". Mediante el empleo dé úngete sólo se puede poner un carácter en el buffer del fichero fd.

jueves, 3 de diciembre de 2009

Ficheros Estándar

Cuando se inicia la ejecución de un programa C se produce la apertura automàtica de tres ficheros, antes de que llegue a producirse la llamada a main(). Estos ficheros son la entrada estándar "stdin" (standard input, normalmente el teclado) la salida estàndar "stdout" (standard output, normalmente la pantalla de vídeo) y el fichero estàndar de salida de errores "stederr" (standard error, normalmente la pantalla de video).

Este encaminamiento normal de los ficheros estándar (pantalla y teclado por defecto), puede verse modificado a través del intérprete de comandos de Unix y reencaminado hacia ficheros, "tuberías" (pipes) o regiones de memoria compartida.

La librería estándar de E/S declara stdin, stdout y stderr como punteros a estructuras FILE para los ficheros de ejitrada estándar, salida estándar y fichero estándar de errores, respectivamente.

Las funciones getchar y putehar son macros, en lugar de auténticas funciones, definidas en como:

#define getchar() getc(stdin)

#define putchar(c) putc(c, stdout)

Hay que advertir que stdin, stdout y stderr son constantes y no pueden ser reasingnados mediante fopen como podrìa parecer natural.

stdout = fopen("myfile", "w");

no es un procedimiento válido para redireccionar la salida estándar al fichero myfile. Sin embargo,

freopen("myfile", "w", stdout);


sí podría servir para este propósito, debido a que freopen cierra y abre el fichero, como comentamos anteriormente.

lunes, 1 de junio de 2009

Salida con formato

printf es la funciòn bàsica utilizada para salida con formato; es llamada en la forma:

printf(control, argl, arg2,...)

char *control;

Esta funciòn acepta un nùmero variable de argumentos, convirtièndolos, formateàndolos e imprimièndolos bajo las especificaciones incluidas en "control". Los caracteres del string de control se vuelcan en el fichero de salida estàndar, salvo el metacaràcter "%", que se emplea como una especificaciòn de formato para controlar la impresiòn de los argumentos.

• un signo menos "-", indicando que el siguiente argumento debe imprimirse justificando a la izquierda en su campo de salida;

• una cadena de dìgitos, especificando el tamaño mìnimo del campo de salida para ese argumento. Si el argumento ya formateado ocupa menos caracteres que la anchura del campo que le ha sido asignado se completará con caracteres por la izquierda (o por la derecha si se ha especificado justificación a la izquierda).

Si la especificación de la anchura del campo contiene un cero como primer carácter (por ejemplo OSd), la longitud total del campo se completará con ceros en lugar de con espacios en blanco. La inclusión de este cero por la izquierda no debe confundirse en ningún caso con la expresión de una constante en octal (por ejemplo, el carácter espacio en blanco, ASCII 32 en decimal, se expresa como 040 en octal).

A diferencia de la salida con formato en Fortran, printf no trunca la conversión de argumentos en caso de que necesiten una extensión mayor que la especificada para el campo de salida;

• un punto, separando el ancho del campo de salida, de la precisiòn;

• una cadena de dìgitos que puede especificar tanto el nùmero màximo de caracteres a imprimir de una cadena, como el nùmero de dìgitos a imprimir a la derecha del punto decimal cuando se están imprimiendo números en coma flotante (float o double);

• una ele "l", que indica que el siguiente argumento es un long it, en lugar de un int;

• algunas implementaciones de printf interpretan el caràcter asterisco "*" como una anchura de campo o precisión, con el significado de que el siguiente argumento indicará realmente la anchura del campo o precisión del argumento a imprimir. Por ejemplo:

printf("%.*s", longitud, cadena);

imprimirá al menos "longitud" caracteres de la cadena de caracteres "cadena".


Los caracteres de conversiòn de salida son:

d- Convierte el argumento entero a un número decimal con signo.

o- Convierte su argumento (entero) a base octal.

x- El argumento entero se convierte a hexadecimal.

u- El argumento entero se convierte a notación decimal sin signo.

c- Interpreta su argumento como un único carácter.

s- Considera su argumento una cadena (string).

e- Convierte su argumento en coma flotante (interpretado como double, porque C siempre pasa los números en coma flotante como double) a notación exponencial, con signo, mantisa y exponente:

[-]m.nnnnE[-]xx

La longitud de la cadena de enes "n" viene determinada por la precisión, que es de 6 por defecto. (Recordemos que float proporcionaba 6 dígitos de precisión y double 15.) * • ' - El argumento en coma flotante se expresa en notación de coma fija:

[-jmmm.nnnn

La longitud de la cadena de enes "n" se toma nuevamente de 6 por defecto.

g- Convierte su argumento en coma flotante a formato "%f o "%e", dependiendo de cuál de los dos proporcione una cadena de menor longitud.

Cualquier otro caràcter distinto de los especificados anteriormente y que siga a un signo "%" se imprimirá literalmente. Así:

printf("%%");

Imprimirá un único carácter"'%".

La apariciòn de los anteriores caracteres en mayùsculas (D, O, X, U, E, F o G) se interpreta como si una ele "l" precediese al caràcter correspondiente en, minúculas. Así

printf("%D", valor);

es equivalente a

printf("%ld", valor);

La salida con formato especificada por printf y enviada por esta función al fichero de salida estándar tambièn se puede enviar a otro fichero o a una cadena de caracteres, por medio de las funciones fprintf y sprintf, respectivamente.

fprintf(fp, control, argl, arg2,...)

FILE *fp;

char *cntrol;

realiza su salida sobre el fichero especificado por fp.

sprintf(string, control, argl, arg2,...)

lleva su salida al array string de acuerdo con las especificaciones de formato incluidas, en lugar de poner la salida en un fichero.

Entrada con formato

scanf es la funciòn bàsica de entrada con formato.

int scanf (control, argl, arg2, ...)

char *control;

Esta funciòn lee caracteres con formato a partir del fichero de entrada estàndar "stdin", interpretàndolos de acuerdo a las especificaciones de la cadena de control.

Cada uno de sus argumentos debe ser un puntero, especificando la dirección de la variable donde deberá almacenarse el resultado. Obviamente, scanf es una función que necesita "llamada por referencia", pues va a modificar las variables que se le pasan como argumentos. Un error frecuente en su uso consiste en la omisión de los "&" en cada uno de los argumentos.

Los caracteres de separación como espacios en blanco, fabuladores y caracteres de salto de línea que figuren en la cadena de control, serán ignorados.

Los restantes caracteres (excepto el"%") se corresponden con una especificación de formato de entrada, pudiendo consistir en:

• el carácter asterisco "*", indicando que el valor leído no debe almacenarse en la variable;

• una cadena de dìgitos, especificando la longitud màxima del campo de entrada (el número de caracteres a convertir);

• carácter "h , para indicar que el siguiente argumento debe ser considerado como un puntero a un short int, o el carácter "i' indicando que debe ser tratado como un puntero a un long int, o a un double (equivalente a long float);

• carácter de conversión.

Las conversiones de caracteres de entrada permitidas son:

d - Lee un entero decimal. El argumento debe ser un puntero a un entero (o un puntero a un short int o long int, si se hubiesen antepuesto "h" o "1" a la especificación de formato "d").

o - Lee un número entero octal.

x - Lee un número entero hexadecimal.

c - Lee un único carácter de* la entrada. El argumento debe ser un puntero a un carácter.

s - Acepta una cadena de caracteres terminada por un espacio en blanco o un carácter de salto de línea. El array de caracteres donde se guarde el resultado debejser lo bastante grande como para contener todos los caracteres y el carácter nulo terminador de cadena.

e - Lee un número en coma flotante. El argumento debeser un float (o un double, con especificación "le").

f - Análogo al anterior. Acepta un número en coma flotante.

[ - Lee una cadena de caracteres limitada por separadores arbitrarios, almacenándola en el array apuntado por el argumento. El corchete de apertura "[" va seguido por un conjunto de caracteres y un corchete de cierre "]". Si el carácter inmediatamente posterior a "[" no es un circunflejo "ó", entonces scanf leerá solamente los caracteres que aparezcan en el conjunto de caracteres entre corchetes. Por el contrario, si el carácter inmediatemente posterior a"[" es un circunflejoentonces scanf leerá caracteres hasta que encuentre algún carácter de los contenidos en el conjunto de caracteres entre corchetes.

Los caracteres de conversión d, o, x, e, y f pueden aparecer en mayúsculas o precedidos por una ele "i", para indicar que el correspondiente puntero apunta a un long int o long float.

scanf interrumpe la lectura cuando llega al final.de la cadena de control, o cuando la entrada no cumple la especificación, de formato impuesta (por ejemplo, intentar leer un literal con una especificación %d de número entero).

scanf devuelve un número entero indicando el número de asignaciones que ha realizado o EOF si ha encontrado un final de fichero y esperaba leer más caracteres.

Es importante aclarar que el valor cero no quiere decir que se haya alcanzado el final de fichero, sino que no se ha convertido correctamente ningún campo de entrada.

Análogamente a lo descrito para printf, scanf también permite que su entrada provenga de una cadena de caracteres o de un fichero.

int fscanf(fd, control, argl, arg2,...)

FILE *fd;

char *control;

es similar a scanf, con la diferencia de que toma su entrada del fichero fd, en lugar de "stdin".

int sscanf(control, argl, arg2,...)

char *control;

tomaría su entrada de una cadena de caracteres. Como la lectura de una cadena no viene acompañada de efectos laterales (side effects), sscanf es generalmente más útil que scanf o fscanf.