在 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);
对于您阅读的每个字符,您有两件事要做:
- 检查是否为 EOF。
- 如果不是,将其写入输出。
你的问题是你做这两件事的顺序不对。
可能有几种不同的方法可以解决这个问题。你选择哪一个取决于你有多关心你的程序看起来不错,而不是仅仅工作。
一个。从您编写的代码开始,我们可以将其更改为:
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。我已将您对 fgetc
和 fputc
的调用替换为更传统的 getc
和 putc
。我不确定是谁告诉你使用 fgetc
和 fputc
,并且在一些模糊的情况下你需要它们,但它们非常罕见,在我看来人们还不如忘记 "f" 变体存在,并且总是使用 getc
和 putc
.
当我在 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);
对于您阅读的每个字符,您有两件事要做:
- 检查是否为 EOF。
- 如果不是,将其写入输出。
你的问题是你做这两件事的顺序不对。
可能有几种不同的方法可以解决这个问题。你选择哪一个取决于你有多关心你的程序看起来不错,而不是仅仅工作。
一个。从您编写的代码开始,我们可以将其更改为:
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。我已将您对 fgetc
和 fputc
的调用替换为更传统的 getc
和 putc
。我不确定是谁告诉你使用 fgetc
和 fputc
,并且在一些模糊的情况下你需要它们,但它们非常罕见,在我看来人们还不如忘记 "f" 变体存在,并且总是使用 getc
和 putc
.