C語言中的輸入、輸出函數,在C++中一直使用cin、cout,對scanf和printf的使用不太熟悉,現做以下整理。
scanf()函數詳解
函數名:scanf
功能:執行格式化輸入
用法:int scanf(char *format,[argument,...])
;
scanf()
函數是通用終端格式化輸入函數,它從標準輸入設備(鍵盤)讀取輸入的信息。可以讀入任何固有類型的數據並自動把數值變換成適當的機內格式。
其調用格式爲:scanf(“<格式化字符串>”,<地址表>);
scanf()
函數返回成功賦值的數據項數,出錯時則返回EOF;
其控制串由三類字符構成:
1、格式化說明符
2、空白符
3、非空白符
格式化說明符
格式化字符 | 說明 |
---|---|
%a | 讀入一個浮點值(僅C99有效) |
%A | 同上 |
%c | 讀入一個字符 |
%d | 讀入十進制整數 |
%i | 讀入十進制,八進制,十六進制整數 |
%o | 讀入八進制整數 |
%x | 讀入十六進制整數 |
%X | 同上 |
%c | 讀入一個字符 |
%s | 讀入一個字符串 |
%f | 讀入一個浮點數 |
%F | 同上 |
%e | 同上 |
%E | 同上 |
%g | 同上 |
%G | 同上 |
%p | 讀入一個指針 |
%u | 讀入一個無符號十進制整數 |
%n | 至此已讀入值的等價字符數 |
%[] | 掃描字符集合 |
%% | 讀%符號 |
附加格式說明字符表
修飾符 | 說明 |
---|---|
L/l長度修飾符 | 輸入“長”數據 |
h長度修飾符 | 輸入“短”數據 |
W整型常數 | 指定輸入數據所佔寬度 |
*星號 | 空讀一個數據 |
hh,ll | 同上h、l,但僅對C99有效 |
空白字符
空白字符會使scanf()
函數在讀操作中略去輸入中的一個或多個空白字符,空白符可以是space,tab,newline等等,直到第一個非空白符出現爲止。
非空白字符
一個非空白字符會使scanf()
函數在讀入時剔除掉與這個非空白字符相同的字符。
實例詳解
問題一
例1:
#include "stdio.h"
int main(void)
{
int a,b,c;
scanf("%d,%d,%d",&a,&b,&c);
printf("%d,%d,%d/n",a,b,c);
return 0;
}
運行時按如下方式輸入三個值:
3□4□5 ↙(輸入a,b,c的值)
3,4,5 (printf輸出的a,b,c的值)
(1) &a、&b、&c中的&是地址運算符,分別獲得這三個變量的內存地址。
(2) “%d%d%d”是按十進值格式輸入三個數值。輸入時,在兩個數據之間可以用一個或多個空格、tab鍵、回車鍵分隔。
以下是合法輸入方式:
① 3□□4□□□□5↙
② 3↙
4□5↙
③ 3(tab鍵)4↙
5↙
例2
#include "stdio.h"
int main(void)
{
int a,b,c;
scanf("%d,%d,%d",&a,&b,&c);
printf("%d,%d,%d/n",a,b,c);
return 0;
}
運行時按如下方式輸入三個值:
3,4,5 ↙(輸入a,b,c的值)
或者
3,□4,□5 ↙(輸入a,b,c的值)
3,□□□4,□5 ↙(輸入a,b,c的值)
……
都是合法的,但是”,”一定要跟在數字後面,如:
3□,4,□5 ↙就非法了,程序出錯。(解決方法與原因後面講)
再如:
1、sacnf()中的變量必須使用地址
int a, b;
scanf("%d%d",a,b); //錯誤
scanf("%d%d",&a,&b);
2、scanf()的格式控制串可以使用其它非空白字符,但在輸入時必須輸入這些字符。
例:
scanf("%d,%d",&a,&b);
輸入: 3,4 ↙(逗號與”%d,%d”中的逗號對應)
scanf("a=%d,b=%d",&a,&b);
輸入: a=3,b=4 ↙(”a=”,”b=”,逗號與”%d,%d”中的”a=”,”b=”及逗號對應)
3、在用”%c”輸入時,空格和“轉義字符”均作爲有效字符。
例:
scanf("%c%c%c",&c1,&c2,&c3);
輸入:a□b□c↙
結果:a→c1,□→c2,b→c3 (其餘被丟棄)
scanf()
函數接收輸入數據時,遇以下情況結束一個數據的輸入:(不是結束該scanf()
函數,scanf()
函數僅在每一個數據域均有數據,並按回車後結束)。
① 遇空格、“回車”、“跳格”鍵。
② 遇寬度結束。
③ 遇非法輸入。
問題二
scanf()
函數不能正確接受有空格的字符串?如: I love you!
#include <stdio.h>
int main()
{
char str[80];
scanf("%s",str);
printf("%s",str);
return 0;
}
輸入:I live you!
輸出:I
scanf()函數接收輸入數據時,遇以下情況結束一個數據的輸入:(不是結束該scanf函數,scanf函數僅在每一個數據域均有數據,並按回車後結束)。
① 遇空格、“回車”、“跳格”鍵。
② 遇寬度結束。
③ 遇非法輸入。
所以,上述程序並不能達到預期目的,scanf()掃描到”I”後面的空格就認爲對str的賦值結束,並忽略後面的”love you!”.這裏要注意是”love you!”還在鍵盤緩衝區(關於這個問題,網上我所見的說法都是如此,但是,我經過調試發現,其實這時緩衝區字符串首尾指針已經相等了,也就是說緩衝區清空了,scanf()函數應該只是掃描stdin流,這個殘存信息是在stdin中)。我們改動一下上面的程序來驗證一下:
#include <stdio.h>
int main()
{
char str[80];
char str1[80];
char str2[80];
scanf("%s",str);/*此處輸入:I love you! */
printf("%s",str);
sleep(5);/*這裏等待5秒,告訴你程序運行到什麼地方*/
scanf("%s",str1);/*這兩句無需你再輸入,是對鍵盤盤緩衝區再掃描 */
scanf("%s",str2);/*這兩句無需你再輸入,是對鍵盤盤緩衝區再掃描 */
printf("/n%s",str1);
printf("/n%s",str2);
return 0;
}
輸入:I love you!
輸出:I
love
you!
問題三
鍵盤緩衝區殘餘信息問題
#include <stdio.h>
int main()
{
int a;
char c;
do
{
scanf("%d",&a);
scanf("%c",&c);
printf("a=%d c=%c/n",a,c);
/*printf("c=%d/n",c);*/
}while(c!='N');
}
scanf("%c",&c);
這句不能正常接收字符,什麼原因呢?我們用printf("c=%d/n",c)
;將C用int表示出來,啓用printf("c=%d/n",c);
這一句,看看scanf()
函數賦給C到底是什麼,結果是 c=10 ,ASCII值爲10是什麼?換行即/n.對了,我們每擊打一下”Enter”鍵,向鍵盤緩衝區發去一個“回車”(/r),一個“換行”(/n),在這裏/r被scanf()函數處理掉,而/n被scanf()
函數“錯誤”地賦給了c.
解決辦法:可以在兩個scanf()
函數之後加個fflush(stdin);
,還有加getch();
getchar()
;也可以,但是要視具體scanf()
語句加那個,這裏就不分析了,讀者自己去摸索吧。但是加fflush(stdin)
;不管什麼情況都可行。
函數名: fflush
功 能: 清除一個流
用 法: int fflush(FILE *stream);
#include <stdio.h>
int main()
{
int a;
char c;
do
{
scanf("%d",&a);
fflush(stdin);
scanf("%c",&c);
fflush(stdin);
printf("a=%d c=%c/n",a,c);
}while(c!='N');
}
問題四
int main()
{
int a,b,c; /*計算a+b*/
scanf("%d,%d",&a,&b);
c=a+b;
printf("%d+%d=%d",a,b,c);
}
如上程序,如果正確輸入a,b的值,那麼沒什麼問題,但是,你不能保證使用者每一次都能正確輸入,一旦輸入了錯誤的類型,你的程序不是死鎖,就是得到一個錯誤的結果,呵呵,這可能所有人都遇到過的問題吧?
解決方法:scanf()函數執行成功時的返回值是成功讀取的變量數,也就是說,你這個scanf()函數有幾個變量,如果scanf()函數全部正常讀取,它就返回幾。但這裏還要注意另一個問題,如果輸入了非法數據,鍵盤緩衝區就可能還個有殘餘信息問題。
正確的例程:
#include <stdio.h>
int main()
{
int a,b,c; /*計算a+b*/
while(scanf("%d,%d",&a,&b)!=2)fflush(stdin);
c=a+b;
printf("%d+%d=%d",a,b,c);
}