Ir ao conteúdo

Posts recomendados

Postado

galera to com uma calculadora so com as operações basica,mas o meu professor pediu para fazer uma especie de proteção no codigo para caso o usuario entre com uma variavel diferente da que ele deve o codigo recuse,por exemplo pede um float o usuario usa um char ele quer que o codigo não aceite ou retorne erro.observação ainda a erros na calculadora mas serão acertados pelos outros mebros do grupo.

int main(){
float num1,num2;
char oper;
float notas;
float total = 0;
int i,a,x,op;
float subtracao= 0;
float divisao= 0;
float media = 0;
float multiplicacao=0;

        do
        {

            printf("Operacoes disponiveis\n");
            printf("'+' : soma\n");
            printf("'-' : subtracao\n");
            printf("'*' : multiplicao\n");
            printf("'/' : divisao\n");
            printf("'%%' : resto da divisao\n");
            scanf(" %c",&oper);
            system("cls || clear");
            switch( oper )
            {
                case '+':
printf("Insira a quantidade de notas:\n");
scanf("%d",&a);

printf("Insira notas:\n");

for(i=0;i<a;i++){

scanf("%f",&notas);

}

for(i=0;i<a;i++){

total += notas;
printf("sua soma e igual=%f",total);

}

                        break;

                case '-':
printf("digite a nota que deseja que seja subtraida:\n");
scanf("%d",&x);

printf("Insira a quantidade de notas:\n");
scanf("%d",&a);

printf("Insira notas:\n");

for(i=0;i<a;i++){

scanf("%f",&notas);

}

for(i=0;i<a;i++){

total += notas;

}
subtracao= x-total;

printf("A media do aluno: %f ", subtracao);

                        break;

                case '*':
                printf("digite a nota que deseja que seja multiplicada");
                 float y;
                int i,a;
                scanf("%f",&y);
printf("Insira a quantidade de notas:\n");
scanf("%d",&a);

printf("Insira notas:\n");

for(i=0;i<a;i++){

scanf("%f",&notas);

}

for(i=0;i<a;i++){

total *= notas;
multiplicacao= total;
printf("a multiplicação e igual a %f",multiplicacao);
}

printf("total = %f\n",total);



                        break;

case '/':
printf("digite a nota que deseja que seja dividida:\n");
scanf("%d", &x);

printf("Insira a quantidade de notas:\n");
scanf("%d",&a);

printf("Insira notas:\n");

for(i=0;i<a;i++){

scanf("%f",&notas);

}

for(i=0;i<a;i++){

total += notas;

}
divisao= x/total;

printf("A media do aluno: %f ", divisao);




                       break;
        default:
                if(num1 != 0 && oper != '0' && num2 != 0){
                            printf(" Operador invalido\n\n ");
              } else{
              printf(" Fechando calculadora!\n ");

             }
            }
        }
        while(op != 0);
  }

 

  • Curtir 2
Postado

@luckaris Tem várias maneiras de se proteger contra entradas inválidas.

scanf() retorna 0 para uma entrada inválida, e retorna 1 para uma entrada válida.

Teste o seguinte:

float num;
int ch;
while(scanf("%f", &num) != 1) {
    printf("Entrada inválida!\n");
    while((ch = getchar()) != EOF && ch != '\n');
}
Vocês fizeram um menu... Interessante, porém, sugiro uma ideia mais prática:

Todas essas operações poderiam ser feitas digitando-se algo no formato <número> <operação> <número>, que pode ser lido por uma função scanf(), e o resultado poderia ser atribuído à uma variável chamada Ans, para ser usada mais tarde caso necessário.

Caso se interessar por essa ideia (e não vá contra o enunciado de sua questão), tente desenvolvê-la.

  • Curtir 1
  • Obrigado 2
Postado
2 horas atrás, Lucca Rodrigues disse:

scanf() retorna 0 para uma entrada inválida, e retorna 1 para uma entrada válida

 

Não, scanf() não faz isso.

 

