Como hemos visto en el apartado anterior, las funciones gets
y scanf usadas para leer cadenas de caracteres son propensas a errores, pues
no controlan que el usuario haya introducido más caracteres que el que puede
albergar el array definido para almacenarlos. Para ello, contamos con dos
funciones que hacen segura la lectura de cadenas introducidas por el
usuario, que son fgets
y getline
.
fgets
La sintaxis de la función fgets
es:
#include <stdio.h> char *fgets(char *s, int n, FILE *stream);
s
referencia a un array de caracteres, que
almacena lo que lee de un fichero apuntado por
stream
. n
especifica el número máximo de
elementos del array (caracteres). La función lee hasta n-1
caracteres, y añade el caracter nulo para que la cadena quede bien
formada. Si no ha llegado hasta n-1 caracteres pero llega a un caracter de
nueva línea, '\n', también para de leer y devuelve la cadena (con ese
carácter de nueva línea incluido). Si no hay errores, la función devuelve
el puntero s
. Si encuentra el final de fichero (EOF) o existe
algún error, devuelve null
.
fgets
es así más segura que
gets
, pero tienes que lidiar con un par de cosas. Una es que
si has introducido más caracteres de los que ha podido leer, el resto de
caracteres se quedan en el buffer de entrada (en stdin), así que tendrás
que eliminarlos para que no sean leídos en el próximo fgets
si no quieres. Lo segundo es que fgets
incluye el carácter
'\n' al final, así que tendrás que quitarlo.
getline
La librería GNU ofrece la función no estándar
getline
que hace sencilla la lectura de líneas:
#include <stdio.h> ssize_t getline(char **lineptr, size_t *n, FILE *stream);
Esta función lee una línea entera de stream
,
almacenando el texto (incluyendo el carácter de nueva línea y el de
terminación) en un buffer y almacenando la dirección del buffer en
*lineptr
. Antes de llamar a getline
, tienes que
colocar en *lineptr
la dirección de un buffer de
*n
bytes de largo usando malloc
. Si este buffer
no es lo suficientemente grande como para albergar la frase leída,
getline
hace el buffer más grande usando
realloc
, actualizando la nueva dirección en
*lineptr
y el tamaño en *n
. Si inicializas
*lineptr
a null
y *n
a cero,
getline
hace ese malloc
por tí.
Si todo ha ido bien, *lineptr
es un
char *
que apunta al texto que se ha leido. La función
devuelve el número de caracteres leídos aunque sin contar el carácter '\0'
de terminación (sí con el de nueva línea);
si ha habido algún error o
se alcanza final de fichero, devuelve -1.
Siempre que tengas que leer una línea de
texto del teclado, hazlo pues con getline
; te
evitarás cualquier problema posterior.
El siguiente programa muestra cómo usar
getline
para leer una línea de texto desde teclado de manera
segura. Intenta teclear más de 10 caracteres, verás que
getline
lo gestiona correctamente, independientemente del
número de caracteres que teclees.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <stdio.h> #define TAM_MAXIMO 10 int main(void) { ssize_t bytes_leidos; size_t numero_bytes; //ssize_t y size_t son sinónimos de unsigned int char *cadena; puts("Por favor, introduce una línea de texto:\n"); /* Puedes pasar a getline los argumentos inicializados: */ //numero_bytes = TAM_MAXIMO; //cadena = (char *) malloc (numero_bytes + 1); //bytes_leidos = getline(&cadena, &numero_bytes, stdin); /*O bien, más sencillo, poner el número a 0 y la cadena a NULL, para que él mismo te haga la reserva necesaria*/ numero_bytes = 0; cadena = NULL; bytes_leidos = getline(&cadena, &numero_bytes, stdin); if (bytes_leidos == -1) { puts("Error."); } else { puts("La línea es:"); puts(cadena); } free(cadena); return 0; } |
Comprueba con estas preguntas si has entendido este documento.
Indica la afirmación INCORRECTA respecto a la función getline
: