C中的不同输出内容文件副本

C中的不同输出内容文件副本,c,file-copying,fgetc,getc,C,File Copying,Fgetc,Getc,您好,我有一个简单的复制文件程序在C中,但我不能解释为什么我得到不同的输出在目标文件时,我使用第二种方法。 具有for循环的正确输出: I am the worst programmer in the world! :D And this is bla bla bla bla more bla bla bla... 但在while循环中,会在EOF中生成一个随机字符: I am the worst programmer in the world! :D And this is bla b

您好,我有一个简单的复制文件程序在C中,但我不能解释为什么我得到不同的输出在目标文件时,我使用第二种方法。 具有for循环的正确输出:

I am the worst programmer in the world!
:D
 And this is bla bla bla bla
 more bla bla bla...
但在while循环中,会在EOF中生成一个随机字符:

I am the worst programmer in the world!
:D
 And this is bla bla bla bla
 more bla bla bla...

代码是

int main()
{
int i;
char ch;
create_files();
FILE *src = fopen("best.txt", "r");
FILE *dst = fopen("copied.txt", "w");
for(i=getc(src); i!=EOF; i=getc(src))  //correct copy
    {
        putc(i, dst);
    }

/* while(!feof(src))                  //woot?
    {
        ch=fgetc(src);
        fputc(ch,dst);
    }*/

fclose(dst);
fclose(src);
return 0;
}

void create_files()
{
    FILE *fp;
    fp = fopen("best.txt","w");
    fprintf(fp,"I am the worst programmer in the world!\n:D\n And this is bla bla bla bla\n more bla bla bla...\n");
    fclose(fp);
}
我使用了fputc或putc和fgetc或getc,但仍然是一样的。我忘了什么吗?

编辑 看起来这不是真正的问题,但我会保留答案作为建议


我唯一注意到的是:

char ch;
根据您的系统,
char
可以是有符号的,也可以是无符号的,足以容纳EOF,或者不够。您的
while
循环可能表明您的操作系统适合后一种情况


改为使用
int
并尝试一下。

您的
while
循环有一个off by one错误。它读/写一个额外的字符,这就是奖金
来自-您将
fgetc()
返回的EOF值写入了输出文件

第一个循环获取字符(可能检测到EOF),然后检查未检测到EOF的值,并可能执行写入字符的块(直到读取所有字符)

第二个循环检查是否检测到EOF,获取字符(可能检测到EOF),写入字符(不考虑可能是什么),并可能继续下一个字符(如果未检测到EOF)


在第二个循环中,在检查字符是否为EOF之前写入该字符。

while循环会给您一个随机字符,因为在读取失败之前,EOF实际上不会被标记。因此,while循环中发生的事情是,执行读取操作,
fgetc
失败,设置EOF,并返回一个duff值,然后打印

构造while循环的更好方法是:

ch=fgetc(src);
while (!feof(src)) {
   fputc(ch,dst);
   ch=fgetc(src);
}
什么

是的,是:

  • 检查EOF
  • 读取一个字符,可能导致EOF
  • 输出刚刚读取的字符,不检查EOF
  • 当EOF发生时,(3)仍在下一次迭代中签入(1)之前执行。特殊值
    EOF
    转换为
    char
    并输出

    正确的循环是

    while ((ch = fgetc(src)) != EOF)
        fputc(ch, dst);
    
    假设
    ch
    给出类型
    int
    ,因为
    char
    不能表示
    EOF
    。注意支票内的分配;有些程序员会告诉你这很难看,但是很多人都在使用它,你可能会习惯它。用于
    循环的变量
    也是正确的

    (1除外:
    fputc
    相当于
    putc
    fgetc
    getc
    ,只要您不尝试在函数指针上下文中使用它们。)


    (旁白2:您的
    while
    循环也不会检查流错误,而检查
    EOF
    也会返回捕捉到的内容。)

    不会做您认为它会做的事情。阅读文档。它不测试下一次读取是否会尝试读取超过文件结尾的内容;它检查上次失败的读取尝试是否失败,因为已经到达文件末尾。@pmg是正确的
    feof
    应在循环后使用,以检查是否发生EOF而不是错误。谢谢。我认为(!feof(src)与((ch=fgetc(src))相同!=EOF)@GeoPapas:否。您必须在读取和写入之间进行检查,然后还必须检查
    ferror
    。如果我想在第一次复制后重新复制文件,则必须使用ungetc?@GeoPapas:否。您应该
    fseek
    到文件的开头。
    ungetc
    只保证可以推送一个字符k、 它用于在标记器中实现预读。
    while ((ch = fgetc(src)) != EOF)
        fputc(ch, dst);