[C語言] scanf溢出問題研究與解決




最近幫忙朋友解答了一個有關scanf()溢出問題,程式碼是這樣的

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char stdNumber[10];
    char stdName[10];
    int numlen;
    int stdlen;

    while(1){
        printf("請輸入學號:");
        fflush(stdin);
        scanf("%s",stdNumber);
        numlen= strlen(stdNumber);
        if(numlen == 10){
            break;
        }
    }
    
    while(1){
        printf("請輸入姓名:");
        fflush(stdin);
        scanf("%s",stdName);
        stdlen = strlen(stdName);
        if(stdlen <= 10){
            break;
        }
        else{
            printf("長度不合法\n");
            continue;
        }
    }

    printf("學號: %s\n",stdNumber);
    printf("姓名: %s",stdName);

    return 0;
}

乍看之下沒有問題,但是當執行時輸入姓名長度>10,這時候程式會要求你重新輸入,你也重新依照要求輸入了正確格式,但是印出時卻發生問題了...

發生問題

試了好久都無解,最後只好印出記憶體位址

printf("%d %d\n",&stdNumber,&stdName);

印出來後才真正發現問題,原來是因為兩個位置相鄰在一起。stdName從6356734開始,而stdNumber從 6356724 開始,那如果 stdName 使用超過10個位址就會直接覆蓋掉 stdNumber

C 語言是不檢查邊界溢出的

那既然知道問題了就很方便修正

char stdNumber[11]; //擴充至11
char stdName[11];
scanf("%10s",stdNumber); //將原本%s取代成%10s
scanf("%10s",stdName);

這段代碼意義在scanf現在只會讀取前10個字元並且在結尾附加'\0'結尾字元,長度為10+1

並且要在所有scanf()後面加上fflush(stdin)清空輸入緩存,這樣前面輸入超過10個字元的部分才不會被後面的scanf()吃進去

scanf("%10s",stdNumber);
fflush(stdin);
因為沒有使用fflush(stdin)導致"姓名"吃到前面的"學號"

修正後的程式碼如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char stdNumber[11];
    char stdName[11];
    int numLen=0;
    int stdLen=0;

    while(1){
        printf("請輸入學號:\n");
        scanf("%10s",stdNumber);
        fflush(stdin);
        numLen= strlen(stdNumber);
        if(numLen == 10){
            break;
        }
    }


    while(1){
        printf("請輸入姓名:\n");
        scanf("%10s",stdName);
        fflush(stdin);
        stdLen = strlen(stdName);
        if(stdLen <= 10){
            break;
        }
    }

    printf("STD_NUM %s\n",stdNumber);
    printf("STD_NAME %s\n",stdName);

    return 0;
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料