Vamos Programar? – Introdução à Programação #22
Um pouco mais sobre a função scanf e algumas dicas
O mundo está constantemente a evoluir: desde o mais pequeno inseto à espécie Humana. Dentro das palavras que mais ouvimos atualmente, incluímos “evolução”, “mudança”, “futuro”.
A tecnologia tem revolucionado o mundo das mais diversas formas: do mais simples aparelho para medir o tempo ao mais complexo acelerador de partículas. Se quer entrar no mundo da tecnologia e deixar a sua marca, pode começar aqui.
O artigo de hoje irá incidir sobre algumas sugestões a referir dadas por leitores no artigo da semana passada, mas também iremos começar a abordar outro tópico.
Limpeza do buffer
No artigo número nove da presente saga introduzimos as seguintes funções:
1 2 | _fpurge(); fflush(); |
Ambas as funções permitem-nos limpar o buffer de entrada, porém não são muito seguras. Em programação profissional de C (e outras linguagens), estas funções não são utilizadas por motivos de segurança.
Claro que existem "soluções" alternativas. O leitor José Carlos Ferreira, no artigo da semana anterior, sugeriu-nos o seguinte:
1 | #define CLEAR_INPUT while (!getchar ()) |
O que nos permite utilizar o trecho de código:
1 | while (!getchar ()) |
Recorrendo apenas ao nome "CLEAR_INPUT".
Alternativa a gets e a scanf
Devido à falta de uma solução efetiva ao problema existente com a função scanf e à existência de alguns contra-tempos com a função gets foi sugerido, pelos leitores Zé e lmx a utilização da função fgets.
Sintaxe
Esta função tem algumas diferenças relativamente às funções mencionadas no título. Ora veja a sintaxe:
1 | fgets(char *str, int n, FILE *stream); |
Onde:
- str - O apontador para um array de caracteres onde a \textit{string} será armazenada.
- n - O número máximo de caracteres a serem lidos (incluindo o delimitador final). Geralmente é igual ao tamanho do array.
- stream - O apontador para o ficheiro ou objeto donde serão lidos os caracteres.
Exemplo
Vejamos então um exemplo baseado no boletim de informação criado no artigo anterior.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include <stdio.h> #include <stdlib.h> int main() { char nome[21], apelido[21], morada[51], codigoPostal[11]; printf("Por favor insira os seus dados conforme pedido:\n\n"); printf("Primeiro nome: "); fgets(nome, 21, stdin); printf("Último nome: "); fgets(apelido, 21, stdin); printf("Morada: "); fgets(morada, 51, stdin); printf("Código Postal: "); fgets(codigoPostal, 11, stdin); printf("\nO seu Cartão de Identificação:\n"); printf("Nome: %s, %s\n", apelido, nome); printf("Morada: %s\n", morada); printf("Código Postal: %s\n", codigoPostal); return 0; }</stdlib.h></stdio.h> |
Remoção das Mudanças de Linha
Mas, se corrermos o código acima, iremos receber algo parecido com o seguinte:
1 2 3 4 5 6 7 | O seu Cartão de Identificação: Nome: Apelido , Nome Morada: Morada Código Postal: CP |
Como pode verificar, isto mostra que os arrays ficaram, também com os delimitadores da mudança de linha ("\n"). Para removermos estes delimitadores podemos recorrer à função "strtok".
Sintaxe
Ora veja a sintaxe desta função.
1 | strtok(char *str, const char *delim); |
Onde:
- str - O apontador para um array de caracteres onde a \textit{string} está armazenada.
- delim - O delimitador em questão ou uma constante que o contenha.
Exemplo
Então, para que o exemplo acima imprima corretamente o Bilhete de Informação, devem ser adicionadas as seguintes linhas antes de ser imprimida qualquer informação:
1 2 3 4 | strtok(nome, "\n"); strtok(apelido, "\n"); strtok(morada, "\n"); strtok(codigoPostal, "\n"); |
Mais uma vez, gostávamos de saber a sua opinião. Caso tenha alguma dúvida, pode sempre utilizar os comentários para colocar a questão. Caso o faça, pedimos que utilize a keyword [DUVIDA] no início do seu comentários.
Esta saga |
Henrique Dias |
|
Mais episódios: [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13][12] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23][24] |
Este artigo tem mais de um ano
O fflush perfeitamente seguro (o que evidentemente não exclui que algum compilador faça “sei lá eu o quê” com a função).
A questão é que lhe é atribuída frequentemente uma finalidade que não resulta do C padrão, nomeadamente a de limpar os buffers de entrada.
http://www.cplusplus.com/reference/cstdio/fflush/?kw=fflush
Em relação ao resto não posso estar mais de acordo. Nas versões mais recentes dos meus cursos introdutórios ao C/C++ simplesmente não ensinava sequer as gets ou scanf, dava a penas uma nota como coisa a evitar. A getc é segura, mas prefiro substituir-la por fgetc por uma questão de tornar a explicação mais coerente.
MAIS se se precisar dos formatos habitualmente associados a scanf a única maneira estável de ler qualquer coisa é ler essa qualquer coisa para uma string muito grande (típico 512 caracteres) e depois usar calmamente sscanf. A string grande é reutilizada em cada leitura pelo que não esgota recursos significativos.
Olá José Simões!
Obrigado pelo seu feedback e pela informação sobre a função fflush. Esta saga está quase a acabar. Os próximos artigos serão “projetos”.
Esperemos mais opiniões para continuar a saga “Vamos Programar?” e extendê-la a outras linguagens. Quando lançarmos a compilação final colocarei essa informação.
Desejo-lhe um excelente resto de fim de semana. 🙂