scanf , abreviatura de scan formatted, es una función de la biblioteca estándar de C que lee y analiza texto de 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 readfen ALGOL 68 .
Las cadenas de formato de entrada son complementarias a las cadenas de formato de salida (ver printf ), que proporcionan una salida formateada ( plantillas ).
Historia
La biblioteca de entrada/salida portátil de Mike Lesk , incluida scanf, se convirtió oficialmente en parte de Unix en la versión 7. [ 1]
Uso
La scanffunción lee la entrada de números y otros tipos de datos desde la entrada estándar .
El siguiente código C lee una cantidad variable de números 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 )
{
entero n ;
mientras ( scanf ( "%d" , & n ) == 1 )
printf ( "%d \n " , n );
devuelve 0 ;
}
Para entrada:
456 123 789 456 12
456 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 char [ 20 ];
si ( scanf ( "%19s" , palabra ) == 1 )
pone ( palabra );
devuelve 0 ;
}
Independientemente del tipo de datos que el programador desee que lea, los argumentos (como &nlos anteriores) deben ser punteros que apunten a la memoria. De lo contrario, la función no se ejecutará 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 la entrada.
En el último ejemplo, no se utiliza un operador de dirección de ( &) para el argumento: como es el nombre de una matriz de , como tal es (en todos los contextos en los que evalúa una dirección) equivalente a un puntero al primer elemento de la matriz. Si bien la expresión evaluaría numéricamente 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 ella. Este hecho debe tenerse en cuenta al asignar la salida a las cadenas.
wordchar&wordscanf
Como scanfestá designado para leer solo desde la entrada estándar, muchos lenguajes de programación con interfaces , como PHP , tienen derivados como sscanfy fscanfpero no scanfél mismo.
Especificaciones de la cadena de formato
Los marcadores de formato en scanfson más o menos los mismos que en printf, su función inversa. Al igual que en printf, n$se define la extensión POSIX. [2]
En una cadena de formato rara vez hay constantes (es decir, caracteres que no son marcadores de posiciónscanf de formato), principalmente porque un programa no suele estar diseñado para leer datos conocidos, aunque los acepta si se especifican explícitamente. La excepción es uno o más caracteres de espacio en blanco , que descarta todos los caracteres de espacio en blanco en la entrada. [2]
Algunos de los marcadores de posición más utilizados son los siguientes:
%a:Escanea un número de punto flotante en su notación hexadecimal.%d:Escanee un entero como un número decimal con signo .%i: Escanea un entero como un número con signo. Similar a%d, pero interpreta el número como hexadecimal cuando va precedido de0xy octal cuando va precedido de0. Por ejemplo, la cadena031se leería como 31 usando%d, y como 25 usando%i. El indicadorhen%hiindica la conversión a ashortyhhla conversión a achar.%u:Escanear en busca de decimalesunsigned 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. Consultestrtoul(). [ verificación fallida ] ) En consecuencia,%huescanea en busca de ununsigned shorty%hhuen busca de ununsigned 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.%gutiliza letras minúsculas y%Gutiliza mayúsculas.%x,%X: Escanea un entero como un número hexadecimal sin signo .%o:Escanea un entero como un número octal .%s: Escanear 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 suministrado debe tener al menos un carácter más que la longitud de entrada especificada.%c: Escanea un carácter (char). No se agrega ningún carácter nulo .- Espacio en blanco : cualquier carácter de espacio en blanco activa un análisis en busca de cero o más caracteres de espacio en blanco . La cantidad y el tipo de caracteres de espacio en blanco no necesitan coincidir en ninguna dirección.
%lf:Escanear como un número de punto flotante doble . Formato "flotante" con el especificador "largo".%Lf: Escanear como un número de punto flotante doble largo . Formato "Float" para el especificador "long long".%n:No se espera nada. La cantidad de caracteres consumidos hasta el momento a partir de 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 utilizar en combinación con modificadores numéricos y los modificadores l, Lque representan "long" y "long long" 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, precediendo a los longmodificadores si los hay, que especifican la cantidad 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 se almacenará en una variable. No se debe incluir ningún argumento detrás de la cadena de formato para esta variable descartada.
El ffmodificador en printf no está presente en scanf, lo que provoca diferencias entre los modos de entrada y salida. Los modificadores lly hhno 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 un double . Por lo tanto, un programa robusto debe verificar si la scanfllamada tuvo éxito y tomar la acción apropiada. Si la entrada no estaba en el formato correcto, los datos erróneos seguirán estando en el flujo de entrada y deben descartarse antes de que se pueda leer una nueva entrada. Un método alternativo, que evita esto, es usar fgetsy luego examinar la cadena leída. El último paso puede realizarse mediante sscanf, por ejemplo.
En el caso de los numerosos caracteres de tipo flotante a, e, f, g , muchas implementaciones optan por agruparlos en el mismo analizador. Microsoft MSVCRT lo hace con e, f, g , [4] mientras que glibc lo hace con los cuatro. [2]
La norma ISO C99 incluye el inttypes.harchivo de encabezado que incluye una serie de macros para su uso en scanfcodificación independiente de la plataforma. Deben estar fuera de las comillas dobles, por ejemplo:scanf("%" SCNd64 "\n", &t);
Los macros de ejemplo incluyen:
Vulnerabilidades
scanfes vulnerable a ataques de formato de cadena . 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 que scanfse ejecute la función. Esto significa que %slos marcadores de posición sin especificadores de longitud son inherentemente inseguros y explotables para desbordamientos de búfer . Otro problema potencial es permitir cadenas de formato dinámicas, por ejemplo, cadenas de formato 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 la cadena de formato se verifique de antemano 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, según la implementación particular de varargs .
Véase también
- Lenguaje de programación C
- Ataque de cadena de formato
- Cadena de formato printf
- Interpolación de cadenas
Referencias
- ^ McIlroy, MD (1987). Un lector de Unix para investigación: extractos anotados del Manual del programador, 1971–1986 (PDF) (Informe técnico). CSTR. Bell Labs. 139.
- ^ abc – Manual del programador de Linux – Funciones de la biblioteca
- ^ Estándar C99, §7.19.6.2 "La función fscanf", párrafo 11.
- ^ "Caracteres del campo de tipo scanf". docs.microsoft.com . 26 de octubre de 2022.
Enlaces externos
- – Referencia de interfaces del sistema, la especificación única de UNIX , versión 4 de The Open Group
- Referencia de C++ para std::scanf