scanf函數說明
scanf函數是對來自于標準輸入流的輸入數據作格式轉換,并將轉換結果保存至format后面的實參所指向的對象。
而const char*format 指向的字符串為格式控制字符串,它指定了可輸入的字符串以及賦值時轉換方法。
簡單來說給一個打印格式(輸入數據格式),scanf函數會將打印數據格式的結果轉換放到后面的實參變量當中。
比如下面的代碼
#include<stdio.h>
int main()
{int a = 0;char ch = 0;double b = 0.0;scanf("%d %c %lf", &a, &ch, &b);printf("%d %c %lf", a, ch, b);return 0;
}
但scanf函數有一個缺點,就是scanf讀取不了空格和回車等字符,當scanf讀到這兩個字符時,scanf會讀取失敗返回EOF,如果匹配錯誤也會讀取失敗返回EOF(比如應該是%d的數據轉換到了char實參變量當中)。
EOF
EOF全名是:End of File 在<stdio.h>頭文件中被定義為負值,即-1。
EOF的值不同編譯器下值不同,在VS2019是-1?
如果沒有將頭文件<stdio.h>包含到程序中,那么EOF就沒有定義,程序不能編譯和運行。
getchar和putchar
putchar的返回值是int,因為字符在程序存儲的是ASCII碼值,而且putchar只能打印字符,不能打印字符串,就是配合getchar()使用的。如果putchar成功獲取了字符就返回所寫字符,失敗就返回EOF。
#include<stdio.h>
int main()
{putchar('a');putchar('b');putchar('c');return 0;
}
getchar返回也是int,參數是void,可有可無,getchar是從標準輸入流讀取字符(空格 回車都可以讀取)并將其返回,如果讀取失敗就返回EOF。?
比如
#include<stdio.h>
int main()
{int ch;while ((ch = getchar()) != EOF){putchar(ch);}return 0;
}
getchar如果緩沖區沒有字符,getchar會等待我們的輸入且摁下回車鍵才會打印在屏幕上。
配合putchar使用。
?按下回車鍵后才在屏幕上輸出對應字符。
?ctrl+Z是將程序結束掉,退出了程序終止了代碼循環。
crtl+Z相當于EOF。
?為什么按回車鍵才會將字符輸出到屏幕上呢?
?C語言的輸入輸出一般會將讀入的字符以及待輸出的字符暫時保存在緩存中(緩沖區),當達到以下條件才進行實際的輸入輸出操作。
1.緩存已滿 2.輸入換行符(\n)? 3.立即輸出
對應方式稱為1.全緩沖 2.行緩沖 3,無緩沖
鍵盤輸入的內容不會直接給cpu處理打印在屏幕上 而是交給緩存 提高cpu運行效率。
getchar與scanf的關系
我們根據下圖代碼來分析getchar和scanf之間的關系
#include<stdio.h>
int main()
{char password[20] = { 0 };printf("請輸入密碼:>");scanf("%s", password);printf("請確認密碼正確Y/N:>");char ch = 0;scanf("%c", &ch);if ('Y' == ch){printf("密碼正確\n");}else{printf("密碼錯誤\n");}return 0;
}
?當程序運行時,我們剛輸入完密碼程序直接結束了,都沒有確定密碼的正確性,這是為什么呢?
當我們輸入密碼摁下回車鍵時,在緩沖區輸入了1234\n,回車鍵相當于換行等于轉義字符\n
第一個scanf讀取了1234 第二個scanf讀取了\n 直接填滿了兩個scanf的嘴巴,因此直接程序結束
并且結果為密碼錯誤,當我們輸入完1234摁下回車鍵那刻\n也被載入到了緩沖區,第二個scanf
定睛一看緩沖區有內容直接就讀取走了。
解決辦法?
?這時我們就要請出getchar給scanf擦屁股了,因為getchar能讀取回車 空格等字符。
#include<stdio.h>
int main()
{char password[20] = { 0 };printf("請輸入密碼:>");scanf("%s", password);printf("請確認密碼正確Y/N:>");char ch = 0;getchar();scanf("%c", &ch);if ('Y' == ch){printf("密碼正確\n");}else{printf("密碼錯誤\n");}return 0;
}
但如果有人在設置密碼時寫入了空格,而且scanf讀取不了空格和回車字符,這時還是會出現代碼判斷錯誤導致運行結果錯誤。
我們直接用while循環搞一個一勞永逸的解決方案
直接使用循環清空緩沖區的空格 回車等字符
#include<stdio.h>
int main()
{char password[20] = { 0 };printf("請輸入密碼:>");scanf("%s", password);printf("請確認密碼正確Y/N:>");char ch = 0;while ((getchar()) != '\n'){;}
//以下兩種寫法都okscanf("%c",&ch);//ch=getchar();if ('Y' == ch){printf("密碼正確\n");}else{printf("密碼錯誤\n");}return 0;
}
?關系
輸入b后摁下回車鍵形成\n
緩沖區載入的就是b\n
第一個scanf讀取b 第二個scanf讀取\n? 因此程序結束語在第三行
輸入a\n
scanf讀取a getchar讀取\n putchar輸出a?
?輸入a\n 第一個scanf讀走a? getchar讀走\n
第二個scanf正常使用再次輸入b\n? putchar在下一行輸出b
scanf讀走as \nbxx是putchar讀取的? ?a是第二個scanf讀取的后面還有個\n
所以程序結束語在第4行。
總結
如果scanf輸入過程中遇到空格 回車鍵等字符,scanf自己處理不了的讀取字符時,就用getchar來解決,如果有多個處理不了的特殊字符就用while循環來處理(scanf處理不了的空格 回車鍵等特殊字符),配合getchar和putchar來給scanf的正常使用(擦屁股)。