Lenguaje C: Entrada y salida
-
- Salida con formato: printf()
- Entrada de datos con formato: scanf()
- Entrada de caracteres: getchar()
- Salida de caracteres: putchar()
- Entrada y salida de cadenas
-
- Apertura y cierre de un fichero
- Fin de fichero
- Entrada y salida de texto
- Entrada y salida de caracteres
- Entrada y salida de cadenas
- Lectura y escritura de datos binarios
- Entrada y salida con formato
- Entrada y salida mediante acceso directo
- Otras operaciones sobre ficheros
E/S estándar
Las entradas y salidas de información de un programa pueden realizarse:
- Sobre las unidades de almacenamiento
- Apertura del archivo
- Operación de lectura/escritura sobre el archivo
- Cierre del archivo
- Sobre dispositivos periféricos
- Directamente sobre los periféricos: operación hardware
- A través de los controladores de los periféricos
- Con los recursos ofrecidos por el sistema operativo
Cuando un programa está en ejecución, se convierte en un proceso que dispone de:
- Un canal estándar de entrada asociado por defecto al teclado:
sdtin
- Lo que el usuario escribe en el teclado va a parar al canal
stdin
- Un canal estándar de salida asociado por defecto a la pantalla:
stdout
- Lo que el proceso escribe en el canal
stdout
va a parar a la pantalla
- Un canal estándar para salida de errores asociado por defecto a la pantalla:
stderr
- Lo que el proceso escribe en el canal
stderr
también va a parar a la pantalla
El estándar ANSI C creó un conjunto de funciones estándar para la entrada y salida a través de los ficheros estándar stdin
y stdout
- Están definidas en el archivo
stdio.h
, por lo que para utilizarlas en un programa es preciso incluir la línea:
#include <stdio.h>
Las más importantes son:
printf()
para escribir datos con formatoscanf()
para leer datos con formatogetchar()
para leer caracteres del tecladoputchar()
para escribir caracteres en pantalla
Salida con formato: printf()
La función devuelve el número de bytes escritos o EOF
en caso de error
- Plantilla de utilización:
printf("cadena_de_control", lista_de_argumentos);
- Elementos en la “cadena_de_control” :
- Caracteres y símbolos ASCII normales
- Caracteres de escape o secuencias de barra invertida
- Comienzan siempre con símbolo «
»
- Especificadores de formato para la representación de los valores almacenados en variables
- Comienzan siempre con el símbolo «
%
»
- La “lista_de_argumentos” es una relación de las variables (separadas por comas) cuyos contenidos se quiere mostrar
- Tiene que haber al menos tantas variables como especificadores de formato
- Caracteres de escape o secuencias de barra invertida más habituales:
\a | Alarma (pitido) | \ ' | Comilla simple |
\b | Espacio atrás | \“ | Comillas dobles |
\f | Salto de página | \\ | Barra invertida |
\n | Nueva línea | \oo | Carácter ASCII en octal |
\r | Retorno de línea | \xHH | Carácter ASCII en hexadecimal |
\t | Tabulador | \0 | Carácter nulo (Código ASCII cero) |
- Sintaxis de los especificadores de formato:
%[flags][anchura][.precision][prefijo-tipo] formato
flags
: Opcional:-
justifica a la izquierda+
fuerza la aparición del signo siempre0
completa con ceros a la izquierda todo el campo
anchura
: Opcional: Ancho del campo en el que aparecerá el dato.precision
: Opcional:- En enteros, número de dígitos
- En reales, número de dígitos decimales
- En cadenas, número de caracteres
prefijo-tipo
: Opcional, para indicar a la función como debe interpretar el dato contenido en la memoria:h
interpreta unshort
l
interpretalong
en los enteros odouble
en los realesL
interpreta unlong double
formato
: Obligatorio, para determinar el tipo de dato de la variable cuyo contenido se va a mostrar:d
Entero con signo en mostrado en decimalu
Entero sin signo mostrado en decimalo
Entero sin signo mostrado en octalx
Entero sin signo mostrado en hexadecimalf
Número real en formato[–]ddd.ddd
e
Número real en formato[–]d.dddE[±]ddd
g
Número real en el formato más cortoc
Carácters
Cadena de caracteres
- Ejemplos
printf("Número entero: %d", edad); printf("Letra:%c t Octal:%o t Hexadecimal: %x",codigo, codigo, codigo); printf("Número real: %f t %E t %G", estatura, estatura, estatura);
Entrada con formato: scanf()
La función devuelve el número de datos leídos correctamente o EOF en caso de error
- Plantilla de utilización:
scanf("cadena_de_control", lista_de_argumentos);
- Elementos de la
cadena_de_control
:- No es una cadena que aparezca en pantalla
- Se corresponde con la cadena que la función espera encontrarse en el teclado carácter a carácter
- Incluye los caracteres de separación o espacios en blanco que separan los especificadores de formato. Pueden ser
- El espacio en blanco
“ ”
- El tabulador
t
- El retorno de carro
n
- Incluye los especificadores de formato que provocan la captura de un dato
- Sintaxis de los especificadores de formato
%[*][anchura][prefijo-tipo] formato
[*]
: Opcional: anula la asignación al siguiente dato
scanf("%d %*s”, &valor); /* Lee el dato y la cadena que se teclee a continuación del valor entero, pero no se asigna a ninguna variable */
anchura
: Opcional: Número de caracteres a leer (se ignoran los restantes)prefijo-tipo
: Opcional:- En enteros, número de dígitos
- En reales, número de dígitos decimales
- En cadenas, número de caracteres
formato
: Obligatorio, determina el tipo de dato (igual que enprintf()
)- La lista de argumentos es una relación de las direcciones de memoria de las variables (separadas por comas)
- La dirección de una variable se obtiene precediendo el nombre de la variable del operador «
&
» - Debe haber el mismo número de variables que especificadores de formato
El buffer de teclado es una zona de almacenamiento intermedio asociada a la entrada estándar stdin
- Se almacenan los códigos ASCII de las teclas pulsadas
- Se valida cuando se pulsa la tecla INTRO
- Sólo se eliminan del buffer los códigos de los caracteres leídos
- Es la zona de memoria donde
scanf()
obtiene los valores - Puede que no se cojan todos los caracteres tecleados
- Se quedan hasta la siguiente lectura del buffer del teclado
- Hay una función definida en
stdio.h
que borra este buffer
fflush(sdtin);
Entrada de caracteres: getchar()
Función para leer caracteres del teclado. Prototipo:
int getchar(void);
- Definida en
stdio.h
- No requiere ningún argumento
- Devuelve el código ASCII de la tecla pulsada o EOF en caso de error
- Solo finaliza, cogiendo un código, cuando se pulsa la tecla INTRO
- Si se ha pulsado más de una tecla, quedan en el buffer del teclado
- Ejemplo:
char a; a = getchar(void); scanf("%c", &a);
- * Las dos sentencias son equivalentes
- Las teclas especiales (F1…F12) y las combinaciones con CTRL y ALT generan dos códigos de 8 bits, es decir, equivalen a dos pulsaciones (dos caracteres)
Salida de caracteres: putchar()
Función para mostrar caracteres en la pantalla. Prototipo:
int putchar(int variable);
- Definida en
stdio.h
- Como argumento requiere el nombre de la variable que contiene el código a mostrar
- Devuelve en un entero el código ASCII del carácter mostrado o EOF en caso de error
- Ejemplo:
char a; putchar((int)a); printf("%c", a);
- * Las dos sentencias son equivalentes
Lectura y escritura de cadenas
En lenguaje C no existe un tipo de dato de cadena de caracteres, los arrays de caracteres o cadenas de caracteres son vectores:
- Cuyos elementos se almacenan consecutivamente en memoria
- Se puede hacer referencia a todo el conjunto mediante un único identificador
- Para referenciar a un elemento se utiliza el identificador y un índice entre corchetes
cadena[indice]
- El último elemento es siempre el carácter nulo
0
- Declaración de un array (incluido el nulo final):
char nombrevariable[NUMERO_DE_ELEMENTOS];
- Se tratarán con detalle más adelante
Lectura de cadenas: gets( )
gets(char *cadena);
- Definida en
stdio.h
- Necesita, como argumento, el identificador de una cadena de caracteres
- Lee todos los caracteres tecleados hasta el INTRO que lo recoge y lo sustituye por '0' en memoria
- Ejemplo:
#define NUM_ELEM 100 char cadena[NUM_ELEM]; /* Declaración */ gets(cadena); /* Lee una cadena */ scanf("%s", cadena); /* Lee una cadena */
- Las dos sentencias son equivalentes
- Leen todo lo tecleado (sea cual sea el valor de
NUM_ELEM
)
Escritura de cadenas: puts( )
puts(cadena);
- Definida en
stdio.h
- Necesita, como argumento, el identificador de una cadena de caracteres o la propia cadena entre comillas dobles
- Lleva a pantalla los símbolos ASCII de los códigos almacenados hasta encontrar el nulo '0' que es sustituido por un INTRO
- Ejemplo:
puts(cadena) /* Muestra una cadena */ printf("%s", cadena); /* Muestra una cadena */
- Las dos sentencias son equivalentes
- La función
printf()
puede utilizarse para mostrar en pantalla la cadena que va entre comillas como argumento
Ficheros y secuencias
El lenguaje C proporciona mecanismos para la entrada y salida por ficheros:
- Que no dependen del dispositivo físico sobre el que actúen
- Son funciones genéricas, potentes y flexibles
- Distingue dos tipos de elementos
- Ficheros
- Secuencias o streams
- fichero: Dispositivo físico y real sobre el que se realizan las operaciones de entrada o salida
- secuencia (stream): Ente abstracto sobre el que se realiza una operación de entrada o salida genérica
- Las secuencias, en muchas ocasiones, se asocian a dispositivos físicos o a ficheros:
- La secuencia de salida estándar se asocia a la pantalla
- La secuencia de entrada estándar se asocia al teclado
- El concepto de fichero puede aplicarse, además de a ficheros en disco, a impresoras, terminales, controladores, etc.
- El concepto de secuencia puede entenderse como un buffer de datos o un dispositivo lógico que proporciona un camino para los datos en las operaciones de entrada o salida
- Cuando se abre un fichero para operaciones de entrada y/o salida, se le asocia una secuencia, un camino que permitirá la transferencia de información entre ese fichero y el programa.
- El lenguaje C contempla los ficheros como secuencias continuas de bytes que pueden ser accedidos de forma individual:
- Todas las funciones de E/S sirven para todas las secuencias, sólo hay que redirigirlas al fichero deseado
- El sistema operativo (DOS/Windows) admite que un fichero pueda ser abierto de dos modos:
- En modo texto: Los bytes de la secuencia son códigos ASCII
- En modo binario: Los bytes de la secuencia son códigos binarios de 8 bits
- En los sistemas Unix y Linux no existe tal distinción
- No hay ninguna indicación añadida al modo de apertura de un fichero
En modo texto el final de la línea se representa:
- En lenguaje C: como «
n
» (En ASCII CR: Retorno de carro, código 10) - En el sistema operativo Windows: como la sucesión de los códigos ASCII:
CR+LR
(Retorno de carro + Salto de línea, códigos 10 y 13) - Las funciones de lectura en lenguaje C al encontrar la secuencia
CR+LF
, la convierten a «n
» - Las funciones de lectura al encontrar el código correspondiente a
Ctrl+D
(Ctrl+Z
en Windows) lo interpretan comoEOF
(End Of File\, fin de fichero).
- Ejemplo: Si en un fichero de texto del DOS (*.TXT) escribimos:
En un lugar de la mancha,
de cuyo nombre no quiero acordarme.
- Al leer el fichero en modo binario desde un programa en lenguaje C se obtendrá la siguiente secencia:
En un lugar de la mancha, r\nde cuyo nombre no quiero acordarme.EOF
- Si se abre en modo texto , lo que se recogerá será lo siguiente:
En un lugar de la mancha, nde cuyo nombre no quiero acordarme.EOF
Al ejecutar un programa en modo consola, automáticamente el sistema operativo abre tres secuencias estándar:
stdin
- Entrada estándar. Se asocia al teclado
stdout
- Salida estándar. Se asocia a la pantalla
stderr
- Salida estándar de errores. Se asocia a la pantalla
- Las secuencias estándar tienen asociado un buffer de memoria física cada una
- Las E/S por consola operan igual que las E/S por ficheros, pero redirigen la operación real sobre las secuencias estándar
stdin
,stdout
ystderr
Apertura y cierre de un fichero
Para acceder a los ficheros se precisa un descriptor del fichero (puntero de tipo FILE
)
- Declaración:
FILE *puntero;
FILE
es una constante definida enstdio.h
- El descriptor apunta a un buffer que contiene toda la información necesaria para operar con el fichero
- Se utiliza para hacer referencia al fichero en todas las operaciones sobre este
- Debe declararse antes de utilizarse
- El descriptor se inicializa al abrirsin error un fichero al que se le hace apuntar
Antes de cualquier operación sobre un fichero es preciso abrir el fichero, utilizando la función fopen()
- Declaración:
FILE * fopen(char *nombrearchivo, char *modo);
- Devuelve:
- Un descriptor de tipo
FILE
que apunta al fichero abierto - Un descriptor nulo (
NULL
) en caso de error
- Recibe dos cadenas de caracteres:
- La primera con el nombre del fichero (con la ruta de acceso)
- La segunda con el modo de apertura que se selecciona
Modos de apertura de ficheros | |||
Modo | Texto | Binario | Observaciones |
Abrir para leer | "r" | "rb" | Si no existe, se produce error |
Crear para escribir | "w" | "wb" | Si existe, se pierde el contenido |
Abrir o crear para añadir | "a" | "ab" | Si no existe, se crea |
Abrir para leer y/o escribir | "r+" | "rb+" | Debe existir |
Crear para leer y/o escribir | "w+" | "wb+" | Si existe, se pierde el contenido |
Abrir o crear para añadir y/o leer | "a+" | "ab+" | Si no existe, se crea |
Mientras el fichero esté abierto, el descriptor correspondiente apunta a una estructura que contiene toda la información necesaria sobre el fichero:
- Nombre, tamaño, atributos, posición del apuntador para lecturas y/o escritura, etc.
Al finalizar un programa que utiliza ficheros:
- Si termina normalmente, los ficheros que estuviesen abiertos son cerrados por el sistema operativo.
- Un fichero no cerrado correctamente queda inutilizado y la información que pudiera contener se pierde y queda inaccesible.
En previsión de finalizaciones anómalas, tras las operaciones de lectura y/o escritura, es preciso cerrar los ficheros, utilizando la función fclose()
:
- Declaración
int fclose(FILE *descriptor);
- Devuelve
- un entero de valor cero si el cierre ha sido correcto
- EOF en caso de error
- Recibe como argumento el descriptor al fichero que se quiere cerrar
- Ejemplo de apertura y cierre de un fichero:
FILE *pf; /* descriptor a fichero */ if ((pf=fopen("misdatos/prueba.x","w+")) == NULL) { puts("nNo es posible crear el fichero"); exit(0); } else printf("nEl fichero se ha abierto"); /* Tras realizar todas las operaciones necesarias, es preciso cerrar el fichero antes de finalizar el programa */ fclose(pf); /* El fichero ha quedado cerrado */
El carácter de fin de fichero está representado por la constante simbólica EOF
, definida en stdio.h
- Es el último byte del fichero
- Cuando se leen bytes del fichero (con
fgetc()
) puede leerse el EOF y no distinguirse como último carácter, especialmente cuando se trata de secuencias binarias - La función
feof()
, declarada enstdio.h
devuelve un valor distinto de cero (verdadero/true) cuando se lee el byte de fin de fichero (EOF
)
while (!feof(puntfile)) { /* Operaciones sobre el fichero abierto */ }
Entrada y salida de texto
Las funciones de lectura y escritura de caracteres en ficheros están definidas en stdio.h
int fgetc( FILE *pf);
- Lee un carácter en el fichero cuyo descriptor recibe
- Devuelve el carácter leído en un entero o
EOF
en caso de error
int fputc( int car, FILE *pf);
- Escribe un carácter en el fichero cuyo descriptor recibe
- Devuelve
EOF
en caso de error - Recibe como argumentos:
car
: El carácter a escribirpf
: El descriptor al fichero
- Ejemplos de lectura y escritura de un carácter en un fichero:
FILE *pf1, *pf2; char letra; pf1 = fopen("leer.txt", "r"); letra = fgetc(pf1); /* Lee un carácter */ pf2 = fopen ("escribir.txt", "w"); fputc(letra, pf2); /* Escribe un carácter */ fclose(pf1); fclose(pf2);
Las funciones de lectura y escritura de cadenas de texto en ficheros están definidas en stdio.h
char * fgets(char *cad, int numcar, FILE *pf);
- Devuelve un puntero a la cadena leída o un puntero nulo en caso de error
- Recibe como argumentos
cad
: Un puntero a la zona de memoria donde se almacenará la cadenanumcar-1
: Es el número de caracteres a leer. Será añadido el carácter nulopf
: El puntero al fichero
- Si encuentra un carácter de fin de línea (
n
), éste será el último carácter leído
int fputs(char *puntcad, FILE *pf);
- Devuelve en un entero el último carácter escrito o
EOF
en caso de error - Recibe como argumentos
puntcad
: Un puntero a cadena que se quiere escribirpf
: El puntero al fichero
- Ejemplos de lectura y escritura de una cadena de caracteres en un fichero:
FILE *pf1, *pf2; char lect[50]; char escr[]="Mensaje a guardar en el fichero"; int num=50-1; pf1 = fopen("leer.txt", "r"); fgets(lect, num, pf1); /* Lee una cadena de 49 caracteres de leer.txt */ pf2 = fopen ("escribir.txt", "w"); fputs(escr, pf2); /* Escribe la cadena "Mensaje a guardar en el fichero escribir.txt */ fclose(pf1); fclose(pf2);
Lectura y escritura de datos binarios
Para la lectura de un conjunto de datos:
unsigned fread(void *buf, unsigned numbytes, unsigned numdat, FILE *pf);
Para la escritura de un conjunto de datos:
unsigned fwrite(void *buf, unsigned numbytes, unsigned numdat, FILE *pf);
- Devuelven el número de datos leídos o escritos
- Reciben
buf
: Un puntero a los datos que son leídos o escritosnumbytes
: representa el número de bytes de que consta cada uno de los datos a a leer o escribir (se obtiene consizeof()
)numdat
: representa el número total de datos, items o elementos a leer o escribirpf
: es el descriptor al fichero sobre el que van a leer o escribir
- Mediante el manejo de datos binarios, el contenido de los ficheros puede ser similar al contenido de las variables en memoria
- Es importante cuando se trabaja con estructuras y uniones
- Las funciones
fread
yfwrite
pertenecen al ANSI C y están definidas enstdio.h
- Ejemplo de lectura y escritura de datos binarios:
FILE *pf; float valor1=3.5, valor2; pf=fopen ("archivo.dat", "ab+"); /* "a+" en Unix */ fwrite(&valor1, sizeof(valor), 1, pf); /* Escribe */ fread(&valor2, sizeof(float), 1, pf); /* Lee */
Entrada y salida por ficheros con formato
- Las funciones
fprintf()
yfscanf()
son idénticas aprintf()
yscanf()
respectivamente, pero operan sobre un descriptor. También están declaradas enstdio.h
int fprintf(FILE *pf, const char* cad_control, lista_argumentos); int fscanf(FILE *pf, const char* cad_control, lista_argumentos);
- Argumentos que reciben:
pf
: Representa un puntero al fichero sobre el que opera la funcióncad_control
: Es la cadena en la que s e incluyen los especificadores de formato y sus modificadoreslista_argumentos
: Representa la lista de argumentos que se corresponden con los especificadores de formato de la cadena de control (lista de variables cuyos contenidos quieren escribirse o leerse sobre el fichero)
- Devuelven:
fprintf()
devuelve en un entero el número de bytes escritosfscanf()
devuelve en un entero el número de campos correctamente escaneados y almacenados o EOF en caso de error.
- La llamada:
fprintf(stdout, "Número: %d", num);
- es equivalente a la llamada:
printf("Número: %d", num);
- Cuando se escribe en un fichero mediante la función
fprintf(pf, …)
el contenido del fichero es similar al mostrado en pantalla con la funciónfprintf(stdout, …)
- Ejemplo de escritura y lectura con formato:
FILE *pf; int i = 100; char c = 'C'; float f = 1.234; pf = fopen("prueba.dat", "w+"); fprintf(pf, "%d %c %f", i, c, f); /* Escribe en el fichero */ fscanf(pf, "%d %c %f", &i, &c, &f); /* Lee los mismos datos en el fichero */ fclose(pf);
Entrada y salida mediante acceso directo
El acceso a los ficheros puede hacerse:
- En modo secuencial: los datos son leídos o escritos seguidos, sin saltos
- En modo aleatorio: es posible acceder a cualquier posición para realizar una operación de lectura o de escritura
Los punteros de tipo FILE
apuntan a una estructura creada por el sistema operativo que controla las operaciones sobre ese fichero.
- La estructura incluye un puntero de lectura-escritura que determina la posición actual en la que se va a escribir o a leer en cada momento
- Al abrir un fichero, el puntero de lectura-escritura apunta al comienzo del fichero (salvo se si abre para añadir)
La función fseek()
, definida en stdio.h
, permite el movimiento aleatorio por el fichero abierto estableciendo una nueva posición para el apuntador de lectura-escritura:
int fseek(FILE *pf, long nbytes, int origen);
- Devuelve un valor verdadero si el movimiento se realizó con éxito o cero en caso contrario
- Recibe
pf
: Descriptor con el que se operanbytes
: Número de bytes que queremos desplazar el apuntador de lectura-escritura del fichero con relación al punto de partidaorigen
: Representa el punto que se toma como origen o referencia. Se utilizan constantes simbólicas definidas enstdio.h
:SEEK_SET
corresponde al principio del ficheroSEEK_CUR
corresponde a la posición actualSEEK_END
corresponde al final del fichero
- Ejemplo:
#define N 5 /* Será la fila 5 */ int matriz[20][4], *punt; /* 20 filas y 4 columnas*/ FILE *pf; punt = matriz; /* Apertura del fichero sin errores */ fwrite(punt, sizeof(int), 20*4, pf); /* Escribe la matriz en un fichero */ fseek(pf, sizeof(int)*4*N, SEEK_SET); /* Apunta a los datos de la fila N, al ser 4*sizeof(int) el tamaño de una fila */ fread(&matriz[N][0], sizeof(int), 4, pf); /* Lee los datos de la fila N */
Otras operaciones sobre ficheros
- Función
ftell()
long ftell(FILE *pf);
- * Devuelve un entero largo con la posición del apuntador de lectura-esritura del fichero con respecto al principio del fichero.
- Recibe el puntero a un fichero abierto
- Está definida en
stdio.h
- Función
rewind()
void rewind(FILE *pf);
- * Inicializa el indicador de posición o apuntador de lectura-escritura haciendo que apunte al principio del fichero
- No devuelve nada
- Recibe el puntero a un fichero abierto
- Está definida en
stdio.h
- Función
remove()
int remove(char *nombre_archivo);
- * Borra el fichero cuyo nombre se especifique en la cadena que recibe como argumento
- Devuelve cero si la operación tuvo éxito y
-1
si se produce algún error - En caso de error, la variable global
errno
, definida enerrno.h
indicará el tipo de error - Está definida en
stdio.h
- Función
fflush()
int fflush(FILE *pf);
- * Vacía los bufferes de entrada/salida asociados al flujo descrito por
pf
- Devuelve cero si la operación tuvo éxito y NULL si se produce algún error
- Está definida en
stdio.h
- Es muy utilizada para borrar el buffer del teclado y cuando se trabaja con impresoras
- Función
tmpfile()
FILE * tmpfile(void));
- * Crea un fichero temporal que es borrado automáticamente cuando el fichero es cerrado o al terminar el programa
- El fichero temporal se crea en modo
“w+”
- Devuelve un descriptor al fichero temporal creado o un puntero nulo si no se puede crear
- Está definida en
stdio.h
dokuwiki\Exception\FatalException: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes)
An unforeseen error has occured. This is most likely a bug somewhere. It might be a problem in the authplain plugin.
More info has been written to the DokuWiki error log.