【问题标题】:Why is return 0 not working in this case? [duplicate]为什么在这种情况下 return 0 不起作用? [复制]
【发布时间】:2021-02-08 11:19:06
【问题描述】:

我最近开始向 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 不能做我想做的事。我接受了建议使用换行符作为终止程序的信号的答案,因为这与我的想法最接近。谢谢大家。

【问题讨论】:

  • 你是如何输入“EOF”的?
  • 看起来“只复制一次”对你来说很重要,而且你对“一次”有一些特殊的定义。通常,“读取文件一次”意味着在文件末尾停止,这正是您的程序所做的。请澄清“一次”对您意味着什么。你可以edit你的帖子解释一下。
  • @FakeMod 你认为程序如何知道它应该何时结束?完全不清楚你想要什么。
  • 问题是计算机不知道“第一次输入”是什么意思。似乎您已将其定义为“从剪贴板进行一次粘贴操作”(ctrl-z),但程序无法知道文本是来自剪贴板还是来自键盘,因此您不能拥有那种功能。
  • @FakeMod 同样,您应该能够阅读 EOF 几次 次。点击 EOF 后,您将使用clearerr 清除 EOF 和错误指示器s,然后您可以再次循环。此外,一些“粘贴检测”代码是可能的 - 如果您快速连续获得几行代码,那么用户肯定没有粘贴它们,因为即使是最快的打字员也可能不会每秒写一行。

标签: c loops while-loop return infinite-loop


【解决方案1】:

由于您只想读取一行输入,因此可以在行尾字符 '\n' 处终止循环。

c = getchar();

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

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

c = getchar();

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

如果你想从文件/终端读取第一行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;
    }
}

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

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

【讨论】:

    【解决方案2】:

    这段代码在运行时运行良好,但程序永远不会停止。

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

    while (c != EOF)
    

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

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

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

    #include <stdio.h>
    
    int main()
    
    {
        int c;
        c = getchar();
    
        while (c != EOF && c!= 'A') {
            putchar(c);
            c = getchar();
        }
    }
    

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

    【讨论】:

    • 你的情况没有任何意义。这将永远是真的。你需要&amp;&amp;,而'A"有错别字
    • 对不起,我犯了错误,我更正答案
    【解决方案3】:

    对于初学者来说这个循环

    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 如果主函数的返回类型是兼容的类型 int,从初始调用返回到主函数是等价的 使用 main 返回的值调用 exit 函数 函数作为它的参数;11) 到达终止 main 的 } 函数返回值 0。

    例如这两个程序

    int main( void )
    {
        return 0;
    }
    

    int main( void )
    {
    }
    

    有效且等价。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 感谢您的解决方案,但在涉及换行符的情况下,此解决方案会失败,或者至少无法按预期工作。例如,如果我打算复制以下文本块(换行符在此处不起作用,因此我也在我的问题中包含此文本块):“我的代码 [Enter] 不起作用所以 [Enter][Enter] 我是在此处询问 [Enter] 寻求帮助”该程序仅复制第一行(如预期的那样)。因此,它在这种情况下“失败”。我不希望这种情况发生。有什么办法可以保留复制多行文本的功能,并在一次输入后退出程序?
      • @FakeMod 它认为您需要了解 EOF 的含义。实际上,您问题中的第三版 progtam 正是您想要的。您可以输入多行,每行都会回显,但您需要告诉程序输入在某个时间结束,因此您需要按 Ctrl+Z 和 Enter。无论如何,这真的不清楚你想要什么。编辑您的问题并添加一些输入/输出示例。
      • 请看我的编辑(虽然它相当于我的第一条评论)。至于您评论的最后一部分,我正在使我的标准更加清晰(通过示例和更好的措辞),谢谢。
      【解决方案5】:

      您的return 0 不会产生任何影响,因为执行将保留在while 中,直到c 变为EOF。所以你需要使c 等于EOF。根据操作系统尝试 ctrl-D 或 ctrl-Z。

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

      引入如下计数器:

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

      【讨论】:

      • 是的,我可以通过按“Ctrl + C”(适用于任何地方)或按“Ctrl + Z”(仅适用于此处)来终止程序,但这不是我想要做的。我希望程序在复制一次后自行结束。
      • @FakeMod Ctrl+C 是不同的东西。它终止程序。 Ctrl-ZCtrl-D 应该在 stdin 中提供 EOF,使程序自行终止。
      • @FakeMod,问题是“EOF”表示“文件结束”,但您的程序正在从终端读取而不是文件,所以没有结束。你用这里给出的建议来模拟结束(对你来说,CTRL+Z)。
      • @Elliott 是的,EOF 确实表示“文件结束”。有什么方法可以让我在标准中使用“输入结束”?
      • @FakeMod,您的程序如何知道输入何时结束? C被设计成模块化的。它将您的输入视为文件。认为它不知道它的输入来自标准输入(终端),而是学会适应 ctrl+d 或 ctrl+z 来告诉它停止。这不是一个骇人听闻的解决方案。这就是它应该如何工作的方式。
      【解决方案6】:

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

      【讨论】:

      • 谢谢大卫。这很有帮助,但我如何在这里实现计数器?我不知道我的程序在第一次输入时会接收多少个字符,所以我现在也不知道我需要重复循环多少次。至于你的最后一行,为什么使用while(1) 不是一个好习惯?
      • while(1) 真的不是好习惯吗?为何如此?我一直在使用它。
      • 我认为如果你不知道你会收到多少个字符,最好的选择是设置一个转义字符,就像我说的 e 字符之类的。不管怎样,我给你看一个计数器的例子: int main() { int c; c = getchar();整数计数器=0; while (counter
      • 回应 Elliot,while(1) 仅对计划在同一段代码中一直执行的程序有用。它主要用于Arduino编程和其他设备。但总的来说,这会使代码更难理解,如果必须退出循环,就必须使用 go to 或 break 指令,这些都不是好的做法。
      猜你喜欢
      • 2018-08-28
      • 1970-01-01
      • 2021-06-03
      • 1970-01-01
      • 2015-05-20
      • 2017-11-26
      • 2010-12-29
      • 1970-01-01
      • 2021-08-05
      相关资源
      最近更新 更多