scanf() retorna o número de itens lidos, que vai de zero até o total de especificadores fornecidos. Especificadores são as coisas com % na frente

 

Exemplo: 

        int a = 0, b = 0, c = 0;
        int n = scanf("%d,%d,%d", &a, &b, &c);

Esse tem 3 especificadores e espera ler 3 inteiros separados por vírgula. Então pode retornar 0,1,2 ou 3.

Não acho que tenha de fato uma entrada inválida para scanf(). 

Como eu sempre escrevo, essa rotina foi escrita para ler entrada formatada --- scan formatted input --- e se ela não consegue atender o especificado apenas retorna 0. Pode ser um erro de formato, não da rotina. 

 

scanf() lê até o próximo espaço, tab, fim de linha ou fim de arquivo e tenta atender ao que foi pedido. Nada mais. E assim uma entrada "inválida" de um ponto de vista lógico pode levar a resultados inesperados. Em especial porque em geral ninguém lê o retorno de scanf() e ela pode entrar em loop e comer a entrada toda.

 

Exemplo besta, mas sinistro: 

int main()
{
    while (1)
    {
        printf("a,b,c: ");
        int a = 0, b = 0, c = 0;
        int n = scanf("%d,%d,%d", &a, &b, &c);
        printf("scanf() retornou %d\n", n);
        printf("a,b,c = (%d,%d,%d)\n", a, b, c);
    };
};

Esse programa tenta ler os 3 int separados por virgula. Pode ler nenhum, 1, 2 ou 3. E continua lendo até encerrar o programa com Control-C.

 

Se você não testar e o cara digitar algo menos que os 3 vai dar m$%a mesmo.  E não é por causa das vírgulas ou de serem 3 campos. É porque a rotina foi feita pra ler entrada formatada.

 

Mas estamos testando esse sofisticado programa de 10 linhas...

 

um teste

a,b,c: 1,2,3
scanf() retornou 3
a,b,c = (1,2,3)
a,b,c: 1,2
scanf() retornou 2
a,b,c = (1,2,0)
a,b,c: 1
scanf() retornou 1
a,b,c = (1,0,0)
a,b,c: 1,
2
scanf() retornou 2
a,b,c = (1,2,0)
a,b,c: 1,
2,
3
scanf() retornou 3
a,b,c = (1,2,3)
a,b,c:
... ... ...

Eu posso digitar os 3, ou dois ou um. Ou mesmo terminar a linha com a vírgula e continuar adiante. Zoou a tela mas até que está bem.

 

Mas se o cara digitar 1,x

a,b,c: 1,x
scanf() retornou 1
a,b,c = (1,0,0)
a,b,c: scanf() retornou 0
a,b,c = (0,0,0)
a,b,c: scanf() retornou 0
a,b,c = (0,0,0)
a,b,c: scanf() retornou 0
a,b,c = (0,0,0)
a,b,c: scanf() retornou 0
a,b,c = (0,0,0)
a,b,c: scanf() retornou 0
a,b,c = (0,0,0)
a,b,c: scanf() retornou 0
a,b,c = (0,0,0)
a,b,c: scanf() retornou 0
a,b,c = (0,0,0)
a,b,c: scanf() retornou 0

O programa entra em loop porque aquele 'x' não vai ser consumido de jeito nenhum: não tem mais ninguém lendo de stdin --- o teclado ou um arquivo --- e scanf() quando for chamada de novo vai tentar ler um dígito e vai sempre encontrar o x e retornar 0. scanf() é uma rotina ativa, um tipo conhecido como parser e vai furiosamente comer a entrada toda tentando achar o que foi pedido. Talvez isso já tenha acontecido com você que está lendo isso :D 

 

Lógico, não é nada contra a letra x. Podia ser qualquer coisa, várias letras, o gato andando em cima do teclado, mas o programa já era.

 

Por isso se vê tantos iniciantes e mesmo profissionais incautos com programas que passam a leitura de um campo na tela e desprezam outras leituras e seguem loucamente executando sem ter lido nada.

 

Citação

