1. 程式人生 > >C語言的標準輸入輸出

C語言的標準輸入輸出

分別是 空白 col end 底層 idt itl ufs 整數

歡迎探討,如有錯誤敬請指正

如需轉載,請註明出處 http://www.cnblogs.com/nullzx/


1. 標準輸入輸出

技術分享圖片標準輸入、輸出主要由緩沖區和操作方法兩部分組。緩沖區實際上可以看做內存中的字符串數組,而操作方法主要是指printf、scanf、puts、gets,getcha、putcahr等操作緩沖區的方法。在C++以及Java等面向對象的編程語言中,將緩沖區以及操作緩沖區的方法封裝成一類對象,這類對象就稱為流。

緩沖區最大的特點主要體現在數據的一次性,即數據被printf、scanf從緩沖區中取出後就被使用了,或者說消耗了。可以把緩沖區比喻成管道,緩沖區中的數據比喻成水流,printf、scanf等方法比喻成開關,當打開開關,水就會慢慢流逝,而流出去的水就再也收不回來了。

由於不同系統,不的硬件底層實現輸入輸出的具體方法可能不一樣,C語言要求系統為每個程序提供兩個指針,這兩個指針分別指向兩個結構體,這兩個結構體分別表示了鍵盤和屏幕在內存中的抽象表示(緩沖區的地址值被記錄在這個結構體中),並將指向這兩個結構體的指針命名為stdin和 stdout.這兩個指針就是所謂的標準輸入和標準輸出。

還有一點應該始終銘記,標準輸入和輸出緩沖區中存儲的是字符的ASCII碼值。比如你想從鍵盤上輸入了123給一個變量,那麽在緩沖區中存儲是三個字節,分別是字符‘1’的ASCII碼值,字符‘2’的ASCII碼值,字符‘3’的ASCII碼值,然後將這個這三個ASCII值序列轉換為一個數值給這個變量。同理,從屏幕輸出“123”,計算機並不認為它輸出的是一個數值,計算機實際上僅僅是描繪了一個‘1’的ASCII碼值對應的圖形,‘2’的ASCII的值對應的圖形,‘3’的ASCII碼值對應的圖形。

2. getchar、putchar

putchar的作用主要是向輸出緩沖區中寫入一個字符。

getchar的作用主要是向輸入緩沖區中讀取一個字符。如果碰到文件結尾,返回-1

getchar源代碼

1 2 3 4 5 6 7 8 9 10 int getchar(void){ static char buf[BUFSIZ]; static char* bb = buf; static int n = 0; if (n == 0) { n = read(0, buf, BUFSIZ); bb = buf;
} return(--n >= 0) ? (unsigned char)*bb++ : EOF; }

OEF是一個宏,表示-1。getchar的返回值是int,對於文件來說-1表示了文件的結尾。我們可以在鍵盤上利用Ctrl+Z來實現類似的效果

從getchar的源代碼中可以看出,如果發現字符數組buf已空(n==0),則調用read方法從鍵盤讀取數據(該方法會導致阻塞),並讓指針指向數組的首地址。如果緩沖區還有字符沒有被讀取(n > 0),則讀取它,同時n-1,指針(bb)向後移動一位。當緩沖區已空(n==0),且read函數讀取失敗時(讀取到了文件末尾),返回EOF。

從scanf的源代碼中可以看出getchar可以讀入任何字符,包括空白符(空白符包括:空格、換行符、制表符等)。

3. gets、puts

puts函數主要向輸出緩沖區寫入一個字符串,並再字符串輸出結束以後,再額外輸出一個換行符 ‘\n‘

gets用於從輸入流的緩沖區中讀取字符到指定的數組。讀取過程中會忽略所有的前導空白符,讀入的第一個字符為非空白符,直到遇到換行符才停止讀入,結束的換行符(‘\n‘)被gets函數讀從緩沖區讀取走了,存於數組中,然後被替換成‘\0‘

gets 源代碼(只需要看for循環這部分代碼,FLOCKFILE(stdin)表示對輸入緩沖區加鎖對;FUNLOCKFILE(stdin) 表示對輸入緩沖區解鎖)。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 char* gets(char *buf){ int c; char *s; static int warned; static const char w[] = "warning: this program uses gets(), which is unsafe.\n"; FLOCKFILE(stdin); ORIENT(stdin, -1); if (!warned) { (void)_write(STDERR_FILENO, w, sizeof(w) - 1); warned = 1; } for (s = buf; (c = __sgetc(stdin)) != ‘\n‘;) if (c == EOF) if (s == buf) { FUNLOCKFILE(stdin); return (NULL); } else break; else *s++ = c; *s = 0; FUNLOCKFILE(stdin); return (buf); }

從源代碼可以看出,如果讀入了‘\n‘則停止,並替換成‘\0‘

4. printf的使用

定義函數 int printf(const char * format,...);

函數說明 printf()會根據參數format字符串來轉換並格式化數據,然後將結果寫出到標準輸出設備,直到出現字符串結束(‘\n‘)為止。

參數format字符串可包含下列三種字符類型:

(1)一般文本,伴隨直接輸出。

