O que é o EOF e como acioná-lo? [fechadas]

8

Este é o meu código-fonte C.

Quando eu o construo no Ubuntu, ele começa a pegar caracteres, mas eu não sei como terminar o programa, pois ele não termina inserindo ENTER ou um retorno de carro.

O que significa EOF? Como posso ativá-lo?

Esta fonte também está em um livro de Dennis Ritchie:

#include <stdio.h>
    /* count digits, white space, others */
main ()
{
  int c, i, nwhite, nother;
  int ndigit[10];
  nwhite = nother = 0;
  for (i = 0; i < 10; ++i)
    ndigit[i] = 0;
  while ((c = getchar ()) != EOF)
    if (c >= '0' && c <= '9')
      ++ndigit[c - '0'];
    else if (c == ' ' || c == '\n' || c == '\t')
      ++nwhite;
    else
      ++nother;
  printf ("digits =");
  for (i = 0; i < 10; ++i)
    printf (" %d", ndigit[i]);
  printf (", white space = %d, other = %d\n", nwhite, nother);
}
    
por stackprogramer 24.01.2016 / 13:11

3 respostas

18

Tl; dr

Você pode geralmente "disparar EOF" em um programa rodando em um terminal com um pressionamento de tecla CTRL + D logo após o último esvaziamento de entrada.

  

O que significa EOF? Como posso ativá-lo?

EOF significa fim de arquivo.

"Triggering EOF" neste caso significa "tornar o programa ciente de que nenhuma entrada será enviada".

Nesse caso, como getchar() retornará um número negativo se nenhum caractere for lido, a execução será finalizada.

Mas isso não se aplica apenas ao seu programa específico, ele se aplica a muitas ferramentas diferentes.

Em geral, "trigger EOF" pode ser feito com um pressionamento de tecla CTRL + D logo após o último flush de entrada (ou seja, enviando uma entrada vazia).

Por exemplo, com cat :

% cat >file # Hit ENTER
foo # Hit ENTER and CTRL+D
% 

O que está acontecendo sob o capô quando pressionar CTRL + D é que a entrada digitada desde a última descarga de entrada é liberada; quando isso acontece de ser uma entrada vazia, o read() syscall chamado no programa STDIN retorna 0 , getchar() retorna um número negativo ( -1 na biblioteca GNU C) e isso, por sua vez, é interpretado como EOF 1 .

1 - link

    
por kos 24.01.2016 / 13:32
3

TL; DR : o EOF não é um caractere, é uma macro usada para avaliar o retorno negativo de uma função de leitura de entrada. Pode-se usar Ctrl + D para enviar o caractere EOT , o que forçará a função retornar -1

Todo programador deve ter RTFM

Vamos nos referir ao "C A Reference Manual", de Harbison e Steele, 4ª ed. de 1995, página 317:

  

O inteiro negativo EOF é um valor que não é uma codificação de um "real   caractere "... Por exemplo, fget (seção 15.6) retorna EOF quando   no final do arquivo, porque não há "caractere real" para ser lido.

Essencialmente EOF não é um caractere, mas sim um valor inteiro implementado em stdio.h para representar -1 . Assim, a resposta de kos está correta, mas não se trata de receber entradas "vazias". Nota importante é que aqui o EOF serve como comparação valor de retorno (de getchar() ), para não significar um caractere real. O man getchar suporta isso:

  

VALOR DE RETORNO

     

fgetc (), getc () e getchar () retornam o caractere lido como não assinado     char cast para um int ou EOF no final do arquivo ou erro.

     

gets () e fgets () retornam s em sucesso e NULL em erro ou quando terminar     de arquivo ocorre enquanto nenhum caractere foi lido.

     

ungetc () retorna c em sucesso, ou EOF em erro.

Considere o loop while - seu objetivo principal é repetir a ação se a condição entre parênteses for verdadeira . Olhe de novo:

while ((c = getchar ()) != EOF)

Basicamente diz para continuar fazendo coisas se c = getchar() retornar código de sucesso ( 0 ou acima; é uma coisa comum, experimente executar um comando bem-sucedido, então echo $? e depois falha echo $? e ver números Retorna ). Portanto, se conseguirmos obter caractere e associar a C, o código de status retornado será 0, a falha será -1. EOF é definido como -1 . Portanto, quando ocorre a condição -1 == -1 , os loops param. E quando isso acontecerá? Quando não há mais caracteres para obter, quando c = getchar() falha. Você poderia escrever while ((c = getchar ()) != -1) e ainda assim funcionaria

Além disso, vamos voltar ao código real, aqui está um trecho de stdio.h

/* End of file character.
   Some things throughout the library rely on this being -1.  */
#ifndef EOF
# define EOF (-1)
#endif

Códigos ASCII e EOT

Embora o caractere EOF não seja um caractere real, no entanto, existe um caractere EOT (Fim da Transmissão), que tem um valor decimal ASCII de 04; ele está vinculado ao atalho Ctrl + D (representado também como meta caractere ^D ). O fim do caractere de transmissão usado para significar o fechamento de um fluxo de dados quando os computadores eram usados para controlar as conexões telefônicas, portanto, o nome do "fim da transmissão".

Portanto, é possível enviar esse valor ascii para o programa, anote o $'' que é o EOT:

skolodya@ubuntu:$ ./a.out  <<< "a,b,c $''"                                  
digits = 1 0 0 0 1 0 0 0 0 0, white space = 2, other = 9

Assim, podemos dizer que existe, mas não é imprimível

Nota lateral

