C语言 逆序输出文本时为什么会每一行后面都多一行空白行?求高手解答,我是菜鸟,尽可能详细一点

代码:#include <stdio.h>#include <stdlib.h>#include <ctype.h>#define CHARCOUNT 1e3FILE *GetData(void);void Reverse(FILE *);void PutFileData(FILE *);int main(int argc, char *argv[]){ FILE *fp; fp = GetData(); PutFileData(fp); Reverse(fp); if (fclose(fp) != 0) { fprintf(stderr, "Closed failure!\n"); exit(EXIT_FAILURE); } return 0;}FILE *GetData(void){ FILE *fp; if ((fp=fopen("filedata.txt", "w+"))!=NULL) { int ch_count = 0; char ch; while (ch_count++ < CHARCOUNT) { do { ch = rand() % 128; } while (!isprint(ch)); fputc(ch, fp); if (ch_count % 50 == 0) fputc('\n', fp); } } else { fprintf(stdout, "Data creat failure!\n"); exit(EXIT_FAILURE); } /*if (fopen_s(&fp, "a.txt", "r") != 0) { fprintf(stdout, "Data creat failure!\n"); exit(EXIT_FAILURE); }*/ return fp;}void PutFileData(FILE *fp){ rewind(fp); while (!feof(fp)) putchar(fgetc(fp));}void Reverse(FILE *fp){ long int flenth; fseek(fp, 0L, SEEK_END); flenth = ftell(fp); for (long int i = 1; i <= flenth; i++) { fseek(fp, -i, SEEK_END); putchar(fgetc(fp)); }}

首先告诉你这是正常现象。要克服的话把逆序函数改如下:

void Reverse(FILE *fp){
    long int flenth;
    char ch;//这里加一个变量
    fseek(fp, 0L, SEEK_END);
    flenth = ftell(fp);
    for(long int i = 1; i <= flenth; i++){
        fseek(fp, -i, SEEK_END);
        putchar(ch=fgetc(fp));//这里同时把读出的字符存入ch以供下一句处理
        if(ch=='\n') i++;//加上这一行
    }
}

原因先自己琢磨,因为要打比较多的字。可续问。

顺便说一句,你的PutFileData函数也有点潜在纰漏。

追问

在以文本打开方式打开文件时,从文件中读数据时windows会将\r\n转换成\n,向文件中写数据时会将\n转换成\r\n;
1.对于二进制文件是否也是像文本一样进行这样的转换?
2.逆序输出的时候\r\n是否就变成了\n\r?我输出printf("2\r\n3");和printf("2\n\r3");是一样的;
3.PutFileData函数的纰漏是什么?真心感谢!

追答

    你已经找到关键了,但细节没有弄清楚。关键在于由于“那种转换”的缘故,所以文件操作库函数fgetc之类对\r\n字符的读取与其他字符是不同的;以fgetc为例,无论先读到\n还是\r,fgetc都认为是'\n',且由于文件中的\r\n不分家,所以fgetc会在功能上相当于跳过一个字符;而当逆序时,读文件指针是向“前”移的——比如文件中是...x\n\r123...,fgetc读到\r后翻译成了'\n',文件指针就指向了'2',可是fseek把指针强行向“后”移到了'\n'处,使fgetc又读到'\n',也被解释为'\n;结果putchar把两个'\n'都换成\n\r输出了,造成了问题中的现象。

    PutFileData这个函数中feof(fp)的使用有问题。这个函数必须在逻辑上紧跟在“读文件动作”之后才能正确生效,你这里第一次进入while循环时还没有产生读动作,而当文件最后读到结束符时,putchar都把它输了,才返回去判断是否文件已结束了。在你这里由于由于是按字符读取的,结束符-1是打不出符号来的,所以看不出来;如果是按行读取,常常会最后多出一行乱七八糟的字符串来。类似代码,不少朋友是这样写的:

    char ch=fgetc(fp);

    while (!feof(fp)){

        putchar(fgetc(fp));

        ch=fgetc(fp);

    }

   这无疑是正确的。不过我觉得如下更专业一些:
   char ch;
   while(ch=fgetc(fp),!feof(fp))
       putchar(fgetc(fp));
   或者如下更简练:
   char ch;
   while((ch=fgetc(fp))!=EOF)
       putchar(fgetc(fp));
   供参考……

追问

大神你太牛了,非常相当之详细,看来你的回答十分的感谢。我的一点感悟想和大神交流一下。

我觉得只有\n和\r相邻,读取的时候fgetc才会认为是'\n'。这段代码在输出文件内容的时候不会把'\r'读成'\n'(字数超标了,截图请见谅)

追答

不好意思,前面回答提供的三段代码中的putchar(fgetc(fp));应该是putchar(ch);,歉正!
我试了一下你提供的代码,输出结果确实是你说的那样。但如果是只有\n\r在一起时才被当一个\n读取,这在正读时很好解释,但如我给你改过的逆读函数就不好解释了:逆读肯定与正读次序相反,怎么会知道前一个是跟它“作伴”的呢?让我们共同研究吧!你很有探究精神,肯定能学好。祝走运……

温馨提示:答案为网友推荐,仅供参考
相似回答