int printf(const char * format, ... );
很顯然,與其他庫函數不同的是,printf 函數是一個“可變引數函數”(即函數引數的個數是可變的)。確切地說,是其輸出引數的個數是可變的,且每一個輸出引數的輸出格式都有對應的格式說明符與之對應,從格式串的左端第 1 個格式說明符對應第 1 個輸出引數,第 2 個格式說明符對應第 2 個輸出引數,第 3 個格式說明符對應第 3 個輸出引數,以此類推。其中,格式說明符的一般形式如下(方括號 [] 中的項為可選項):
%[flags][width][.prec][length] type_char
/*用中文標識如下:*/
%[標誌符][寬度][精度][長度]型別符
符 號 | 類 型 | 說 明 | 示 例 | 結 果 |
---|---|---|---|---|
% | 無 | 輸出字元“%”本身 | pnntf("%%"); | % |
d、i | int | 以整型輸出 | printf("%i,%d", 100,100); | 100,100 |
u | unsigned int | 以無符號整型輸出 | printf( "%u,%u",100u,100); | 100,100 |
o | unsigned int | 以八進位制無符號整S輸出 | printf( "%o”,100); | 144 |
x | unsigned int | 以十六進位制小寫輸出 | printf("%x",11); | b |
X | unsigned int | 以十六制大寫輸出 | printf("%X",11); | B |
int main(void) { int pos=0; int x = 123; int y = 456; printf("%d%n%dn", x, &pos, y); printf("pos=%dn", pos); return 0; }很顯然,上面程式碼中的 pos 將輸出 3,即“123”的長度,執行結果為:
int main(void) { char buf[20]; int pos=0; int x = 0; snprintf(buf, sizeof(buf), "%.100d%n", x, &pos); printf("pos=%dn", pos); return 0; }很顯然,上面的程式碼會輸出 100,而不是 20。
char daddr[16]; int main(void) { char buf[100]; int x=1; memset(daddr,'/0',16); printf("前X: %d/%#x (%p)n", x, x, &x); strncpy(daddr,"AAAAAAA%n",9); snprintf(buf,sizeof(buf),daddr); buf[sizeof(buf) - 1] = 0; printf("後X: %d/%#x (%p)n",x, x, &x); return 0; }在上面的程式碼中,x 將被從 1 修改成 7,其執行結果為:
符號 | 說 明 |
---|---|
(空白) | 右對齊,左邊填充 0 和空格 |
(空格) | 輸出值為正時加上空格,為負時加上負號 |
- | 輸出結果為左對齊(預設為右對齊),邊填空格(如果存在表格最後一行介紹的0,那麼將忽略0) |
+ | 在數位前增加符號“+”(正號)或“-”(負號) |
# | 類塑符是o、x、X吋,增加字首0、0x、0X;型別符是e、E、f、F、g、G時,一定要使用小數點;型別符是g、G時,尾部的 0 保留 |
0 | 引數的前面用0填充,直到佔滿指定列寬為止(如果同時存在“-”,將被“-”覆蓋,導致 0 被忽略 |
符號 | 說 明 |
---|---|
n | 至少輸出 n 個字元(n 是一個正整數)。如果輸出少於 n 個字元,則用空格填滿餘下的位置(如果識別符號為“-”,則在右側填,否則在左端填) |
0n | 至少輸出 n 個字元(n 是一個正整數)。如果輸出值少於 n 個字元,則在左側填滿 0 |
* | 輸出字元個數由下一個輸出引數指定(其必須為一個整形量) |
符號 | 說 明 |
---|---|
無 | 系統預設精度 |
.0 | 對於 d、i、o、u、x、X等整形型別符,採用系統預設精度;對於f、F、e、E等浮點型別符,不輸出小數部分 |
.n |
1) 對於d、i、o、u、x、X型別符,至少輸出 n 位數位,且:
3) 對於 g 和 G 型別符,最多輸出 n 位有效數位 4) 對於 s 型別符,如果對應的輸出串的長度不超過 n 個字元,則將其原樣輸出,否則輸出其頭 n 個寧符 |
* | 輸出精度由下一個輸出引數指定(其必須為一個整型量) |
符號 | 說 明 |
---|---|
hh | 與d、i 一起使用,表示一個signed char 型別的值;與o、u、x、X—起使用,表示一個unsigned char 型別的值;與 n 一起使用,表示相應的變元是指向 signed char 型變數的指標(c99 ) |
h | 與d、i、o、u、x、X 或 n 一起使用,表示一個short int 或 unsigned short int 型別的值 |
l | 與d、i、o、u、x、X 或 n 一起使用,表示一個 long int 或者 unsigned long int 型別的值 |
ll | 與 d、i、o、u、x、X 或 n —起使用,表示相應的變元是 long long int 或 unsigned long long int 型別的值(c99 ) |
j | 與 d、i、o、u、x、X 或 n —起使用,表示匹配的變元是 intmax_t 或 uintmax_t 型別,這些型別在“stdint. h”中宣告(c99 ) |
z | 與 d、i、o、u、x、X 或 n —起使用,表示匹配的變元是指向 size_t 型別物件的指標,該型別在“stddef. h”中宣告(c99 ) |
t | 與d、i、o、u、x、X 或 n —起使用,表示匹配的變元是指向 ptrdiff_t 型別物件的指標,該型別在“stddef. h”中宣告(c99 ) |
L | 和a、A、e、E、f、F、g、G—起使用,表示一個long double型別的值 |
int k=8; printf("%d,%dn",k,++k);對於上面的程式碼,表面上看起來輸出的結果應該是“8,9”。但實際情況並非如此,在呼叫printf函數時,其引數是從右至左進行處理的,即將先進行 ++k 運算,所以最後的結果是“9,9”。由此可見,千萬不要在 printf 語句中試圖改變輸出變數的值,如果確實需要改變,可以按照下面的範例程式碼形式來處理:
printf("%dn",k); printf("%dn",++k);這樣處理之後,其結果就是我們所需要的“8,9”了。
int scanf (const char *format, ...);從函數原型可以看出,同 printf 函數相似,scanf 函數也是一個“可變引數函數”。同時,scanf 函數的第一個引數 format 也必須是一個格式化串。除此格式化串之外,scanf 函數還可以有若干個輸入地址,且對於每一個輸入地址,在格式串中都必須有一個格式說明符與之一一對應。即從格式串的左端第 1 個格式說明符對應第 1 個輸入地址,第 2 個格式說明符對應第 2 個輸入地址,第 3 個格式說明符對應第 3 個輸入地址,以此類推。
%[*][width][length] type_char
/*用中文標識如下:*/
%[*][寬度][長度]型別符
int main(void) { char c[5]; int i=0; printf("輸入資料(hello):n"); for(i = 0;i < 5; ++i) { scanf("%c", &c[i]); } printf("輸出資料:n"); printf("%sn", c); return 0; }對於上面這段範例程式碼,我們希望在“c[5]”字元陣列中能夠儲存“hello”字串,並在最後輸出到螢幕上。從表面上看,這段程式沒有任何問題,但實際情況並非如此。當我們依次輸入“h(回車)”“e(回車)”,然後再輸入“l”時,問題發生了。此時,程式不僅中斷輸入操作,而且會列印出字元陣列 c 中的內容,其執行結果為:
#include <stdio.h> void flush() { char c; while ((c=getchar()) != 'n'&&c!=EOF); } int main(void) { char c[5]; int i=0; printf("輸入資料(hello):n"); for(i = 0; i < 5; ++i) { scanf("%c", &c[i]); flush(); } printf("輸出資料:n"); printf("%sn", c); return 0; }這樣,就從根本上解決了輸入緩衝區問題,其執行結果為:
int main(void) { int a=0; printf("輸入資料:n"); /*請注意,這裡多了一個回車符n*/ scanf("%dn",&a); printf("輸出資料:n",a); printf("%dn",a); return 0; }在上面的程式碼中,因為在“scanf("%dn",&a);”語句中多加了一個回車符“n”,導致的結果就是要輸入兩個數,程式才會正常結束,而不是我們所期望的一個數。執行結果為: