为什么 return 0 在这种情况下不起作用?

Why is return 0 not working in this case?

我最近开始从 Brian KernighanDennis RitchieThe C Programming Language 那里学习 C。在那本书中,有一个完整的小节(1.5.1,第 2 版),作者在其中创建了一个文件复制程序(但我将其用作文本(由用户输入)复制程序)。他们的代码基本上是这样的

#include <stdio.h>

int main()

{
    int c;
    c = getchar();

    while (c != EOF) {
        putchar(c);
        c = getchar();
    }
}

此代码在 运行 时运行良好,但程序永远不会停止。该程序一直在等待输入并继续复制它们,无休止地,永不终止。现在我想创建一个程序,让这种无休止的复制终止。为此,我稍微调整了代码。这是我的代码

#include <stdio.h>

int main()

{
    int c;
    c = getchar();

    while (c != EOF) {
        putchar(c);
        c = getchar();
    }

    return 0;

}

我认为在末尾显式写入 return 0; 可能会完成这项工作,但输出似乎根本没有改变。我还尝试使用 if-else 条件并将它们循环如下

#include <stdio.h>

int main()

{
    int c;
    c = getchar();

    while (1) {

        if (c != EOF){
            putchar(c);
            c = getchar();
        }

    else
        return 0;
    }
}

但在这种情况下,程序也完全没有改变。

我的问题是如何更改代码,以便我的程序在复制一次后立即结束(或者,更好的是,将其概括为复制 n 次)?

在这里,我必须澄清“一次”(或“n 次”)的意思。当我使用命令提示符(我使用 Windows)来 运行 编译文件时,程序需要一个输入。我通过键盘输入,然后按 Enter 以查看复制的输入。在此之后,程序再次要求我输入一些内容。我不希望这发生。我希望程序在复制我的输入一次后自行结束。这就是我所说的“一次”的意思(上面的定义也可以很容易地扩展为“n 次”)。


@anatolyg@Jabberwocky 建议使用 \n(新行转义字符)使程序运行。但是当输入包含换行符时,此解决方案失败,例如

我的代码可以
这么不行

我在问
在这里寻求帮助

将其作为输入复制到命令提示符中,并使用上述两个用户建议的程序只产生 my code does 作为输出,这不是我想要的输出。有什么办法可以让这个程序适用于带有换行符的文本块,并让它在一次输入后停止(在这种情况下,整个文本块只是一个输入)?


和这里的其他人交流后,我发现我对“一次输入”或“一次”的定义很模糊,不明确,一点也不具体。因此,C 不能做我想让它做的事,这只不过是预料之中的事情。我接受建议使用换行符作为终止程序的信号的答案,因为这与我的想法最接近。谢谢大家

您的 return 0 不会产生任何影响,因为执行将停留在 while 直到 c 变为 EOF。所以你需要让 c 等于 EOF。根据 OS.

尝试 ctrl-D 或 ctrl-Z

My question is that how do I change the code so that my program ends just after copying once (or, even better, generalising it to copying n times)?

引入一个像这样的计数器:

#define MAX_INPUTS 10

...

int cnt = 1;
while (c != EOF && cnt < MAX_INPUTS) {
    putchar(c);
    c = getchar();
    ++cnt;
}

This code works fine when run, but the program never stops.

这不是真的,如果你不满足while语句的条件:

while (c != EOF)

程序将终止。 现在如何将 EOF 发送到输入?

视情况而定。您要对 EOF 执行哪个标准输入操作?如果标准输入是终端输入,只需按 control-D。如果您要发送的唯一内容是 EOF,请使用 echo -n | (your program)。如果你从你的 C 程序发送它,你几乎无法退出程序,此时它的 stdout 的状态将是 EOF,这将反映在它被重定向到的任何 stdin 中。我很确定你不能在没有获得底层缓冲区的情况下从 C 中发送 EOF,这不是标准化的,因此会让你做一些肮脏的编程。

另一种解决方案是在 while 条件中签入或一些可数字字符,例如:

#include <stdio.h>

int main()

{
    int c;
    c = getchar();

    while (c != EOF && c!= 'A') {
        putchar(c);
        c = getchar();
    }
}

在这种情况下,如果您输入“A”,程序将结束。

函数 getChar() 在这种情况下总是在等待新字符,在这种情况下 c 永远不会获得 EOF 值。您可以设置一个字符来完成(例如 'e' 退出),或者您可以在退出循环时用计数器计数。不要使用 while(1) 因为这不是一个好习惯。

Ypur 最新编辑建议您可能需要这样的东西:

#include <stdio.h>

int main()    
{
  int c;
  c = getchar();

  while (1) {
    if (c != EOF && c != '\n') {  // '\n' is End of line (Enter)
      putchar(c);
      c = getchar();
    }

    else
      return 0;
  }
}

或更简单:

int main()
{
  do
  {
    int c = getchar();

    if (c != EOF && c != '\n') {  // '\n' is End of line (Enter)
      putchar(c);
    }
    else
    {
      return 0;
    }
  } while (1);
}

对于初学者来说这个循环

while (c != EOF) {
    putchar(c);
    c = getchar();
}

不是无穷无尽的。 while循环中有一个条件,如果不满足则循环终止。

要生成等于 EOF 的函数 getchar 的输出,您应该在 Windows 中输入组合键 Ctrl + c 或在 Unix 系统中输入组合键 Ctrl + d。

在循环体中或循环后添加 return 语句不会主要影响程序控制流。

注意main中的return语句可以省略。来自 C 标准(5.1.2.2.3 程序终止)

1 If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument;11) reaching the } that terminates the main function returns a value of 0.

例如这两个程序

int main( void )
{
    return 0;
}

int main( void )
{
}

有效且等效。

由于您只想读取一行输入,因此可以在 end-of-line 字符 '\n'.

处终止循环
c = getchar();

while (c != '\n') {
    putchar(c);
    c = getchar();
}

如果您使用 Windows 终端向您的程序输入数据,这就足够了。如果您将输入重定向到您的程序,以便它来自文件,它将读取文件直到第一个换行符。但是,如果文件不包含换行符,您的程序将在文件末尾得到 EOF。所以终止条件也应该检查 EOF.

c = getchar();

while (c != '\n' && c != EOF) {
    putchar(c);
    c = getchar();
}

如果您想阅读 file/terminal 的前 n 行,您需要一个计数器。那么你的代码会变得有点复杂,我认为中间有退出的无限循环会是一个更好的实现。

int line_counter = 0;
int max_lines = 5;

while (1) {
    int c = getchar();
    if (c == EOF)
        break;

    putchar(c);

    if (c == '\n')
    {
        ++line_counter;
        if (line_counter == max_lines)
            break;
    }
}

另一种分隔输入的方法是使用空行。这将输入格式重新定义为具有文本“段落”。这会使代码更复杂一些——它还应该保存它读取的前一个字符。要检测标记段落结束的空行:如果前一个字符和当前字符都是 end-of-line 个字符,则文本段落刚刚结束。

int record_counter = 0;
int max_records = 5;
int prev_c = '\n';

while (1) {
    int c = getchar();
    if (c == EOF)
        break;

    putchar(c);

    if (prev_c == '\n' && c == '\n')
    {
        ++record_counter;
        if (record_counter == max_records)
            break;
    }

    prev_c = c;
}