假设交换文件中的每两行,直到只剩下一行或所有行都用尽。我不想在这样做时使用其他文件。
这是我的代码:
#include <stdio.h>
int main() {
FILE *fp = fopen("this.txt", "r+");
int i = 0;
char line1[100], line2[100];
fpos_t pos;
fgetpos(fp, &pos);
//to get the total line count
while (!feof(fp)) {
fgets(line1, 100, fp);
i++;
}
i /= 2; //no. of times to run the loop
rewind(fp);
while (i-- > 0) { //trying to use !feof(fp) condition to break the loop results in an infinite loop
fgets(line1, 100, fp);
fgets(line2, 100, fp);
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fgetpos(fp, &pos);
}
fclose(fp);
return 0;
}
this.txt中的内容:
aaa
b
cc
ddd
ee
ffff
gg
hhhh
i
jj
运行程序后内容
b
aaa
ddd
cc
ddd
c
c
c
i
jj
我甚至尝试使用fseek
代替fgetpos
来获得相同的错误结果。
根据我的想法,在第二个while循环运行了两次(即前四行已经处理完毕)之后,光标正确地位于第17个字节,在那里它应该是(由对ftell(fp)
的调用返回)甚至第4行之后的文件内容都没有改变,并且由于某种原因,当循环运行第三行时调用fgets
时间,读入数组line1和line2的内容分别为“c \ n”和“ddd \ n”。
再说一遍,我不想用另一个文件来完成这个,我只需要弄明白屏幕背后到底出了什么问题
任何线索都会受到赞赏。谢谢。
答案 0 :(得分:3)
您的代码中存在多个问题:
您不检查fopen()
是否成功,冒着未定义的行为风险。
确定总行数的循环不正确。
在此处了解原因:Why is “while ( !feof (file) )” always wrong?
您实际上并不需要计算总行数。
在更改回写到阅读之前,您应该调用fflush()
将内容写回文件。
C标准为在更新模式下打开的文件指定了此限制:
7.21.5.3
fopen
功能[...]输出不能直接跟随输入,而无需对
fflush
函数或文件定位函数(fseek
,fsetpos
或{{进行干预调用。 1}}),除非输入操作遇到文件结束,否则输入不应直接跟随输出,除非输入操作遇到文件结束。
这解释了为什么在以相反顺序写入行之后读取文件位置会导致问题。致电rewind
应解决此问题。
以下是更正后的版本:
fflush()
答案 1 :(得分:2)
更改文件的当前位置时,可能不一定刷新缓冲区。所以必须明确刷新它。
E.g使用fflush(fp);
更改
fputs(line2,fp);
fputs(line1,fp);
到
fputs(line2,fp);
fputs(line1,fp);
fflush(fp);
答案 2 :(得分:2)
为什么不使用两个文件指针,两个指向同一个文件,一个读取,一个写入?无需跟踪文件位置,无需寻找,无需冲洗。
这种方法可以为你提供很多复杂的东西。这些不必要的努力更好地投入到如下的一些复杂的错误检查/记录中; - ):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
int result = EXIT_SUCCESS;
size_t blocks = 0;
int l1_done = 0;
int l2_done = 0;
FILE *fpin = fopen("this.txt", "r");
FILE *fpout = fopen("this.txt", "r+");
if (NULL == fpin)
{
result = EXIT_FAILURE;
perror("fopen() to for reading failed");
}
if (NULL == fpout)
{
result = EXIT_FAILURE;
perror("fopen() for writing failed");
}
while (EXIT_SUCCESS == result && !l1_done && !l2_done)
{
result = EXIT_FAILURE;
char line1[100];
char line2[100];
if ((l1_done = (NULL == fgets(line1, sizeof line1, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks);
break;
}
}
if ((l2_done = (NULL == fgets(line2, sizeof line2, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks + 1);
break;
}
}
{
size_t len = strlen(line1);
if (((sizeof line1 - 1) == len) && ('\n' != line1[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks);
break;
}
}
{
size_t len = strlen(line2);
if (((sizeof line2 - 1) == len) && ('\n' != line2[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks + 1);
break;
}
}
if (!l2_done)
{
if (EOF == fputs(line2, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks + 1, 2*blocks);
break;
}
}
if (!l1_done)
{
if (EOF == fputs(line1, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks, 2*blocks + 1);
break;
}
}
++blocks;
result = EXIT_SUCCESS;
}
if (EXIT_SUCCESS == result && !ll_done && l2_done)
{
fprintf(stderr, "Odd number of lines.\n");
}
fclose(fpin); /* Perhaps add error checking here as well ... */
fclose(fpout); /* Perhaps add error checking here as well ... */
return result;
}