【问题标题】:C structure not scanning all the inputsC结构不扫描所有输入
【发布时间】:2013-10-22 22:53:21
【问题描述】:

我有这个 C 代码:

#include "stdio.h"

main()
{
    struct books
    {
        char name[100],author[100];
        int year,copies;
    }book1,book2;

    printf("Enter details of first book\n");
    gets(book1.name);
    gets(book1.author);
    scanf("%d%d",&book1.year,&book1.copies);

    printf("Enter details for second book\n");
    gets(book2.name);
    gets(book2.author);
    scanf("%d%d",&book2.year,&book2.copies);

    printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
    printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);  
}  

这里发生的是它只扫描到第二本书的作者姓名。之后,它直接打印输出。

这是我的输入:(前两行是最初的 printf 语句)

Enter details of first book
warning: this program uses gets(), which is unsafe.
the c programmign laguagne
dfadsda
3432
23
Enter details for second book
ruby on rails
mark hammers  

之后它直接打印输出

the c programmign laguagne
dfadsda
3432
23

ruby on rails
0
0

这里有什么问题?我们还可以看到,第二本书的名称被分配给了作者。

我在 Mac OS X ML 上使用 gcc 作为编译器。

【问题讨论】:

    标签: c structure scanf fgets gets


    【解决方案1】:

    请注意,您可能应该使用 fgets() 而不是 gets(),因为由于缓冲区安全问题,它现在已被弃用。

    这是因为scanf() 在读取下一个条目的数据之前会吃掉最后一个\n

    【讨论】:

    • 如何使用fgets()
    • fgets() 需要 3 个参数。第一个是您的字符串/字符数组,第二个是要复制的字符数,第三个是您正在读取的流。所以像fgets(buffer, 20, stdin) 这样的东西会从标准输入复制20个字符到你的缓冲区数组中。
    • 但我从scanf() 获取整数值。我如何从fgets() 获得相同的信息?我可以使用fgets() 获取字符串。
    • 哦,哎呀..是的,你可能需要sscanf() (double s) 它的用法与fgets() cplusplus.com/reference/cstdio/sscanf非常相似
    【解决方案2】:

    在每个输入语句之前使用fflush(stdin)。此方法将清除输入缓冲区。 修改后您的代码将是-

    #include "stdio.h"
    
    int main()
    {
        struct books
        {
            char name[100],author[100];
            int year,copies;
        }book1,book2;
    
        printf("Enter details of first book\n");
        gets(book1.name);
        fflush(stdin);
    
        gets(book1.author);
        fflush(stdin);
    
        scanf("%d%d",&book1.year,&book1.copies);
        fflush(stdin);
    
        printf("Enter details for second book\n");
        gets(book2.name);
        fflush(stdin);
    
        gets(book2.author);
        fflush(stdin);
        scanf("%d%d",&book2.year,&book2.copies);
    
        printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
        printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);  
        return 0;
    } 
    

    您可以查看fflush()here的详细信息。

    更新: 在 scanf() 语句之后,您需要刷新输入缓冲区。 fflush() 方法在这里没有用,因为它只为输出流定义。您可以在每个 scanf() 行之后使用单行代码来使用部分读取的行的其余部分,例如 -

    while((c = getchar()) != '\n' && c != EOF);
    

    你的代码将是:

    #include "stdio.h"
    
    int main()
    {
        struct books
        {
            char name[100],author[100];
            int year,copies;
        }book1,book2;
        char c;
        printf("Enter details of first book\n");
        gets(book1.name);
        gets(book1.author);
    
        scanf("%d%d",&book1.year,&book1.copies);
        while((c = getchar()) != '\n' && c != EOF);
    
        printf("Enter details for second book\n");
        gets(book2.name);
        gets(book2.author);
        scanf("%d%d",&book2.year,&book2.copies);
        while((c = getchar()) != '\n' && c != EOF);
    
        printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
        printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);  
        return 0;
    } 
    

    输出:

    Enter details of first book
    warning: this program uses gets(), which is unsafe.
    sadsadas
    asa
    12
    34
    Enter details for second book
    zxczxc
    sds
    23
    22
    sadsadas
    asa
    12
    34
    zxczxc
    sds
    23
    22
    

    【讨论】:

    • 你执行了这个程序,看看它是否工作?您不应该将 fflush 用于标准输入。阅读thisthis
    【解决方案3】:

    在您的源代码中,

    scanf("%d%d",&book1.year,&book1.copies);
    

    不读取“23”之后的“\n”,因为这只是读取两个整数。

    这个问题的一个解决方案是在阅读第二本书之前执行gets(),例如:

    #include "stdio.h"
    
    main()
    {
        struct books
        {
            char name[100],author[100];
            int year,copies;
        }book1,book2;
    
        printf("Enter details of first book\n");
        gets(book1.name);
        gets(book1.author);
        scanf(" %d %d",&book1.year,&book1.copies);
        char a[100];
        gets(a);
    
        printf("Enter details for second book\n");
        gets(book2.name);
        gets(book2.author);
        scanf("  %d  %d",&book2.year,&book2.copies);
    
        printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
        printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);  
    }  
    

    因此,使用gets读取整数,然后使用atoi是更简单的方法。

    #include "stdio.h"
    
    main()
    {
        struct books
        {
            char name[100],author[100];
            int year,copies;
        }book1,book2;
    
        printf("Enter details of first book\n");
        gets(book1.name);
        gets(book1.author);
        char buff[100];
        gets(buff);
        book1.year = atoi(buff);
        gets(buff);
        book1.copies = atoi(buff);
    
        printf("Enter details for second book\n");
        gets(book2.name);
        gets(book2.author);
        gets(buff);
        book2.year = atoi(buff);
        gets(buff);
        book2.copies = atoi(buff);
    
        printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
        printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);  
    }  
    

    【讨论】:

    • 在这两种方法中,我都需要为额外的gets()(对吗?)提供额外的输入,这是我不想要的。
    • @xmpirate 第二个示例的gets() 不是额外的代码,而是scanf() 的替代品。但是如果你连这本书都不想要,你可以把第一本书scanf()的格式字符串改成%d%d\n,虽然这样不会输出输入第二本书的提示。
    • @xmpirate 那么你可以使用第二个例子。如果要使用scanf格式,可以使用sscanf解析buff
    【解决方案4】:

    试试这个

    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
        struct books
        {
            char name[100],author[100];
            int year,copies;
        }book1 = { 0 },book2 = { 0 }; // initialize to 0
    
        printf("Enter details of first book\n");
        printf( "name>" ); 
        fgets(book1.name, sizeof(book1.name), stdin);
        // remove \n
        book1.name[strlen(book1.name)-1] = '\0';
    
        printf( "author>"); 
        fgets(book1.author, sizeof(book1.author), stdin);
        book1.author[strlen(book1.author)-1] = '\0'; // remove \n
        printf( "year copies>");
        scanf("%d %d",&book1.year,&book1.copies);
        fflush(stdin); // remove any garbage remaining like \n
    
        printf("Enter details for second book\n");
        printf( "name>" );
        fgets(book2.name, sizeof(book2.name), stdin);
        book2.name[strlen(book2.name)-1] = '\0';
    
        printf( "author>"); 
        fgets(book2.author, sizeof(book2.author), stdin);
        book2.author[strlen(book2.author)-1] = '\0';
        printf( "year copies>");
        scanf("%d %d",&book2.year,&book2.copies);
        printf("%s\n%s\n%d\n%d\n",
          book1.name,book1.author,book1.year,book1.copies);
        printf("%s\n%s\n%d\n%d\n",
          book2.name,book2.author,book2.year,book2.copies);  
        return 0;
    }  
    

    【讨论】:

      【解决方案5】:

      解决方案:

      #include <stdio.h>  /* Using fgets(), scanf(), printf() in this program */
      #include <string.h> /* Using strlen() in this program */
      
      int main()
      {
          struct books
          {
              char name[100],author[100];
              int year,copies;
          }book1,book2;
      
          char c;
          char read_new_line;
      
          printf("Enter details of first book\n");
          if (fgets(book1.name, sizeof(book1.name), stdin) == NULL)
          {
              fprintf(stderr, "error reading name of book 1\n");
              return -1;
          }
          /* Strip out \n character added by fgets */
          book1.name[strlen(book1.name) - 1] ='\0';
      
          if (fgets(book1.author, sizeof(book1.author), stdin) == NULL)
          {
              fprintf(stderr, "error reading author of book 1\n");
              return -1;
          }
          /* Strip out \n character added by fgets */
          book1.author[strlen(book1.author) - 1] ='\0';
      
          scanf("%d %d",&book1.year,&book1.copies);
          /* Strip out \n character left out in input stream */
          while ((read_new_line = getchar()) != EOF && read_new_line != '\n')                                             
              ;
      
          printf("Enter details for second book\n");
          if (fgets(book2.name, sizeof(book2.name), stdin) == NULL)
          {
              fprintf(stderr, "error reading name of book 2\n");
              return -1;
          }
          /* Strip out \n character added by fgets */
          book2.name[strlen(book2.name) -1 ] = '\0';
      
          if (fgets(book2.author, sizeof(book2.author), stdin) == NULL)
          {
              fprintf(stderr, "error reading author of book 2\n");
              return -1;
          }
          /* Strip out \n character added by fgets */
          book2.author[strlen(book2.author) - 1] ='\0';
      
          scanf("%d %d",&book2.year,&book2.copies);
          /* Strip out \n character left out in input stream */
          while((c = getchar()) != '\n' && c != EOF)
              ;
      
          printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
          printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);  
          return 0;
      }
      

      观察问题中发布的代码:

      让我们试着理解为什么你的代码不工作:

      从下面的语句调用 scanf 之后

      scanf("%d%d",&book1.year,&book1.copies);
      

      你的输入是

      3432\n
      23\n
      

      scanf 读入3432 并存储在&amp;book1.year 中,随后\n 在输入中被遗漏 溪流。然后,第二个%d 丢弃前导空格(此上下文中的空格包括空格、制表符、换行符等)并读入23 并将其存储在&amp;book1.copies 中,随后\n 被排除在外输入流。

      gets(book2.name) 在输入流中被称为\n 时,输入流匹配gets() 标准,因此“空字符串”被分配给book2.name,并且为book2.name 提供的任何含义和用户输入都存储在@ 987654339@。

      后跟用于book2.author 的任何字符串,并在用户输入时键入分配给book2.year%d 转换已完成,但它失败了,因为没有输入正确的整数并且scanf() 返回失败。

      注意:

      【讨论】:

      • 但是scanf() 不能扫描多字串。这就是我使用gets()的原因。
      • @smRaj 在之前的帖子中,我很困惑。 n 谢谢我学到了一些东西:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多