Ir ao conteúdo

Posts recomendados

Postado

#include<stdio.h>
#include<stdlib.h>


int main (){
  
  float notas[3];
int c=0;

for(int c=0;c<3;c++){
printf("Digite a notaa %d :",c+1);
scanf("%.1f",&notas[c]);

}

for(int c=0;c<3;c++){
printf("NOTA %d : %.1f " ,c+1,notas[c]);
}

}

Ao executar o código,  ele solicita a primeira  nota porém após  isso ele pula todas etapas até  o final do código.

  • Amei 1
Postado

@MarianaN    você colou caracteres inválidos no scanf , e não está pulando o printf , não mas sim  o scanf ;

// scanf("%.1f",&notas[c]);   na leitura não pode especificar a qtd de casas decimais
                           // apenas na escrita "printf("%5.2f\n", notas[c]);"
scanf( "%f" , & notas[c]);

outra forma de validar os dados inseridos pelo usuário seria usar uma string :
#include <ctype.h>
#include <string.h>
#include <stdlib.h>  
char str[20];
l1:
scanf("%s",str); // Aqui não precisa do "&" de endereco pois já o tem
for(int i=0; str[i] != 0; i++)
    if( ! isdigit(str[i]) && str[i] !='.' ) goto l1;
notas[c] = atof(str);

 

  • Curtir 2
Postado

Procure alinhar seu código para ficar mais legível.

 

Algo assim seria comum:

 

#include <stdio.h>
#include <stdlib.h>

int main()
{
    float notas[3];
    int   c = 0;

    for (int c = 0; c < 3; c++)
    {
        printf("Digite a notaa %d :", c + 1);
        scanf("%.1f", &notas[c]);
    }

    for (int c = 0; c < 3; c++)
    {
        printf("NOTA %d : %.1f ", c + 1, notas[c]);
    }
}

 

TESTE o retorno de scanf() como descrito no manual. É ingênuo seguir sem testar. 

 

 

  • Curtir 2
  • Obrigado 1
Postado

@MarianaN Você pode fazer o seguinte, se quer limitar a quantidade de caracteres lidos no formato de float:

int ch = 0;
// Limitado a ler 3 caracteres <d.d>
scanf("%3f", &notas[c]);
// Lendo o que ha de resto
while((ch = fgetc(stdin)) != '\n' && ch != EOF);

Isto é, se tem certeza de que a nota é composta por somente um dígito antes da vírgula, e nesse caso não vão ocorrer arredondamentos:
image.png.8d1801c1dc550c6e37b036fea9b8eb10.png

Em geral não tem muito sentido em cobrar a nota dessa forma, acho que vale mais a pena ler a nota do jeito que o usuário inserir e arredondar na hora de imprimir, como você já fez:

10 horas atrás, MarianaN disse:
printf("NOTA %d : %.1f " ,c+1,notas[c]);

 

Se quer testar o retorno da scanf(), pode usar um loop:

while(scanf("%3f", &notas[c]) < 1)
{
    // Lendo o que ha de resto
    while((ch = fgetc(stdin)) != '\n' && ch != EOF);
    // Informando o usuario
    printf("Entrada invalida!\nDigite a nota %d: ", c + 1);
}

A scanf() retorna a quantidade de itens lidos e gravados, então nesse caso deveria ser 1.

Se for 0, não gravou nada.

  • Curtir 1
Postado
1 hora atrás, Lucca Rodrigues disse:
scanf("%3f", &notas[c]);

 

É ingênuo escrever assim. Se o cara bater o dedo no 'w' ao invés de '2' já era. E tem o problema do ponto decimal. Se o usuário digitar ponto ao invés de vírgula ou vice-versa?

 

Nem para um exemplo num forum de iniciantes, eu acho.

 

1 hora atrás, Lucca Rodrigues disse:
while(scanf("%3f", &notas[c]) < 1)

 

:) aí sim.

 

1 hora atrás, Lucca Rodrigues disse:

A scanf() retorna a quantidade de itens lidos e gravados, então nesse caso deveria ser 1.

Se for 0, não gravou nada

 

Pode retornar -1 em caso de erro ou o total de especificadores atendidos. Aquelas coisas que começam por % e não por %%. No caso aqui um só --- "%3f"--- , então pode retornar -1, 0 ou 1 

 

 

 

  • Curtir 2
Postado
29 minutos atrás, arfneto disse:

É ingênuo escrever assim. Se o cara bater o dedo no 'w' ao invés de '2' já era. E tem o problema do ponto decimal. Se o usuário digitar ponto ao invés de vírgula ou vice-versa?

Esse tipo de coisa acontece, daí a gente aplica os mínimos cuidados com a scanf(): verifica o retorno, lê a besteira que o usuário digitou se o retorno não for o esperado e informa que a entrada não é válida. 😁

No mais, é o que foi dito no outro tópico por você:

Citação

O teclado tem mais de 100 teclas e modificadores como control alt e shift. O que se faz é testar o que está sendo digitado.

