你的sscanf用對了嗎


用sscanf解析輸入字符串

我們平常編寫的很多應用程序都會處理各種各樣的輸入,這些輸入或來自本地文件,或來自網絡,或來自用戶的輸入。今天,讓我們來看看sscanf這個和字符串相關的函數可能給你帶來的麻煩。

下面是演示代碼,這段代碼將一些以字符串形式保存的數據加載到程序中。這些字符串可以來自任何地方,本演示代碼對字符串進行了硬編碼。

 1 struct Data
 2 {
 3     char item1;
 4     char item2;
 5     char item3;
 6     char item4;
 7 };
 8 
 9 int main()
10 {
11     Data data;
12     memset(&data, 0, sizeof(data));
13 
14     char data1[] = "1";
15     char data2[] = "2";
16     char data3[] = "3";
17     char data4[] = "4";
18 
19     sscanf_s(data4, "%d", &data.item4);
20     sscanf_s(data3, "%d", &data.item3);
21     sscanf_s(data2, "%d", &data.item2);
22     sscanf_s(data1, "%d", &data.item1);
23 
24     printf_s("item1:%d\n", data.item1);
25     printf_s("item2:%d\n", data.item2);
26     printf_s("item3:%d\n", data.item3);
27     printf_s("item4:%d\n", data.item4);
28 
29     getchar();
30     return 0;
31 }

 

你覺得執行結果會是什么?

奇怪嗎?

 

分析

讓我們分析一下:

第19行代碼將4賦值給了item4,第20行代碼將3賦值給了item3, 第21行代碼將2賦值給了item2, 第22行代碼將1賦值給了item1。似乎沒什么問題。

還是來調試下程序吧。

 

下面幾張圖片演示了程序在執行過程中的內存布局

執行第一條sscanf_s前的內存布局

 

執行第一條sscanf_s后的內存布局

 

執行第二條sscanf_s后的內存布局

 

執行第三條sscanf_s后的內存布局

 

執行第四條sscanf_s后的內存布局

 

到這里,相信大家都已經明白程序的輸出結果為何是1,0,0,0了。

 

演示代碼不僅發生了內存越界,而且后續所有的輸入都覆蓋了上一條的執行結果。

 罪魁禍首就是sscanf_s中的格式字符串"%d","%d"表明將輸入字符串作為一個int類型來保存到目標地址處。而演示代碼的書寫方式很顯然不符合Data這個結構體中各成員所聲明類型的要求。

 

將個數字符串修改為"%c"后,程序執行正確:

 

 

當然,我們其實可以在編譯階段發現這類問題

 

 

結語

通過今天這個演示,更加讓自己明白了一定要多留意編譯期間的警告信息,盡全力將其消滅。

本博客僅僅演示了sscanf_s這類函數的冰山一角,對於其他需要注意的地方可以參考Format Specifiers Checking

 


免責聲明!

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



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