详细聊聊c语言中的缓冲区问题

 更新时间:2021年11月21日 10:12:51   作者:厚积薄发ض  
缓冲区又称为缓存,它是内存空间的一部分,也就是说在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区,这篇文章主要给大家介绍了关于c语言中缓冲区问题的相关资料,需要的朋友可以参考下

发现问题

你是不是总会出现当你输入的时候(你想的是只输出一个内容),但是最后却输入两个。

比如下面这个例子

 那这到底是是哪出了问题呢?

没错这就是关于缓冲区的问题。

我们先仔细了解这个题目

例题

判断字母是否为元音字母包括大小写。

看代码实现(错误的)

#include<stdio.h>
int main()
{
	int i = 0;
	char ch = 0;
	char yyzm[20] = { 'a','A','e','E','i','I','o','O','u','U' };
	while(scanf("%c", &ch)!=EOF)
	{
		for (i = 0; i < 10; i++)
		{
			if (ch == yyzm[i])
			{
				printf("元音字母\n");
				break;
			}
		}
		if (i == 10)
		{
			printf("辅音字母\n");
		}
	}
	
	return 0;
}

问题原因

我们一般怎么输入呢?

我们先输入元音字母o然后在按一下回车,一般输入都是这样输入的到底是哪出了问题呢?

没错就是那个回车惹的祸。每当我们输入一个字母的时候,scanf读取字母之后,就会放入缓冲区中,回车一下当然也会放个'\n'字符也就是空格,当计算机拿取字符的时候先拿走一个字符,接着看里面还有没有字符,如果有字符就会继续读取,如果没有则进行下面的内容。

在我们这个代中由于是多次输入数据,就会读入字符后第一个if语句结束,如果还有字符的话,计算机就会继续拿字符,这时就拿了一个'\n','\n'不是元音字母就会进入下一个if语句输出。

那我们如何解决呢?

解决方法一:

在后面加入getchar(),它的作用就是清理缓存区,由于输入字符,计算机是一个一个字符读取的,又因为我们多次输入,所以getchar总是会读取那个'\n';

解决方法二:

我们在scanf%c后面加个'\n',由于是一个一个读取字符的,如果后面有'\n',就会把\n也拿走。

解决方案三:

在%c前面加个空格,这样做的目的是每次读取下一个字符时,就会把上一个字符后面的'\n'清理掉。

正确的代码:

#include<stdio.h>
int main()
{
	int i = 0;
	char ch = 0;
	char yyzm[20] = { 'a','A','e','E','i','I','o','O','u','U' };
	while(scanf(" %c", &ch)!=EOF)//可以在%c后面加个'\n',也可以在%c前面加个空格,目的是清理缓冲区
	{
		for (i = 0; i < 10; i++)
		{
			if (ch == yyzm[i])
			{
				printf("元音字母\n");
				break;
			}
		}
		if (i == 10)
		{
			printf("辅音字母\n");
		}
	}
	//getchar();清理缓冲区
	return 0;
}

出错二

当我们用scanf输入字符串的时候,如果遇到空格也会出现问题,这时我们就可以引入另外一个函数那就是gets函数

gets函数引入

gets函数的优点与scanf对比:

gets() 函数不仅比 scanf 简洁,而且,就算输入的字符串中有空格也可以直接输入,不用像 scanf 那样要定义多个字符数组。

关于使用 gets() 函数需要注意:使用 gets() 时,系统会将最后“敲”的换行符从缓冲区中取出来,然后丢弃,所以缓冲区中不会遗留换行符。这就意味着,如果前面使用过 gets(),而后面又要从键盘给字符变量赋值的话就不需要吸收回车清空缓冲区了,因为缓冲区的回车已经被 gets() 取出来扔掉了。(此段话是在网上查到的,整理为复习准备,请见谅)。

我们来做个题吧

逆序字符串


#include<stdio.h>
#include<string.h>
void swap(char* str)
{
    int i = 0;
    int len = strlen(str);
    for (i = 0; i < len / 2; i++)
    {
        char tmp = 0;
        tmp = str[i];
        str[i] = str[len - i - 1];
        str[len - i - 1] = tmp;
    }
    printf("%s", str);
}
int main()
{
    //逆序字符串的内容
    char str[100];
    int i = 0;
    gets(str);
    swap(str);
 
    return 0;
}

为什么要引入缓冲区

比如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。

又比如,我们使用打印机打印文档,由于打印机的打印速度相对较慢,我们先把文档输出到打印机相应的缓冲区,打印机再自行逐步打印,这时我们的CPU可以处理别的事情。

现在您基本明白了吧,缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。 

缓冲区的类型

缓冲区 分为三种类型:全缓冲、行缓冲和不带缓冲。

1) 全缓冲

在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。

2) 行缓冲

在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是标准输入(stdin)和标准输出(stdout)。

3) 不带缓冲

也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。

总结

相关文章

  • C++实现LeetCode(103.二叉树的之字形层序遍历)

    C++实现LeetCode(103.二叉树的之字形层序遍历)

    这篇文章主要介绍了C++实现LeetCode(103.二叉树的之字形层序遍历),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++利用std::forward_list查找插入数据方法示例

    C++利用std::forward_list查找插入数据方法示例

    这篇文章主要给大家介绍了关于C++利用std::forward_list查找插入数据的相关资料,文中先对std::forward_list进行了详细的介绍,而后通过示例代码给大家介绍了查找的方法,需要的朋友可以参考借鉴,下面话不多说了,来一起看看吧。
    2017-08-08
  • C++ Boost Optional示例超详细讲解

    C++ Boost Optional示例超详细讲解

    Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
    2022-11-11
  • 详解C语言中结构体的使用

    详解C语言中结构体的使用

    结构体是一些值的集合,这些值称为成员变量,结构体的每个成员可以是不同类型的变量。本文将通过示例为大家详细讲讲C语言中结构体的使用,需要的可以参考一下
    2022-07-07
  • VC++进度条process Bar的用法实例

    VC++进度条process Bar的用法实例

    这篇文章主要介绍了VC++进度条process Bar的用法,是进行VC++应用程序开发中非常常见的实用技巧,需要的朋友可以参考下
    2014-10-10
  • 详解C++中赋值,关系,函数调用运算符重载的实现

    详解C++中赋值,关系,函数调用运算符重载的实现

    本文主要为大家讲解一下三个C++中的运算符重载,分别是赋值运算符重载、关系运算符重载和函数调用运算符重载,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-06-06
  • C语言由浅入深了解变量的应用

    C语言由浅入深了解变量的应用

    这篇文章主要介绍了C语言的变量,变量是C语言语法和语义中一个很重要的知识点,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • 200行C语言代码实现简易三子棋游戏

    200行C语言代码实现简易三子棋游戏

    三子棋(井字棋)我们的童年或多或少都体验过这个游戏的乐趣,本子随手一画就是一局游戏的开始,下面这篇文章主要给大家介绍了关于200行C语言代码实现简易三子棋游戏的相关资料,需要的朋友可以参考下
    2023-05-05
  • 简单掌握桶排序算法及C++版的代码实现

    简单掌握桶排序算法及C++版的代码实现

    桶排序是将要排序的算法按桶分组排序之后再遍历汇总的一种线性排序算法,下面就让我们来通过小例子简单掌握桶排序算法及C++版的代码实现^^
    2016-07-07
  • C++友元(Friend)用法实例简介

    C++友元(Friend)用法实例简介

    这篇文章主要介绍了C++友元(Friend)用法,对于C++的学习来说有很好的参考价值,需要的朋友可以参考下
    2014-08-08

最新评论