Tem muitas maneiras. A mais flexível é ler tecla a tecla sem mostrar e só mostrar depois de testar. O mais simples é ler e testar em um loop, mas pode zoar a tela.

Acho que é o mais adequado, mas foram poucas as vezes que vi alguém aplicar em uma atividade acadêmica ou coisa do tipo.

Eu tinha feito isso há um tempo, só não sei se o comportamento da peek() ou da wait() muda entre os compiladores. Testei com o GCC:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

char LerChar(void);
int LerInt(int minval, int maxval);
float LerFloat(float minval, float maxval);

int main()
{
    printf("Digite algum numero inteiro entre -300 e 300: ");
    int x = LerInt(-300, 300);
    printf("\n\nDigite algum numero real entre -1.2 e 5.6: ");
    float y = LerFloat(-1.2f, 5.6f);

    printf("\n\nValor inteiro: %d\nValor real: %f\n", x, y);

    return 0;
}

char LerChar(void)
{
	INPUT_RECORD record;
	HANDLE console = GetStdHandle(STD_INPUT_HANDLE);
	int total = 0;
	// Tecla
	char c = 0;

	do {
		FlushConsoleInputBuffer(console);
		WaitForSingleObject(console, INFINITE);

		/* Se PeekConsoleInput() for bem-sucedida,
	    o valor retornado será diferente de zero */
		if(!PeekConsoleInput(console, &record, 1, (LPDWORD)&total))
            return 1;
		if(total > 0)
            if(record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown)
            {
                c = record.Event.KeyEvent.uChar.AsciiChar;
                FlushConsoleInputBuffer(console);
                if(c == '\r')
                    c = '\n';
                return c;
            }
	} while(1);
}

int LerInt(int minval, int maxval)
{
	char str[12];
	int x = 0;
	int i = 0;
    int ch;

	while((ch = LerChar()) != EOF && ch != '\n')
    {
        if(i == 0 && ch == '-')
        {
            // '-' no início
            putchar(ch);
            str[i++] = ch;
        }
        else if(ch == '\b' && i > 0)
        {
            // Backspace
            printf("\b \b");
            str[--i] = '\0';
        }
        else if(ch >= '0' && ch <= '9')
        {
            // Entre '0' e '9'
            str[i++] = ch;
            str[i] = '\0';
            /* Caso o primeiro número seja 0 e haja outro
            em sequência, o mesmo é retirado da string */
            if((str[0] == '0' && str[1] == '0') || (str[0] == '-' && str[1] == '0' && str[2] == '0'))
                str[--i] = '\0';
            else if(atoll(str) <= (long long)maxval && atoll(str) >= (long long)minval)
                putchar(ch);
            else
                str[--i] = '\0';
        }
    }

    str[i] = '\0';
    // Caso algum valor tenha sido digitado
    if(str[0] >= '0' || (str[0] == '-' && str[1] >= '0'))
        x = atoi(str);

    return x;
}

float LerFloat(float minval, float maxval)
{
    int aloc = 101;
	char* str = (char*)malloc(aloc);
	float x = 0.0f;
	int pnt = -1;
	int i = 0;
    int ch;

	while((ch = LerChar()) != EOF && ch != '\n')
    {
        if(i == (aloc - 1))
        {
            aloc += 100;
            str = (char*)realloc(str, aloc);
        }

        if(i == 0 && ch == '-')
        {
            // '-' no início
            putchar(ch);
            str[i++] = ch;
        }
        else if(pnt == -1 && ch == '.')
        {
            // '.'
            pnt = i;
            putchar(ch);
            str[i++] = ch;
        }
        else if(ch == '\b' && i > 0)
        {
            // Backspace
            printf("\b \b");
            str[--i] = '\0';
            if(i == pnt)
                pnt = -1;
        }
        else if(ch >= '0' && ch <= '9')
        {
            // Entre '0' e '9'
            str[i++] = ch;
            str[i] = '\0';
            /* Caso o primeiro número seja 0 e haja outro
            em sequência, o mesmo é retirado da string */
            if((str[0] == '0' && str[1] == '0') || (str[0] == '-' && str[1] == '0' && str[2] == '0'))
                str[--i] = '\0';
            else if(strtold(str, NULL) <= (long double)maxval && strtold(str, NULL) >= (long double)minval)
                putchar(ch);
            else
                str[--i] = '\0';
        }
    }

    str[i] = '\0';
    // Caso algum valor tenha sido digitado
    if(str[0] >= '0' || (str[0] == '-' && str[1] >= '0') || (str[0] == '-' && str[1] == '.' && str[2] >= '0'))
        x = strtof(str, NULL);

    return x;
}

Desse jeito o usuário não consegue digitar um valor fora do intervalo, nem zoar o programa digitando letras ou coisa do tipo.

  • Obrigado 1
Postado
23 minutos atrás, Lucca Rodrigues disse:

Acho que é o mais adequado, mas foram poucas as vezes que vi alguém aplicar em uma atividade acadêmica ou coisa do tipo.

Eu tinha feito isso há um tempo, só não sei se o comportamento da peek() ou da wait() muda entre os compiladores

 

