太长不看

太长不看

这是我的 C 源代码。

当我在 Ubuntu 中构建它时,它开始获取字符,但我不知道如何结束该程序,因为它不能通过输入ENTER或回车来结束。

EOF 是什么意思?我该如何触发它?

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);
}

答案1

太长不看

通常,您可以在终端中运行的程序中,在最后一次输入刷新后立即使用CTRL+键来“触发 EOF”。D


EOF 是什么意思?我该如何触发它?

EOF 表示文件结束。

在这种情况下,“触发 EOF”大致意味着“让程序意识到不会再发送任何输入”。

在这种情况下,由于getchar()如果没有读取任何字符就会返回负数,因此执行终止。

但这不仅适用于您的特定程序,也适用于许多不同的工具。

一般来说,“触发 EOF”可以在最后一次输入刷新之后立即通过CTRL+键来完成(即通过发送一个空输入)。D

例如cat

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

CTRL当按下+时,底层发生的情况D是,自上次输入刷新以来输入的内容被刷新;当这恰好是一个空输入时,read()在程序的 STDIN 上调用的系统调用0getchar()返回一个负数(-1在 GNU C 库中),而这又被解释为 EOF 1


1 -https://stackoverflow.com/a/1516177/4316166

答案2

总结:EOF 不是字符,它是用于评估输入读取函数的负返回值的宏。可以使用Ctrl+D发送EOT字符,这将强制函数返回-1

每个程序员都必须阅读手册

让我们参考 Harbison 和 Steele 编写的《CA 参考手册》,1995 年第 4 版,第 317 页:

负整数 EOF 是一个不是“真实字符”编码的值。。。例如 fget(第 15.6 节)返回 EOF当到达文件末尾时,因为没有可读取的“真实字符”。

本质上EOF不是一个角色,而是一个整数值实现来stdio.h表示-1。因此,kos 的答案就这一点而言是正确的,但它与接收“空”输入无关。重要的是要注意,这里的 EOF 充当返回值(的getchar())比较,不表示实际字符。man getchar支持:

返回值

fgetc()、getc() 和 getchar() 将读取的字符作为无符号字符返回,并在文件末尾或出现错误时转换为 int 或 EOF。

如果成功则 gets() 和 fgets() 返回 s,如果出错或到达文件末尾而未读取任何字符则返回 NULL。

如果成功则 ungetc() 返回 c,如果出错则返回 EOF。

考虑while循环——它的主要目的是重复动作如果括号中的条件为真。再看一下:

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

它基本上是说如果 c = getchar()返回成功代码(0或以上;顺便说一下,这很常见,尝试运行成功的命令,然后echo $?失败echo $?并查看它们返回的数字),则继续执行操作。因此,如果我们成功获取字符并赋值给 C,则返回的状态代码为 0,失败为 -1。EOF定义为-1。因此,当条件-1 == -1发生时,循环停止。什么时候会发生这种情况?当没有更多字符可获取时,即c = getchar()失败时。您可以编写它while ((c = getchar ()) != -1),它仍然可以工作

另外,让我们回到实际的代码,下面是摘录自stdio.h

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

ASCII 代码和 EOT

尽管 EOF 字符不是实际字符,但是存在一个EOT(传输结束)字符,其 ASCII 十进制值为 04;它与Ctrl+D快捷方式(也表示为元字符^D)相关联。传输结束字符用于表示在计算机用于控制电话连接时关闭数据流,因此得名“传输结束”。

因此可以像这样将该 ascii 值发送给程序,注意哪个$'\04'是 EOT:

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

因此,我们可以说它确实存在,但不可打印

边注

我们常常忘记,过去的计算机并不像现在这样多功能——设计师必须利用每个可用的键盘键。因此,EOT使用 CtrlD 发送字符仍然是“发送一个字符”,与键入大写字母 A、ShiftA 不同,您仍然可以通过可用的键为计算机提供输入。因此,EOT 是一个真正的字符,因为它确实来自用户,计算机可以读取(但不能打印,人类看不到),它存在于计算机内存中

字节指挥官的评论

如果您尝试从 /dev/null 读取,也应该返回 EOF,对吗?或者我在那里得到了什么?

是的,完全正确,因为/dev/null没有实际的字符要读取,因此它将c = getchar()返回-1代码,程序将立即退出。再次命令不返回 EOF。EOF 只是等于 -1 的常量变量,我们用它来比较 getchar 函数的返回码.EOF并不以字符形式存在,它只是里面的一个静态值stdio.h

演示:

# 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

棺材上又钉上一颗钉子

有时会尝试用如下代码来证明 EOF 是一个字符:

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

问题在于 char 数据类型可以是有符号或无符号值。此外,它们是最小可寻址数据类型,这使得它们在内存有限的微控制器中非常有用。因此,在int foo = 25;内存较小的微控制器或类似情况下,通常会使用声明而不是声明char foo = 25;。此外,字符可以是有符号的,也可以是无符号的

可以使用如下程序来验证字节大小:

#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

重点到底是什么?重点是 EOF 定义为 -1,但是char 数据类型可以打印整数值

好的。。。那么如果我们尝试将字符打印为字符串会怎么样?

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

显然是一个错误,但尽管如此,错误会告诉我们一些有趣的事情:

skolodya@ubuntu:$ gcc EOF.c -o EOF
EOF.c: 在函数‘main’中:EOF.c:4:5: 警告:格式‘%s’需要类型为‘char *’的参数,但参数 2 的类型为 'int' [-Wformat=] printf("%s",EOF);

十六进制值

将 EOF 打印为十六进制值将得到FFFFFFFF,一个 16 位(8 字节)的值,即 的二进制补码-1

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

输出:

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

以下代码还发生了另一件奇怪的事情:

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

如果按下Shift+ A,我们会得到十六进制值 41 ,显然与 ASCII 表中的值相同。但对于Ctrl+ D,我们再次得到——存储在 中ffffffff的返回值。getchar()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

参考其他语言

请注意,其他语言可以避免这种混淆,因为它们对函数退出状态进行评估,而不是将其与宏进行比较。如何在 Java 中读取文件?

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

那 Python 怎么样?

with open("/etc/passwd") as file:
     for line in file:
          print line

答案3

末梢血代表文件结尾。虽然我不知道如何触发以下符号,但你可以通过管道文件来运行以下程序,它会发送末梢血最后信号:

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

a.out你的编译源代码在哪里

相关内容