標籤:safe des printf函數 工作 keyword 變數 sso syntax 進位
歡迎探討,如有錯誤敬請指正
如需轉載,請註明出處 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原始碼
| 12345678910 |
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) 表示對輸入緩衝區解鎖)。
| 1234567891011121314151617181920 |
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‘。
| 12345678 |
#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。
| 1234567 |
#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中讀取資料
| 1234567 |
#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語言的標準輸入輸出