如題,朋友領導的孩子大學作業是個C語言編寫的管理信息系統發來要我給改改,原代碼的配置環境是Windows的C環境,由於10多年沒有搞過Windows下的C語言了於是換上了Ubuntu18.04的系統上,本以為都是C語言的標准函數在哪個系統上區別不大,不過正是這個想法要自己調到了坑里,其中最大的一個坑就是scanf的輸入問題,代碼如下:
#include <stdio.h> #include <stdlib.h> void clean_stdin(void) { int c; do { c = getchar(); } while (c != '\n' && c != EOF); } /* return 1 means yes, return 0 means no */ int check_input(char content []) { char c[5]; fflush(stdin); int r = scanf("%s",&c); /* int r = scanf("%d %d", &c1, &c2); 如果數據類型不匹配就會輸入失敗 !!! %d整型數據輸入了字符型%c r=0表示全部沒有輸入成功, r=1表示成功輸入1個數值, r=2表示成功輸入2個數值 */ c[4] = '\0'; while(!(r==1&&(strcmp(c, "Y")==0||strcmp(c, "y")==0||strcmp(c, "yes")==0||strcmp(c, "N")==0||strcmp(c, "n")==0||strcmp(c, "no")==0))) { // printf("輸入有誤,請重新輸入!!!\n若是請回復Y/y/yes,若退出程序請回復N/n/no\n"); printf("%s", content); if(r==0) // linux系統中scanf數據類型匹配錯誤情況下fflush(stdin)無效 clean_stdin(); fflush(stdin); r = scanf("%s",&c); } if(strcmp(c, "Y")==0||strcmp(c, "y")==0||strcmp(c, "yes")==0) { return 1; } return 0; } int main() { char content[] = "輸入有誤,請重新輸入!!!\n確認操作請輸入Y/y/yes,退回主菜單請輸入N/n/no\n"; printf("確認操作請輸入Y/y/yes,退回主菜單請輸入N/n/no\n"); int res = check_input(content); if(res==0) // return 1 means yes, return 0 means no { printf("退回操作!!!\n"); } else { printf("繼續操作!!!\n"); } }
這個代碼本身也刷新了我很多的知識點,以前都沒有想過 scanf 這個函數還有返回值,畢竟當年用的時候也是在上大學本科的時候,而且這個返回值還挺有用。
(畢竟上學時候重來不會考慮輸入檢測這事情)
/*
int r = scanf("%d %d", &c1, &c2);
如果數據類型不匹配就會輸入失敗 !!! %d整型數據輸入了字符型%c
r=0表示全部沒有輸入成功, r=1表示成功輸入1個數值, r=2表示成功輸入2個數值
*/
==============================================
需要注意的是如果scanf中是字符輸入是永遠不會出現類型匹配錯誤的,因為所有輸入都可以看做是字符輸入,如:
scanf("%c", &c );
scanf("%s", &c );
會出現scanf匹配錯誤的是這種:
scanf("%d", &c );
在Windows系統下 scanf 因為類型不匹配是不太會引起太多問題的,即使出現問題使用fflush(stdin)然后一個循環輸入就解決了,而在linux系統下發現這個是不好用的。
在linux中如果 scanf 輸入類型不匹配這時fflush(stdin)是不起作用的,輸入緩沖中的值會一直存在的(不清空),然后就會造成死循環然后一直循環輸入。
例子:
#include <stdio.h> #include <stdlib.h> void clean_stdin(void) { int c; do { c = getchar(); } while (c != '\n' && c != EOF); } /* return 1 means yes, return 0 means no */ int check_input(char content []) { int c; fflush(stdin); int r = scanf("%d",&c); /* int r = scanf("%d %d", &c1, &c2); 如果數據類型不匹配就會輸入失敗 !!! %d整型數據輸入了字符型%c r=0表示全部沒有輸入成功, r=1表示成功輸入1個數值, r=2表示成功輸入2個數值 */ while(!(r==1&&(c==1||c==2))) { printf("%s", content); // if(r==0) // linux系統中scanf數據類型匹配錯誤情況下fflush(stdin)無效 // clean_stdin(); fflush(stdin); r = scanf("%d",&c); } if(c==1) { return 1; } return 0; } int main() { char content[] = "輸入有誤,請重新輸入!!!\n確認操作請輸入 1,退回主菜單請輸入 2\n"; printf("確認操作請輸入 1,退回主菜單請輸入 2\n"); int res = check_input(content); if(res==0) // return 1 means yes, return 0 means no { printf("退回操作!!!\n"); } else { printf("繼續操作!!!\n"); } }
該代碼運行時如果輸入字符,如“a”回車后就會死循環:
同時使用 fflush(stdin)和getchar()的使用:
#include <stdio.h> #include <stdlib.h> void clean_stdin(void) { int c; do { c = getchar(); } while (c != '\n' && c != EOF); } /* return 1 means yes, return 0 means no */ int check_input(char content []) { int c; fflush(stdin); int r = scanf("%d",&c); /* int r = scanf("%d %d", &c1, &c2); 如果數據類型不匹配就會輸入失敗 !!! %d整型數據輸入了字符型%c r=0表示全部沒有輸入成功, r=1表示成功輸入1個數值, r=2表示成功輸入2個數值 */ while(!(r==1&&(c==1||c==2))) { printf("%s", content); if(r==0) // linux系統中scanf數據類型匹配錯誤情況下fflush(stdin)無效 clean_stdin(); fflush(stdin); r = scanf("%d",&c); } if(c==1) { return 1; } return 0; } int main() { char content[] = "輸入有誤,請重新輸入!!!\n確認操作請輸入 1,退回主菜單請輸入 2\n"; printf("確認操作請輸入 1,退回主菜單請輸入 2\n"); int res = check_input(content); if(res==0) // return 1 means yes, return 0 means no { printf("退回操作!!!\n"); } else { printf("繼續操作!!!\n"); } }
重要部分代碼:
if(r==0) // linux系統中scanf數據類型匹配錯誤情況下fflush(stdin)無效 clean_stdin();
需要注意的是只有在scanf匹配錯誤的時候才好使用getchar函數,否則多需要輸入一次回車才可以,因為getchar是阻塞操作如果緩沖區空間中沒有結束符會一直等待輸入。
更穩妥的方式可以寫為:
if(r==0) // linux系統中scanf數據類型匹配錯誤情況下fflush(stdin)無效 clean_stdin(); else fflush(stdin);
整體代碼:
#include <stdio.h> #include <stdlib.h> void clean_stdin(void) { int c; do { c = getchar(); } while (c != '\n' && c != EOF); } /* return 1 means yes, return 0 means no */ int check_input(char content []) { int c; fflush(stdin); int r = scanf("%d",&c); /* int r = scanf("%d %d", &c1, &c2); 如果數據類型不匹配就會輸入失敗 !!! %d整型數據輸入了字符型%c r=0表示全部沒有輸入成功, r=1表示成功輸入1個數值, r=2表示成功輸入2個數值 */ while(!(r==1&&(c==1||c==2))) { printf("%s", content); if(r==0) // linux系統中scanf數據類型匹配錯誤情況下fflush(stdin)無效 clean_stdin(); else fflush(stdin); r = scanf("%d",&c); } if(c==1) { return 1; } return 0; } int main() { char content[] = "輸入有誤,請重新輸入!!!\n確認操作請輸入 1,退回主菜單請輸入 2\n"; printf("確認操作請輸入 1,退回主菜單請輸入 2\n"); int res = check_input(content); if(res==0) // return 1 means yes, return 0 means no { printf("退回操作!!!\n"); } else { printf("繼續操作!!!\n"); } }
==========================================
引用: https://www.shuzhiduo.com/A/E35poObJvX/
在Windows中不匹配的問題:
==========================================
附加說明:
在linux系統中本文所寫的函數 clean_stdin 中利用getchar函數對EOF進行判斷是無意義的,因為在linux系統中是無法從鍵盤輸入這個字符的。
(具體也不是很理解)
詳細見:https://www.codenong.com/9796054/
==========================================
參考:
https://blog.csdn.net/chunqiu_lfq/article/details/21841217
https://blog.csdn.net/weixin_30883777/article/details/97901491
https://www.shuzhiduo.com/A/E35poObJvX/