当我在输出文件末尾的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);
答案 0 :(得分:4)
对于您阅读的每个角色,您有两件事要做:
你的问题是你正在以错误的顺序做这两件事。
可能有几种不同的解决方法。你选择哪一个取决于你关心你的程序看起来好多少,而不仅仅是工作。
一。从您编写的代码开始,我们可以将其更改为:
while (curr_char != EOF)
{
curr_char = getc(original_file);
if(curr_char == EOF) break;
putc(curr_char, second_file);
}
在这里,我们在写入之前,在阅读之后立即测试该角色是否为EOF。如果它是EOF,我们会提前摆脱循环。这样可行,但很难看:有两个不同的地方我们测试EOF,其中一个从不“开火”。 (另外,正如评论员提醒我的那样,第一次通过循环问题,我们在设置它之前测试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
的赋值都隐藏在while
循环的控制表达式中。这取决于在C中,赋值表达式具有与任何其他表达式一样的值。也就是说,表达式a = b
的值是我们刚刚分配给a
的任何值(即b
的值)。所以表达式curr_char = getc(original_file)
的值是我们刚读过的字符。因此,当我们说while ((curr_char = getc(original_file)) != EOF)
时,我们实际上说的是,“致电getc
,将结果分配给curr_char
,如果不等于EOF
,请选择另一个围绕循环旅行。“
(如果您仍然遇到此问题,我已在these notes和this writeup中撰写了其他解释。)
这段代码既好又坏。这很好,因为我们只有一个地方我们读过字符,一个地方我们测试字符,一个地方我们写字符。但它有点不好因为,让我们承认,起初它有点神秘。很难想到这个任务 - 埋藏在 - while
- 条件中。像这样的代码给C带来了充满晦涩的gobbledegook的声誉。
但是,至少在这种情况下,真的值得学习这个成语,并且对它感到满意,因为减少到只有一个读取和一个测试,一个写入真正 美德。在这样一个微不足道的案例中,这并不重要,但在其他原因复杂的实际程序中,如果在两个不同的地方发生了一些关键的功能,那么很容易忽视这个事实,并且改变其中一个,但忘了把它交给另一个。
(事实上,这只发生在我上周的工作中。我试图修复别人的代码中的错误。我终于弄清楚当代码执行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
,在C中为“true”。这将工作也很好,并且它具有一次读取,一次测试和一次写入的优点。它实际上最终完成了与3号完全相同的操作和完全相同的顺序,但是通过线性布局它可能更容易理解。
4号唯一的问题是它是一个非常规的“中间突破”循环。就我个人而言,我没有中间突破循环的问题,我发现它们不时出现,但如果我写了一个而且有人说“史蒂夫,这很难看,这不是任何人认可的成语,它会让人迷惑“,我必须同意。
P.S。我已将fgetc
和fputc
的来电替换为更传统的getc
和putc
。我不确定是谁告诉你使用fgetc
和fputc
,并且有一些模糊的情况你需要它们,但它们是如此罕见,以至于我认为人们可能会忘记“ f“变体存在,并始终使用getc
和putc
。