Ir ao conteúdo
  • Cadastre-se

C Utilização de scanf e EOF


kampa896

Posts recomendados

Pessoal, boa noite.

Estou com uma dúvida sobre a utilização do EOF durante leitura com scanf. O sistema é Linux, Ubuntu 20.04.

 

Graças ao pessoal do Fórum, adquiri uns livros sobre linguagem C e estou iniciando meus estudos. Já entendi que o C deixa grande parte dos erros cometidos pelo programador e roda a aplicação mesmo assim. Companheiros aqui do fórum me ensinaram a melhorar o desempenho do compilador, com um comando de otimização, para localizar os erros que possam ocorrer. Porém mesmo assim, o problema roda normalmente.

Estou com dificuldade para entender o macro EOF após uma tentativa de leitura com scanf. O scanf retorna o número de itens que ele conseguiu ler e atribuir com êxito, a um valor. Caso ocorra algum problema na leitura, retorna EOF.

Porém, um exemplo de código abaixo, ele não registra o erro e apesar do loop com condição falsa, roda normalmente. Alguém poderia me ajudar?

#include <stdio.h>

int main() {

    unsigned short int reclamar;


    while(scanf("%hd", &reclamar) != EOF){
        if(reclamar == 0){
            printf("vai ter copa!\n");
        }
        else{
            printf("vai ter duas!\n");
        }

    }

    return 0;
}

 

Captura de tela de 2020-10-11 01-47-54.png

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

2 horas atrás, kampa896 disse:

Já entendi que o C deixa grande parte dos erros cometidos pelo programador e roda a aplicação mesmo assim.

 

Essa afirmação não está totalmente correta. C é uma linguagem com um conjunto de regras bem específico e não vai compilar quando a primeira delas for violada. Não há exceção. Não apenas C mas muitas outras linguagens da mesma família não podem reger problemas que estejam fora do seu escopo. Por exemplo, um erro de lógica do programador, escrito com a sintaxe correta, é um programa perfeitamente compilável mas vai produzir o resultado errado. Outro exemplo, um erro durante o tempo de execução é completamente alheio ao compilador.

 

No seu caso o programa compilou? caso positivo, ele não possui erros semânticos mas o compilador não sabe nem o objetivo do programa ou se ele foi construído com a lógica correta pra atingir esse resultado. Essa é a sua função e não do C.

 

Veja, no caso em tela, EOF significa "end of file", ou seja, fim do arquivo. Qual é o arquivo cujo final você está checando? caso você não saiba responder essa pergunta, o compilador tampouco vai saber. Caso você responda que está testando o final do arquivo stdin, então, eu poderia perguntar em seguida: você abriu esse arquivo? você testou se o arquivo está devidamente aberto? você sabe quantas linhas há nele? caso não saiba responder a esta pergunta também, advinha? o compilador tampouco. Caso você tenha respondido "não" pra alguma dessas perguntas, não há razão pro seu programa funcionar, aliás há uma grande chance dele não funcionar. Seja em C ou em Python.

 

E se, por exemplo, toda vez que você digitar uma entrada no teclado, a shell do Ubuntu está adicionando uma nova linha ao buffer que representa a stdin? então nunca iriamos atingir o final do arquivo.

 

Então, como você não sabe como a shell do Ubuntu está implementando o arquivo de entrada do seu programa, seria bom programar uma lógica que não dependesse desse arquivo. Por exemplo,

 

while (scanf("%hd", &reclamar) == 1)

 

Ou seja, ao invés de testar o final de um arquivo completamente desconhecido, você poderia tentar uma lógica segura, no caso, instruindo scanf a ler um short int e, em qualquer outro caso (retornando 0), induzir a execução a terminar.

 

E por fim, dependendo da implementação do scanf que você está utilizando, ela retornaria EOF apenas se houvesse um erro de leitura do stdin antes de guardar a entrada em reclamar. Um erro bem raro de acontecer. Caso contrário ela retornaria infinitamente, com 1 elemento lido ou 0 elementos lidos.

  • Curtir 1
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

8 horas atrás, kampa896 disse:

o macro EOF

 

EOF é apenas uma constante. Se usa um IDE moderno ele deveria mostrar isso para você apenas ao parar o mouse sobre o símbolo

 

image.png.6ba72adb847157e2a24ba0a947136ece.png

 

8 horas atrás, kampa896 disse:

Porém, um exemplo de código abaixo, ele não registra o erro e apesar do loop com condição falsa, roda normalmente

 

