与控制台输入相比较的字符串和整数的文件输入作为猜谜游戏

时间:2017-10-13 02:45:16

标签: c file input comparison

我正在努力完成一项任务。我是C的新手,事情并没有像我希望的那样好。

我们的任务是编写一个小程序,通过命令行从用户那里获取输入,询问他们的名字,然后猜测幻数。我们有一个.txt文档,其中包含三个带有关联数字的名称。它的三行,每行都有一个名字,后跟一个空格,然后是数字。如果用户名不等于这三个中的一个,则幻数默认为12345.

每次猜测后,程序应该说出数字是太高还是太低,然后退出(是的,我不知道为什么)。

我一直在调试printf语句,但无法弄清楚为什么它不会进入代码的比较部分。

非常感谢任何帮助或提示!

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

typedef struct {
    char list_name[20];
    int list_num;
}list;

    char user_name[20];
    int user_magic_num;


main(){

    FILE *fp;
    int i;
    list answers;

    //
    fp = fopen("answers.txt", "rb");
    if(fp == NULL)
        {
      perror("Error opening file");
      return(-1);
        }

    printf("\n Hi, what's your name? \n \n");
    scanf("%s",user_name);
    printf("\n Hello, %s! \n \n What's the magic number? \n \n",user_name);
    scanf("%d", &user_magic_num);
    printf("You guessed %d.\n\n", user_magic_num);

    for (i=0; i<=4;i++)
    {
        fgets(answers.list_name, 20, fp);
        puts(answers.list_name);
        if (strcmp(answers.list_name,user_name)==0)
        {
            printf("entered first if statement");
            if(user_magic_num==answers.list_num)
                 {
                printf("You guess correctly! %d is the magic number!", 
answers.list_num);
                break;
            }
            else if(user_magic_num>answers.list_num)
            {
                printf("Too high.");
            }
            else if(user_magic_num<answers.list_num)
            {
                printf("Too low");
            }
        }
        else
        {
            user_magic_num = 12345;
        }
    }
  return 0;
}

*********编辑:     #包括     #include

typedef struct list{
char list_name[20];
int list_num;
}list;

char user_name[20];
int user_magic_num;


main(){

FILE *fp;
int i;
list answers;

//
fp = fopen("answers.txt", "rb");
if(fp == NULL)
    {
  perror("Error opening file");
  return(-1);
    }

printf("\n Hi, what's your name? \n \n");
scanf("%s",user_name);
printf("\n Hello, %s! \n \n What's the magic number? \n \n",user_name);
scanf("%d", &user_magic_num);
printf("You guessed %d.\n\n", user_magic_num);

 while (fscanf(fp, "%s %d",answers.list_name, &answers.list_num) != EOF)
{
    //printf("%s\n", answers.list_name);
    if(strcmp(user_name, answers.list_name)==0)
    {
        if (user_magic_num == answers.list_num)
        {
            printf("\nYes! %d is the magic number!\n", user_magic_num);
            break;
        }
        else if (user_magic_num > answers.list_num)
        {
            printf("\nNope. Too high.\n");
            break;
        }
        else
        {
            printf("\nNope. Too low.\n");
            break;
        }
    }
    else
    {
        answers.list_num = 12345;
        printf("\nUser not recognized. Default magic number set.\n");
        if (user_magic_num == answers.list_num)
        {
            printf("Yes! %d is the magic number!", user_magic_num);
            break;
        }
        else if (user_magic_num > answers.list_num)
        {
            printf("\nNope. Too high.\n");
            break;
        }
        else
        {
            printf("\nNope. Too low.\n");
            break;
        }
    }
}

返回0; }

我刚刚这样做了。它现在可以工作,但仅适用于txt文件中的第一个名称。文本文件如下所示:

Bob 123
Mike 23
Rachel 345

但是只有当我输入Bob然后输入123时它才有效。但是如果我尝试Mike或者Rachel,它就像未知的那样对待它并将幻数重置为12345.我假设这是fscanf的东西,我'我做错了。

3 个答案:

答案 0 :(得分:0)

loop块中存在一些错误,请先单独阅读namemagic_number。然后你额外else if检查了你的最后一次   else if 声明。

        else if(user_magic_num<answers.list_num)
         {
             printf("Too low");
         }

应该是

     else 
         printf("Too low");

for循环中的一些修改:

    for (i=0; i<2;i++)
    {
      fscanf(fp,"%s %d",answers.list_name,&answers.list_num);
      puts(answers.list_name);
      if (strcmp(answers.list_name,user_name)==0)
      {
         if(user_magic_num==answers.list_num)
              {
              printf("You guess correctly! %d is the magic number!\n", 
              answers.list_num);
             break;
          }
         else if(user_magic_num>answers.list_num)
         {
             printf("Too high.\n");
         }
         else 
         {
             printf("Too low\n");
         }
      }
      else
        user_magic_num = 12345; 
   }

答案 1 :(得分:0)

你可以这样做:

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

