1. 程式人生 > >C語言之清空快取區

C語言之清空快取區

在C語言中,我們常常需要去清空快取區,對於快取區清空的重要性,接下來我們進行具體的說明。
首先我們先解釋一下快取區。

1.快取區

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是無快取的。

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

2.清空快取區

所以我們要對快取區清空是很重要的,在這裡我們給出了下面三種辦法來實現:

  • 使用fflush()函式

fflush()函式沖洗流中的資訊,該函式通常用於處理磁碟檔案。清除讀寫緩衝區,需要立即把輸出緩衝區的資料進行物理寫入時。fflush()函式包含在stdio.h標頭檔案中。
函式原:int fflush(FILE *stream),在這裡的stream就是所要清除快取區的檔案。
函式的返回值:當進行重新整理成功返回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函式接收字元。
接下來是第二種方法。

  • 使用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;
}

這裡寫圖片描述
依然可以達到我們要的效果。

  • 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;
}

這裡寫圖片描述