C结构不扫描所有输入

时间:2013-10-15 08:03:42

标签: c structure scanf fgets gets

我有这个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作为编译器。

5 个答案:

答案 0 :(得分:1)

在每个输入语句之前使用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

答案 1 :(得分:1)

在您的源代码中

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);  
}  

答案 2 :(得分:1)

<强>解决方案:

#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并存储在&book1.year中,\n后面的输入被遗漏 流。然后,第二个%d丢弃前导空格(此上下文中的空格包括空格,制表符,换行符等)并读入23并将其存储在&book1.copies中,跟随 { {1}}在输入流中被遗漏。

在调用\n时,输入流中遗漏的gets(book2.name)符合\n条件,因此将“空字符串”分配给gets(),无论是什么意思和提供的用户输入book2.name的{​​{1}}存储在book2.name中。

跟随book2.author所用的任何字符串并输入,因为用户输入已分配给book2.author%d已完成转换并且失败,因为没有输入正确的整数且book2.year返回失败。

注意:

答案 3 :(得分:0)

请注意,您应该使用fgets()代替gets(),因为由于缓冲区安全问题,现在已弃用它。

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

答案 4 :(得分:0)

试试这个

#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;
}