(2)轉義字符,如\t、\n等。

(3)格式轉換字符,格式轉換為一個百分比符號(%)及其後的格式字符所組成。一般而言,每個%符號在其後都必需有一printf的參數與之相呼應(只有當%%轉換字符出現時會直接輸出%字符)

格式轉換字符詳解 “%[符號][寬度][.精度]類型”

[寬度]:表示最少輸出的字符個數

[符號]:“-”表示對齊方式

(1)%-8,左對齊,當顯示字符不足8時,右補空格

(2)%08,右對齊,當顯示字符不足8時,左補0

[.精度]對於浮點數表示小數點後的位數

數值小數點後的位數大於顯示精度,則只能顯示[.精度]個小樹位數(四舍五入),如果數值小數點後的位數小於顯示精度,則補零。

%.5 小數點後顯示5位

類型

(1)%d:用於顯示十進制有符號數,char,short,int,long long

(2)%u:用於顯示十進制無符號數,unsinged short,unsigned int,

unsigned long long

(3)%x: 用於顯示十六進制整數,所有有符號及無符號整型

(4)%f:用於顯示十進制浮點數,float,double

(5)%c:顯示字符

(6)%s:顯示字符串

printf(“%s”,xxx)puts(xxx)的區別:puts函數會自動添加換行,而printf(“%s”,……)不會。

5. scanf的使用

定義函數 int scanf(const char * format,...);

函數說明 scanf()會將輸入的數據根據參數format字符串來轉換並格式化數據。Scanf()格式轉換的一般形式如下:

“%[寬度][數據所占字節數]輸入類型”

[寬度]:最多輸入的字符個數

[數據類型]:

h表示兩字節,short

l表示八字節,用於long long和 double

什麽都沒有表示四字節

[數據類型]輸入類型

(1)%d:int

(2)%f:float

(3)%lf:double

(4)%hd:short

scanf(“%c”,&x) 等價於 x = getchar(),雖然getchar的返回值是int類型,但不影響使用

(5)%s:字符串

用scanf讀取字符串時,忽略前導的空白符,再次遇到空白符會結束輸入,並將再次遇到的空白符留在緩沖區內,自動添加字符串數組的結束標誌‘\n‘

1 2 3 4 5 6 7 8 #include <stdio.h> void main(int argc, char* argv[]){ char a[20]; int ch; scanf_s("%s",a,20); printf("%s\n", a); while ((ch = getchar()) != EOF ){ putchar(ch); } }

技術分享圖片

我們輸入i love you(ctrl+z)

scanf_s 讀取字符‘i以後結束(i後是空格),通過getchar函數第一個讀取的字符就是空格,getchar會一直讀取緩沖區中,直到緩沖區為空。

6. fgets、fputs、fscanf、fprintf、fgetchar、fputchar

上述方法只是多了個參數FILE * stream,表示這時的輸入以stream指定的文件作為輸入或者輸出

char* fgets(char* _Buf, int _MaxCount, FILE* _File);

int fputs(const char * _Str,FILE* _File);

int fprintf(FILE* _File, const char * _Format, ...);

int fscanf(FILE* _File, const char * _Format, ...);

int fgetc (FILE* _File) ;

int fputc(int _Ch, FILE* _File);

7. 其它相關函數

int sprintf( char *_Dest, const char * format,...);

函數說明sprintf和printf函數很類似,printf是將結果寫入到標準輸出流中,而sprintf是將結果寫入到字符串數組_Dest中。返回值返回值返回參數str字符串長度,失敗則返回-1。

1 2 3 4 5 6 7 #include<stdio.h> void main(){ char* a = "This is string A!"; char buf[80]; sprintf_s(buf,"begin %s end\n", a); printf("%s",buf); }

技術分享圖片

int sscanf_s(const char * _Src, const char * _Format, ...);

sscanf函數與scanf類似,只不過scanf是從輸入流中讀取數據,而sscanf是從字符串數組_Src中讀取數據

1 2 3 4 5 6 7 #include<stdio.h> void main(int argc, char* args[]){ int i; double n; char str[20] = "123 3.1415"; sscanf_s(str, "%d%lf", &i, &n); printf("%d\n%f\n", i, n); }

技術分享圖片

設置流緩沖

int fflush(FILE* stream);

void setbuf(FILE* stream, char* buf);

int setvbuf(FILE* stream, char* buf, int mode);

數據總是先寫入(或者讀取)到流中,當緩沖區滿了後,在將其寫入到設備(或者獲取讀取到程序中),這樣的工作方式效率更高。但是有時候我們可能需要更快的相應速度,我們可以調用fflush方法來沖刷緩沖區,註意這裏沖刷的意思不是將緩沖區的內容刪除,而是將還未滿的緩沖區中的內容寫入到設備(或者讀取到程序中)

setbuf中可以由參數buf自己設定緩沖區的位置和大小(大小由buf數組的大小決定)。

setvbuf中的第三個參數決mode定了緩沖區的緩沖類型。它由三種取值

_IOFBU:全滿緩沖類型

_IOLBU:行滿緩沖類型

_IONBU:無緩沖類型

C語言的標準輸入輸出