C语言使用getchar方法清除输入缓冲区和fgets函数的使用

        计算机CPU的处理速度是很快的,我们用键盘输入速度比不上CPU的处理速度,CPU就得等键盘输入完,很浪费资源,所以,当键盘输入完了,让CPU一次性处理,可以大大提高效率。

getchar:

        函数声明:int getchar(void);

        字符输入函数,程序第一次遇到getchar函数,会让用户输入,当输入回车时结束,此时输入的内容存入到缓冲区中(包括回车符号\n)。并且返回缓冲区里读取一个字符对应的ASCII编码(通过调用putchar(n)或者printf("%c", temp1)的方式输入第一个字符)。

下面看个例子:

#include <stdio.h>

int main()
{
    int temp1;
    temp1 = getchar();
    putchar(temp1);
    temp1 = getchar();
    putchar(temp1);
    printf("\n");
    return 0;
}

运行结果: 

         输入asd,会输出as。当执行第一次getchar方法时,获取到的是第一个字符"a",下次在执行getchar方法时可以获取到第2个字符"s"。说明getchar方法内部实现了i的自增。

        如果希望将输入的每一个字符都打印出来可以用while循环:

         如果希望另一个变量temp2使用getchar方法,并且是temp2另起一行重新输入,那么需要先清空缓冲区,这样输入的内容才是temp2的内容。实际上temp2只要不是程序检测到的第一个输入函数,都需要清理。

清理缓冲区代码:

int temp = 0;
	while ((temp = getchar()) != '\n')
	{
		;
	}

        下面看一个例子:

#include <stdio.h>

int main()
{
    char* temp1;
    printf("学号:");
    scanf("%s", temp1);
    int temp2 = 0;
    printf("姓名:");
    temp2 = getchar();
    printf("您的学号:%s\n", temp1);
    printf("您的姓名:%c\n", temp2);
    return 0;
}

        使用scanf时, 会将\n存入输入缓冲区。所以getchar不会触发二次输入姓名,直接将\n赋值给了temp2,清空缓冲区即可:

        同样地,如果使用fgets输入函数一样需要清理缓存区否则会出现非预期的效果。

        代码:

#include <stdio.h>


int main()
{
    char sc[100];
    scanf("%s", sc);// 只能获得单词
    printf("先使用scanf:%s\n", sc);
    int temp = 0;
	// while ((temp = getchar()) != '\n')
	// {
	//	;
	// }
    char words[10];
    fgets(words, 10, stdin);
    fputs(words, stdout);
    fgets(words, 20, stdin);
    fputs(words, stdout);
    
    printf("%c:", *words);
    puts("Done");
}

        执行结果: 

 

         可以发现,使用scanf方法输入的回车会被第一个fgets获取到,此时words里只有一个\n字符。当第二次调用fgets方法时,又可以正常让我们输入了。所以需要在scanf函数之后就开始遍历执行getchar方法,来清空scanf方法输入的剩余字符(包括最后一个回车字符),当然这里只有一个\n字符的情况下,调用一次getchar()而不使用while循环也能达到预期效果。

        实际上两个fgets之间往往需要删除缓冲区多余的字符,fgets函数用于读取一整行输入数据。第2个参数限制读入的字符来解决溢出的问题,如果参数是n,则读取n-1个字符或者遇到第一个换行符为止,换行符存入到字符串中。第3个参数指明要读入的文件,如果读入从键盘输入的数据,要以stdin为参数。如果输入了大于等于n个字符,第1个参数只获取n-1个字符,最后一个字符为\0,结果值为aa...\0,并且剩余部分还在缓冲区里。如果输入n-1个字符换行,最后的值为aa...\n,小于n-1个字符,最后的值为aa...\n\0,长度为输入的字符数在加2个字符。如输入一个字符,长度就是3。

        所以当实际输入内容大于限制的字符数时,使用fgets读取完指定长度字符以后需要将剩余部分读取完:

#include <stdio.h>

