C/scanf
A función scanf()
lee datos do ficheiro de entrada estándar, stdin
, asociado ao teclado, os interpreta de acordo co formato especificado, e os almacena nos argumentos especificados. A función devolve un enteiro coa cantidade de datos lidos e asignados. A súa sintaxe básica é a seguinte:
scanf("Cadea co formato de entrada",lista de argumentos);
O primeiro argumento é unha cadea que contén o formato de entrada dos datos por parte do usuario, utilizando para tal fin marcadores de formato. O resto dos argumentos son as variables nas que se van cargar os datos interpretados pola función a partir da información introducida polo usuario. Os argumentos coas variables estarán na mesma orde que os seus correspondentes marcadores de formato, e as variables estarán precedidas por un &
(paso por referencia). Vexamos un exemplo:
scanf("%d, %f",&numero_corredor, &puntuacion);
Onde temos que introducir primeiro o número do corredor (numero_corredor
, de tipo enteiro en sistema decimal) e a súa puntuación (puntuacion
, de tipo float
), separados por unha coma e un espazo en branco.
Cómpre ter en conta que a función scanf
, ao premer o usuario INTRO
para indicar o final da lectura de datos, deixa ese último carácter (|n
) no búfer de entrada por teclado e imprímeo ao mesmo tempo no programa, é dicir, despois da lectura de datos faise un salto de liña.
Limpar o lixo
[editar]Aínda que pode soar algo estraño para quen o escoite por vez primeira, «scanf()
deixa lixo, e hai que limpalo».
scanf()
le unha serie de datos que o usuario introduce por teclado, e remata a lectura unha vez o usuario preme INTRO
, é dicir, introduce un salto de liña (\n
). O caso é que este salto de liña, que scanf()
non necesita ler, queda no búfer de entrada por teclado (lixo), e a seguinte función que lea datos por teclado, coma o caso doutro scanf()
ou similar, lerá dito dato coma se o usuario o acabase de introducir. E na meirande parte dos casos o desenvolvedor non quererá que isto aconteza.
Para evitalo existen diversas solucións, pero o problema da meirande parte delas é que depende moito do compilador e do sistema operativo con que se utilice. É por isto que a solución máis sinxela é unha función que se encargue de limpar o búfer de entrada por teclado:[1]
void Limpar(void)
{
// Declaración de variables
int ch;
// Limpar
while
(
(ch = fgetc(stdin)) != EOF
&&
ch != '\n'
);
}
Así que, despois dun scanf()
ou antes dunha función susceptible de ler o lixo do búfer de entrada, cómpre utilizar esta función.
Lectura de cadeas
[editar]scanf()
pode ler cadeas de caracteres. A sintaxe para esta tarefa difire lixeiramente da sintaxe que utiliza para ler caracteres ou valores numéricos:
scanf("%s",cadea);
Hai dous diferencias clave. A primeira e a máis obvia é o uso de %s
, que indica que o dato a recibir vai ser unha cadea de caracteres. A segunda diferencia puido parecerlle a máis de un unha errata, pero o caso é que para ler cadeas fai falla omitir o símbolo &
da variable que vai conter a cadea de caracteres lida por scanf()
.
Pero, se ben pode facelo, scanf()
presenta unha serie de inconvenientes á hora de ler cadeas que o converten probablemente na peor función que poidamos usar para realizar este tipo de tarefas. Un dos inconvenientes máis salientables é o feito de que scanf()
interpreta os espazos en branco coma separadores, polo que non nos permitiría introducir nunha variable unha cadea de caracteres que contivese espazos en branco.
Xeralmente, á hora de ler cadeas de texto, a función estándar de C escollida é gets()
.
Manexo de erros
[editar]Cómpre lembrar que scanf()
non «le un ou máis datos», senón que máis ben «intenta ler un ou máis datos». En todo momento hai que ter en conta a posibilidade de que o usuario introduza un valor que scanf()
non sexa capaz de ler. Así que un programa ten que estar preparado para o que queira que introduza o usuario. Para iso abonda con coñecer as diferentes saídas que pode dar a función scanf()
e mailo seu significado, e modificar o programa de xeito que actúe en función de dita saída, que haberá que asignar a unha variable numérica.
A función pode devolver un valor numérico entre -1 e o número de datos que esperaba recibir. Se non é capaz de procesar un dos datos introducidos, a función devolverá o número correspondente á posición ordinal de dito dato menos 1, é dicir, se por exemplo non procesa correctamente o segundo dato introducido, devolverá 1
. En caso de que a función lea correctamente todos os datos introducidos, devolverá un número igual á cantidade de datos que tiña que ler. En caso de que a función lea o carácter ASCII 255, FdF, devolverá a constante EOF.
Sempre que a función falle ao procesar un dato introducido polo usuario, este dato quedará no búfer de entrada por teclado. Isto significa que o búfer quedará "manchado", e será necesario limpalo antes de que o programa volva utilizalo con outra función de entrada por teclado. Para facelo utilizaremos unha función que xa tivemos o pracer de coñecer: fflush()
. Podemos situar dita función ben antes de calquera función de lectura por teclado, ou ben a continuación dela.
Un exemplo de manexo de erros con scanf()
podería ser:
do{
p=scanf("%d",&variable);
fflush(stdin);
}while(p!=1);
Este ciclo pediralle ao usuario que introduza un valor para variable, e mentres o usuario non introduza un valor correcto, o ciclo repetirase. Se quitásemos a función fflush()
e o usuario introducise un valor incorrecto, o ciclo entraría nun bucle sen fin.
Notas
[editar]- ↑ Neste fío dun foro discútense as distintas alternativas para limpar o lixo que deixa a función
scanf()
.