scanf , abreviatura de escaneo formateado, es una función de biblioteca estándar de C que lee y analiza texto desde la entrada estándar .
La función acepta un parámetro de cadena de formato que especifica el diseño del texto de entrada . La función analiza el texto de entrada y carga valores en variables según el tipo de datos .
Funciones similares, con otros nombres, son anteriores a C, como readf
en ALGOL 68 .
Las cadenas de formato de entrada son complementarias de las cadenas de formato de salida (consulte printf ), que proporcionan una salida formateada ( templates ).
La biblioteca portátil de entrada/salida de Mike Lesk , incluida scanf
, pasó a formar parte oficialmente de Unix en la Versión 7 . [1]
La scanf
función lee la entrada de números y otros tipos de datos de la entrada estándar .
El siguiente código C lee un número variable de enteros decimales sin formato de la entrada estándar e imprime cada uno de ellos en líneas separadas:
#incluir <stdio.h> int principal ( vacío ) { int norte ; mientras ( scanf ( "%d" , & n ) == 1 ) printf ( "%d \n " , n ); devolver 0 ; }
Para entrada:
456 123 789 456 12456 1 2378
La salida es:
456 123 789 456 12 456 1 2378
Para imprimir una palabra:
#incluir <stdio.h> int principal ( vacío ) { palabra de caracteres [ 20 ]; if ( scanf ( "%19s" , palabra ) == 1 ) pone ( palabra ); devolver 0 ; }
No importa cuál sea el tipo de datos que el programador quiera que lea el programa, los argumentos (como los &n
anteriores) deben ser punteros que apunten a la memoria. De lo contrario, la función no funcionará correctamente porque intentará sobrescribir las secciones incorrectas de la memoria, en lugar de apuntar a la ubicación de la memoria de la variable para la que está intentando obtener información.
En el último ejemplo, no se utiliza un operador de dirección de ( &
) para el argumento: al igual que el nombre de una matriz de , como tal es (en todos los contextos en los que se evalúa como una dirección) equivalente a un puntero al primer elemento de la matriz. Si bien la expresión se evaluaría numéricamente con el mismo valor, semánticamente tiene un significado completamente diferente, ya que representa la dirección de toda la matriz en lugar de un elemento de la misma. Es necesario tener en cuenta este hecho al asignar salida a cadenas.word
char
&word
scanf
Como scanf
está diseñado para leer solo desde entrada estándar, muchos lenguajes de programación con interfaces , como PHP , tienen derivados como sscanf
y fscanf
pero no scanf
el mismo.
Los marcadores de posición de formato son más o menos scanf
los mismos que los de printf
, su función inversa. Como en printf, n$
se define la extensión POSIX. [2]
Rara vez hay constantes (es decir, caracteres que no son marcadores de posición de formato ) en una cadena de formato, principalmente porque un programa generalmente no está diseñado para leer datos conocidos, aunque scanf
los acepta si se especifican explícitamente. La excepción son uno o más caracteres de espacio en blanco , que descartan todos los caracteres de espacio en blanco en la entrada. [2]
A continuación se muestran algunos de los marcadores de posición más utilizados:
%a
: escanea un número de punto flotante en su notación hexadecimal.%d
: escanea un número entero como un número decimal con signo .%i
: escanea un número entero como un número con signo. Similar a %d
, pero interpreta el número como hexadecimal cuando está precedido por 0x
y octal cuando está precedido por 0
. Por ejemplo, la cadena 031
se leería como 31 usando %d
y 25 usando %i
. La bandera h
en %hi
indica conversión a a short
y hh
conversión a char
.%u
: Busque decimales unsigned int
(tenga en cuenta que en el estándar C99 el signo menos del valor de entrada es opcional, por lo que si se lee un signo menos, no surgirán errores y el resultado será el complemento a dos de un número negativo, probablemente un valor muy grande. Consulte strtoul()
. [ verificación fallida ] ) En consecuencia, %hu
busca un unsigned short
y %hhu
un unsigned char
.%f
: escanea un número de punto flotante en notación normal ( punto fijo ).%g
, %G
: escanea un número de punto flotante en notación normal o exponencial. %g
usa letras minúsculas y %G
usa mayúsculas.%x
, %X
: escanea un número entero como un número hexadecimal sin signo .%o
: escanea un número entero como un número octal .%s
: escanea una cadena de caracteres . El escaneo termina en un espacio en blanco . Se almacena un carácter nulo al final de la cadena, lo que significa que el búfer proporcionado debe tener al menos un carácter más largo que la longitud de entrada especificada.%c
: escanea un carácter (char). No se agrega ningún carácter nulo .%lf
: escanea como un número de punto flotante doble . Formato "flotante" con el especificador "largo".%Lf
: escanea como un número largo de punto flotante doble . Formato "flotante" para el especificador "largo, largo".%n
: No se espera nada. La cantidad de caracteres consumidos hasta el momento desde la entrada se almacena a través del siguiente puntero, que debe ser un puntero a int. Esto no es una conversión y no aumenta el recuento devuelto por la función.
Lo anterior se puede usar en combinación con modificadores numéricos y los l
modificadores L
que significan "largo" y "largo, largo" entre el símbolo de porcentaje y la letra. También puede haber valores numéricos entre el símbolo de porcentaje y las letras, antes de los long
modificadores, si los hay, que especifican el número de caracteres que se escanearán. Un asterisco opcional ( *
) justo después del símbolo de porcentaje indica que el dato leído por este especificador de formato no debe almacenarse en una variable. No se debe incluir ningún argumento detrás de la cadena de formato para esta variable eliminada.
El ff
modificador en printf no está presente en scanf, lo que provoca diferencias entre los modos de entrada y salida. Los modificadores ll
y hh
no están presentes en el estándar C90, pero sí en el estándar C99. [3]
Un ejemplo de una cadena de formato es
"%7d%s %c%lf"
La cadena de formato anterior escanea los primeros siete caracteres como un entero decimal, luego lee el resto como una cadena hasta que se encuentra un espacio, una nueva línea o una tabulación, luego consume espacios en blanco hasta que se encuentra el primer carácter que no es un espacio en blanco, luego consume ese carácter. y finalmente escanea los caracteres restantes como dobles . Por lo tanto, un programa sólido debe verificar si la scanf
llamada tuvo éxito y tomar las medidas adecuadas. Si la entrada no estaba en el formato correcto, los datos erróneos seguirán estando en el flujo de entrada y deberán descartarse antes de que se puedan leer nuevas entradas. Un método alternativo que evita esto es utilizar fgets
y luego examinar la cadena leída. El último paso lo puede realizar sscanf
, por ejemplo.
En el caso de los muchos caracteres de tipo flotante a, e, f, g , muchas implementaciones optan por colapsar la mayoría en el mismo analizador. Microsoft MSVCRT lo hace con e, f, g , [4] mientras que glibc lo hace con los cuatro. [2]
ISO C99 incluye el inttypes.h
archivo de encabezado que incluye una serie de macros para usar en scanf
codificación independiente de la plataforma. Deben estar fuera de comillas dobles, por ejemploscanf("%" SCNd64 "\n", &t);
Las macros de ejemplo incluyen:
scanf
es vulnerable a ataques de cadenas de formato . Se debe tener mucho cuidado para garantizar que la cadena de formato incluya limitaciones para los tamaños de cadena y matriz. En la mayoría de los casos, el tamaño de la cadena de entrada de un usuario es arbitrario y no se puede determinar antes de scanf
ejecutar la función. Esto significa que %s
los marcadores de posición sin especificadores de longitud son inherentemente inseguros y explotables para desbordamientos del búfer . Otro problema potencial es permitir el formato dinámico de cadenas, por ejemplo, formatear cadenas almacenadas en archivos de configuración u otros archivos controlados por el usuario. En este caso, la longitud de entrada permitida de los tamaños de cadena no se puede especificar a menos que se verifique de antemano el formato de la cadena y se apliquen limitaciones. Relacionado con esto hay marcadores de posición de formato adicionales o no coincidentes que no coinciden con la lista vararg real . Estos marcadores de posición pueden extraerse parcialmente de la pila o contener punteros no deseados o incluso inseguros, dependiendo de la implementación particular de varargs .