2010-06-04 14 views
10

Probablemente una respuesta muy simple a este extremadamente simple pregunta: ¿El uso de scanf en un bucle while

estoy leyendo "C Primer Plus" por Pratta y se sigue usando el ejemplo

while (scanf("%d", &num) == 1)... 

¿Está el == 1 realmente necesario? Parece que uno solo se pudo escribir:

while (scanf("%d", &num)) 

Parece que la prueba de la igualdad es innecesaria, ya que scanf devuelve el número de objetos leídos y 1 haría que el bucle while cierto. ¿Es la razón para asegurarse de que la cantidad de elementos leídos sea exactamente 1 o es totalmente superfluo?

+0

Sí, parece bastante redundante para mí ... – tzaman

Respuesta

22

En C, 0 se evalúa como falso y todo lo demás como verdadero. Por lo tanto, si scanf devolvió EOF, que es un valor negativo, el bucle se evaluaría como verdadero, que no es lo que usted desearía.

+0

EOF fue el elemento clave aquí, buena captura. –

3

Has entendido correctamente el código C.

A veces la razón para probar el número de elementos leídos es que alguien quiere asegurarse de que todos los elementos se leyeron en lugar de scanf quitting early cuando la entrada no coincidía con el tipo esperado. En este caso particular, no importó.

Normalmente, scanf es una opción deficiente de funciones porque no cumple con las necesidades de entrada interactiva de un usuario humano. Por lo general, una combinación de fgets y sscanf produce mejores resultados. En este caso particular, no importó.

Si los capítulos posteriores explican por qué algunos tipos de prácticas de codificación son mejores que este ejemplo trivial, bueno. Pero si no, debes volcar el libro que estás leyendo.

Por otro lado, su código sustituto no es exactamente un sustituto. Si scanf devuelve -1, entonces se ejecutará su ciclo while.

+0

Incorrecto, ver las otras respuestas. Devuelve -1 cuando se golpea EOF o se produce un error de lectura. –

+2

"Incorrecto, vea las otras respuestas". - quieres decir mal, mira mi propia respuesta, porque es por eso que escribí "Si scanf devuelve -1, entonces tu bucle while se ejecutará". –

8

Dado que scanf devuelve el valor EOF (que es -1) al final del archivo, el ciclo como está escrito es correcto. Se ejecuta siempre que la entrada contenga texto que coincida con %d, y se detiene en el primer archivo que no coincide o al final del archivo.

Hubiera sido más claro de un vistazo si scanf estaban esperando más de una entrada ....

while (scanf("%d %d", &x, &y)==2) { ... } 

sería salir del bucle cuando la primera vez fue incapaz de igualar dos valores, ya sea debido a final de final de archivo del archivo (scanf rendimientos EOF (que es -1)) o en error de entrada a juego (por ejemplo, la entrada de xyzzy 42 no coincide %d %d así scanf paradas en el primer fallo y devuelve 0 sin escribir a cualquiera de x o y) cuando devuelve algún valor menor que 2.

Por supuesto, scanf es no tu amigo al analizar la entrada real de humanos normales. Hay muchos escollos en su manejo de casos de error.

Editar: corregido un error: scanf rendimientos EOF en el final del archivo, o un número entero no negativo contando el número de variables que se marcó con éxito.

El punto clave es que, dado que cualquier valor distinto de cero es TRUE en C, si no se prueba el valor de retorno correctamente en un bucle como este, se puede generar un comportamiento inesperado.En particular, while(scanf(...)) es un bucle infinito a menos que encuentre texto de entrada que no se puede convertir de acuerdo con su formato.

Y no puedo enfatizar lo suficiente que scanf es no su amigo. Una combinación de fgets y sscanf puede ser suficiente para un análisis simple, pero incluso así es fácilmente abrumado por casos extremos y errores.

1

Si bien no es estrictamente necesario, algunas personas lo prefieren por varias razones.

En primer lugar, al comparar con 1 se convierte en un valor booleano explícito (verdadero o falso). Sin la comparación, está probando un entero, que es válido en C, pero no en idiomas posteriores (como C#).

En segundo lugar, algunas personas leerían la segunda versión en términos de while ([función]), en lugar de while ([return value]), y se confundirían momentáneamente al probar una función, cuando lo que claramente valor de retorno

Esto puede ser completamente una cuestión de preferencia personal, y en lo que a mí respecta, ambos son válidos.

1

Uno probablemente podría escribirlo sin una comparación explícita (sin embargo, vea la respuesta de JRL), pero ¿por qué lo haría? Diría que las condiciones sin comparación solo deberían usarse con valores que tienen una semántica booleana explícita (como una llamada isdigit(), por ejemplo). Todo lo demás debería usar una comparación explícita. En este caso (el resultado de scanf), la semántica es pronunciadamente no booleana, por lo que la comparación explícita está en orden.

Además, la comparación que generalmente se puede omitir es normalmente una comparación con cero. Cuando sienta el impulso de omitir la comparación con otra cosa (como 1 en este caso), es mejor pensar dos veces y asegurarse de saber lo que está haciendo (vea la respuesta de la JRL nuevamente).

En cualquier caso, cuando la comparación se puede omitir con seguridad y realmente se omite, el significado semántico real de la condición sigue siendo el mismo. No tiene ningún impacto en la eficiencia del código resultante, si es algo que te preocupa.

Cuestiones relacionadas