Isso é comumente discutido tópico, cheia de opinião, mas interessante, nenhum a menos. Tenho observado que uma grande maioria daqueles que já respondeu a perguntas semelhantes sobre este site cair do lado de fgets()
. Eu sou um deles. Eu encontrar fgets()
para ser muito melhor utilização para o usuário de entrada de scanf()
com poucas exceções. scanf()
é considerado por muitos como sub-ótimo método para o tratamento de usuário de entrada. Por exemplo
"...ele vai dizer se ele conseguiu ou não, mas posso dizer apenas aproximadamente onde ele falhou, e não como ou por quê. Você
tem muito pouca oportunidade para fazer qualquer recuperação de erro."
(jamesdlin). Mas, no interesse da tentativa de equilíbrio, vai começar citando essa discussão.
Para a entrada do usuário que vem de stdin
, i.e. a entrada do teclado, fgets()
vai ser uma melhor escolha. É muito mais indulgente em que a cadeia de lê-lo pode ser validados antes da conversão é tentada
Uma das poucas vezes através de um formulário de scanf(): fscanf() ficaria bem usar pode ser ao converter a entrada de um muito controlado de origem, por exemplo, a leitura de uma estritamente de arquivo formatado com a repetição previsível campos.
Para uma discussão mais, esta comparação dos dois destaques adicionais, vantagens e desvantagens de ambos.
Editar: para endereço OP adicionais pergunta sobre estouro:
"Mais uma coisa que eu quero perguntar é: até quando podemos usar fgets o que aconteceria se o usuário digitar os caracteres mais do que o limite (eu quero dizer um monte de
caracteres), não é levar a estouro de buffer? Então, como lidar com
ele?"
[fgets()](https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm está muito bem concebido para evitar estouro de buffer, simplesmente usando seus parâmetros corretamente, por exemplo:
char buffer[100] = {0};
...
while fgets(buffer, sizeof buffer, stdin);
Isso impede a entrada maior do que o tamanho do buffer a ser processado, evitando assim o excesso.
mesmo usando scanf()
prevenção de estouro de buffer é bastante simples: Usar um especificador de largura na cadeia de caracteres de formato. Se você quiser ler a entrada, por exemplo, e o limite de tamanho de entrada do usuário para 100 caracteres, no máximo, o código deve incluir o seguinte:
char buffer[101] = {0};// includes space for 100 + 1 for NULL termination
scanf("%100s", buffer);
^^^ width specifier
No entanto, com números, o excesso não é tão agradável usando scanf()
. Para o demonstrar, utilizar este código simples, introduzir os dois valores indicados no comentário de um por executar:
int main(void)
{
int val = 0;
// test with 2147483647 & 2147483648
scanf("%d", &val);
printf("%d\n", val);
return 0;
}
Para o segundo valor, o sistema lança o seguinte:
NON-FATAL RUN-TIME ERROR: "test.c", line 11, col 5, thread id 22832: Function scanf: (errno == 34 [0x22]). Range error
`
Aqui você precisa ler em uma seqüência de caracteres e, em seguida, siga com uma seqüência de caracteres para o número de conversão usando um dos strto_()
funções: strtol(), strtod(), ...). Ambos incluem a capacidade de teste de estouro de antes , causando um tempo de execução de aviso ou de erro. Note que a utilização de atoi()
, atod()
não vai proteger contra sobrecarga de qualquer um.