【问题标题】:fgetc not starting at beginning of file - c [duplicate]fgetc 未从文件开头开始 - c [重复]
【发布时间】:2013-12-08 19:23:32
【问题描述】:

问题在这里解决: fgetc not starting at beginning of large txt file

我在 c 中工作,而 fgetc 没有从文件开头获取字符。它似乎是在\n 之后的文件中随机开始的。该函数的目标是修改数组 productsPrinted。如果遇到“需要更多数据”或“隐藏未列出”,则数组中的位置 productsPrinted[newLineCount] 将更改为 0。感谢任何帮助。

更新:它适用于较小的文件,但不能从较大的 617kb 文件的开头开始。

函数调用到类别:

findNoPics(image, productsPrinted);
findVisible(visible, productsPrinted);
removeCategories(category, productsPrinted);

来自 fgetc() 的示例输入:

Category\n
Diagnostic & Testing /Scan Tools\n
Diagnostic & Testing /Scan Tools\n
Hidden non listed\n
Diagnostic & Testing /Scan Tools\n
Diagnostic & Testing /Scan Tools\n
Hand Tools/Open Stock\n
Hand Tools/Sockets and Drive Sets\n
More Data Needed\n
Hand Tools/Open Stock\n
Hand Tools/Open Stock\n
Hand Tools/Open Stock\n
Shop Supplies & Equip/Tool Storage\n
Hidden non listed\n
Shop Supplies & Equip/Heaters\n

代码:

void removeCategories(FILE *category, int *prodPrinted){

char more[17] = { '\0' }, hidden[18] = { '\0' };
int newLineCount = 0, i, ch = 'a', fix = 0;

while ((ch = fgetc(category)) != EOF){  //if fgetc is outside while, it works//

    more[15] = hidden[16] = ch;
    printf("%c", ch);

    /*shift char in each list <- one*/
    for (i = 0; i < 17; i++){
        if (i < 17){
            hidden[i] = hidden[i + 1];
        }
        if (i < 16){
            more[i] = more[i + 1];
        }
    }

    if (strcmp(more, "More Data Needed") == 0 || strcmp(hidden, "Hidden non listed") == 0){
        prodPrinted[newLineCount] = 0;
        /*printf("%c", more[0]);*/
    }
    if (ch == '\n'){
        newLineCount++;
    }
} 

}