int main()
{
    char words[10];
    int i;
    // 当第一个字符输入换行符时退出程序
    while (fgets(words, 10, stdin) != NULL && words[0] != '\n')
    {
        i = 0;
        while (words[i] != '\n' && words[i] != '\0')
            i++; // 匹配换行符\n或者空字符\0
        if (words[i] == '\n')
        words[i] = '\0'; // 换行符替换成空字符
        else while (getchar() != '\n') {
            continue; // 遇到空字符\0,这是因为输入的超过10个字符了但是还没换行,
            // 此时words中的最后一个字符赋值为空字符\0,前面9个是输入的合法内容,
            // 我们需要丢弃剩下的字符所以需要清空缓冲区剩余字段,否则下个输入函数不会另起一行输入而是从缓冲区直接取
        }
        puts(words);
    }
    puts("Done");
}

如果先遇到换行符,换行符替换成空白符(如果不替换,下一个fgets会获取这个换行符)。如果先遇到空字符,说明输入的内容超过限制的内容然后while循环将剩余部分读取完,当然最后一个换行符也会被getchar获取到,只不过不会执行continue罢了。这样就可以保证我们每次调用fgets方法,都会另起一行重新计数,当输入第一个字符为换行符时,整个程序退出第一个while循环:

如果使用scanf函数,也需要及时清除:

scanf("%d", &current->rating);

while (getchar() != '\n')

{

continue;

}

将fgets封装成一个函数:

char *s_gets(char *st, int n)
{
    char *ret_val;
    char *find;
    ret_val = fgets(st, n, stdin);
    printf("%s\n", ret_val);
    if (ret_val)
    {
        find = strchr(st, '\n');
        if (find)
        {
            *find = '\0';
        }
        else
        {
            while (getchar() != '\n')
            {
                continue;
            }
        }
    }
    return ret_val;
}

        strchr函数(char *strchr(const char *str, int c))返回一个指向该字符串中第一次出现的字符的指针,如果字符串中不包含该字符则返回NULL空指针。需要引入string.h,这里的执行结果是在参数 st 所指向的字符串中搜索第一次出现字符'\n'的位置。如果是换行符,说明输入的内容没有超过限制,只需将换行符换成空字符:*find = '\0',否则输入的内容超过了n个字符,需要将缓冲区全部读取。

        s_gets函数使用:while (s_gets(input, TSIZE) != NULL && input[0] != '\0')  { // 内部实现 }

       

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1. getchar()函数:从标准输入读取一个字符(包括空格、制表符、回车符等),返回值为int类型,表示读取到的字符的ASCII码值。 2. scanf()函数:格式化输入函数,可以读取各种数据类型,包括字符型。使用%s格式控制符读取字符串时,会自动忽略前面的空格和制表符,直到遇到第一个非空格字符为止。 3. gets()函数:读取一行字符串,包括空格和制表符,直到遇到回车符为止。该函数不安全,容易发生缓冲区溢出,已经被废弃。 4. fgets()函数:读取一行字符串,包括空格和制表符,读取的最大字符数由第二个参数指定,读取到的字符串会自动添加一个结束符'\0'。该函数比gets()更安全,可以避免缓冲区溢出。 5. getc()函数:从指定文件中读取一个字符,返回值为int类型,表示读取到的字符的ASCII码值。该函数getchar()函数类似,但可以从指定文件中读取字符。 6. fgetc()函数:从指定文件中读取一个字符,返回值为int类型,表示读取到的字符的ASCII码值。该函数与getc()函数类似,但是可以指定读取哪个文件。 7. getchar_unlocked()函数:与getchar()函数类似,但是不进行线程锁定,因此速度更快。 8. getw()函数:从指定文件中读取一个整数,返回值为int类型,表示读取到的整数。该函数通常用于读取二进制文件。 9. scanf_s()函数:安全的格式化输入函数,可以读取各种数据类型,包括字符型。与scanf()函数类似,但可以指定读取的最大字符数,避免缓冲区溢出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

heine162

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值