Como comentamos en el tema 5, el uso de "gets" está desaconsejado a partir del estándar C99 (de 1999), por tratarse de una orden poco segura, pero esta orden ni siquiera existirá en los compiladores que sigan el estándar C11 (de diciembre de 2011). Una alternativa, en compiladores modernos, es usar "get_s" que recibe como segundo parámetro el tamaño máximo del texto. Otra alternativa, más segura que gets, que permite que la cadena contenga espacios, y que funcionará en cualquier compilador de C, es usar "fgets".
"fgets" espera 3 parámetros: la variable en la que se guardará el texto, la anchura máxima y el fichero desde el que leer. El "truco" para usar "fgets" para leer de teclado es indicar "stdin" (standard in, entrada estándar) como nombre que fichero, que es un identificador predefinido en el sistema:
fgets(nombre, 20, stdin);
Eso sí, "fgets" tiene un problema para este uso: conserva el avance de línea (\n). Por eso, habrá que eliminarlo "a mano" (si la cadena no está vacía y si realmente termina en avance de línea, porque puede no ser así si la cadena era más larga que lo esperado y se ha truncado):
if ((strlen(nombre)>0) && (nombre[strlen (nombre) - 1] == '\n'))
nombre[strlen (nombre) - 1] = '\0';
Con esas dos órdenes podriamos evitar los problemas de "gets" de una forma que se comporte bien en cualquier compilador, usando "fgets" para leer de teclado como si fuera un fichero.
No es la única forma: hay autores que prefieren no usar ficheros sino un formato avanzado de "scanf", en el que se le indica que acepte todo hasta llegar a un avance de línea, pero esto puede no ser admitido por todos los compiladores:
scanf("%[^\n]s",nombre);
Para evitar problemas de desbordamiento, deberíamos indicar la anchura máxima:
scanf("%20[^\n]",nombre);
También podemos delimitar los caracteres admisibles (nuevamente, quizá no todos los compiladores lo permitan):
scanf("%10[0-9a-zA-Z ]s", nombre);
Muchos expertos recomiendan no usar directamente "gets" ni "scanf", ni siquiera para leer datos numéricos, sino hacer la lectura en una cadena de texto con "fgets" y luego extraer la información de ella con "sscanf".
Ejercicio propuesto: