1. 程式人生 > >C和C++格式化輸入輸出

C和C++格式化輸入輸出

一、printf()函式
printf()函式是格式化輸出函式, 一般用於向標準輸出裝置按規定格式輸出
資訊。在編寫程式時經常會用到此函式。printf()函式的呼叫格式為:
printf(”<格式化字串>”, <參量表>);
其中格式化字串包括兩部分內容: 一部分是正常字元, 這些字元將按原
樣輸出; 另一部分是格式化規定字元, 以”%”開始, 後跟一個或幾個規定字元,
用來確定輸出內容格式。
參量表是需要輸出的一系列引數, 其個數必須與格式化字串所說明的輸出
引數個數一樣多, 各引數之間用”,”分開, 且順序一一對應, 否則將會出現意想
不到的錯誤。
1. 格式化規定符
Turbo C2.0提供的格式化規定符如下:
━━━━━━━━━━━━━━━━━━━━━━━━━━
符號 作用
——————————————————————————
%d 十進位制有符號整數
%u 十進位制無符號整數
%f 浮點數
%s 字串
%c 單個字元
%p 指標的值
%e 指數形式的浮點數
%x, %X 無符號以十六進位制表示的整數
%0 無符號以八進位制表示的整數
%g 自動選擇合適的表示法
━━━━━━━━━━━━━━━━━━━━━━━━━━
說明:
(1). 可以在”%”和字母之間插進數字表示最大場寬。
例如: %3d 表示輸出3位整型數, 不夠3位右對齊。
%9.2f 表示輸出場寬為9的浮點數, 其中小數位為2, 整數位為6,
小數點佔一位, 不夠9位右對齊。
%8s 表示輸出8個字元的字串, 不夠8個字元右對齊。
如果字串的長度、或整型數位數超過說明的場寬, 將按其實際長度輸出。
但對浮點數, 若整數部分位數超過了說明的整數位寬度, 將按實際整數位輸出;
若小數部分位數超過了說明的小數位寬度, 則按說明的寬度以四捨五入輸出。
另外, 若想在輸出值前加一些0, 就應在場寬項前加個0。
例如: %04d 表示在輸出一個小於4位的數值時, 將在前面補0使其總寬度
為4位。
如果用浮點數表示字元或整型量的輸出格式, 小數點後的數字代表最大寬度,
小數點前的數字代表最小寬度。
例如: %6.9s 表示顯示一個長度不小於6且不大於9的字串。若大於9, 則
第9個字元以後的內容將被刪除。
(2). 可以在”%”和字母之間加小寫字母l, 表示輸出的是長型數。
例如: %ld 表示輸出long整數
%lf 表示輸出double浮點數
(3). 可以控制輸出左對齊或右對齊, 即在”%”和字母之間加入一個”-” 號可
說明輸出為左對齊, 否則為右對齊。
例如: %-7d 表示輸出7位整數左對齊
%-10s 表示輸出10個字元左對齊
2. 一些特殊規定字元
━━━━━━━━━━━━━━━━━━━━━━━━━━
字元 作用
——————————————————————————
\n 換行
\f 清屏並換頁
\r 回車
\t Tab符
\xhh 表示一個ASCII碼用16進表示,
其中hh是1到2個16進位制數
━━━━━━━━━━━━━━━━━━━━━━━━━━
例1

