C/C++之诡异的fgets()函数的疑问!!!

拿一个简单的acm题来说:

单词个数:
Description

给定一句话,长度不超过1000,请你看看里面有几个单词,单词均为大小写字母构成,单词间会有一个或多个空格等非字母隔开

Input

只有一个字符串

Output

输出单词的个数
如果使用fgets()函数的话代码如下:

#include<cstdio>   //代码一;
#include<cstring>
#include<cctype>
char s[1005];
int main()
{
    fgets(s,sizeof(s),stdin);
    int len = strlen(s);
    int flag = 1;
    int num = 0;
    for(int i = 0;i < len; ++i)
    {
        if(isalpha(s[i]))
        {
            if(flag)
            {
                num++;
                flag = 0;
            }
        }
        else flag = 1;
    }
    printf("%d\n",num);
    return 0;
}

有关fgets与isalpha的相关介绍请看我的其他文章。
到这里还没有什么问题但是,由于写期末实验题,我把这个代码稍微改造一下就出现了问题。
问题代码:

#include<iostream>   //代码二;
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cstdlib>
using namespace std;
char s[1005];
void f(){
    fgets(s,sizeof(s),stdin);
    int len = strlen(s);
    int flag = 1;
    int num = 0;
    for(int i = 0;i < len; ++i)
    {
        if(isalpha(s[i]))
        {
            if(flag)
            {
                num++;
                flag = 0;
            }
        }
        else flag = 1;
    }
    cout<<num;
}
int main()
{
    int num;
    cin>>num;
    switch(num){
        case 1:
            f();
            break;
    }
    return 0;
}

把上组代码当作一个函数调用,然后,运行一下的小伙伴会发现,通过switch掉用会直接跳过fegts函数的键盘输入。如果不通过switch调用,代码如下:

#include<iostream>  //代码三;
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cstdlib>
using namespace std;
char s[1005];
void f(){
    fgets(s,sizeof(s),stdin);
    int len = strlen(s);
    int flag = 1;
    int num = 0;
    for(int i = 0;i < len; ++i)
    {
        if(isalpha(s[i]))
        {
            if(flag)
            {
                num++;
                flag = 0;
            }
        }
        else flag = 1;
    }
    cout<<num;
}
int main()
{
    f();
    return 0;
}

其结果与代码一是一样的。一旦通过switch调用就会直接输出0,没有丝毫给一个从键盘输入字符串的机会。(很诡异!!!)。
接下来,为了找出原因,我又实验出更诡异的事,代码如下:

#include<iostream>   //代码四;
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cstdlib>
using namespace std;
char s[1005];
void f(){
    cin>>s;
    fgets(s,sizeof(s),stdin);
    int len = strlen(s);
    int flag = 1;
    int num = 0;
    for(int i = 0;i < len; ++i)
    {
        if(isalpha(s[i]))
        {
            if(flag)
            {
                num++;
                flag = 0;
            }
        }
        else flag = 1;
    }
    cout<<num;
}
int main()
{
    f();
    return 0;
}

就是代码四,代码四只是在代码二的基础上在fgets前面加上了一句“cin>>s;“,然后诡异的事情出现了。运行后终端不再跳过键盘输入了,可以正常的从键盘输入,但是,运行后发现:”cin竟然可以读入带空格的字符串了!!!!“(众所周知,cin只会读取空格之前的字符,一旦遇到空格就停止读取了。)也就是cin可以读取空格之后的字符了。还有,输出的结果num也不对,怎么不对呢?输出的num总是比实际的少1!!!

后来在网上查找了一下,网友只解释了:“关于fgets从键盘读取,直接跳过键盘输入的问题”,原因是stdin缓存没有清除干净的缘故。
C语言里的gets()函数功能是从输入缓存中读取多个字符,遇到回车符时,结束输入。当使用gets()函数之前有过数据输入,并且,操作者输入了回车确认,这个回车符没有被清理,被保存在输入缓存中时,gets()会读到这个字符,结束读字符操作。因此,从用户表面上看,gets()没有起作用,跳过了。
解决办法:
方法一、在fgets()前加fflush(stdin); //强行清除缓存中的数据(windows下可行)
方法二、根据程序代码,确定前面是否有输入语句,如果有,则增加一个getchar()命令,然后再调用fgets()命令。

原来,造成跳过键盘输入的原因是在我输入switch中的num后需要通过按确认键及回车键来进行下一步,于是fgets读取到了这个被保存在输入缓存中的回车键,然后,fgets跳过了。

但是,fgets函数跳过的问题解决了,“cin>>s;”的问题原因是啥呢???
求教懂的大佬!!!!

猜你喜欢

转载自blog.csdn.net/henu1710252658/article/details/80189415