scanf()函數的原理


最近使用scanf發現了自己對scanf函數還是不太了解,主要出現在無意中出現的一個錯誤;

scanf正確的寫法是,scanf中以什么格式輸入變量,則變量的類型就應該是什么格式,如下面scanf輸入到變量的格式是%c形式,因此變量sum的類型必須是char型,要不存儲到sum中的數值會出錯;

注意:打印的時候是分別以%c、%d 的形式答應的
字符a的ASCII碼值是97

char sum; printf("請輸入一個字符:"); scanf("%c", &sum); printf("%c\n", sum); printf("%d\n", sum);

 如果將sum定義成int類型,但是scanf以%c的格式賦值給sum,會出現什么樣的錯誤呢

int sum; printf("請輸入一個字符:"); scanf("%c", &sum); printf("%c\n", sum); printf("%d\n", sum);

看問題來了,為什么sum為int類型時;以%d輸出時明顯不對,%c輸出卻沒有問題?

%c格式輸出沒有問題說明scanf以%c格式輸入到sum的過程是沒有問題的,出現問題的原因是scanf內部實現的原理沒弄清楚

第一個首相想到,難道是一個字符/字符變量賦值給一個整形變量,再以%d形式打印時會出現這樣的問題嗎?
其實是不會的因為編譯器會進行自動轉換(隱式轉換),但還是看一下這種情況是什么樣子的

int sum; char p; p = 'a'; sum = p; printf("%c\n", sum); printf("%d\n", sum);

第二個猜測是,在scanf內部實現中以什么樣的格式賦值給變量時,就會以此格式對應類型的內存大小賦值給變量且,如果變量原本所占內存比scanf中所用格式的內存大,則多出的那一部分會被填充為1(為什么會猜測填充為1呢? 主要是上面以%d輸出是數值很大,並且為負值),下面寫代碼驗證一下

int sum; char *b; b = (char *)∑ *b = 'a'; printf("%c\n", sum); printf("%d\n", (char)sum); printf("%d\n", sum);

 

看上面sum中的值61前面全是c,c在16進制中為1100,61表示97,所以在低地址值是正確的,但在高地址處被填充的1100;並且紅色全出的數值和scanf出錯的那部分相同,所以scanf中內部實現原理是和上面代碼類似的。以char類型解釋;
即scanf(“%c”, &sum)時;內部會將 &sum 強制轉換成 (char *)類型,並且賦值給 char * 類型的變量b,然后用 *b 來接收輸入的值,也就改變了 sum中的值,但因為char字節小於int字節數,所以多余的字節會被其它值填充。

再看看上面隱士轉換情況多余的地址被填充了什么,為方便對照,再把代碼寫一遍;

int sum; char p; p = 'a'; sum = p; printf("%c\n", sum); printf("%d\n", sum);

隱士轉換多余字節被填充為0;所以隱士轉換不影響值(數值比較小時)的顯示,但可能會字節數不相等會影響結果精度等。

淺析Scanf源碼


免責聲明!

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



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