7

假设交换文件中的每两行,直到只剩下一行或所有行都用完。我不想在这样做时使用另一个文件。

这是我的代码:

#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”。

再次,我不想使用另一个文件来完成这个,我只需要弄清楚屏幕后面到底出了什么问题

任何线索将不胜感激。谢谢你。

4

3 回答 3

4

您的代码中有多个问题:

  • 您不检查是否fopen()成功,冒着未定义行为的风险。

  • 确定总行数的循环不正确。
    在这里了解原因:为什么“while (!feof (file))”总是错误的?

  • 您实际上不需要计算总行数。

  • fflush()在从写回变为读取之前,您应该调用将内容写回文件。

C 标准对以更新模式打开的文件指定了此限制:

7.21.5.3fopen功能

[...] 输出不应直接跟在输入后面,而没有对fflush函数或文件定位函数的中间调用( fseekfsetposrewind, 除非输入操作遇到文件结尾。

这解释了为什么在以相反顺序写入行后仅读取文件位置会导致问题。调用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.txt\n");
        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;
}
于 2017-02-04T23:33:58.500 回答
3

更改文件的当前位置时,可能不一定会刷新缓冲区。所以它必须显式刷新。

例如使用fflush(fp);

改变

fputs(line2,fp);
fputs(line1,fp);

fputs(line2,fp);
fputs(line1,fp);
fflush(fp);
于 2017-02-04T23:17:25.350 回答
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;
}
于 2017-02-05T13:04:38.983 回答