Eu escrevi de propósito então é divertido. Mas na prática é um inferno.

 

Dando uma olhada no que acontece

 

Vamos colocar um if lá quando scanf() retorna zero e ler o que tem lá dentro

        if (n == 0)
        {   // se nao leu nada deve ter algo errado pra ler
            while (!feof(stdin))
            {
                char c = fgetc(stdin);
                if (isprint(c))
                    printf("Para ler ainda: c = '%c', codigo = %d\n", c, c);
                else
                    printf("Para ler ainda: codigo = %d\n", c);

                if (c == '\n') break;
            };
        };  // if()

E rodar de novo digitando 1,x

a,b,c: 1,x
scanf() retornou 1
a,b,c = (1,0,0)
a,b,c: scanf() retornou 0
a,b,c = (0,0,0)
Para ler ainda: c = 'x', codigo = 120
Para ler ainda: codigo = 10
a,b,c: 1,errei aqui
scanf() retornou 1
a,b,c = (1,0,0)
a,b,c: scanf() retornou 0
a,b,c = (0,0,0)
Para ler ainda: c = 'e', codigo = 101
Para ler ainda: c = 'r', codigo = 114
Para ler ainda: c = 'r', codigo = 114
Para ler ainda: c = 'e', codigo = 101
Para ler ainda: c = 'i', codigo = 105
Para ler ainda: c = ' ', codigo = 32
Para ler ainda: c = 'a', codigo = 97
Para ler ainda: c = 'q', codigo = 113
Para ler ainda: c = 'u', codigo = 117
Para ler ainda: c = 'i', codigo = 105
Para ler ainda: codigo = 10
a,b,c:

E fica claro como funciona: o x e \n do enter estão lá para serem lidos. 10 é o código do enter, o tal newline, \n

scanf() não leu p$RR@ nenhuma então volta pro loop e vem outro scanf() para ler os 3 int. Só que tem um 'x' solitário lá. Então ela retorna zero e volta pro loop e vai ficar assim para todo o sempre.

 

Na segunda execução digitei '1,errei aqui'

 

E isso tudo fica lá pra ser lido. Como eu disse, de propósito é divertido. Mas se o programa estivesse lendo uma série de campos num formulário... 

 

Essa rotina não foi escrita para ler do teclado.

 

De volta ao tópico e à questão do autor:

 

Use o retorno de scanf() para ver se leu o float. Se não leu nada então leia tudo que tem pra ler até ler um \n antes de chamar scanf() de novo. Algo simples como uma única linha

    FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); // esta em windows.h

no Windows,  ou um loop 

    while ((c = getchar()) != '\n' && c != EOF);

 

Então como ler com segurança do teclado?

  • Leia letra a letra mas não mostre --- leia sem eco, como uma senha --- e não mova o cursor
  • Veja se é uma letra válida para o que está esperando. Só se for você mostra e avança o cursor
  • Se terminou de ler o campo continua
  • Se o cara digitou algo errado apenas toque o bip por exemplo. codigo do bip: 7

Sempre dá certo.

 

E scanf() não presta?

 

Pelo contrário. E uma rotina bem esperta e acho que foi escrita por um dos melhores programadores de todos os tempos. Para um outro uso.

 

E porque eu escrevi isso tudo?

 

Porque eu vejo que acontece toda hora esse tipo de problema e alguém pode acabar lendo ;) isso aqui

Não é a linguagem comum de "apagar o lixo do teclado", ou "limpar o buffer", não dá pra saber o que é lixo. Não é um problema de scanf(). Não é o caso de chamar setbuf(). É o caso de ler o manual e agir de acordo. Por exemplo lendo de outro jeito

 

Há outras maneiras de mesmo esse minúsculo programa falhar. É só um exemplo.

 

 

 

  • Curtir 1
  • Obrigado 1
Postado

Leia a linha inteira: Depois teste para caracteres somente decimais com exceção um (.) que separara as frações. Se tive OK converta para float usando a função sscanf (); Senão solicite nova entrada. 

  • Obrigado 1

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!