-2

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

4

6 回答 6

5

return 0不会有任何区别,因为执行将一直while持续到cEOF。所以你需要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;
}
于 2020-10-26T07:48:17.560 回答
2

对于初学者这个循环

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

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

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

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

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

1 如果主函数的返回类型是与int兼容的类型,则从初始调用主函数返回相当于以主函数返回的值作为参数调用exit函数;11)到达}终止主函数返回值 0。

所以例如这两个程序

int main( void )
{
    return 0;
}

int main( void )
{
}

是有效的和等效的。

于 2020-10-26T08:08:54.530 回答
1

此代码在运行时工作正常,但程序永远不会停止。

如果您不满足 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”,程序将结束。

于 2020-10-26T07:49:35.493 回答
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);
}
于 2020-10-26T08:04:25.120 回答
1

由于您只想读取一行输入,因此可以在 end-of-line character 处终止循环'\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;
}
于 2020-10-26T08:09:39.830 回答
0

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

于 2020-10-26T07:50:18.187 回答