【问题讨论】:

  • fseek 到文件开头(我猜你在其他地方使用这个FILE * 或者多次调用这个函数
  • 这与fgetc() not working — returns same char repeatedly 密切相关。针对该问题确定的特定缺陷已得到修复(如果您接受答案会很好 - 它让人们知道您感谢他们的帮助)。循环已经改变了;缩进仍然不稳定。结构相似——但意图仍然不明确。
  • (a) 这个程序/函数试图做什么; (b) 调用代码是什么样的?您应该查看阅读 EOF 时发生的情况(您当然会在数据发生后处理数据,就好像它没有发生一样)。拥有几 (2-5) 行输入数据以及这些输入行的预期输出将大有帮助。
  • 你不能正确地终止你的字符串。读取/赋值行more[15] = hidden[16] = ch = fgetc(category); 覆盖morehidden 末尾的空值,使您的字符串没有空终止符,因此当您最终将字符移动到开头时strcmp() 操作失败字符串。

标签: c fgetc


【解决方案1】:

让计算机来计算。你没有正确地终止你的字符串。固定字符串(mdnhdl 已初始化但没有空终止符,因此使用它们的字符串比较未定义。

鉴于此示例数据:

Example 1
More Data Needed
Hidden non listed
Example 2
Keeping lines short.
But as they get longer, the overwrite is worse...or is it?
Hidden More Data Needed in a longer line.
Lines containing "Hidden non listed" are zapped.
Example 3

这个版本的程序:

#include <stdio.h>
#include <string.h>

static
void removeCategories(FILE *category, int *prodPrinted)
{
    char more[17] = { '0' };
    char hidden[18] = { '0' };
    char mdn[17] = { "More Data Needed" };
    char hnl[18] = { "Hidden non listed" };
    int newLineCount = 0, i, ch = '\0';

    do
    {
        /*shift char in each list <- one*/
        for (i = 0; i < 18; i++)
        {
            if (i < 17)
                hidden[i] = hidden[i + 1];
            if (i < 16)
                more[i] = more[i + 1];
        }
        more[15] = hidden[16] = ch = fgetc(category);
        if (ch == EOF)
            break;
        printf("%c", ch);           /*testing here, starts rndmly in file*/
        //printf("<<%c>> ", ch);           /*testing here, starts rndmly in file*/

        //printf("more <<%s>> hidden <<%s>>\n", more, hidden);
        if (strcmp(more, mdn) == 0 || strcmp(hidden, hnl) == 0)
        {
            prodPrinted[newLineCount] = 0;
        }
        if (ch == '\n')
        {
            newLineCount++;
        }
    } while (ch != EOF);
}

int main(void)
{
    int prod[10];
    for (int i = 0; i < 10; i++)
        prod[i] = 37;
    removeCategories(stdin, prod);
    for (int i = 0; i < 10; i++)
        printf("%d: %d\n", i, prod[i]);
    return 0;
}

产生这个输出:

Example 1
More Data Needed
Hidden non listed
Example 2
Keeping lines short.
But as they get longer, the overwrite is worse...or is it?
Hidden More Data Needed in a longer line.
Lines containing "Hidden non listed" are zapped.
Example 3
0: 37
1: 0
2: 0
3: 37
4: 37
5: 37
6: 0
7: 0
8: 37
9: 37

【讨论】:

  • 添加了一些示例输入和函数调用,请看一下。
  • 我认为我在猜测您的数据是什么样子以及数据结构是什么样子方面做得不错。我的回答中的分析同样准确。我将代码更改为使用 20 的数组(足以容纳 15 行示例数据的数据),然后在您的示例数据上进行尝试,并将对应于第 4、9 和 14 行的条目归零,如你似乎期待。
【解决方案2】:

您可以检查您打开文件的模式,并且您可能会进行一些错误检查以确保您获得了正确的返回值。

这里可以参考man fopen获取哪个模式导致流位置。

   The fopen() function opens the file whose name is the string pointed to
   by path and associates a stream with it.
   The argument mode points to a string beginning with one of the  follow‐
   ing sequences (Additional characters may follow these sequences.):

   r      Open  text  file  for  reading.  The stream is positioned at the
          beginning of the file.

   r+     Open for reading and writing.  The stream is positioned  at  the
          beginning of the file.

   w      Truncate  file  to  zero length or create text file for writing.
          The stream is positioned at the beginning of the file.

   w+     Open for reading and writing.  The file is created  if  it  does
          not  exist, otherwise it is truncated.  The stream is positioned
          at the beginning of the file.

   a      Open for appending (writing at end of file).  The file  is  cre‐
          ated  if it does not exist.  The stream is positioned at the end
          of the file.

   a+     Open for reading and appending (writing at end  of  file).   The
          file is created if it does not exist.  The initial file position
          for reading is at the beginning  of  the  file,  but  output  is
          always appended to the end of the file.

另外还有一个提示,就是你操作的文件不能超过2G,不然可能有问题。

您可以使用fseek 来设置文件位置指示器。

而且你可以使用调试器来观察这些变量,看看为什么会有随机值。我认为调试比跟踪输出更有效。

【讨论】:

  • 附加信息:文件大小:617kb,为“r”打开。
  • 我尝试 fseek 将开始位置设置为开头,结果相同。
  • 你能在函数 removeCategories() 之后添加 fgetc() 吗?看得到的是哪个字符,是不是也是随机字符?
  • 刚试了一下,它从文件开头开始扫描。但是,如果我将 fgetc() 放在 while 循环中的任何位置,它就会开始在文件中随机扫描。什么可能导致这种行为?
  • 我不认为这是 fgetc() 错误,我已经重新检查了您的代码,您已经更新了您的代码。我已经对其进行了测试, fgetc() 得到了正确的字符,所以你能否提供更多关于它的细节但保持简单,以便我可以构建相同的环境进行调试?另一个注意事项是您定义了错误数组。您定义的隐藏和更多数组比预期少 1 个字符。隐藏数组是从[0]到[16],最后一个字符应该是[17],并且应该是'\0'以便strcmp做比较工作,你可以在for循环之后做一个printf来检查这个.
【解决方案3】:

也许您可以尝试在函数的开头回退文件指针。

 rewind(category);

很可能另一个函数正在从同一个文件中读取。如果这解决了您的问题,最好找出从同一文件中读取的其他函数(或之前对该函数的调用),并确保倒回指针不会破坏其他内容。

编辑:

为了确定,也许您可​​以将双重赋值更改为两个不同的语句。基于此post,您的问题也可能是由该行的编译器优化引起的。我没有检查过标准,但根据最佳答案,c 和 c++ 中的行为可能是未定义的,因此你的结果很奇怪。祝你好运

【讨论】:

  • 该文件仅用于一个功能。尝试从 printf 添加具有相同结果的 rewind(category)。
  • 我在您的代码中发现了一些问题。有一个循环在运行 until.control 变量达到 17,如果你的 cotrol 变量达到 17,你只有 2 个条件永远不会为真。另一个建议是始终对 'if'、'else'、'while 使用括号' 等,无论您是否只有一条指令或更多指令。从标准输入读取时,您也没有检查 for.errors。本次讨论可能对您有所帮助:stackoverflow.com/questions/3495092/read-from-file-or-stdin-c
  • 在上述链接中,您可以找到 your.problem 的解决方案。 stdin 是流而不是 FILE *。您的代码中的所有其他问题也应该得到修复,但他已经回答了您的问题。祝你好运。
  • 好的,谢谢。我去看看。
  • “for”循环中的第一个“if”也是一个重言式。这将始终是正确的,因为您的控制变量将始终
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-06
  • 2015-08-10
  • 2014-10-31
  • 1970-01-01
  • 2020-05-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多