【问题标题】:fgetc is not stopping my loopfgetc 没有停止我的循环
【发布时间】:2015-11-19 13:18:50
【问题描述】:
int ch;
char Name1[24], Name2[24],*p1,*p2;  
while ((ch = fgetc(inz)) != EOF){

            fseek(inz, -1, SEEK_CUR);

        fgets(Name1, 24, inz);
        fgets(Name2, 24, inz);
        p1 = Name1;
        p2 = Name2;
        p1 += 3;
        p2 += 3;

        if (atoi(p1) > atoi(p2)){
            fseek(inz, -46, SEEK_CUR);              
            fputs(Name2, inz);              
            fputs(Name1, inz);              

        }
        fseek(inz, -23, SEEK_CUR);      
        i --;
    }

我有这个代码。 inz 是我在 r+ mod 中的文件。我想将每个字符串与下一个字符串进行比较,并根据第四个字符对它们进行排序。该功能正在运行,但是..它不可阻挡,它永远运行... **我已尝试更改 int ch;也烧焦。还是没用,feof也没用。

【问题讨论】:

  • “i”在哪里定义,它的作用是什么?我认为您永远不会到达 EOF,因为您反复调用 fseek 来倒带文件。我建议开始将有序列表写入另一个文件。
  • 在循环的每次迭代中,在读入所有变量(chName1Name2p1p2)后打印出所有变量。另外,打印ftell() 的结果,这样您就可以看到您在文件中的位置。这应该能让你很好地了解你的逻辑哪里出了问题。
  • 请出示预期变更后的文件,并附上文件样本。
  • 每次读取文件中的字符时,都会在文件中后退(至少一个位置)。这是一个永无止境的循环,因为您将永远无法到达文件末尾...

标签: c loops fgetc


【解决方案1】:

你的代码有几个问题:

1) 您假设每行至少有 4 个字符长(加上换行符)。如果该行小于 4 个字节,您将不会根据字符串本身进行排序,并且可能会根据未初始化的内存进行排序。

2) 您说要根据第 4 个字符比较每一行,但实际上是根据从第 4 个字符开始的字符串进行比较。您将其转换为整数,这意味着您还假设该行包含一个数值。

3) 您假设每个字符串在文件中占用 24 个字节。我猜你假设每个字符串都是 23 个字符长加上一个换行符?这个假设有效吗?如果行可以短于 24 字节,则此代码不正确:

fseek(inz, -46, SEEK_CUR);              

相反,您想回退到两个字符串加上两个换行符的实际总长度。即使字符串是 23 字节,你也没有考虑换行符,所以你想倒带 -48 而不是 -46。

4) 将字符串写回文件时,您使用的是不包含换行符的 fputs。

5) 您并没有真正对文件进行排序,您只是经历了一次冒泡排序。您正在根据比较重新排序当前的两行,但这不会对整个文件进行排序。所以排序的逻辑也是错误的。

读取每一行,将其放入数组中,根据您提到的标准对数组进行排序,然后将其写回文件会更简洁。

除此之外,为什么循环永远不会结束?

循环中的最后一行是这样的:

fseek(inz, -23, SEEK_CUR);  

这意味着它总是在尝试获取下一个字符 (fgetc) 之前返回 23 个字节。那时你将永远看不到 EOF。

【讨论】:

    【解决方案2】:

    好吧,如果你在文件指针已经位于文件末尾的情况下执行fgets,你只会得到一个EOF。而您测试返回值的唯一 fgetc 之前的指令是 fseek(inz, -23, SEEK_CUR);

    这意味着当您到达文件末尾时,您首先返回 23 个字节,成功读取某些内容,并且可能会在后面的两个 fgets 中的任何一个上获得一个 EOF,返回值被忽略。并永远重复……

    你应该怎么做?至少测试每个读取函数的返回值:

        if (fgets(Name1, 24, inz) == NULL) break;
        if (fgets(Name2, 24, inz) == NULL) break;
    

    但这还不是全部。除非您非常确定您的所有行总是正好有 23 个字符并且文件以二进制模式打开(或者您在 Linux 上),否则永远不要使用 fseek。唯一合理的方法是使用ftell 存储一个位置,然后将fseek 存储到该位置。

    最后但并非最不重要的一点是,您的算法会回溯一行以在 Name1 中读取您刚刚在 Name2 中读取的内容。您应该交换 p1 和 p2,始终读入 p2 并比较 p1 和 p2

    只要它们都短于 SIZE 但长于 4,则无论行大小如何,这都会对文件进行排序:

    size_t oldpos = 0, tmp;
    char Name1[SIZE], Name2[SIZE],*p1,*p2;
    p1 = Name1;
    p2 = Name2;
    /* read first line and note position after it */
    if (fgets(p1, SIZE, inz) == NULL) return;
    tmp = ftell(inz);
    /* loop reading in p2 */
    while (fgets(p2, SIZE, inz) != NULL){
    
        if (atoi(p1 + 3) > atoi(p2 + 3)){
            /* swap last two lines */
            fseek(inz, oldpos, SEEK_SET);              
            fputs(p2, inz);
            fputs(p1, inz);          
            /* and go back to beginning of file - not optimal but robust */    
            fseek(inz, 0, SEEK_SET);
            /* again last line in p1 and note position */
            fgets(p1, SIZE, inz);
            oldpos = 0;
            tmp = ftell(inz);
        }
        else {
            /* order is ok untill here, note new position and swap buffers */
            oldpos = tmp;
            tmp = ftell(inz);
            swap(&p1, &p2);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多