为什么我需要键入两次 Ctrl-D 来标记文件末尾?

Why do I need to type Ctrl-D twice to mark end-of-file?

提问人:mualloc 提问时间:1/21/2014 最后编辑:mualloc 更新时间:8/21/2018 访问量:9157

问:

char **query; 
query = (char**) malloc ( sizeof(char*) );

int f=0;
int i=0,j=0,c;


while((c=getchar())!=EOF)
{      
    if(!isalpha(c))
        continue;

    if(f==1)
        query=(char**) realloc(query,(i+1)*sizeof(char*));

    query[i]=(char*) malloc(sizeof(char));
    query[i][j]=c;
    j++;


    while( (c=getchar())!=EOF&&c!=' '&&c!='\t' )
    {      

        query[i]=(char*) realloc(query[i],(j+1)*sizeof(char));

        query[i][j]=c;
        ++j;
    }   

    query[i][j]='\0';
    printf("%s\n",query[i]);
    if(c==EOF){

        break;
    }   

   ++i;
   f=1;
   j=0;
}

我希望上面的代码片段读取一行由空格和制表符分隔的字符串,直到一个 EOF,但它需要 2 个 EOF 才能结束循环。此外,字符串只能由字母字符组成。

我在大约 2 天里挣扎。 请提供一些反馈。

编辑:很可能是我在写最后一个字符串而不是回车键后按了 CTRL+D 键,但现在我按了 Enter,然后按 CTRL+D,它按预期工作。 但是,在最后一个字符串之后按一次 CTRL+D 后,我怎样才能将其更改为完成?

c eof getchar

评论

1赞 lurker 1/21/2014
它不需要两个 EOF 来结束循环。它只需要一个。在循环内部,当它确定尚未看到 EOF 时,有一个内部循环继续扫描输入。该内部循环也将在 EOF(只有一个)上停止,当遇到一个 EOF 时,后续循环将脱离循环。if(c==EOF)
1赞 1/21/2014
sizeof(char)永远是一个。并且不要强制转换 malloc() 的返回值
0赞 mualloc 1/21/2014
H2CO3 我认为 sizeof(char)=1 有问题,如果不强制执行 malloc 的返回值,它会返回 void。
3赞 Keith Thompson 1/21/2014
sizeof(char)==1语言绝对保证。如果不强制转换 的结果,则结果将隐式转换为赋值的目标类型。malloc()void*

答:

0赞 rullof 1/21/2014 #1

Return 键不会生成 EOF,这就是条件无法识别它的原因。您可以通过在 Windows 中按 + 或在 Unix 中按 + 来完成。getchar() != EOFCTRLZCTRLD

评论

2赞 Keith Thompson 1/21/2014
如果您使用的是 Ubuntu,请不要打扰 Control-Z;那只会暂停您的程序。
44赞 Keith Thompson 1/21/2014 #2

在类 Unix 系统上(至少在默认情况下),文件结束条件是通过在一行的开头键入或键入 Ctrl-D 两次(如果您不在行的开头)来触发的。Ctrl-D

在后一种情况下,您阅读的最后一行的末尾不会有 a;您可能需要允许这一点。'\n'

这是由 POSIX / The Open Group Base Specifications Issue 7 在第 11 节中(特别是 11.1.9)中(相当间接地)指定的:

EOF
输入上的特殊字符,如果 ICANON 标志是 设置。接收到后,所有等待读取的字节都会立即被读取 在不等待<换行符>的情况下传递到进程,并且 EOF 是 丢弃。因此,如果没有字节等待(即 EOF 发生在一行的开头),字节计数为零应为 从 read() 返回,表示文件结束指示。如果 ICANON 已设置,EOF 字符在处理时应丢弃。

POSIX 函数通过返回字节计数为零向其调用方指示文件结束(或错误)条件,指示没有更多要读取的数据字节。(在POSIX系统上,C是建立在POSIX和其他特定功能之上的。read()<stdio>read()

默认情况下,EOF(不要与 C 宏混淆)映射到 。在行的开头键入 EOF 字符(在输入的开头或换行符之后)会立即触发文件结束条件。键入 EOF 字符(而不是在行的开头)会导致该行上的上一个数据立即由下一个请求足够字节的调用返回;再次键入 EOF 字符会执行相同的操作,但在这种情况下,没有剩余的字节可供读取,并且会触发文件结束条件。行中间的单个 EOF 字符将被丢弃(如果已设置,则通常为)。EOFCtrl-Dread()ICANON

评论

0赞 mualloc 1/21/2014
你能提供你的答案吗?
1赞 Keith Thompson 1/21/2014
我无法找到这方面的参考资料(我稍后会再看)。但你可以自己尝试。在 shell 提示符下,键入 ,然后键入 ,然后键入 control-D 两次。输出应为 ,表示看到 3 个字符,其中 0 个是换行符。wcabcabc 0 1 3wc
0赞 Keith Thompson 1/21/2014
@nos:我敢肯定它在某个地方被记录下来。
1赞 Keith Thompson 1/30/2014
@mualloc: I've updated my answer to (try to) explain how POSIX implies you need to Ctrl-Ds. As for the downvote, I can't explain (I didn't downvote your question myself, and downvotes are anonymous by design), but your question as it's currently written is a bit unclear. I'll update the title in a moment; please check that it still reflects what you're asking.
1赞 Keith Thompson 1/30/2014
@mualloc: The downvote on your question is still there. I upvoted it. (You lose 1 rep point for each downvote, gain 5 for each question upvote, and gain 10 for each answer upvote; your question currently has a net score of 0 for which you've gotten a net 4 rep points.)
1赞 tlochner95 2/10/2018 #3

In the off chance that someone sees this that needs the help I've been needing... I had been searching, trying to figure out why I was getting this strange behavior with my while(scanf). Well, it turns out that I had . The editor I am using (Atom) automatically put a "\n" in my scan, with out me noticing. This took me hours, and luckily someone pointed it out to me.while (scanf("%s\n", string) > 0)