【问题标题】:Scanf needs more values than it should in CScanf 需要比 C 中更多的值
【发布时间】:2014-04-06 16:07:14
【问题描述】:

我正在尝试学习结构,我正在使用此代码

#include <stdio.h>

struct elements
{
    char name[50];
    int semester;
    char  am[15];
}student[100];

void read_struct(struct elements p[]);
int i=0;

main()
{

    for (i=0;i<2;i++)
    {
        read_struct(student);

    }
    for (i=0;i<2;i++)
    {   printf("%d\n",i);
        printf("%s\n",student[i].name);
        printf("%s\n",student[i].am);
        printf("%d\n",student[i].semester);
    }

    system("pause");
}
void read_struct(struct elements p[])
{

    gets(student[i].name);
    gets(student[i].am);
    scanf("%d\n",&student[i].semester);
}

我面临以下问题: 在第二次迭代中,当我输入变量student[1].semester 的值时,程序不会打印我输入的内容,但它会等待我输入另一个数字,然后按回车键然后打印。我在每次gets和scanf之后都尝试了fflush(stdin),但我遇到了同样的问题。

【问题讨论】:

  • 缩进已修复。现在为什么p 没有被用于read_struct,而student 甚至存在于这段代码的any 中。 发布真实代码.

标签: c struct scanf


【解决方案1】:

尝试替换

scanf("%d\n", &student[i].semester);

scanf("%d", &student[i].semester);

除此之外,fflush(stdin) 会调用未定义的行为,所以不要使用它。

【讨论】:

  • 然后scanf 将在输入缓冲区中保留换行符,以便下次调用gets,这将读取一个空行。
  • “使用 fflush(stdin) 调用未定义的行为”...我不确定。 C 标准仅指定在输出流上调用 fflush 时会发生什么。我相信 Linux 发行版为输入流提供了增值的东西。所以我认为它的实现是定义的,而不是未定义的。如果标准中的措辞发生了变化,请接受我的道歉。
  • 它起作用了!虽然为什么?如果是 \n 问题,为什么 fflush 没有修复它?
  • @jww 检查标准的 J2,long 一连串未定义的行为和可移植性问题。其中fflush的不当使用:*“fflush函数的流指向一个输入流或一个更新流,其中输入了最近的操作”。和 C99 7.21.5.2 “如果流指向输出流或更新流,其中未输入最近的操作,fflush 函数会导致该流的任何未写入数据被传递到主机环境以写入文件;否则,行为未定义。"
【解决方案2】:

您的代码在很多层面上都是错误的。我将向您展示一种“更正确”的方式,而不仅仅是添加评论指出它们:

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

struct elements
{
    char name[50];
    int semester;
    char  am[15];
};

#define MAX_STUDENTS 2

void read_struct(struct elements *p);

int main(void)
{
    struct elements students[MAX_STUDENTS];  /* No longer global */

    for (size_t i = 0;i < MAX_STUDENTS; ++i)
        read_struct(&students[i]);  /* Pass pointer to single structure */

    for (size_t i = 0;i < MAX_STUDENTS; ++i)
    {
        printf("%ld\n", i);
        printf("%s\n", students[i].name);
        printf("%s\n", students[i].am);
        printf("%d\n", students[i].semester);
    }
}

void read_struct(struct elements *p)
{
    /* fgets is safe, in that it will not overwrite your buffer */
    fgets(p->name, sizeof(p->name), stdin);
    fgets(p->am, sizeof(p->am), stdin);
    scanf("%d", &p->semester);

    /* Skip trailing whitespace (like the newline) in the input buffer
     * left after the `scanf` call above.
     * Do it by reading one character and see if it's a newline. If it's
     * not a newline, then read next character, and so on until we get
     * the newline. It's safe because we *know* there is a newline in the
     * input buffer after the `scanf` call above.
     */
    int c;
    while ((c = fgetc(stdin)) != EOF && c != '\n')
        ;

    /* The `fgets function leaves the newline in the buffer so we
     * have to remove it, if it's there.
     * This is done by first checking if the last character (strlen(...) - 1)
     * is a newline, and if it is then we change that newline to the string
     * terminator character so the string is terminated there.
     */
    if (p->name[strlen(p->name) - 1] == '\n')
        p->name[strlen(p->name) - 1] = '\0';
    if (p->am[strlen(p->am) - 1] == '\n')
        p->am[strlen(p->am) - 1] = '\0';
}

尾随空格不起作用的原因是scanf 函数将继续读取输入,直到它看到非空格。在这种情况下,在您输入最后一个数据后,scanf 仍然想读取并丢弃所有空格,它不知道用户不应再输入任何输入。

您确实必须像我上面的程序中那样手动读取和跳过尾随空格。

【讨论】:

  • chrk 告诉我们要使用 scanf("%d", &student[i].semester);工作..你能告诉我为什么吗?
  • @chuckbartowski 更新了我的答案,解释了为什么在这种情况下您不能使用 scanf 跳过尾随空格。
  • 什么问题?因为说实话,我真的不明白你在用 read_struct 函数的代码做什么
  • @chuckbartowski 你有scanf 格式的换行符告诉scanf 读取并丢弃输入后输入的换行符。但是如果你不删除它,下次你调用gets 时会发生什么(并且不要使用那个函数!)?然后gets 将看到该换行符并将其读取为空行。
  • +1 以获得更好的答案。将fgets()scanf() 混合使用具有挑战性。可能是fgets/sscanf() or strtol() 路由&amp;p-&gt;semester
猜你喜欢
  • 2014-02-19
  • 2021-11-10
  • 2014-06-13
  • 2022-06-16
  • 1970-01-01
  • 2018-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多