我有这个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
作为编译器。
答案 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
返回失败。
注意:
使用scanf()
本身就很糟糕。当您使用gets()
时,您需要确保防止缓冲区溢出,这是%s
无法做到的。阅读: Why does everyone say not to use gets()?
部分已发布的答案似乎建议gets()
清算
fflush()
流。阅读, Why Shouldn't I use fflush(stdin)?
答案 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;
}