最近幫忙朋友解答了一個有關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);

修正後的程式碼如下
#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; }