paulo1205
(usa Ubuntu)
Enviado em 12/07/2019 - 16:17h
Bacagine escreveu:
Minhas dúvidas são:
1) Por que devo usar getchar no lugar de getch?
Porque
getch () não é uma função padronizada e, portanto, não existe em qualquer sistema (existe uma
getch () no Linux, como parte da biblioteca Curses, mas o comportamento dela é diferente da versão que tem no MS-DOS).
2) Porque devo usar getchar duas vezes (um professor me eplicou uma vez mas acabei esquecendo e gostaria de me lembrar)
O que acontece, tanto no Linux como no Windows, é que geralmente a entra e saída de dados são orientadas a linha. A orientação a linha implica que simplesmente apertar uma tecla não basta para que a a função
getchar () retorne imediatamente, porque, por trás de um
getchar (), a biblioteca de entrada e saída do C está tentando ler uma linha inteira, e essa tentativa só acaba sendo bem sucedida quando o caráter de fim de linha é encontrado, ou quando acaba o espaço interno de
buffer para conter os caracteres encontrados antes do caráter que marca o fim da linha.
Além disso, o caráter de fim de linha, quando encontrado, é colocado no
buffer de entrada como parte do conteúdo lido; se ele não for explicitamente consumido pelo seu programa, ficará lá, à espera da próxima operação de leitura. Quando seu programa executa “
scanf("%f", &x) ”, o que acontece não é a leitura de uma linha inteira e a extração do número de ponto flutuante que está presenta nessa linha; a função
scanf () é muito mais complexa que isso — e por isso eu recomendo que sua documentação seja lida com muito cuidado. O que acontece realmente é que a conversão
"%f" provoca um descarte de espaços que porventura ocorram antes do número, seguida pela busca de caracteres que possam compor o número, até que seja encontrado o primeiro caráter que não possa ser considerado parte do número. Tal caráter, quando encontrado, não é consumido, mas permanece no
buffer de leitura.
Se, no momento da execução, o usuário digitar “
2.5 ”, o programa (isto é: a biblioteca de entrada e saída que seu programa usa) vai continuar aguardando a marca de fim de linha. Quando o usuário aperta a tecla <Enter>, essa marca finalmente injeta o caráter de fim de linha no terminal, e o programa recebe esse caráter e o coloca no
buffer .
scanf (), por sua vez, vê que a marca de fim de linha não faz parte do número, e grava o valor lido no local apontado, deixando a marca de linha de linha no
buffer . Se a operação de leitura seguinte for “
scanf("%f", &y) , a marca de fim de linha que tinha ficado pendente no
buffer será consumida como parte do descarte automático de espaços, antes de começar a consumir os caracteres que compõem o número a ser lido. Se o usuário digitar “1.5” e teclar <Enter>, a conversão var consumir
'1' ,
'.' e
'5' , mas mas deixar o
'\n' correspondente à tecla <Enter> no
buffer , até a próxima operação de leitura.
Então, se você quiser ler um único caráter, é importante garantir que não haja nenhuma sobra de operações anteriores no
buffer .
Fora tudo isso, que está sob o controle do programa em C usando funções padronizadas, o próprio driver do terminal, sob controle do sistema operacional, também emprega
buffers , para que o que é digitado não se perca, caso a aplicação que está rodando no terminal demore pedir para a ler o que o usuário digita.
getchar () poderia retornar imediatamente após uma tecla ser apertada. Mas, para isso, você teria primeiro de ter o cuidado de não deixar sobras no
buffer , e depois teria de pedir à biblioteca de leitura do C que parasse de usar orientação à linha e pedir ao sistema operacional que altere o comportamento do driver do terminal, a fim de eliminar o efeito dos seus
buffers . O primeiro pedido pode ser feito com funções do C padrão; o segundo requereria o uso de funções particulares do seu sistema operacional.
getch () é uma maneira de pedir ao sistema operacional que interaja diretamente com o terminal, sem passar pelo sistema de entrada e saída do C. Misturar
getch () com funções de leitura padronizadas do C aplicadas ao terminal é geralmente um erro, inclusive no MS-DOS/Windows.
3) Por que em partes do código como esta não aceitam apenas que eu escreva main():
else{
main();
}
}while (x != -0);
Queria que caso o usuario não digitasse nenhuma das opções anteriores, o programa mostrasse o que tem na função main, no entanto não consigo fazer isso para o LINUX.
Seria importante ver a mensagem de erro específica que o compilador mostra. Mas eu não consigo pensar em nenhum caso válido pelo qual um programa devesse chamar
main () explicitamente. A forma como você fez isso no seu programa denota um erro de modelagem.
A forma correta de fazer em C o que você fez (mantendo as mesmas funções que você fez, embora eu também não ache que elas estão muito bem divididas) seria mais ou menos a seguinte.
bool read_until_eol(void){
int ch;
while((ch=getchar())!=EOF && ch!='\n')
;
return ch=='\n';
}
void input_error(){
if(
ferror(stdin) ||
(fprintf(stderr, "Dados inválidos. Tentando limpar o buffer... "), !read_until_eol())
){
perror("Erro de leitura");
exit(1);
}
fprintf(stderr, "OK.\n");
}
void soma(void){
while(1){
float x, y;
printf("Digite a primeira parcela (ou 0 para encerrar): ");
if(scanf("%f", &x)!=1){
input_error();
fprintf(stderr, "Tecle <Enter> para voltar ao menu principal.");
read_until_eol();
break;
}
else if(x==0.0f)
break;
printf("Digite a segunda parcela: ");
if(scanf("%f", &y)!=1){
input_error();
fprintf(stderr, "Tecle <Enter> para voltar ao menu principal.");
read_until_eol();
break;
}
printf("%f%+f=%f\n\n", x, y, x+y);
}
}
void subtracao(void){ /* Semelhante a soma, com as devidas alterações. */ }
void multiplicacao(void){ /* Semelhante a soma, com as devidas alterações. */ }
void divisao(void){ /* Semelhante a soma, com as devidas alterações. */ }
bool menu(void){
/* Apresenta menu. */
/* Lê opção. */
switch(opcao){
case 1: soma(); break;
case 2: subtracao(); break;
case 3: multiplicacao(); break;
case 4: divisao(); break;
case 0: return false;
}
return true;
}
int main(void){
do {
printf("blablabla... \n");
} while(menu());
return 0;
}
... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)