fgets()和scanf()之间的区别

时间:2015-12-19 13:36:48

标签: c user-input scanf fgets

这是我的代码。我不想使用scanf()来读取名称,我尝试使用fgets()但是在我输入第一个名字和年龄之后,第二次和第三次我的程序运行for循环它不需要年龄。< / p>

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

struct student
{
    char name[15];
    int age;
};


int main()
{
    int i;
    struct student s[A];
    for (i = 0 ; i < A ; i++)
    {
        printf("enter the names and age\n");
        fgets(s[i].name, 10, stdin);
        scanf("%d", &s[i].age);
    }
    printf("\n\n");

    for (i = 0 ; i < A ; i++)
    {
        printf("%s\t%d\n", s[i].name, s[i].age);
    }
    return 0;
}

它不起作用,为什么?

但是当我用

替换fgets时
scanf("%s%d",s[i].name,&s[i].age);

工作正常

3 个答案:

答案 0 :(得分:2)

  

fgets()和scanf()

之间的区别

fgets(...)通常会在收到'\n'

之前读取

scanf("%d", ...)通常:
 1.读取并丢弃前导空白区域  2.读取数字输入(符号,数字),直到扫描非数字为止  3.对于下一个输入函数,非数字放回stdin

示例:

Ĵ 0 ħ 名词 输入
"John\n"会将fgets()读入s[0].name

2 1 输入
21会将scanf("%d",...)读入s[0].age'\n'放回stdin

"\n"将{p> fgets()读入s[1].name

中号
"M"读取scanf("%d",...)s[1].age中没有任何内容。 'M'放回stdin

- [R ý 输入
"Mary\n"会将fgets()读入s[2].name

1 9 输入
19会将scanf("%d",...)读入s[2].age'\n'放回stdin

"\n"将{p> fgets()读入s[3].name

替代方法:要阅读2行,请拨打fgets()两次,然后解析:

int Scan_student(struct student *dest) {
  char buffer[2][80];
  dest->name[0] = '\0';
  dest->age[0] = -1;
  printf("enter the names and age\n");
  for (int i=0; i<2; i++) {
    if (fgets(buffer[i], sizeof buffer[i], stdin) == NULL) {
      return EOF; // stdin was closed, no more input (or input error)
    }
    buffer[i][strcspn(buffer[i], "\r\n")] = '\0'; // lop off potential trailing \n
  }
  // parse the 2 buffers: MANY options here - something simple for now.
  if (sscanf(buffer[0], " %14[-'A-Za-z ]", dest->name) != 1) {
    return 0;
  }
  if (sscanf(buffer[1], "%d", &dest->age) != 1) {
    return 0;
  }
  return 1;
}


int i;
struct student st[3];
for (i = 0 ; i < sizeof(st) / sizeof(st[0]) ; i++) {
  if (Scan_student(&st[i]) != 1) break;
}

答案 1 :(得分:1)

如果您在一行中输入名称和年龄,那么这是正常行为,因为fgets()将读取整行,直到9字节(在您的情况下)为阅读或找到'\n'

您需要其中一个,例如,您只能使用fgets()这样的

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

struct student
{
    char name[100];
    int age;
};


int main()
{
    int i;
    struct student s[1];
    for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
    {
        char number[100];
        char *unconverted;
        printf("Name > ");
        fgets(s[i].name, sizeof(s[i].name), stdin);
        if ((unconverted = strchr(s[i].name, '\n')) != NULL)
            *unconverted = '\0'; // Remove the trailing '\n'
        printf("Age  > ");
        fgets(number, sizeof(number), stdin);
        s[i].age = strtol(number, &unconverted, 10);
        if ((*unconverted != '\0') && (*unconverted != '\n'))
            s[i].age = -1; // Invalid value indicating input error
    }

    for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
        printf("Name: %s\nAge : %d\n", s[i].name, s[i].age);
    return 0;
}

或仅scanf()

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

struct student
{
    char name[100];
    int age;
};


int main()
{
    int i;
    struct student s[1];
    for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
    {
        printf("Name Age > ");
        if (scanf("%99s%d", s[i].name, &s[i].age) != 2)
        {
            fprintf(stderr, "input error\n");
            s[i].name[0] = '\0';
            s[i].age = -1;
        }
    }

    for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
        printf("Name: %s\nAge : %d\n", s[i].name, s[i].age);
    return 0;
}

然后您可以在一行中输入姓名和年龄。

fgets()方法更好,因为您不需要处理'\n'scanf()获取的stdin。如果您小心强制用户在单独的行中输入值,则组合将起作用。

答案 2 :(得分:-1)

说实话,这里不需要fgets(),因为你已经指定从stdin读取,你应该只使用gets()默认情况下从stdin读取。如果您在scanf()语句和gets()语句之间移动,则应使用fflush(stdin)清除输入流,例如:

scanf("%99s", s[i].name);
fflush(stdin);
gets(s[i].age);

一般来说,你最好坚持使用scanf()或gets()而不是将它们组合起来。