Linux中scanf類型匹配錯誤,特指scanf("%d", &c ) ,導致死循環的解決方法 —— fflush(stdin)和getchar()的使用


如題,朋友領導的孩子大學作業是個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/ 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM