应该在文件中每隔两行交换一次,直到只剩下一行或用完所有行。我不想使用其他文件这样做。
这是我的代码:
#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;
}
.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)
的调用返回)再说一次,我不想用另一个文件来完成这件事,我只需要弄清楚屏幕后面到底出了什么问题
任何线索都将不胜感激。非常感谢。
您的代码中存在多个问题:
-
您不检查
fopen()
是否成功,这可能会导致未定义的行为。 -
用于确定行总数的循环不正确
在此处了解原因:为什么"while(!feof(file))"总是错误的? -
实际上,您不需要计算行的总数。
-
在从写回更改为读取之前,您应该调用
fflush()
将内容写回文件。
C标准为在更新模式下打开的文件指定了此限制:
7.21.5.3
fopen
函数在没有对
fflush
函数或文件定位函数(fseek
、fsetpos
或rewind
)的介入调用的情况下,[…]输出后不应直接跟着输入,并且在没有对文件定位函数的介入调用情况下,输入后不应直接输出,除非输入操作遇到文件结尾。
这解释了为什么在按相反顺序写入行之后只读取文件位置会导致问题。调用fflush()
应该可以解决此问题。
这是一个更正的版本:
#include <stdio.h>
int main(void) {
FILE *fp;
char line1[100], line2[100];
fpos_t pos;
fp = fopen("this.txt", "r+");
if (fp == NULL) {
fprintf(stderr, "cannot open this.txtn");
return 1;
}
while (fgetpos(fp, &pos) == 0 &&
fgets(line1, sizeof line1, fp) != NULL &&
fgets(line2, sizeof line2, fp) != NULL) {
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fflush(fp);
}
fclose(fp);
return 0;
}
更改文件的当前位置时,缓冲区可能不一定要刷新。因此,它必须显式刷新。
E.g使用fflush(fp);
更改
fputs(line2,fp);
fputs(line1,fp);
至
fputs(line2,fp);
fputs(line1,fp);
fflush(fp);
为什么不使用两个文件指针,都指向同一个文件,一个读,一个写?无需跟踪文件位置,无需四处寻找,无需冲洗。
这种方法省去了很多复杂的东西。这些不必要的努力最好投资于一些复杂的错误检查/日志记录,如下所示;-):
#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;
}