標籤:include 程式員 關鍵字 c語言 運算式
------- IOS培訓期待與您交流! ----------
寫代碼的時候,我們可以看得出,幾乎每一個C程式都會包括輸入輸出。輸入輸出是程式中最基本的操作之一。C語言本身並不提供輸入輸出的語句,輸入輸出操作是由C標準函數庫中的函數來實現的。今天就先說說輸入:scanf函數。
scanf函數與printf函數一樣,都不是C語言的關鍵字,而只是函數庫的名字,它們被定義在stdio.h裡,因此在使用scanf函數時要加 上#include<stdio.h>。它是格式輸入函數,即按使用者指定的格式從鍵盤上把資料輸入到指定的變數之中,其關鍵字最末一個字母f 即為“格式”(format)之意。
scanf函數的一般形式:scanf(格式控制,地址表列)int scanf(char *format[,argument,...]);
“格式控制”的是用雙引號括起來 字串,稱“轉換控制字元串”,簡稱“格式字串”,它包含兩個資訊:
(1)、格式聲明:由%和格式字元組成,作用是將輸入的資料轉變為指定的格式後輸入,總是由%字元開始的;
(2)、一般字元:即是需要在輸出時原樣輸入的字元。
“地址表列”是由若干個地址組成的表列,可以是變數的地址,或字串首地址或運算式。
scanf()函數返回成功賦值的資料項目數,出錯時則返回EOF。
/*例:使用scanf函數輸入資料*/ #include<stdio.h> void main() { int a,b,c; printf("input a,b,c/n"); scanf("%d%d%d",&a,&b,&c); printf("a=%d,b=%d,c=%d",a,b,c);}
%a,%A 讀入一個浮點值(僅C99有效)
%c 讀入一個字元
%d 讀入十進位整數
%i 讀入十進位,八進位,十六進位整數
%o 讀入八進位整數
%x,%X 讀入十六進位整數
%s 讀入一個字串,遇空格、定位字元或分行符號結束
%f,%F,%e,%E,%g,%G 用來輸入實數,可以用小數形式或指數形式輸入
%p 讀入一個指標
%u 讀入一個無符號十進位整數
%n 至此已讀入值的等價字元數
%[] 掃描字元集合
%% 讀%符號
附加格式說明字元表修飾符說明
L/l 長度修飾符 輸入"長"資料
h 長度修飾符 輸入"短"資料
W 整型常數 指定輸入資料所佔寬度
* 表示本輸入項在讀入後不賦值給相應的變數
scanf的傳回值有後面的參數決定
scanf("%d%d", &a, &b);
(1)如果a和b都被成功讀入,那麼scanf的傳回值就是2
(2)如果只有a被成功讀入,傳回值為1
(3)如果a和b都未被成功讀入,傳回值為0
(4)如果遇到錯誤或遇到end of file,傳回值為EOF,且傳回值為int型.
(1)sacnf()中的變數必須使用地址
(2)scanf()的格式控制串可以使用其它非空白字元,但在輸入時必須輸入這些字元
(3)在用"%c"輸入時,空格和“逸出字元”均作為有效字元
下面讓我們來舉例說明一下scanf函數的具體使用以及使用過程中遇到的一些問題:
/*問題一:scanf()函數不能正確接受有空格的字串?如: I love you!*/#include <stdio.h>int main(){ char str[80]; scanf("%s",str); printf("%s",str); return 0;}
scanf()函數接收輸入資料時,遇以下情況結束一個資料的輸入:(不是結束該scanf函數,scanf函數僅在每一個資料域均有資料,並按斷行符號後結束)。
(1)遇空格、“斷行符號”、“跳格”鍵
(2)遇寬度結束
(3)遇非法輸入
因 此,上述程式並不能達到預期目的,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!
現在原因知道了,那麼scanf()函數能不能完成這個任務?回答是:能!別忘了scanf()函數還有一個 %[] 格式控制符(如果對%[]不瞭解的請查看本文的上篇),請看下面的程式:
#include "stdio.h"int main(){ char string[50];/*scanf("%s",string);不能接收空格符*/ scanf("%[^/n]",string); printf("%s/n",string); return 0;}
此時程式就行正確的輸出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);不管什麼情況 都可行。
#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‘);}
這裡再給一個用“空格符”來處理緩衝區殘餘資訊的樣本:運行出錯的程式:
#include <stdio.h>int main(){ int i; char j; for(i = 0;i < 10;i++) { scanf("%c",&j);/*這裡%前沒有空格*/ }}
使用了空格控制符後:
#include <stdio.h>int main(){ int i; char j; for(i = 0;i < 10;i++) { scanf(" %c",&j);/*注意這裡%前有個空格*/ }}
可以運行看看兩個程式有什麼不同哦~~
/*問題三: 如何處理scanf()函數誤輸入造成程式死結或出錯?*/#include <stdio.h>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);}
補充: fflush(stdin)這個方法在GCC下不可用。(在VC6.0下可以),以下是 C99 對 fflush 函數的定義:
int fflush(FILE *stream);
如果stream指向輸出資料流或者更新流(update stream),並且這個更新流最近執行的操作不是輸入,那麼fflush函數將把任何未被寫入的資料寫入stream指向的檔案(如標準輸出檔案stdout)。否則,fflush函數的行為是不確定的。fflush(NULL)清空所有輸出資料流和上面提到的更新流。如果發生寫錯誤,fflush函數會給那些流打上錯誤標記,並且返回EOF,否則返回0。由此可知,如果 stream 指向輸入資料流(如 stdin),那麼 fflush 函數的行為是不確定的。故而使用fflush(stdin) 是不正確的,至少是移植性不好的。可採用如下方法:
/* 此函數可以和scanf函數一起使用,但使用%c輸入時要注意,即此函數只能用於緩衝區非空的情況 */void flush() { char c; while ((c=getchar()) != ‘/n‘&&c!=EOF) ; } #include <stdio.h> int main() { int a,b,c; /*計算a+b*/ while(scanf("%d,%d",&a,&b)!=2) flush(); c=a+b; printf("%d+%d=%d",a,b,c);}
黑馬程式員--C語言基礎之--scanf函數