當前位置:
首頁 > 知識 > 一道C語言安全編碼題目

一道C語言安全編碼題目

1、前言

最近在網上看到一道C語言題目,用C語言實現一個函數,給定一個int類型的整數,函數輸出逆序的整數,例如輸入123,則輸出字元串"321",,輸入-123,則輸出字元串"-321"。題目要求,不使用標準庫,不得分配內存。當時覺得蠻簡單的,這不就是類似字元串逆轉嘛,自己嘗試做了一下,測試發現,還是有很多地方考慮不周全。今天在此整理一下基礎知識,作為一名安全開發人員,時刻需要注意代碼的安全,防止有任何漏洞。題目給出的函數如下:

#include

const char * parseInt(int data)
{
return "321";
}

int main
{
printf("%s
", parseInt(123));
return 0;
}

2、思考過程

寫代碼最怕的就是沒有想好,一上來就寫,在寫的過程中不斷的測試修改,這樣很浪費時間。因此需要先好好想一下,這個題目到底考些什麼呢?

(1)int類型的整數分為正數、0、負數,如何處理這些邊界值

(2)整數與字元串之間的轉換,如何將一個整數轉換為一個字元

(3)如何返回一個const char * 類型的字元串

(4)當輸入的整數超過int的範圍如何處理

3、編碼過程

開始寫代碼的思路如下:定義一個char類型的數組,用於保存結果。使用對10取余和除法操作依次獲取每一位的數字,然後根據ASSIC碼轉換為字元。將字元拼接起來,返回字元串數組結果。編碼實現如下:

const char * parseInt(int data)
{
char str[16] = {0};
int i = 0;
if (data < 0) { data = -data; str[i++] = "-"; } int tmp = data; while (tmp / 10) { char ch = tmp % 10 + 48; tmp = tmp / 10; str[i++] = ch; } str[i++] = tmp % 10 + 48;return str; }

當初沒有考慮那麼多,編譯發現出現如下錯誤:

一看編譯錯誤,才意識到自己掉入坑中。題目要求返回一個字元串,而且不用分配內存。當時就想直接定義一個字元數組進行返回,而定義的str屬於函數局部變數。

一個函數的局部變數都是存在stack中的,當這個函數調用過程結束時,這個局部變數都是要釋放掉的,所以就會產生這樣的warning,這個是和變數的life time相關的,所以解決方法有:

1.將char result[16]改為static型

2.使用malloc向heap申請,這些是需要caller用free去釋放的

於是使用static 類型字元串,代碼改進如下:

1 const char * parseInt(int data)
2 {
3 static char str[16] = {0};
4 int i = 0;
5
6 if (data < 0) { 7 data = -data; 8 str[i++] = "-"; 9 } 10 11 int tmp = data; 12 while (tmp / 10 != 0) { 13 char ch = tmp % 10 + 48; 14 tmp = tmp / 10; 15 str[i++] = ch; 16 } 18 str[i++] = tmp % 10 + 48; 20 return str; 21 }

int main

{

printf("%s
", parseInt(123));

printf("%s
", parseInt(12345678));

printf("%s
", parseInt(-89790));

return 0;

}

測試結果如下:

改為static之後,編譯成功,看輸出的結果上看,前面兩個輸出是正確的,而第三個輸出的結果是錯誤的。尼瑪,再次掉入坑中,對static變數的應用不精通啊。為什麼每次到看到結果後才想起來?

雖然在函數中定義了static局部變數,使得變數的變為靜態stack存儲區域,生命周期從函數中變成了這個程序的範圍。但是static局部變數在函數第一次調用的時候會初始化,後面調用就不會了,直接使用了。因此導致了剛才的結果輸出不對,復用了上次遺留的結果。

static靜態局部變數屬於靜態存儲方式,它具有以下特點:

(1)靜態局部變數在函數內定義 它的生存期為整個源程序,但是其作用域仍與自動變數相同,只能在定義該變數的函數內使用該變數。退出該函數後, 儘管該變數還繼續存在,但不能使用它。

(2)允許對構造類靜態局部量賦初值 例如數組,若未賦以初值,則由系統自動賦以0值。

(3)對基本類型的靜態局部變數若在說明時未賦以初值,則系統自動賦予0值。而對自動變數不賦初值,則其值是不定的。 根據靜態局部變數的特點, 可以 看出它是一種生存期為整個源程序的量。雖然離開定義它的函數後不能使用,但如再次調用定義它的函數時,它又可繼續使用, 而且保存了前次被調用後留下的 值。 因此,當多次調用一個函數且要求在調用之間保留某些變數的值時,可考慮採用靜態局部變數。雖然用全局變數也可以達到上述目的,但全局變數有時會造成 意外的副作用,因此仍以採用局部靜態變數為宜。

第一次調用函數,static變數,初始化。 第二次,及以後,調用函數,static變數,不會初始化。

繼續改進代碼,在函數中將static變數每次使用for循環進行初始化,改進代碼如下:

1 #include
2
3 const char * parseInt(int data)
4 {
5 static char str[16] = {0};
6 int i = 0;
7
8 int t = 0;
9 for (; t < 16; t++) { 10 str[t] = 0; 11 } 12 13 if (data < 0) { 14 data = -data; 15 str[i++] = "-"; 16 } 17 18 int tmp = data; 19 while (tmp / 10 != 0) { 20 char ch = tmp % 10 + 48; 21 tmp = tmp / 10; 22 str[i++] = ch; 23 } 24 25 str[i++] = tmp % 10 + 48; 26 27 return str; 28 } 29 30 int main 31 { 32 printf("%s ", parseInt(123)); 33 printf("%s ", parseInt(12345678)); 34 printf("%s ", parseInt(-89790)); 35 return 0; 36 }

這次輸出結果如下:

終於得到了正確答案,看似很簡單的題目,折騰的這麼久,才搞出來。擴展一下,大家看看如下這個輸出什麼呢:

printf("%s, %s, %s
", parseInt(98989),parseInt(-4567), parseInt(123456));

這個結果是什麼呢?為什麼會這樣呢?

printf("%s
", parseInt(0x8FFFFFFF));
printf("%s
", parseInt(0xFFFFFFFF));

這個結果是什麼呢?為什麼會這樣呢?

int 類型4個位元組,32位組成。int的最高位作為符號位,需要特殊處理。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 達人科技 的精彩文章:

並行模式庫PPL應用實戰(一):使用task類創建並行任務
Linux之rsync遠程同步
EF Core學習Code First
多線程和非同步編程示例和實踐-踩過的坑

TAG:達人科技 |

您可能感興趣

題目是《剜目》
這是一道風霏國內的奇葩題目
來做幾道文學史的題目
一道數學題讓中國隊全軍覆沒,網友:我連題目都看不懂
強網杯web題目四道
這篇文章的題目應該叫什麼?
TOPIK考試題目看不懂?題干高頻核心辭彙大整理
《鹿鼎記》中最難的十五道題目,答對五道小編甘拜下風
不知道取什麼題目了,不寫題目了
金庸十四部小說中的十四道題目,答對一半小編認你做師父
《把信寫給埃米莉》 輯三讀書筆記題目
鍾漢良押題,易烊千璽押題,竟通通命中全國I卷作文題目
25道SVM題目,測一測你的基礎如何?
王維的這首唐詩寫得妙:20字內容就像謎語,一看題目才知道是謎底
丁肇中談阿爾法磁譜儀項目:大科學項目要選對題目
做一下這十道題目對比一下你是否是「癌癥候選人」
題目:油畫繪畫五要素
漫畫:這道題目太難了
題目有十一個字不信你數
選題太另類:爆笑奇葩論文題目讓你打開眼界