【问题标题】:fgets storing unknown data from text filefgets 存储来自文本文件的未知数据
【发布时间】:2018-12-29 19:15:38
【问题描述】:

我正在创建一个猜词游戏,它每行读取一个文本文件行,直到找到一个随机单词并将其存储在一个字符串中 (word)。然后用户输入字母,直到显示所存储单词的所有字母。

到目前为止,它运行良好,但每次读取第一个单词时,一些未知字符都会存储在char word[20] 的开头。

请注意,我使用 C 移动应用程序,并且我认为它使用 clang 6.0 编译器。那么错误是来自我的代码还是来自他们的应用程序? (我喜欢)。

这是完整的、更清晰的代码:

//guess the right word

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

#define TRUE 1
#define FALSE 0
#define NB_OF_WORDS 3 //number of words in text file

main() {
    char begin, word[20] = { 0 }, guessedletter;
    int num, rightletter, success;
    int i = 0;
    int show[20] = { 0 };//shown letters

    FILE *ressource = NULL;
    srand(time(NULL));

    if ((ressource = fopen("ressource.txt", "r")) == NULL) {
        fprintf(stderr, "Error ressource.txt");//open in read only mode
        exit(EXIT_FAILURE);
    }

    printf("Welcome to Word Guess, a word guessing contest.\n"
           "You have to find the letters of a word and guess what word it is.\n"
           "Begin? (y/n)\n");

    while ((begin = getchar()) == 'y') { //game loop
        /*reinitializations*/
        fseek(ressource, 3, SEEK_SET);//replaces rewind(ressource)
        success = FALSE;
        rightletter = 0;
        num = 0;
        num = rand() % NB_OF_WORDS; //random number between 0 and NB-1
        for (i = 0; i < 20; i++) {
            show[i] = FALSE;
            word[i] = 0;
        }
        i = 0;
        /*end of reinitializations*/

        while (i <= num) {//reads line by line until random word is stored
            if (fgets(word, 20, ressource) == NULL) {
                fprintf(stderr, "fgets did not work");
                exit(EXIT_FAILURE);
            }
            i++;
        }

        printf("%s", word);//here is just for testing if the read word is well read. Which isn't the case if num=0 

        for (i = 0; i < 20; i++)
            if (word[i] == '\n')
                word[i] = '\0';//adds zero character to show where the string ends
        while (!success) { //guessing loop
            printf("\nWrite a letter: ");
            scanf("%c", &guessedletter);
            printf("\n");

            for (i = 0; word[i] != '\0'; i++) { //compares entered letter to letter from string. If they match...
                if (word[i] == guessedletter) {
                    if (!show[i])
                        rightletter++;//avoids letters entered twice from increasing count
                    show[i] = TRUE;
                }
                if (show[i])
                    printf("%c", word[i]);//...a letter is revealed...
                else
                    printf("*");//else it stays hidden
            }
            if (rightletter == strlen(word))
                success=TRUE;//if all the right letters found (same number of letters found as number of letters in the words) you win
        }

        printf("\nCongratulations you have won!\nDo you want to replay? (y/n)");
        getchar();//clears newline character
    }

    fclose(ressource);
    return 0;
}

当 num=0 时,我在打印的单词前得到一个奇怪的符号,好像文本文件的第一个字符不应该在那里......

此外,在猜谜游戏中,如果要猜的单词 (word[20]) 是“烦人的”,假设它是“ressource.txt”中的第一个单词 (num=0)。一旦我猜到了所有的字母,这个词就会像这样在屏幕上打印出来:***烦人。列表中的任何其他单词都不会发生这种情况。

我是这个网站的新手,我是用手机发帖的……如有任何错误,我深表歉意。

编辑:删除 fgetc 的 fgets。如果 fgets 读取第一行,仍然会得到几个未知字符。

编辑 2:添加整个代码,将 mot[20] 翻译成 word[20],添加错误测试

编辑 3:替换 rewind(ressource);通过 fseek(资源,3,SEEK_SET);解决了这个问题。这意味着文本文件的开头确实有三个未知字符

【问题讨论】:

  • 不要混用你的输入法。上面偷看的while(begin=='y')是什么?
  • 循环前调用了scanf:scanf("%c", &begin);如果你输入yes,循环开始,如果你继续输入'y'(yes)会重新开始
  • 请参阅scanf() leaves the newline char in the buffer。那是等待fgets 收集,以及您的scanf 不过滤空格(如链接所示)。
  • 不要混用你的输入法。如果您在主循环中使用fgets,请在任何地方使用它。您关于“向前移动光标”的说法是无稽之谈。输入流没有“光标”。
  • 该文件必须以 Unicode BOM 开头。我敢打赌这些(未提及的)字符是小写的并且带有一些口音,对吧?检查您使用的文本编辑器是否可以在没有 BOM 的情况下保存文件。

标签: c file text fgets


【解决方案1】:

贴出的代码存在多个问题:

  • 您只发布了一段代码,其余功能可能会导致无法从您发布的内容分析的问题。请将完整代码发布到出现问题的最小程序中。
  • 您没有在while 循环中测试文件结尾。如果您尝试跳过的行数多于文件中的行数,则此循环将无限期运行。
  • 你没有测试fgets()的返回值:如果你在前面的while循环中偶然跳过了文件的全部内容,fgets()将失败并返回NULL,留下mot未确定的状态,导致后续printf 出现意外行为。

编辑:修改后的代码仍然没有检查fgets()的返回值。

编辑:感谢您发布完整代码,但以这种方式修改问题会使此答案与 cmets 无关。

您的字典文件ressource.txt 似乎以UTF-8 编码的BOM (Byte Order Mark) 开头。我猜它包含法语单词,包括一些带有重音字母的单词,例如 reculéesencodées...您的文本编辑器将其保存为 UTF-8 编码并带有一个额外的代码点开始时其他程序可以轻松确定此编码。问题在于您的程序不处理 UTF-8。它假定从stdin 读取的每个字节都代表一个字符。它可能会偶然匹配一些带有重音字母的单词,但更有可能找不到它们。

【讨论】:

  • 最新的/修改过的代码编译不干净!请更正代码
  • @user3629249:OP 的最新代码仍然有一些编译警告,我只是更改了布局,而不是代码本身。要执行他的程序,您需要一个字典文件 ressource.txt(请原谅我的法语),他没有提供该文件,并且以 UTF-8 BOM 序列开头,导致输出中出现 funny 字符。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-19
  • 1970-01-01
相关资源
最近更新 更多