#include<stdio.h>
#include<string.h>
int main()
{
char c, s[20], *p;
int a=1234, *i;
float f=3.141592653589;
double x=0.12345678987654321;
p=”How do you do”;
strcpy(s, “Hello, Comrade”);
*i=12;
c=’\x41′;
printf(”a=%d\n”, a); /*結果輸出十進位制整數a=1234*/
printf(”a=%6d\n”, a); /*結果輸出6位十進位制數a= 1234*/
printf(”a=%06d\n”, a); /*結果輸出6位十進位制數a=001234*/ printf(”a=%2d\n”, a); /*a超過2位, 按實際值輸出a=1234*/ printf(”*i=%4d\n”, *i); /*輸出4位十進位制整數*i= 12*/ printf(”*i=%-4d\n”, *i); /*輸出左對齊4位十進位制整數*i=12*/ printf(”i=%p\n”, i); /*輸出地址i=06E4*/ printf(”f=%f\n”, f); /*輸出浮點數f=3.141593*/ printf(”f=6.4f\n”, f); /*輸出6位其中小數點後4位的浮點數 f=3.1416*/ printf
(”x=%lf\n”, x); /*輸出長浮點數x=0.123457*/ printf(”x=%18.16lf\n”, x);/*輸出18位其中小數點後16位的長浮點 數x=0.1234567898765432*/ printf(”c=%c\n”, c); /*輸出字元c=A*/ printf(”c=%x\n”, c); /*輸出字元的ASCII碼值c=41*/ printf(”s[]=%s\n”, s); /*輸出陣列字串s[]=Hello, Comrade*/ printf(”s[]=%6.9s\n”, s);/*輸出最多9個字元的字串s[]=Hello, Co*/ printf(”s=%p\n”, s); /*輸出陣列字串首字元地址s=FFBE*/ printf(”*p=%s\n”, p); /* 輸出指標字串p=How do you do*/ printf(”p=%p\n”, p); /*輸出指標的值p=0194*/ getch(); retunr 0; }

二、scanf()函式
scanf()函式是格式化輸入函式, 它從標準輸入裝置(鍵盤) 讀取輸入的資訊。
其呼叫格式為:
scanf(”<格式化字串>”, <地址表>);
格式化字串包括以下三類不同的字元;
1. 格式化說明符: 格式化說明符與printf()函式中的格式說明符基本相同。
2. 空白字元: 空白字元會使scanf()函式在讀操作中略去輸入中的一個或多
個空白字元。
3. 非空白字元: 一個非空白字元會使scanf()函式在讀入時剔除掉與這個非
空白字元相同的字元。
地址表是需要讀入的所有變數的地址, 而不是變數本身。這與printf()函式
完全不同, 要特別注意。各個變數的地址之間同”,”分開。
例2:

main()
{
int i, j;
printf(”i, j=?\n”);
scanf(”%d, %d”, &i, &j);
}

上例中的scanf()函式先讀一個整型數, 然後把接著輸入的逗號剔除掉, 最
後讀入另一個整型數。如果”,”這一特定字元沒有找到, scanf()函式就終止。若
引數之間的分隔符為空格, 則引數之間必須輸入一個或多個空格。
說明:
(1). 對於字串陣列或字串指標變數, 由於陣列名和指標變數名本身就
是地址, 因此使用scanf()函式時, 不需要在它們前面加上”&”操作符。
例3

mian()
{
char *p, str[20];
scanf(”%s”, p); /*從健盤輸入字串*/
scanf(”%s”, str);
printf(”%s\n”, p); /*向螢幕輸出字串*/
printf(”%s\n”, str);
}

(2). 可以在格式化字串中的”%”各格式化規定符之間加入一個整數, 表示
任何讀操作中的最大位數。
如例3中若規定只能輸入10字元給字串指標p, 則第一條scanf() 函式語句
變為
scanf(”%10s”, p);
程式執行時一旦輸入字元個數大於10, p就不再繼續讀入, 而後面的一個讀
入函式即scanf(”%s”, str)就會從第11個字元開始讀入。
實際使用scanf()函式時存在一個問題, 下面舉例進行說明:
當使用多個scanf()函式連續給多個字元變數輸入時, 例如:

main()
{
char c1, c2;
scanf(”%c”, &c1);
scanf(”%c”, &c2);
printf(”c1 is %c, c2 is %c”, c2\1, c2);
}