É verdade. Acho que claramente vem dos livros e instrutores, que nunca apresentam scanf() como uma função que retorna um int, antes de tudo.

 

E esse é um dos erros mais comuns nas tais "atividades acadêmicas". :) 

 

E scanf() não foi escrita para isso, para ler do teclado. A ideia na época era consumir dados tabulares, como arquivos csv. Uma alternativa a usar AWK que era comum naquele tempo. Por isso o nome: scan formatted input.

 

Para ler do teclado sempre foi mais flexível usar fgets() e atoi atod atof e tal.

 

29 minutos atrás, Lucca Rodrigues disse:

Eu tinha feito isso há um tempo, só não sei se o comportamento da peek() ou da wait() muda entre os compiladores

 

Essas funções dependem apenas do Windows.

 

Mas nem precisa disso. Pode simplesmente desligar o eco e o LINE INPUT e ler com fgetc() as letrinhas uma por uma. É o mais flexível. Já te falei sobre isso. Se a letra for uma das que aceita então guarda e mostra. Se não for então pode tocar um bip e seguir lendo, sem mostrar nada.

 

E no linux é igual. Apenas as chamadas são diferentes e se usa ioctl().

 

Uma coisa que sempre dá certo é usar algo como a PICTURE do COBOL, afinal já são 70 anos de COBOL :D Pode ser uma expressão regular nos tempos modernos pós '70.

 

exemplo como no COBOL: "$ZZZ9V99" aceita um número. O Z é um número opcional, o 9 é um número obrigatório e V é a posição assumida para o ponto.  $ vira o símbolo da moeda no país. Então aceitaria 1 como R$ 0,01, 9999 como R$ 99,99 e tal. "A" indica uma letra, "X' aceita qualquer coisa. Acho que deu pra entender.

 

	void* meu_leitor( const char* mascara ); 

 

Então a função recebe uma string com isso e retorna o valor. Só um exemplo. E faz o que eu disse: desliga echo e line input para não mexer na tela, lê lê as letras uma a uma e testa com a máscara de leitura. Deu certo mostra, deu errado não mostra. Na saída restaura as opções do terminal.  Seguro e simples desde os '60. 

 

Pode claro retornar qualquer coisa. Uma função pra ler inteiros podia ser só 

 

	double meu_leitor_d( const char* mascara ); 

 

 E chamada com

 

	double nota = meu_leitor_d("ZZVZ9");

 

para o exemplo aqui. E aceitaria notas de 0 a 99.99. E não seria nada novo nem nos anos 70 :D 

 

 

Em geral isso é tratado com uma máquina de estados que vai acompanhando a string com a mascara e completando o valor conforme a digitação. É rápido de escrever.

  • Curtir 1
  • Obrigado 1
Postado
35 minutos atrás, arfneto disse:

Mas nem precisa disso. Pode simplesmente desligar o eco e o LINE INPUT e ler com fgetc() as letrinhas uma por uma. É o mais flexível. Já te falei sobre isso. Se a letra for uma das que aceita então guarda e mostra. Se não for então pode tocar um bip e seguir lendo, sem mostrar nada.

Em geral o resultado é o mesmo para o caso, só que não uso fgetc() porque tenho que teclar Enter duas vezes. Dá pra chamar read() com o mesmo esquema, desabilitando echo e line input:

char LerChar(void)
{
    DWORD mode;
    int total = 0;
    int c = 0;

    HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
    if(h == NULL)
    {
        // GetStdHandle() falhou
        return '\0';
    }

    GetConsoleMode(h, &mode);
    SetConsoleMode(h, mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));

    ReadConsole(h, &c, 1, (LPDWORD)&total, NULL);

    SetConsoleMode(h, mode);

    if(total > 0)
    {
        if(c == '\r')
            c = '\n';
        return (char)c;
    }
    else
    {
        // não leu nada
        return '\0';
    }
}

LerInt() e LerFloat() do código que postei avaliam o caractere digitado que é inserido na string caso o valor resultante após a inserção esteja dentro do intervalo.

  • Curtir 1
Postado
1 minuto atrás, Lucca Rodrigues disse:

Em geral o resultado é o mesmo para o caso, só que não uso fgetc() porque tenho que teclar Enter duas vezes. Dá pra chamar read() com o mesmo esquema, desabilitando echo e line input:

 

LINE INPUT no Windows é que faz isso: esperar o ENTER

 

E usaria fread mesmo, ou fgetc. Pode deixar a questão do sistema operacional resolvida no início e assim usar o mesmo código em Windows MAC ou Linux

  • Curtir 1
Postado

@MarianaN Olá.

Essa falha e outras são detectáveis, quase senão por todos, os compiladores. Para isso, incremente suas opções de Alerta [consulte o manual do IDE] para todos [-Wall] erros [-Werror]. Com isso será praticamente educado(a) pelo compilador, algo que é quase sempre o suficiente.

 

Veja

Uma imagem da falha

image.png.dccf5265a85a9a98881275b1fff296eb.png

Com esses alerta, além de detecta a falha, exercita o inglês convenientemente!

[:)]  

  • Curtir 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!