Como o scanf funciona em C: entrada, formatação e armadilhas comuns

7

A entrada é a força vital de qualquer programa interativo. Sem ele, você estará apenas operando uma calculadora no vácuo. Na linguagem de programação C, o carro-chefe para obter dados do teclado é scanf. É simples. Está em todo lugar. Mas também é conhecido por ser implacável quando as coisas dão errado.

Para scripts básicos ou protótipos rápidos, scanf faz o trabalho. Ele lê stdin (entrada padrão). Se você estiver digitando em um teclado, é aí que seus personagens vão parar. A função é versátil, mas carece de tratamento robusto de erros. Não importa se você digita uma letra quando espera um número. Ele simplesmente ficará parado ou, pior, travará seu programa. É por isso que é ótimo para tarefas simples, mas ruim para software de nível de produção.

A sintaxe e o E comercial

Vejamos o caso de uso mais simples possível. Você quer um número inteiro. Você pede por isso. Você armazena.

scanf("%d", &b);

É isso. Dois argumentos. A string de formato e o destino.

O %d diz ao scanf para esperar um número inteiro. É o mesmo espaço reservado que você usa em printf. A variável b deve ser declarada como um int. Se não for, você está procurando problemas.

Aqui está a parte que sempre confunde os iniciantes: o e comercial (& ).

&b não é um erro de digitação. É um ponteiro. Especificamente, é o endereço da variável b. scanf não assume o valor; ele precisa do local da memória para gravar a entrada. Esqueça o &. Seu código pode ser compilado. Mas quando você o executa? Colidir. Segfault. Vazio. É quase certo que o programa terminará abruptamente porque tenta gravar em um endereço de memória aleatório.

Formatando sinalizadores

scanf usa os mesmos especificadores de conversão que printf. Se você conhece um, você conhece o outro. Mas o contexto é importante.

  • Inteiros : %d
  • Números de ponto flutuante : %f
  • Caracteres únicos : %c
  • Sequências : %s

Mantenha-os retos. Troque um %f por um número inteiro e você obterá dados inúteis ou uma falha.

Por que scanf não é suficiente

Você pode encadear chamadas scanf para ler vários valores.

Isso funciona para números. Está limpo o suficiente. Mas tente ler uma linha completa de texto? Ele quebra. scanf com %s para no primeiro espaço em branco. Não lê a linha inteira. E não lida com buffer overflows com segurança.

Para programas reais, você deve evitar scanf para entrada de texto. Em vez disso, use gets (que está obsoleto e perigoso) ou, preferencialmente, fgets. Essas funções leem uma linha por vez em um buffer. Depois de ter a linha, você pode analisá-la. Você pode verificar se há erros. Você pode validar se a entrada se parece com um número antes de tentar convertê-la. scanf pula esta etapa. Pressupõe que você sabe o que está fazendo. Você geralmente não faz isso.

Quebrando coisas de propósito

A melhor maneira de aprender C não é lendo documentação. É quebrando o compilador.

Pegue este trecho:

Modifique-o. Torne tudo pior.

Exclua b da declaração da variável. Observe o compilador gritar sobre uma variável indefinida.

Exclua um ponto e vírgula. Veja como o erro de sintaxe se propaga.

Remova uma chave. Observe o analisador enlouquecer.

Exclua um parêntese. Observe a confusão