執行該程式, 輸入一個字元A後回車 (要完成輸入必須回車), 在執行scanf
(”%c”, &c1)時, 給變數c1賦值”A”, 但回車符仍然留在緩衝區內, 執行輸入語句
scanf(”%c”, &c2)時, 變數c2輸出的是一空行, 如果輸入AB後回車, 那麼輸出結
果為: c1 is A, c2 is B。
要解決以上問題, 可以在輸入函式前加入清除函式fflush()修改以上程式變成:

#include<stdio.h>
main()
{
char c1, c2;
scanf(”%c”, &c1);
fflush(stdin);
scanf(”%c”, &c2);
printf(”c1 is %c, c2 is %c”, c1, c2);
}

1.1.2 非格式化輸入輸出函式
非格式化輸入輸出函式可以由上面講述的標準格式化輸入輸出函式代替, 但
這些函式編譯後代碼少, 相對佔用記憶體也小, 從而提高了速度, 同時使用也比較
方便。下面分別進行介紹。
一、puts()和gets()函式
1. puts()函式
puts()函式用來向標準輸出裝置(螢幕)寫字串並換行, 其呼叫格式為:
puts(s);
其中s為字串變數(字串陣列名或字串指標)。
puts()函式的作用與語printf(”%s\n”, s)相同。
例4:

main()
{
char s[20], *f; /*定義字串陣列和指標變數*/
strcpy(s, “Hello! Turbo C2.0″); /*字串陣列變數賦值*/
f=”Thank you”; /*字串指標變數賦值*/
puts(s);
puts(f);
}

說明:
(1). puts()函式只能輸出字串, 不能輸出數值或進行格式變換。
(2). 可以將字串直接寫入puts()函式中。如:
puts(”Hello, Turbo C2.0″);

  1. gets()函式
    gets()函式用來從標準輸入裝置(鍵盤)讀取字串直到回車結束, 但回車符
    不屬於這個字串。其呼叫格式為:
    gets(s);
    其中s為字串變數(字串陣列名或字串指標)。
    gets(s)函式與scanf(”%s”, &s)相似, 但不完全相同, 使用scanf(”%s”, &s)
    函式輸入字串時存在一個問題, 就是如果輸入了空格會認為輸入字串結束,
    空格後的字元將作為下一個輸入項處理, 但gets() 函式將接收輸入的整個字元
    串直到回車為止。
    例5
main()
{
char s[20], *f;
printf(”What’s your name?\n”);
gets(s); /*等待輸入字串直到回車結束*/
puts(s); /*將輸入的字串輸出*/
puts(”How old are you?”);
gets(f);
puts(f);
}

*************************c++***************************************************
cin與cout
一:標準輸入函式cin
不知道說它是個函式對還是不對,它是代表標準的輸入裝置–鍵盤。他是屬於流的,他的用法和流的用法是一樣的。也就是:cin>>變數;
小小的說明一下,輸入多個變數可以寫在一行,如:cin>>x>>y>>z;
這樣寫不是不允許,而是不好看,如果是不同的變數型別,那就更是沒頭沒腦了。除了你,人家是不知道該輸入什麼的,所以,一般在輸入語句的前面,我們一般都
要做一個提示,請輸入×××,讓人家心裡有個底,知道這個變數是做什麼的。
另外,這個函式是不用帶地址符號”&”的,也不用寫明變數型別,千萬不要跟scanf混淆。當然他就也不檢查變數輸入是否合法。如:

int i; 
cout<<"please input a number:" 
cin>>i; 
cout<<"i="<<i<<endl; 

如果你輸入的是一個字元如’a’那麼他也不檢查,但你輸出的結果不是正確的,這要是手工進行檢查。當然他也跟scanf一樣,如果在迴圈內部輸入不合法的變數值,那麼也將陷入死迴圈。如下:
/一個輸入不合法變數陷入死迴圈的例子/

