Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Regla 0x400Bh: No uses fflush(stdin); consumi el buffer con getchar()

Archivos y E/S (0x40XX)

Universidad Nacional de Río Negro

0x400Bh: No uses fflush(stdin); consumi el buffer con getchar()

Enunciado normativo

NO DEBE usarse fflush(stdin); es comportamiento indefinido. Consumi el buffer con getchar() o lei con fgets.

Síntoma en el código del estudiante

Después de un scanf aparece fflush(stdin) con el comentario mental de “limpiar el búfer de entrada”. También suele verse fflush(stdin) antes de leer una cadena con fgets, para descartar el salto de línea que quedó pendiente.

Diagnóstico

Mecanismo del defecto

fflush está pensado para flujos de salida: fuerza el vaciado del búfer hacia el dispositivo. Su efecto sobre un flujo de entrada no está definido por el estándar. En glibc, de hecho, descarta los bytes pendientes y parece funcionar; en otras bibliotecas no hace nada, y en algunas puede fallar. El programa que depende de fflush(stdin) es, por lo tanto, no portable.

El problema de fondo es no entender que scanf("%d", &x) deja en el búfer el salto de línea u otro texto que no pudo convertir. La limpieza del búfer no se hace con fflush, sino consumiendo explícitamente los caracteres sobrantes o leyendo por líneas.

Consecuencia observable

En Linux con glibc el código suele “funcionar”, lo que oculta el defecto. Al compilarlo en otra plataforma, fflush(stdin) no limpia y la lectura siguiente —un %c o un fgets— recibe el salto de línea residual y avanza sola, con resultados inesperados. A veces también se descarta entrada legítima que el usuario tipeó de más.

Fundamento en el estándar C11

ISO/IEC 9899:2011 §7.21.5.2 define fflush: si el flujo apunta a un archivo de salida o de actualización cuya última operación fue de salida, escribe los datos pendientes; para los demás casos, el comportamiento no está definido. La entrada estándar cae en esa zona no definida. Depender de ella viola el principio de escribir C portable y verificable.

Corrección idiomática

❌ Código con el antipatrón

int x;
printf("Ingrese un numero: ");
scanf("%d", &x);
fflush(stdin);
char nombre[32];
fgets(nombre, sizeof(nombre), stdin);

Por qué es incorrecto: fflush(stdin) no está garantizado por el estándar. Si no limpia, fgets lee el '\n' que quedó tras el número y devuelve una cadena vacía.

✅ Código refactorizado

int x;
printf("Ingrese un numero: ");
if (scanf("%d", &x) != 1) {
    return -1;
}

int c;
do {
    c = getchar();
} while (c != '\n' && c != EOF);

char nombre[32];
if (fgets(nombre, sizeof(nombre), stdin) == NULL) {
    return -1;
}

El bucle do ... while consume explícitamente los caracteres que quedaron pendientes hasta el fin de línea, sin depender de comportamiento indefinido. El do respeta la delimitación obligatoria con llaves (0x100Eh: Delimitación obligatoria con bloque de llaves en lazos do-while) y evita la asignación dentro de la condición (0x1012h: Prohibición de expresiones de asignación dentro de estructuras de control).

Errores típicos al compilar o ejecutar

No hay error de compilación. En entornos donde la limpieza no funciona, el efecto es que una lectura posterior se saltea.

Ingrese un numero: 42
Ingrese su nombre: [se saltea la lectura]

En algunos compiladores con advertencias estrictas puede aparecer una alerta sobre el uso de fflush sobre stdin.

warning: fflush on input stream is a common source of bugs

Checklist de verificación

Reglas relacionadas