Publi

Por qué no debemos utilizar gets()

getsA veces me sorprendo (como profesor de programación) de que en muchos sitios siguen enseñando la función gets() para la entrada de datos desde teclado sin explicar lo que puede pasar.

gets() es una función peligrosa. Imaginemos que escribimos el siguiente programa:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main()
{
  char cadena2[10];
  char cadena1[10];

  printf("c1: %x\nc2: %x\n", cadena1, cadena2);
  gets(cadena1);

  printf("Cadena 2: %s\n", cadena2);
}

Ahora la compilamos, ejecutamos e introducimos un texto de prueba:

$ gcc -o test3 test3.c
/tmp/ccK2P2ON.o: In function `main’:
test3.c:(.text+0x32): warning: the `gets’ function is dangerous and should not be used.
$ ./test3
c1: bfc81580
c2: bfc8158a
Escribo un texto de mas de 10 caracteres
Cadena 2: texto de mas de 10 caracteres
Violación de segmento

Ya de primeras nos avisa gcc de que la función no debería ser usada, a lo que muchos se sorprenden.
Luego, en la ejecución, tal como se indica en el código fuente, mostramos las direcciónes de memoria donde se ubicarán cadena1 (c1) y cadena2 (c2).
Tras ello escribimos: “Escribo un texto de mas de 10 caracteres“, que se introducirá en la variable cadena1 y mostramos la variable cadena2, que muestra parte de lo que escribimos antes… y además de regalo una violación de segmento, porque nuestro programa ha terminado accediendo a una región de memoria que no le pertenecía.

Todo esto sucede porque gets() no tiene ninguna manera de saber cuánto puede escribir (recordemos que cuando trabajamos con Arrays en C, sólo pasamos la dirección de memoria del primer elemento y no el tamaño) y por ello, escribirá todo lo que pulsemos por teclado en la variable, sin preocuparnos de si tengo sitio o no (por eso en el ejemplo de arriba, aunque hemos pedido cadena1, terminamos escribiendo en cadena2). Con esto quiero decir que podemos usar gets() para hacer una prueba de concepto rápida, cuando tengamos el entorno controlado, aunque nunca para un programa real, de todas formas no debemos darlo todo por perdido, tenemos una excelente función, muy parecida fgets(), aunque tiene más parámetros:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

#define MAX_LON_CADENA 10

int main()
{
  char cadena2[MAX_LON_CADENA];
  char cadena1[MAX_LON_CADENA];

  printf("c1: %x\nc2: %x\n", cadena1, cadena2);

/*   gets(cadena1); */
  fgets(cadena1, MAX_LON_CADENA, stdin);
  printf("Cadena 1: "%s"\n", cadena1);
  printf("Cadena 2: %s\n", cadena2);
}
  1. El primer parámetro de fgets() es dónde vamos a almacenar lo leído. Es decir, nuestra cadena de caracteres.
  2. El segundo parámetro es cuántos caracteres leeremos como máximo (incluyendo el terminador de cadena). Y si hemos definido un valor máximo para la cadena, podemos utilizar éste. Aquí le decimos a fgets() que todo lo que sobrepase este tamaño lo ignore.
  3. El tercero es de dónde lo leemos, y si queremos hacerlo desde teclado, usaremos stdin. Esta función puede servir también para leer contenidos de un fichero o un dispositivo.

Actualización 10/11/2015: He cambiado algunas palabras y he extendido un poco más el post (pero muy poco)y he añadido una imagen de cabecera.

También podría interesarte...

There are 5 comments left Ir a comentario

  1. Pingback: Bitacoras.com /

  2. Fabricio /
    Usando Google Chrome Google Chrome 5.0.375.55 en Linux Linux

    Muchas gracias, muy útil información 😉

  3. Pingback: Tweets that mention Poesía binaria » Por qué no debemos utilizar gets() — Topsy.com /

  4. Edgardo /
    Usando Mozilla Firefox Mozilla Firefox 3.6.13 en Ubuntu Linux Ubuntu Linux

    Gracias, muy útil informacion y muy buena forma de explicarlo.

    1. admin / Post Author
      Usando Mozilla Firefox Mozilla Firefox 4.0 en Linux Linux

      Gracias a ti!

Leave a Reply