C語言基礎 —— 清空緩存區

其實好多大佬都寫了有關清除緩存區的博客,這裏我整理一下,
感謝 宇哲_安菲爾德 大佬的大部分博文
感謝紫紅的淚 大佬的大部分博文
感謝C語言中文網
下面進入正題,先了解一下緩存區

緩存區

C語言中的緩衝區又稱爲緩存,它是內存空間的一部分。
  也就是說,在內存空間中預留了一定的存儲空間,這些存儲空間用來緩衝輸入或輸出的數據,這部分預留的空間就叫做緩衝區。
    C語緩衝區分爲三種類型:1、全緩衝 2、行緩衝 3、不帶緩衝。
  緩衝區根據其對應的是輸入設備還是輸出設備,分爲輸入緩衝區和輸出緩衝區。

例如,在我們平時要在磁盤中讀取信息的情況下,先會把數據放到緩存區中,讀取完後,再次從磁盤中讀取信息。
緩存區,他的意義就是在高速CPU與低速的設備之間的一個區域,這個區域讓CPU工作效率更高。

  1. 全緩衝
    當填滿標準I/O緩存後才進行實際I/O操作。全緩衝的典型代表是對磁盤文件的讀寫。

  2. 行緩衝
    當在輸入和輸出中遇到換行符時,執行真正的I/O操作。這時,我們輸入的字符先存放在緩衝區,等按下回車鍵換行時才進行實際的I/O操作。典型代表是標準輸入(stdin)和標準輸出(stdout)。

  3. 不帶緩衝
    也就是不進行緩衝,標準出錯情況stderr是典型代表,這使得出錯信息可以直接儘快地顯示出來。

大部分系統默認使用下列類型的緩存:
標準出錯是不帶緩存的。
如果是涉及終端設備的流,則它們是行緩存的,否則是全緩存的。

我們經常用到的輸入輸出流,在目前的ANSI C 中緩存的特徵是:stdin和stdout是行緩存;而stderr是無緩存的。

瞭解了這些,接下來我們進入正題,接下來我們要清楚爲什麼要清空緩存區,
這是因爲在你有的時候在輸入一個字符後,在輸入一個字符,如果你不清空緩衝區,那上一個字符還在你的緩衝區內!這樣就造成錯誤了!

清空緩存區

1、使用fflush()函數

fflush()函數沖洗流中的信息,該函數通常用於處理磁盤文件。清除讀寫緩衝區,需要立即把輸出緩衝區的數據進行物理寫入時。fflush()函數包含在stdio.h頭文件中。
函數的返回值:當進行刷新成功返回0,失敗返回EOF。沒有緩衝區或者只讀打開時也返回0值。
還有需要注意的是:如果fflush返回EOF,數據可能由於寫錯誤已經丟失。
用法示例:fflush(stdin)刷新標準輸入緩衝區,fflush(stdout)刷新標準輸出緩衝區。 printf(“。。。。。。。。。。。”);後面加fflush(stdout);可提高打印效率
代碼示例:

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int num;
    char a;
    scanf("%d", &num);
    a = getchar();
    printf("num=%d,a=%c\n", num, a);
    system("pause");
    return 0;
}

在這裏插入圖片描述
在執行這個程序的時候我們會發現,在我們輸入第一個字符後敲擊‘\n’之後,程序就結束了,這是因爲我們沒有清空緩存區,getchar()函數接收的是‘\n’,最後造成了程序的停止。
接下來我們來使用fflush()函數。

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int num;
    char a;
    scanf("%d", &num);
    fflush(stdin);
    a = getchar();
    printf("num=%d,a=%c\n", num, a);
    system("pause");
    return 0;
}

在這裏插入圖片描述
我們在這裏可以看到,當使用了fflush()函數對輸入流進行清空緩存區以後,就可以正常讓getchar函數接收字符。

2、使用while((ch = getchar()) != ‘\n’ && ch != EOF);語句

這種方法可以稱爲萬能清空緩存區御語句。
代碼示例:

#include <stdio.h>
#include<stdlib.h>

int main()
{
    char c1 = 0;
    char c2 = 0;
    scanf("%c", &c1);
    c2 = getchar();
    printf("c1=%d,c2=%c", c1, c2);
    system("pause");
    return 0;
}

在這裏插入圖片描述

在這裏我們依然沒有清空緩存區,得到的效果是這樣的,getchar()函數依然接收了’\n’,造成程序停止。
接下來,我們使用while((ch = getchar()) != ‘\n’ && ch != EOF);語句

#include <stdio.h>
#include<stdlib.h>

int main()
{
    char c1 = 0;
    char c2 = 0;
    int ch;
    scanf("%d", &c1);
    while ((ch = getchar()) != EOF && ch != '\n')
    {
        ;
    }
    c2 = getchar();
    printf("c1=%d,c2=%c", c1, c2);
    system("pause");
    return 0;
}

在這裏插入圖片描述

加入了while ((ch = getchar()) != EOF && ch != ‘\n’);語句,完成了清空緩存區
事實上有時我們會將這個語句封裝在一個函數中,這樣會讓程序的可移植性更強。

#define CLEAR_BUF \
    {\
    int ch; \
while ((ch = getchar()) != EOF && ch != '\n')\
        {\
        ; \
        }\
    }


#include <stdio.h>
#include<stdlib.h>

int main()
{
    char c1 = 0;
    char c2 = 0;
    scanf("%d", &c1);
    CLEAR_BUF
        c2 = getchar();
    printf("c1=%d,c2=%c", c1, c2);
    system("pause");
    return 0;
}
3、使用 scanf("%*[^\n]"); scanf("%*c"); 語句

原理如下:
首先需要明白的是,等到需要清空緩衝區的時候,緩衝區中的最後一個字符一定是換行符\n,因爲輸入緩衝區是行緩衝模式,用戶按下回車鍵會產生換行符,結束本次輸入,然後輸入函數開始讀取。

scanf("%*[^\n]");將換行符前面的所有字符清空,scanf("%*c");將最後剩下的換行符清空。

4、setbuf()函數關閉緩存區

接下來我們要說另外一種清空緩存區的方法,與其說是清空緩存區,不如說他是關閉緩存區。
setbuf()函數
linux中的C函數,主要用於打開和關閉緩衝機制。包含在頭文件stdio.h中。
setbuf函數具有打開和關閉緩衝機制。爲了帶緩衝進行I/O,參數buf必須指向一個長度爲BUFSIZ的緩衝區。通常在此之後該流就是全緩衝的,但是如果該流與一個終端設備相關,那麼某些系統也可以將其設置爲行緩衝。爲了關閉緩衝,可以將buf參數設置爲NULL。
函數原型:void setbuf(FILE *stream,char *buf);一個參數是文件流,一個參數是buf指向的緩衝區長度,這個長度就是在stdio.h中定義的宏BUFSIZ所決定的。當定義buf爲空時,setbuf函數將使的文件I/O不帶緩衝。

#include <stdio.h>
#include<stdlib.h>
char outbuf[50];
int main(void)
{
    /* 將outbuf與stdout輸出流相連接 */
    setbuf(stdout, outbuf);
    /* 向stdout中放入一些字符串 */
    puts("This is a test of buffered output.");
    puts("This output will go into outbuf");
    puts("and won't appear until the buffer");
    puts("fills up or we flush the stream.\n");
    /* 以下是outbuf中的內容 */
    puts(outbuf);
    /*刷新流*/
    fflush(stdout);
    system("pause");
    return 0;
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章