scanf() não foi escrita para ler do teclado. Foi escrita, como diz o nome, para ler entrada formatada --- scan formatted input.

 

O que seria um erro? Não ler nada? Isso é uma situação normal de programa.

escreva algo assim:
 

Citação

int main(void)
{
    unsigned short int reclamar;
    do
    {
        printf("Valor: ");
        int res = scanf("%hd", &reclamar);
        switch (res)
        {
        case EOF:
            printf("fim de arquivo!\n");
            return 0;
            break;
        case 0:
            printf("Nao leu nada!\n");
            break;
        case 1:
            if (reclamar == 0)
            {
                printf("vai ter copa!\n");
            }
            else
            {
                printf("vai ter duas!\n");
            };
            break;
        default:
            break;
        };  // switch()

 

8 horas atrás, kampa896 disse:

Já entendi que o C deixa grande parte dos erros cometidos pelo programador e roda a aplicação mesmo assim

 

Não, não é o caso. O compilador compila seguindo uma sintaxe e uma gramática rígida.

A definição de um erro como o que imagina está na lógica do programa...

 

Essa ideia de que C seja, digamos, excessivamente permissiva vem do propósito da linguagem, que foi escrita para escrever sistemas. 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Como sempre, vocês salvando a minha pele. Obrigado @V1OL4DOR e @arfneto.

 

Entendi as colocações de vocês e cada dia mais ampliando meu entendimento em linguagem C.

 

Só uma última dúvida. Se eu instanciei uma variável com unsigned short int, e a leitura pela teclado foi de um outro valor, que não é compatível, tipo um inteiro muito grande ou um inteiro negativo, já não tinha que ter erro de leitura e o programa parar?

 

Ou é apenas o erro de leitura realmente, como o @V1OL4DOR explicou? Que é raro de acontecer. Apesar de ter lido uma variável incompatível com o tipo criado, o stdin leu, apenas não armazenou. E por isso não retornaria EOF. É isso?

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

1 minuto atrás, kampa896 disse:

Se eu instanciei uma variável com unsigned short int, e a leitura pela teclado foi de um outro valor, que não é compatível, tipo um inteiro muito grande ou um inteiro negativo, já não tinha que ter erro de leitura e o programa parar

 

Isso não é um erro de leitura para o programa ou para scanf(). Você não deveria usar scanf() para ler do teclado, como eu disse: o propósito de scanf() é outro.

 

scanf() tem um objetivo a atender: a quantia de especificadores, aquelas coisas com um único % e sem asterisco. Se for para ler %d,%d,%d a função vai tentar ler 3 valores inteiros separados por vírgula.

 

E pode retornar 0,1,2 ou 3. Ou -1 para EOF ou algum erro. 

 

Se deu erro mesmo seria reportado na variável errno e você poderia mostrar usando perror() como é o normal em C. 

 

Mas a noção de erro do sistema é diferente da sua. Por exemplo, se está lendo um int e o cara digita 30 letras e um enter scanf() vai retornar zero. Só isso. Não leu nada. Como ninguém testa o retorno pelo que eu vejo nestes forums, o programa simplesmente continua e dá tudo errado... 

 

Um erro seria você estar usando scanf() para ler de um pen-drive e você tirar o drive da máquina no meio do programa. coisas assim. Teste.

  • Curtir 1
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

13 minutos atrás, kampa896 disse:

Só uma última dúvida. Se eu instanciei uma variável com unsigned short int, e a leitura pela teclado foi de um outro valor, que não é compatível, tipo um inteiro muito grande ou um inteiro negativo, já não tinha que ter erro de leitura e o programa parar?

 

Caso a entrada possua um tipo diferente daquele para o qual scanf foi instruída a ler, ela retornaria 0, indicando que leu zero elementos. Caso sejam vários elementos, ela retornaria então o numero de elementos lidos com sucesso, que pode não ser o total requerido, ou mesmo zero se nenhum dos elementos é compatível. 

 

13 minutos atrás, kampa896 disse:

Ou é apenas o erro de leitura realmente, como o @V1OL4DOR explicou? Que é raro de acontecer.

 

O erro de leitura seria se, repentinamente, o arquivo stdin aberto automaticamente quando o programa começou a executar não pudesse ser lido. Então scanf indicaria o problema retornando EOF, que frequentemente equivale a -1 (depende do compilador).

 

O uso de EOF faz mais sentido pra irmã de scanf, a função fscanf (file scan formatted), operando num arquivo manipulado pelo usuário. Seria muito raro ocorrer um erro com stdin, stdout e stderr, arquivos manipulados automaticamente.

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

18 minutos atrás, V!OLADOR disse:

stdout e stderr

 

Entenda que:

  • stdout e stderr são fluxos de saída então a noção de fim de arquivo fica, digamos, prejudicada  ;) e não se aplica.
     
  • No caso de stdin o fim de arquivo é sinalizado na leitura  pela digitação de contrrol-Z.
     
  • Não se , esqueça que a entrada padrão pode ser redirecionada como em
            Type x.txt | programa 
    no windows e o fim de arquivo em x.tt seria EOF na entrada padrão, claro.
     
22 minutos atrás, V!OLADOR disse:

para o qual scanf foi instruída a ler, ela retornaria 0, indicando que leu zero elementos. Caso sejam vários elementos, ela retornaria então o numero de elementos lidos com sucesso

 

Esses "elementos" são os especificadores na mascara de leitura, os campos com um % e sem asterisco, como eu disse. 

 

E o erro é sinalizado via errno, uma variável global. E pode ser "traduzido" por perror() ou strerr(errno)

 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Caramba, pessoal. Muito obrigado. Entendi perfeitamente agora o que seria um EOF. E sim, algumas coisas eu ainda não entendi, mas tenho certeza que no momento certo as dúvidas surgirão e qualquer coisa recorro a vocês novamente.

 

Mais uma vez, muito obrigado pelo tempo e atenção de vocês, @V1OL4DOR e @arfneto!

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

Bom dia,

 

Muito legal a discussão (alto nível), mas fiquei curioso com afirmação no primeiro 'post', curioso no sentido de como chegou aquela conclusão, e no final qual é a sua nova (e correta) conclusão, porém endorfinas foram liberadas e cada um para o seu lado, naturalmente.

"

 

Ainda assim, meu palpite para sua conclusão original...

Em 11/10/2020 às 01:51, kampa896 disse:

Pessoal, boa noite. [...]

 

Estou com dificuldade para entender o macro EOF após uma tentativa de leitura com scanf. O scanf retorna o número de itens que ele conseguiu ler e atribuir com êxito, a um valor. Caso ocorra algum problema na leitura, retorna EOF. Porém, um exemplo de código abaixo, ele não registra o erro e apesar do loop com condição falsa, roda normalmente. Alguém poderia me ajudar?

 

 

é que veio de uma redação como esta

Citação

7.21.6.4

§ 3º  The scanf function returns the value of the macro EOF if an input failure occurs before the first conversion (if any) has completed. Otherwise, the scanf function returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching
failure.

 

Tradução Eletrônica

A função scanf retorna o valor da macro EOF se uma falha de entrada ocorrer antes do primeiro conversão (se houver) foi concluída. Caso contrário, a função scanf retorna o número de itens de entrada atribuído, que pode ser menor do que o previsto, ou mesmo zero, no caso de uma correspondência antecipada falha.

 

 

Perceba que mesmo com a tradução ruim no final, ainda é possível notar, uma certa clareza, que existem categorias de falhas.

 

Falha de entrada e

Falha de correspondência, são duas categorias de falhas já discutidas; minha atenção foi para o equivoco que se comente ao enxergar duas como uma.

"

 

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

4 horas atrás, kampa896 disse:

Eu não tinha entendido o porque o EOF não retornava ao inserir uma variável de tipo diferente da declarada.

Mas os companheiros aqui já me explicaram e estão me ajudando muito no estudo da linguagem C.

 

Agora que entendeu o  problema pode ajuda dando sua resposta no final dessa discussão assim ajudará outros, que igual a mim, vierem em busca do resultado e não a conversa toda.

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Em 11/10/2020 às 03:53, V!OLADOR disse:

E por fim, dependendo da implementação do scanf que você está utilizando, ela retornaria EOF apenas se houvesse um erro de leitura do stdin antes de guardar a entrada em reclamar. Um erro bem raro de acontecer. Caso contrário ela retornaria infinitamente, com 1 elemento lido ou 0 elementos lidos.

@mauro_b o entendimento do exercício é exatamente o que o nosso colega citou aqui em cima, não entendi sua pergunta. A conversa toda é explicação do problema, a resposta não está apenas em uma mensagem, leia tudo que entenderá o assunto.

  • Curtir 1
  • Triste 1
Link para o comentário
Compartilhar em outros sites

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...