Muitas vezes esquecemos que no passado os computadores não eram tão versáteis - os designers têm que usar todas as teclas do teclado disponíveis. Assim, o envio do caractere EOT com o CtrlD ainda está "enviando um caractere", não diferente de digitar maiúscula A, ShiftA, você ainda dá ao computador uma entrada com as teclas disponíveis. Assim EOT é um personagem real no sentido de que ele vem do usuário, é legível por computador (embora não seja imprimível, não visível por humanos), ele existe na memória do computador

Comentário do Byte Commander

  

Se você tentar ler de / dev / null, isso deve retornar um EOF também,   certo? Ou o que eu chego lá?

Sim, exatamente correto, porque em /dev/null não há nenhum caractere real a ser lido, portanto, c = getchar() retornará -1 code e o programa será encerrado imediatamente. Novamente, o comando não retorna EOF. EOF é apenas variável constante igual a -1, que usamos para comparar o código de retorno da função getchar . EOF não existe como caractere, é apenas um valor estático dentro de stdio.h .

Demo:

# cat /dev/null shows there's no readable chars
DIR:/xieerqi
skolodya@ubuntu:$ cat /dev/null | cat -A        

# Bellow is simple program that will open /dev/null for reading. Note the use of literal -1                                   
   DIR:/xieerqi
skolodya@ubuntu:$ cat readNull.c                                               
#include<stdio.h>

void main()
{
   char c;
    FILE *file;
    file = fopen("/dev/null", "r");

    if (file) 
    {
    printf ("Before while loop\n");
        while ((c = getc(file)) != -1)
            putchar(c);
    printf("After while loop\n"); 
    fclose(file);
    }
}

DIR:/xieerqi
skolodya@ubuntu:$ gcc readNull.c -o readNull                                   

DIR:/xieerqi
skolodya@ubuntu:$ ./readNull
Before while loop
After while loop

Outro prego no caixão

Às vezes, tenta-se provar que o EOF é um personagem com um código como este:

#include <stdio.h>
int main(void)
{
    printf("%c", EOF);
    return 0;
}

Problema com isso é que o tipo de dados char pode ser um valor assinado ou não assinado. Além disso, eles são os menores tipos de dados endereçáveis, o que os torna muito úteis em microcontroladores, onde a memória é limitada. Então ao invés de declarar int foo = 25; é comum ver em microcontroladores com pouca memória char foo = 25; ou algo parecido. Além disso, os caracteres podem ser assinados ou não assinados .

Pode-se verificar que o tamanho em bytes com um programa como este:

#include <stdio.h>
int main(void)
{
    printf("Size of int: %lu\n",sizeof(int));
    printf("Sieze of char: %lu\n",sizeof(char));
    //printf("%s", EOF);
    return 0;
}

skolodya@ubuntu:$ ./EOF                                                        
Size of int: 4
Sieze of char: 1

Qual é exatamente o ponto? O ponto é que o EOF é definido como -1, mas o tipo de dados char pode imprimir valores inteiros .

OK. . Então, e se tentarmos imprimir char como string?

#include <stdio.h>
int main(void)
{
    printf("%s", EOF);
    return 0;
}

Obviamente, um erro, mas mesmo assim, o erro nos dirá algo interessante:

  

skolodya @ ubuntu: $ gcc EOF.c -o EOF
  EOF.c: Na função "main": EOF.c: 4: 5: aviso: o formato "% s" espera   argumento do tipo "char *", mas o argumento 2 tem tipo "int"   [-formato =]        printf ("% s", EOF);

Valores hexadecimais

Imprimir EOF como um valor hexadecimal fornece FFFFFFFF , um valor de 16 bits (8 bytes), dois complementos de -1 .

#include <stdio.h>
int main(void)
{
    printf("This is EOF: %X\n", EOF);
    printf("This is Z: %X\n",'Z');
    return 0;
}

Saída:

DIR:/xieerqi
skolodya@ubuntu:$ ./EOF                                                        
This is EOF: FFFFFFFF
This is Z: 5A

Outra coisa curiosa ocorre com o seguinte código:

#include <stdio.h>
int main(void)
{
   char c;
   if (c = getchar())
    printf ("%x",c);
    return 0;
}

Se alguém pressionar Shift + A , obtemos o valor hexadecimal 41, obviamente igual ao da tabela ASCII. Mas para Ctrl + D , temos ffffffff , novamente - o valor de retorno de getchar() armazenado em c .

DIR:/xieerqi
skolodya@ubuntu:$ gcc  EOF.c -o ASDF.asdf                                      

DIR:/xieerqi
skolodya@ubuntu:$ ./ASDF.asdf                                                  
A
41
DIR:/xieerqi
skolodya@ubuntu:$ ./ASDF.asdf                                                  
ffffffff

Consulte outros idiomas

Observe que outras linguagens evitam essa confusão, porque elas operam ao avaliar um status de saída de função, não comparando-o com uma macro. Como se lê um arquivo em Java?

    File inputFile  = new File (filename);
    Scanner readFile = new Scanner(inputFile);
    while (readFile.hasNext())
        { //more code bellow  }

Que tal python?

with open("/etc/passwd") as file:
     for line in file:
          print line
    
por Sergiy Kolodyazhnyy 25.01.2016 / 01:44
2

EOF significa fim do arquivo . Embora eu não saiba como acionar o seguinte símbolo, você pode executar o seguinte programa através da canalização de um arquivo, que envia o sinal EOF no final:

echo "Some sample text" | ./a.out

onde a.out é sua fonte compilada

    
por Paulius Šukys 24.01.2016 / 13:32