typedef struct {
    char list_name[20];
    int list_num;
}list;

char user_name[20];
int user_magic_num;

int main(){

    FILE *fp;
    int i;
    list answers;
    int matched = 0;

    fp = fopen("answers.txt", "rb");
    if(fp == NULL)
    {
      perror("Error opening file");
      return -1;
    }

    printf("\n Hi, what's your name? \n \n");
    scanf("%s",user_name);
    printf("\n Hello, %s! \n \n What's the magic number? \n \n",user_name);
    scanf("%d", &user_magic_num);
    printf("You guessed %d.\n\n", user_magic_num);

    /*
     * i<3 - as per your description, your text document suppose to 
     * 3 names associated with numbers.
     * You can change it as per your requirement.
     */
    for (i=0; i<3; i++)
    {
        fscanf (fp, "%s %d", answers.list_name, &answers.list_num);
        if(feof(fp))
        {
           puts("EOF");     
           break;
        }

        if (strcmp(answers.list_name,user_name)==0)
        {
            if(user_magic_num==answers.list_num)
            {
                printf("You guess correctly! %d is the magic number!\n", answers.list_num);
        matched = 1;
                break;
            }
            else if(user_magic_num>answers.list_num)
            {
                printf("Too high.\n");
            }
            else 
            {
                printf("Too low.\n");
            }
        }
    }
    if (!matched)
    {
        user_magic_num = 12345;
        printf ("Not matched\n");
        /*
         * Considering not matched as error and returning -1
         */
        return -1;
    }
  return 0;
}

答案 2 :(得分:0)

迈克,有许多微妙的问题需要解决,这些都是学习C的正常部分。首先是几个概括:

char user_name[20];   /* avoid global variables unless absolutely */
int user_magic_num;   /* required (that is almost never) */

main中声明您的变量,并根据需要将它们作为参数传递给任何函数。声明全局变量会增加名称冲突和变量阴影的风险,随着代码的增长,它们很难调试。

