在 C 中解决 ÿ 文件结尾

Solve ÿ end of file in C

当我在 C 中将一个文件的内容复制到另一个文件时,在输出文件的末尾我有这个字符 ÿ。感谢这个论坛,我了解到它是 EOF 指示器,但我不知道该怎么做才能在输出文件中摆脱它。

这是我的代码:

second_file = fopen(argv[2], "w+");
while (curr_char != EOF)
{
    curr_char = fgetc(original_file);
    fputc(curr_char, second_file);
}
printf("Your file has been successfully copy\n");
fclose(second_file);
fclose(original_file);

对于您阅读的每个字符,您有两件事要做:

  1. 检查是否为 EOF。
  2. 如果不是,将其写入输出。

你的问题是你做这两件事的顺序不对。

可能有几种不同的方法可以解决这个问题。你选择哪一个取决于你有多关心你的程序看起来不错,而不是仅仅工作。

一个。从您编写的代码开始,我们可以将其更改为:

while (curr_char != EOF)
    {
    curr_char = getc(original_file);
    if(curr_char == EOF) break;
    putc(curr_char, second_file);
    }

在这里,我们明确地测试字符是否为 EOF,在读取之后立即写入,然后再写入。如果是 EOF,我们会提前跳出循环。这会起作用,但它很难看:我们在两个不同的地方测试 EOF,其中一个从不 "fires"。 (此外,正如一位评论员提醒我的那样,问题是第一次通过循环时,我们在设置它之前测试 curr_char。)

两个。你可以这样重新排列它:

curr_char = getc(original_file);
while (curr_char != EOF)
    {
    putc(curr_char, second_file);
    curr_char = getc(original_file);
    }

这里,我们读取一个首字母,只要不是EOF,我们就写入再读取一个。这会工作得很好,但它仍然有点难看,因为这次我们在两个不同的地方读取字符。

三个。你可以这样重新排列它:

while ((curr_char = getc(original_file)) != EOF)
    {
    putc(curr_char, second_file);
    }

这是在 C 中编写字符复制循环的传统方式。对 getc 的调用和对 curr_char 的赋值被隐藏在 [=17= 的控制表达式中] 环形。这取决于这样一个事实,即在 C 中,赋值表达式与任何其他表达式一样具有值。也就是说,表达式 a = b 的值是我们刚刚分配给 a 的任何值(即 b 的值)。所以表达式 curr_char = getc(original_file) 的值就是我们刚刚读取的字符。所以当我们说 while ((curr_char = getc(original_file)) != EOF) 时,我们实际上是在说 "Call getc, assign the result to curr_char, and if it's not equal to EOF, take another trip around the loop."

(如果你还是看不懂,我已经在these notes and this writeup中写了其他解释。)

这段代码有好有坏。这很好,因为我们有一个地方可以读字符,一个地方可以测试字符,还有一个地方可以写字符。但这有点糟糕,因为,让我们承认,一开始它有点神秘。很难想象埋在while条件下的作业。正是这样的代码让 C 有了充满晦涩难懂的官话的名声。

但是,至少在这种情况下,确实值得学习这个惯用语并适应它,因为减少到一次读取、一次测试和一次写入确实 美德。在像这样的微不足道的情况下,这无关紧要,但在由于其他原因而复杂的实际程序中,如果某些关键功能发生在两个不同的地方,则很容易忽略这一事实,并使对其中一个进行了更改,但忘记对另一个进行更改。

(其实我上周刚上班的时候就遇到了这种情况,当时正想修复别人代码中的一个bug,终于想通了,代码做X的时候,不小心把Y清空了。我发现它执行 X 的地方,我添加了一些新代码以正确地重新创建 Y。但是当我测试我的修复时,它不起作用!结果是代码执行 X 的地方有两个不同的地方,我发现并改错了。)

最后,这是一种等效的最小但非常规的循环编写方式:

while (1)
    {
    curr_char = getc(original_file);
    if(curr_char == EOF) break;
    putc(curr_char, second_file);
    }

这有点像数字 1,但它去掉了 while 循环中的冗余条件,并用常量 1 代替它,即 "true" C. 这也能很好地工作,并且它具有一次读取、一次测试和一次写入的优点。它实际上最终执行与数字 3 完全相同的操作和完全相同的顺序,但通过线性布局可能更容易理解。

4 号的唯一问题是它是一个非常规的 "break in the middle" 循环。就个人而言,我对中间循环没有问题,我发现它们时不时会出现,但如果我写了一个并且有人说 "Steve, that's ugly, it's not an idiom anyone recognizes, it will confuse people",我必须同意.

P.S。我已将您对 fgetcfputc 的调用替换为更传统的 getcputc。我不确定是谁告诉你使用 fgetcfputc,并且在一些模糊的情况下你需要它们,但它们非常罕见,在我看来人们还不如忘记 "f" 变体存在,并且总是使用 getcputc.