'fgets'在'printf'之后运行

3
我正在逐步学习C语言。我阅读了这篇关于处理字符串的输入和输出的页面:http://www.cprogramming.com/tutorial/c/lesson9.html 在最后的代码示例中,使用fgets获取并将输入分配给char数组name的变量。我尝试在自己的程序中实现类似的功能。
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

/* This is my very first C program! */

bool test=true;

/* Function Prototypes */

int mult(int x, int y);

/* Structures */

struct Person {
    int age;
    char name[256];
};

/* Complicated Array ;P */

struct Person *FirstPeriod[22];
char FakeString[100];

void PracticeStrings()
{
    int i;
    fgets(FirstPeriod[0]->name, 256, stdin);
    for (i=0;i<256;i++)
    {
            if (FirstPeriod[0]->name[i]=='\n')
                FirstPeriod[0]->name[i]='\0';
    }
    printf("\n\nHello Student 0: %s",FirstPeriod[0]->name);
}

int main()
{
    struct Person DadeLamkins;
    DadeLamkins.age=16;
    int numb;
    int x;
    int *numb_address=&numb;
    numb_address=malloc(sizeof(*numb_address));

    FirstPeriod[0]=&DadeLamkins;

    if (true)
        printf("-__- \n\n");

    printf("Please enter a number: ");
    scanf("%d", &numb);
    switch (numb) {
        case 0:
            printf("Dude, 0 is lame...\n");
            break;
        case 7:
            printf("Dude, 7 is my favorite number!\n");
            break;
        default:
            printf("You entered %d\n", numb);
            break;
    }
    for (x=0;x<numb+1;x++) {
        printf("\n::# %d",mult(x,2));
    }
    printf("\n\n%d",numb_address);
    free(numb_address);
    numb_address=0;
    PracticeStrings();
    getchar();
    return 0;
}

int mult (int x, int y)
{
    return x*y;
}

目前存在问题的是第26行的PracticeStrings函数。当我编译时,在接受输入(来自fgets)之前,它会显示Hello Student 0: 。我正在使用Code::Blocks进行编译。
任何帮助都将不胜感激!
编辑...
哈哈哈,是的,我明白我的程序效率很低,非常愚蠢。正如你所看到的那样,它并没有真正完成什么。它大多只是为了把我当前学习的东西塞进去,并尝试应用而不是逐字复制代码示例(如果我逐字复制,我能学到什么呢?)。无论如何,谢谢你们的帮助!我想那确实有道理!很遗憾我的教程没有提到,我相信这只需要稍微高一点的理解就可以了。我相信教程作者并没有想到有人会像我这样混合使用这些函数。
非常感谢你们!希望我能习惯这个。我做过很多脚本和大量的.net语言,希望我能把C加入到这个列表中 :)

int *numb_address=&numb; numb_address=malloc(sizeof(*numb_address)); -> int *numb_address = malloc(sizeof(numb)); - Ry-
@minitech,没错,说得好。我主要是为了学习而慢慢地在同一个项目上进行构建。我已经用其他语言编程一段时间了,但我想确保我掌握这些基础知识。 - Freesnöw
学习很有趣。当人们学习使用fgets等函数时,与"\n"相关的问题在某种程度上是非常普遍的。如果这让你更了解它,我会说程序已经做得很好了;P - 另外,由于您正在使用CodeBlocks(尽管我建议从简单控制台开始),请启用警告。例如对于GCC:设置->编译器和调试器->[编译器标志][类别->警告]:勾选-Wall,-Wextra,-pedantic。 - Morpfh
同样的问题在这里。感谢你的问题和答案 :) - Gottaquest
2个回答

4
当你阅读这个数字时,是因为:
scanf("%d", &numb);

stdin仍然在缓冲区中有\n。所以当您调用PracticeStrings()并随后:

fgets(FirstPeriod[0]->name, 256, stdin);

当你读取 \n ,最终得到的结果是

FirstPeriod[0]->name[i] == '\0';

此外,随着您的学习,也要学会验证 :)
例如:
if ((foo = malloc(blah)) == NULL) {
    ... err ...

而更为关键的是:

if (scanf(..) != number_of_items_i_want) {
    ... did not get a number, or what ever I wanted ...

etc.


0

我认为你的问题是由于你的控制台行为和你的scanf()调用引起的。

你的控制台默认设置可能是行缓冲。这意味着在你按下回车键之前,你在终端上输入的任何内容都不会发送到stdin。

然而,在main()中调用scanf()时,它只获取你输入的整数 - 而不是尾随的回车符。你的回车符仍然未读取,留存在stdin中,直到第26行的fgets()调用。 解决这个问题的一种方法是让scanf()也消耗尾随的回车符:

scanf("%d%*c", &numb);
这将从stdin中读取整数到&numb中,并读取(并丢弃)一个额外的字符。

这突显了使用scanf()的一个大问题,即如何使其在出现意外字符串时正常工作。 更安全的方法是使用fgets()sscanf()的组合。前者可以让你从文件中读取一个字符串(就像你已经做过的那样),后者将在其上运行格式化字符串。 例如:


    char temp[20];
    fgets(temp, 20, stdin);
    sscanf(temp, "%d", &numb);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接