Cuando aprendemos algoritmos en C, la forma de escanear variables por teclado es a través de scanf. Si bien este método funciona, existe el peligro de un desbordamiento de búfer.

Antes que nada te invito a ver lo que es un desbordamiento de búfer en C.

fgets vs scanf en C

Después de que leíste lo del desbordamiento es hora de ver por qué es mejor usar fgets en lugar de scanf. Esto es porque fgets escanea una variable pero únicamente hasta donde le digamos; es decir, nosotros le decimos cuánto debe leer (el tamaño).

Scanf en cambio no hace eso, lee todo dentro de la posición en memoria.

Leer variable con fgets usando el lenguaje C

Vamos a ver cómo leer una variable usando fgets en C. De hecho esta función lee de un stream, pero igual sirve para escanear datos por teclado.

Para usarlo, la sintaxis es:

fgets(cadena, longitud, stream);

En donde la cadena es la variable en donde almacenaremos lo leído.

La longitud es cuántos caracteres leeremos (aquí es en donde se previene el desbordamiento) y el stream es un stream de tipo FILE; recordemos que stdin es un stream así que viene perfecto para leer datos que el usuario introduzca.

#include <stdio.h>
 
#define LONGITUD 20
int main(){
    char nombre[LONGITUD];
    printf("Dime tu nombre: ");
    fgets(nombre, LONGITUD, stdin);
    printf("Hola, %s", nombre);
}

Lo sé, más difícil que scanf pero es seguro.

Además, tiene otra desventaja y es que lee la última línea; es decir, nuestra cadena contiene el \n al final (no te preocupes, hasta abajo en el post explico cómo tratar con esto).

Prevenir desbordamiento de búfer con fgets en C

Es obligatorio que veas el desbordamiento de búfer con scanf.

Ahora mira este programa pero usando fgets en lugar de scanf. Queda así:

/*
    Ejemplo simple de prevención
    de desbordamiento de búfer en C
    al escanear variables
    @author parzibyte
*/ 
#include <stdio.h>
#include <string.h>
 
// Por si decidimos cambiar la longitud después
#define LONGITUD 4
 
int main() {
  char cadena[LONGITUD];
  int autenticado = 0; // 1 es que sí, 0 que no
 
  printf("Ingresa la contraseña:\n");
  fgets(cadena, LONGITUD,
        stdin); // ----- Aquí está la prevención del desbordamiento
 
 cadena[strcspn(cadena, "\r\n")] = 0;
  if (strcmp(cadena, "123") == 0) {
    autenticado = 1;
  }
 
  if (autenticado)
    printf("Bienvenido al programa");
  else
    printf("Acceso denegado");
 
  printf("\nAl final de todo, el valor que tiene 'autenticado' es: %d",
         autenticado);
}

Lo que cambia es que ahora le indicamos a fgets que lea hasta 4 caracteres (sólo usamos 3 pero necesitamos dejar uno extra, mira más abajo) y lo demás no sé en dónde lo ponga, pero eso me asegura de que no sobrescriba a otras variables ni corrompa la memoria.

De esta manera prevenimos el desbordamiento de búfer en C, al menos cuando leemos variables del usuario.

Por cierto, te estarás preguntando por qué declaramos la cadena para que almacene 4, si sólo nos importan 3, y esto es porque al final fgets le agrega un salto de línea que vamos a remover más tarde.

Limpiar cadena escaneada con fgets en C

Muy bien, ya hemos escaneado y prevenido un desbordamiento de búfer, pero falta limpiar el último carácter. Como lo dije, esta función devuelve todo lo leído, incluso el salto de línea.

Para quitarlo y limpiar nuestra cadena (en caso de que lo requieras) hacemos esto:

cadena[strcspn(cadena, "\r\n")] = 0;

En donde la variable cadena es tu búfer. Lo que hacemos es buscar el índice de la primera aparición del salto de línea y remplazarlo con el carácter nulo.

Ese ejemplo que presento lo usamos cuando vimos cómo invertir una palabra en C.

Para concluir, si vas a limpiar el último carácter de fgets entonces declara tu longitud con un espacio extra.

Es decir, si quieres que sea de 100 entonces declárala de 101.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Cancelar trabajo de impresión con C++

En este post te quiero compartir un código de C++ para listar y cancelar trabajos…

4 semanas hace

Copiar bytes de Golang a JavaScript con WebAssembly

Gracias a WebAssembly podemos ejecutar código de otros lenguajes de programación desde el navegador web…

2 meses hace

Imprimir PDF con Ghostscript en Windows de manera programada

Revisando y buscando maneras de imprimir un PDF desde la línea de comandos me encontré…

2 meses hace

Hacer pruebas en impresora térmica Bluetooth Android

Esta semana estuve recreando la API del plugin para impresoras térmicas en Android (HTTP a…

2 meses hace

Limpiar clave PEM

Hoy te enseñaré a extraer la cadena base64 de una clave PEM usando una función…

2 meses hace

Foco con Telegram, apagador de 3 vías, relevador y ESP8266

Encender un foco con un Bot de Telegram es posible usando una tarjeta como la…

2 meses hace