#include <iostream.h> 
main() 
{ 
     int i; 
     while(i!=-1) 
     { 
         cout<<"i=" 
         cin>>i;    /*請輸入不是一個字元如’a’試試*/ 
         cout<<endl; 
     } 
} 
如上一個程式,如果你輸入的不合法,那就將陷入死迴圈。解決的辦法有個一,把cin>>i;語句移到判斷迴圈的語句中,那麼,你輸入的如果是不合法的變數,他將跳出迴圈。 
cin是用空格來分隔輸入的。請看看如下的例子: 

/*一個空格分隔使輸入的變數達不到希望的

#include <iostream.h> 
main() 
{ 
     char str[20]; 
     cout<<"please input a string:"; 
     cin>>str;    /*你試著輸入"hello word"*/ 
     cout<<endl<<"str="<<str; 
}

結果呢?得到的僅僅是str=hello,為什麼呢?因為cin是以空格為分隔的,當你輸入一個空格時,那他就認為後面的輸入不屬於這裡了,
認為應該給後面的變量了。另外,當你輸入的字串大於分配的空間時,還會出現溢位現象。當然,還有整行輸入的函式,包括空格也一起輸入了,以後也會學到。
二、標準輸出函式cout

/*一個按進位制輸出的例子

#include<iostream.h> 
void main() 
{ 
    int x=30, y=300, z=1024; 
    cout<<x<<’ ’<<y<<’ ’<<z<<endl;                  //按十進位制輸出 
    cout.setf(ios::showbase | ios::uppercase);   //設定基指示符輸出和數值中的字母大寫輸出 
    cout<<x<<’ ’<<y<<’ ’<<z<<endl; 
    cout.unsetf(ios::showbase | ios::uppercase); //取消基指示符輸出和數值中的字母大寫輸出 
    cout.setf(ios::oct);                                    //設定為八進位制輸出,此設定不取消一直有效 
    cout<<x<<’ ’<<y<<’ ’<<z<<endl;                   //按八進位制輸出 
    cout.setf(ios::showbase | ios::uppercase);    //設定基指示符輸出和數值中的字母大寫輸出 
    cout<<x<<’ ’<<y<<’ ’<<z<<endl; 
    cout.unsetf(ios::showbase | ios::uppercase); //取消基指示符輸出和數值中的字母大寫輸出 
    cout.unsetf(ios::oct);                                 //取消八進位制輸出設定,恢復按十進位制輸出 
    cout.setf(ios::hex);                                    //設定為十六進位制輸出 
    cout<<x<<’ ’<<y<<’ ’<<z<<endl; 
    cout.setf(ios::showbase | ios::uppercase); //設定基指示符輸出和數值中的字母大寫輸出 
    cout<<x<<’ ’<<y<<’ ’<<z<<endl; 
    cout.unsetf(ios::showbase | ios::uppercase); //取消基指示符輸出和數值中的字母大寫輸出 
    cout.unsetf(ios::hex);                       //取消十六進位制輸出設定,恢復按十進位制輸出 
    cout<<x<<’ ’<<y<<’ ’<<z<<endl; 
}

cout.setf()設定輸出的格式,用cout.unsetf()取消格式。可以看出10進位制在輸出的時候不管有沒有設定基指示符ios::
showbase,都沒用,8進位制再輸出的時候在前面加0,而16進位制是在前面加0X。而對於數值中字母大寫輸出,只對16進位制有用,以後我們就應該看情
況使用了。當然,我們前面已經說了,還有一種方法也可以實現格式化輸出,那就是使用操縱運算元,如下,
/一個按進位制輸出的例子/

#include<iomanip.h> 
void main() 
{ 
    int x=30, y=300, z=1024; 
    cout<<x<<’ ’<<y<<’ ’<<z<<endl;       //按十進位制輸出 
    cout<<oct<<x<<’ ’<<y<<’ ’<<z<<endl; //按八進位制輸出 
    cout<<setiosflags(ios::showbase);    //設定基指示符 
    cout<<x<<’ ’<<y<<’ ’<<z<<endl;       //仍按八進位制輸出 
    cout<<resetiosflags(ios::showbase); //取消基指示符 
    cout<<hex<<x<<’ ’<<y<<’ ’<<z<<endl; //按十六進位制輸出 
    cout<<setiosflags(ios::showbase | ios::uppercase); 
                  //設定基指示符和數值中的字母大寫輸出, 
    cout<<x<<’ ’<<y<<’ ’<<z<<endl; //仍按十六進位制輸出 
    cout<<resetiosflags(ios::showbase | ios::uppercase); 
                  //取消基指示符和數值中的字母大寫輸出 
    cout<<x<<’ ’<<y<<’ ’<<z<<endl; //仍按十六進位制輸出 
    cout<<dec<<x<<’ ’<<y<<’ ’<<z<<endl; //按十進位制輸出 
}

/*一個使用填充,寬度,對齊方式的例子

#include <iostream.h> 
void main() 
{ 
    cout<<"第一章"<<endl; 
    cout<<"    "; 
    cout.setf(ios::left);        //設定對齊方式為left 
    cout.width(7);               //設定寬度為7,不足用空格填充 
    cout<<"1.1"; 
    cout<<"什麼是C語言"; 
    cout.unsetf(ios::left);      //取消對齊方式,用預設right方式 
    cout.fill(’.’);              //設定填充方式 
    cout.width(30);              //設定寬度,只對下條輸出有用 
    cout<<1<<endl; 
    cout<<"    ";                 
    cout.width(7);               //設定寬度 
    cout.setf(ios::left);        //設定對齊方式為left 
    cout.fill(’ ’);              //設定填充,預設為空格 
    cout<<"1.11"; 
    cout<<"C語言的歷史"; 
    cout.unsetf(ios::left);      //取消對齊方式 
    cout.fill(’.’); 
    cout.width(30); 
    cout<<58<<endl; 
    cout.fill(’ ’); 
    cout<<"第二章"<<endl; 
}

我們多次設定了寬度,為的是使我們的間距能一致,也使用了對齊方式,為的是使我們的資料能對齊顯示,看起來美觀。我們還使用了填充方式。我們下面用操縱運算元來實現也是可以的。
/一個使用填充,寬度,對齊方式的例子/

#include <iomanip.h> 
void main() 
{ 
    cout<<"第一章"<<endl; 
    cout<<"    "; 
    cout<<setiosflags(ios::left)<<setw(7);         //設定寬度為7,left對齊方式 
    cout<<"1.1"; 
    cout<<"什麼是C語言"; 
    cout<<resetiosflags(ios::left);                //取消對齊方式 
    cout<<setfill(’.’)<<setw(30)<<1<<endl;         //寬度為30,填充為’.’輸出 
    cout<<setfill(’ ’);                            //恢復填充為空格 
    cout<<"    "; 
    cout<<setw(7)<<setiosflags(ios::left);         //設定寬度為7,left對齊方式 
    cout<<"1.11"; 
    cout<<"C語言的歷史"; 
    cout<<resetiosflags(ios::left);                //取消對齊方式 
    cout<<setfill(’.’)<<setw(30)<<58<<endl;        //寬度為30,填充為’.’輸出      
    cout<<setfill(’ ’)<<"第二章"<<endl; 
} 
我們輸出了同樣的效果,不過依我的性格,我更喜歡用操縱運算元來進行格式化輸出。最後我們看看浮點數的格式輸出,如下例: 

/關於浮點數的格式/

#include <iostream.h> 
void main() 
{ 
    float f=2.0/3.0,f1=0.000000001,f2=-9.9; 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl;      //正常輸出 
    cout.setf(ios::showpos);              //強制在正數前加+號 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl; 
    cout.unsetf(ios::showpos);            //取消正數前加+號 
    cout.setf(ios::showpoint);            //強制顯示小數點後的無效0 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl; 
    cout.unsetf(ios::showpoint);          //取消顯示小數點後的無效0 
    cout.setf(ios::scientific);           //科學記數法 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl; 
    cout.unsetf(ios::scientific);         //取消科學記數法 
    cout.setf(ios::fixed);                //按點輸出顯示 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl; 
    cout.unsetf(ios::fixed);              //取消按點輸出顯示 
    cout.precision(18);                   //精度為18,正常為6 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl; 
    cout.precision(6);                    //精度恢復為6 
} 
同樣,我們也一樣能用操縱運算元實現同樣的功能: 

/關於浮點數的格式/

#include <iomanip.h> 
void main() 
{ 
    float f=2.0/3.0,f1=0.000000001,f2=-9.9; 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl;      //正常輸出 
    cout<<setiosflags(ios::showpos);      //強制在正數前加+號 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl; 
    cout<<resetiosflags(ios::showpos);    //取消正數前加+號 
    cout<<setiosflags(ios::showpoint);    //強制顯示小數點後的無效0 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl; 
    cout<<resetiosflags(ios::showpoint); //取消顯示小數點後的無效0 
    cout<<setiosflags(ios::scientific);   //科學記數法 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl; 
    cout<<resetiosflags(ios::scientific); //取消科學記數法 
    cout<<setiosflags(ios::fixed);        //按點輸出顯示 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl; 
    cout<<resetiosflags(ios::fixed);       //取消按點輸出顯示 
    cout<<setprecision(18);               //精度為18,正常為6 
    cout<<f<<’ ’<<f1<<’ ’<<f2<<endl; 
    cout<<setprecision(6);                //精度恢復為6 
} 

在c/c++系統中除了標準的輸入輸出外,還提供了更多的輸入函式。這寫函式主要有getch(),getche(),
getchar
(),cin.get(),putch(),putchar(),cout.put(),gets(),cin.getline(),puts()。另外
還有些為了讓緩衝區不影響程式的正確操作的緩衝去的操作,如:cin.putback(),fflush(stdin),cout.flush().我們
做一下簡單的說明。
1、getch()和getche(),非緩衝式輸入,從鍵盤讀入一個字元。getch()讀入字元不顯示。有conio.h支援。
2、cin.get(),getchar(),緩衝式輸入,從鍵盤讀入一個字元,並顯示。getchar()由stdio.h支援,cin.get()由iostream.h支援。
3、putch()和putchar(),非緩衝式輸出,輸出一個字元到顯示器。putch()由conio.h支援,putchar()由stdio.h支援。
4、cout.put(),緩衝式輸出,輸出一個字元到顯示器。由iostream.h支援。
5、gets()和cin.geline(),緩衝式輸入,讀入一字串(包括空格,不包括最後的回車),gets()由stdio.h支援,cin.getline()由iostream.h支援。
6、puts(),非緩衝輸出,輸出一個字串,由stdio.h支援。
7、cin.putback(),把一個字元送回輸入緩衝區。
8、fflush(stdin),清除輸入緩衝區操作。無法清除cin.get()等帶來的操作。
9、cout.flush(),清楚輸出緩衝區。
在這裡我們稍微說一下輸入/輸出緩衝區,這是為了減少程式訪問io帶來中斷而設的一段空間。當程式滿足某個重新整理條件時,那就將清理緩衝區。具體條件為:
1、輸入緩衝區
a,程式要求輸入時,按下了回車鍵。
b,遇到程式結束。
c,遇到下一條輸入語句。
d,遇到清除緩衝區操作
e,緩衝區溢位
2、輸出緩衝區
a,輸出緩衝區溢位
b,遇到下一條輸入語句
c,使用重新整理緩衝區迫使清除
d,程式結束。
緩衝區操作有時會帶來程式的不正確的輸入,如前面說的scanf(),在連續輸入的時候,會把一個回車賦給下一個字元變數。我們操作的時候一定要注意。