main(){

mainint类型的函数。它有两个C标准认可的有效声明:

int main (void)                    /* passes no arguments to main */

int main (int argc, char *argv[])  /* passes argc arguments in argv - use them */

(您还会看到等效的int main (int argc, char **argv)

有关main的进一步讨论,请参阅:C11 Standard §5.1.2.2.1 Program startup (draft n1570)。另见:What should main() return in C and C++?

下一步:

  return(-1);   /* don't return negative values to the shell */

C为main

提供了两个定义的回报
EXIT_SUCCESS     /* 0 */
EXIT_FAILURE     /* 1 */

(虽然它依赖于shell,但应避免返回负值)

验证所有输入 - 期间。特别是如果它来自用户(你知道猫可能只是踩在键盘上)。所有输入函数都有返回。至少,您必须验证返回以了解是否已成功接收输入。如果不这样做是邀请未定义的行为(这是一件非常糟糕的事情......)另外,如果您需要某个范围内的输入值,请验证输入是否在范围。

现在你的问题。所有面向行的输入函数(例如fgets和POSIX getline)都会读取和包括尾随'\n'。它包含在它们填充的缓冲区中。使用fgets正确和推荐的方式来获取输入行(包括用户输入)。虽然scanf家族有它的位置,但它是完整的或陷阱,只是等待陷阱新的C程序员。一次读一行到缓冲区,并从缓冲区中解析所需的值。 (为此目的使用sscanf很好)

您的比较失败了,因为您没有认识到您使用fgets正在将整行(或至少最多19个字符)读入answers.list_name,例如< / p>

fgets(answers.list_name, 20, fp);

不要对缓冲区吝啬。当然要让它们合理,但我更喜欢256-chars to big,而不是1-char太短......(下面我简单地声明一个128-byte缓冲区来读取文件的每一行。)

逻辑。快速逻辑图表示您将如何获得输入,需要对每个变量进行哪些测试,何时要求其他输入,如何响应输入等等。使用铅笔在8.5x11上勾画出来可以节省您几小时的凝视时间在屏幕上希望灵感来袭。 (当你只是坐在屏幕上猜测变化并反复重新编译时,很少会这样做 - 只是让它再次失败)。清晰的逻辑和清晰的路线图表明您需要完成的工作将为您节省时间。

将上述内容放在一起,并抓住可靠的8.5x11和一支铅笔,看来你正试图:

  1. 将用户名作为用户输入

  2. 打开并读取您的文件以匹配用户名,然后阅读 幻数(如果找不到名字,则出错)

  3. 将一个幻数作为用户输入

  4. 提示用户最多猜5次猜测数字

  5. 为下一次猜测提供过高和过低的提示

  6. 如果找不到这个名字该怎么办?

    以下是对我的意图的抨击。仔细查看代码,了解每一行,如果你没有 - 然后问。 注意:程序希望文件名作为程序的第一个参数读取。利用该能力而不是在代码中对路径/文件名进行硬编码。

    另请注意下面使用常量。切勿在代码中对值进行硬编码(具有讽刺意味的是 magic-numbers )。定义一个常量或两个向上的顶部提供了一个方便的位置,可以根据需要进行更改 - 无需选择所有变量和循环声明来进行必要的更改。

    对于scanf 字段宽度限制

    注意:),您只是被卡住了 - 这些必须是硬编码的,这是另一个原因{{1} }(或fgets)是首选)

    note2:我故意在您的代码中留下一行评论getline并提出问题以便您回答)

    //

    示例使用/输出

    #include <stdio.h>
    #include <string.h>
    
    #define MAXC 20         /* define constants when you need one */
    #define MAX_TRIES 5
    #define BUFSZ 128
    
    typedef struct {
        char list_name[MAXC];
        int list_num;
    } list;
    
    int main (int argc, char **argv) {
    
        int i = 0,                  /* always good to initialize variables */
            name_found = 0,
            user_magic_num = 0;
        char user_name[MAXC] = "",
            buf[BUFSZ] = "";
        size_t len = 0;
        list answers = { "", 0 };
        FILE *fp = NULL;
    
        if (argc != 2) {    /* validate argument given on command-line */
            fprintf (stderr, "error: insufficient input.\n"
                             "usage: %s filename\n", argv[0]);
            return 1;
        }
    
        /* open / validate file open for reading */
        if (!(fp = fopen (argv[1], "r"))) {
            fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
            return 1;
        }
    
        printf ("\n Hi, what's your name?: ");
        if (scanf ("%19s", user_name) != 1) {       /* validate ALL input */
            fprintf (stderr, "error: invalid input or EOF - user_name.\n");
            return 1;
        }
        while (fgets (buf, BUFSZ, fp)) { /* read each line from file into buf */
    
            /* fgets reads and *includes* the trailing '\n' in buf, remove it */
            len = strlen (buf);                 /* get length */
            if (len && buf[len - 1] == '\n')    /* check trailing '\n' */
                buf[--len] = 0;                 /* overwite with nul-char */
            else {
                /* handle error - string too long */
            }
    
            /* separate buffer into answers.list_name and answers.list_num */
            if (sscanf (buf, "%19s %d", answers.list_name, &answers.list_num) != 2) {
                fprintf (stderr, "error: failed to parse name and num from line.\n");
                return 1;
            }
    
            if (strcmp (answers.list_name, user_name) == 0) {
                name_found = 1;                     /* flag - name found in file  */
                break;
            }
        }
        fclose (fp);         /* close file - you are done with it */
    
        if (!name_found) {
            fprintf (stderr, "error: name '%s' not found in file.\n", user_name);
            return 1;
        }
    
        printf ("\n Hello, %s! \n \n What's the magic number?: ",user_name);
    
        if (scanf ("%d", &user_magic_num) != 1) {   /* ditto */
            fprintf (stderr, "error: invalid input or EOF - user_magic_num.\n");
            return 1;
        }
        printf (" You guessed: %d\n\n", user_magic_num);
    
        for (i = 0; i < MAX_TRIES; i++)     /* avoid <= (unless required) */
        {
            if (user_magic_num == answers.list_num) {
                printf ("You guessed correctly! %d is the magic number!\n",
                        answers.list_num);
                return 0;
            }
            else if (user_magic_num > answers.list_num)
                printf ("Too high.\n\n");
            else
                printf ("Too low.\n\n");
    
            printf (" What's your next guess %s?: ", user_name);
            if (scanf ("%d", &user_magic_num) != 1) {
                fprintf (stderr, "error: invalid input - user_magic_num\n");
                return 1;
            }
            putchar ('\n');
        }
        fprintf (stderr, "Oops: tries exceed max (%d)\n", MAX_TRIES);
    
        return 0;
    }
    

    如果user_name不在文件中怎么办?

    $ ./bin/magicnum2 dat/magicnum.txt
    
     Hi, what's your name?: Mike
    
     Hello, Mike!
    
     What's the magic number?: 100
     You guessed: 100
    
    Too high.
    
     What's your next guess Mike?: 10
    
    Too low.
    
     What's your next guess Mike?: 20
    
    Too low.
    
     What's your next guess Mike?: 25
    
    Too high.
    
     What's your next guess Mike?: 23
    
    You guessed correctly! 23 is the magic number!
    

    如果我没有从问题中收集你的意图,请告诉我,我很乐意进一步提供帮助。

    最后,每次编译时都不要忘记启用编译器警告。这意味着$ ./bin/magicnum2 dat/magicnum.txt Hi, what's your name?: Frank error: name 'Frank' not found in file. 至少-Wall -Wextragcc(或/W3)至/W4(windoze上的VS)至少cl.exe。要获得更全面的警告,您可以-pedantic添加gcc/Wall使用cl.exe。在没有警告的情况下完全编译之前,请不要接受代码。你可以通过阅读和理解编译器告诉你的内容来学习更多的C,而不是大多数教程......