在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

C語言常見錯誤:數組越界及其避免方法

Q4MP_gh_c472c21 ? 來源:嵌入式ARM ? 作者:嵌入式ARM ? 2020-12-06 09:13 ? 次閱讀

所謂的數組越界,簡單地講就是指數組下標變量的取值超過了初始定義時的大小,導致對數組元素的訪問出現在數組的范圍之外,這類錯誤也是 C 語言程序中最常見的錯誤之一。

在 C 語言中,數組必須是靜態(tài)的。換而言之,數組的大小必須在程序運行前就確定下來。由于 C 語言并不具有類似 Java 等語言中現有的靜態(tài)分析工具的功能,可以對程序中數組下標取值范圍進行嚴格檢查,一旦發(fā)現數組上溢或下溢,都會因拋出異常而終止程序。也就是說,C 語言并不檢驗數組邊界,數組的兩端都有可能越界,從而使其他變量的數據甚至程序代碼被破壞。

因此,數組下標的取值范圍只能預先推斷一個值來確定數組的維數,而檢驗數組的邊界是程序員的職責。

一般情況下,數組的越界錯誤主要包括兩種:數組下標取值越界與指向數組的指針的指向范圍越界。

數組下標取值越界

數組下標取值越界主要是指訪問數組的時候,下標的取值不在已定義好的數組的取值范圍內,而訪問的是無法獲取的內存地址。例如,對于數組int a[3],它的下標取值范圍是[0,2](即a[0]、a[1] 與 a[2])。如果我們的取值不在這個范圍內(如 a[3]),就會發(fā)生越界錯誤。示例代碼如下所示:

很顯然,在上面的示例程序中,訪問 a[3] 是非法的,將會發(fā)生越界錯誤。因此,我們應該將上面的代碼修改成如下形式:

指向數組的指針的指向范圍越界

指向數組的指針的指向范圍越界是指定義數組時會返回一個指向第一個變量的頭指針,對這個指針進行加減運算可以向前或向后移動這個指針,進而訪問數組中所有的變量。但在移動指針時,如果不注意移動的次數和位置,會使指針指向數組以外的位置,導致數組發(fā)生越界錯誤。下面的示例代碼就是移動指針時沒有考慮到移動的次數和數組的范圍,從而使程序訪問了數組以外的存儲單元。

在上面的示例代碼中,for 循環(huán)會使指針 p 向后移動 10 次,并且每次向指針指向的單元賦值。但是,這里數組 a 的下標取值范圍是[0,4](即a[0]、a[1]、a[2]、a[3] 與 a[4])。因此,后 5 次的操作會對未知的內存區(qū)域賦值,而這種向內存未知區(qū)域賦值的操作會使系統(tǒng)發(fā)生錯誤。正確的操作應該是指針移動的次數與數組中的變量個數相同,如下面的代碼所示:

為了加深大家對數組越界的了解,下面通過一段完整的數組越界示例來演示編程中數組越界將會導致哪些問題。

上面的示例代碼模擬了一個密碼驗證的例子,它將用戶輸入的密碼與宏定義中的密碼123456進行比較。很顯然,本示例中最大的設計漏洞就在于 Test() 函數中的strcpy(buffer,str)調用。

由于程序將用戶輸入的字符串原封不動地復制到 Test() 函數的數組char buffer[7]中。因此,當用戶的輸入大于 7 個字符的緩沖區(qū)尺寸時,就會發(fā)生數組越界錯誤,這也就是大家所謂的緩沖區(qū)溢出Buffer overflow漏洞。

但是要注意,如果這個時候我們根據緩沖區(qū)溢出發(fā)生的具體情況填充緩沖區(qū),不但可以避免程序崩潰,還會影響到程序的執(zhí)行流程,甚至會讓程序去執(zhí)行緩沖區(qū)里的代碼。示例運行結果為:

在示例代碼中,flag 變量實際上是一個標志變量,其值將決定著程序是進入密碼錯誤的流程(非 0)還是“密碼正確”的流程(0)。當我們輸入錯誤的字符串1234567或者aaaaaaa,程序也都會輸出“密碼正確”。但在輸入0123456的時候,程序卻輸出“密碼錯誤”,這究竟是為什么呢?

其實,原因很簡單。當調用 Test() 函數時,系統(tǒng)將會給它分配一片連續(xù)的內存空間,而變量char buffer[7]與int flag將會緊挨著進行存儲,用戶輸入的字符串將會被復制進 buffer[7] 中。如果這個時候,我們輸入的字符串數量超過 6 個(注意,有字符串截斷符也算一個),那么超出的部分將破壞掉與它緊鄰著的 flag 變量的內容。

當輸入的密碼不是宏定義的123456時,字符串比較將返回 1 或 -1。我們都知道,內存中的數據按照 4 字節(jié)(DWORD)逆序存儲,所以當 flag 為 1 時,在內存中存儲的是0x01000000。如果我們輸入包含 7 個字符的錯誤密碼,如aaaaaaa,那么字符串截斷符 0x00 將寫入 flag 變量,這樣溢出數組的一個字節(jié) 0x00 將恰好把逆序存放的 flag 變量改為0x00000000。在函數返回后,一旦 main 函數的 flag 為 0,就會輸出“密碼正確”。這樣,我們就用錯誤的密碼得到了正確密碼的運行效果。

而對于0123456,因為在進行字符串的大小比較時,它小于123456,flag的值是 -1,在內存中將按照補碼存放負數,所以實際存儲的不是0x01000000而是0xffffffff。那么字符串截斷后符 0x00 淹沒后,變成0x00ffffff,還是非 0,所以沒有進入正確分支。

其實,本示例只是用一個字節(jié)淹沒了鄰接變量,導致程序進入密碼正確的處理流程,使設計的驗證功能失效。

盡量顯式地指定數組的邊界

在 C 語言中,為了提高運行效率,給程序員更大的空間,為指針操作帶來更多的方便,C 語言內部本身不檢查數組下標表達式的取值是否在合法范圍內,也不檢查指向數組元素的指針是不是移出了數組的合法區(qū)域。因此,在編程中使用數組時就必須格外謹慎,在對數組進行讀寫操作時都應當進行相應的檢查,以免對數組的操作超過數組的邊界,從而發(fā)生緩沖區(qū)溢出漏洞。

除此之外,在 C99 標準中,還允許我們使用單個指示符為數組的兩段“分配”空間,如下面的代碼所示:

在上面的a[MAX]數組中,如果 MAX 大于 10,數組中間將用 0 值元素進行填充(填充的個數為MAX-10,并從 a[5] 開始進行 0 值填充);如果 MAX 小于 10,[MAX-5]之前的 5 個元素(1,2,3,4,5)中將有幾個被[MAX-5]之后的 5 個元素(6,7,8,9,10)所覆蓋,示例代碼如下所示:

運行結果為:

對數組做越界檢查,確保索引值位于合法的范圍之內

要避免數組越界,除了上面所闡述的顯式指定數組的邊界之外,還可以在數組使用之前進行越界檢查,檢查數組的界限和字符串(也以數組的方式存放)的結束,以保證數組索引值位于合法的范圍之內。例如,在寫處理數組的函數時,一般應該有一個范圍參數;在處理字符串時總檢查是否遇到空字符‘’。

來看下面一段代碼示例:

從上面的int*TestArray(int num,int value)函數中不難看出,其中存在著一個很明顯的問題,那就是無法保證 num 參數是否越界(即當num>=ARRAY_NUM的情況)。因此,應該對 num 參數進行越界檢查,示例代碼如下所示:

這樣通過if(num

但是,如果仔細檢查,TestArray() 函數仍然還存在一個致命的問題,那就是沒有檢查數組的下界。由于這里的 num 參數類型是 int 類型,因此可能為負數。如果 num 參數所傳遞的值為負數,將導致在 arr 所引用的內存邊界之外進行寫入。

當然,你可以通過向if(num

但是,這樣的函數形式對調用者來說是不友好的(由于 int 類型的原因,對調用者來說仍然可以傳遞負數,至于在函數中怎么處理那是另外一件事情),因此,最佳的解決方案是將 num 參數聲明為 size_t 類型,從根本上防止它傳遞負數,示例代碼如下所示:

獲取數組的長度時不要對指針應用 sizeof 操作符

在 C 語言中,sizeof 這個其貌不揚的家伙經常會讓無數程序員叫苦連連。同時,它也是各大公司爭相選用的面試必備題目。簡單地講,sizeof 是一個單目操作符,不是函數。其作用就是返回一個操作數所占的內存字節(jié)數。其中,操作數可以是一個表達式或括在括號內的類型名,操作數的存儲大小由操作數的類型來決定。例如,對于數組int a[5],可以使用sizeof(a)來獲取數組的長度,使用sizeof(a[0])來獲取數組元素的長度。

但需要注意的是,sizeof 操作符不能用于函數類型、不完全類型(指具有未知存儲大小的數據類型,如未知存儲大小的數組類型、未知內容的結構或聯合類型、void 類型等)與位字段。例如,以下都是不正確形式:

了解 sizeof 操作符之后,現在來看下面的示例代碼:

從表面看,上面代碼的輸出結果應該是0,1,2,3,4,5,6,7,8,9,但實際結果卻出乎我們的意料,如圖 1 所示。

圖 1 示例代碼在 VC++2010 中的運行結果

是什么原因導致這個結果呢?

很顯然,上面的示例代碼在void Init(int arr[])函數中接收了一個int arr[]類型的形參,并且在main函數中向它傳遞一個a[10]實參。同時,在 Init() 函數中通過sizeof(arr)/sizeof(arr[0])來確定這個數組元素的數量和初始化值。

在這里出現了一個很大問題:由于 arr 參數是一個形參,它是一個指針類型,其結果是sizeof(arr)=sizeof(int*)。在 IA-32 中,sizeof(arr)/sizeof(arr[0])的結果為 1。因此,最后的結果如圖 1 所示。

對于上面的示例代碼,我們可以通過傳入數組的長度的方式來解決這個問題,示例代碼如下:

除此之外,我們還可以通過指針的方式來解決上面的問題,示例代碼如下所示:

現在,Init() 函數中的 arr 參數是一個指向arr[10]類型的指針。需要特別注意的是,這里絕對不能夠使用void Init(int(*arr)[])來聲明函數,而是必須指明要傳入的數組的大小,否則sizeof(*arr)無法計算。但是在這種情況下,再通過 sizeof 來計算數組大小已經沒有意義了,因為此時數組大小已經指定為 10 了。

責任編輯:xj

原文標題:數組越界及其避免方法,C語言數組越界詳解

文章出處:【微信公眾號:嵌入式ARM】歡迎添加關注!文章轉載請注明出處。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • C語言
    +關注

    關注

    180

    文章

    7614

    瀏覽量

    137726
  • 數組
    +關注

    關注

    1

    文章

    417

    瀏覽量

    26028

原文標題:數組越界及其避免方法,C語言數組越界詳解

文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    常見xgboost錯誤及解決方案

    XGBoost(eXtreme Gradient Boosting)是一種流行的機器學習算法,用于解決分類和回歸問題。盡管它非常強大和靈活,但在使用過程中可能會遇到一些常見錯誤。以下是一些常見
    的頭像 發(fā)表于 01-19 11:22 ?460次閱讀

    電源 PCB 布局中的常見錯誤避免方式

    的異常現象、根本原因以及優(yōu)化布局的方法和相關技巧。 1. 常見錯誤一:功率器件散熱不良 異常現象 功率器件溫度過高,可能導致器件性能下降,甚至損壞。例如,MOSFET 的導通電阻會隨溫度升高而增大,進一步增加功耗,形成惡性循環(huán)。
    的頭像 發(fā)表于 01-08 15:28 ?434次閱讀

    EEPROM編程常見錯誤及解決方案

    EEPROM(電可擦可編程只讀存儲器)在編程過程中可能會遇到多種錯誤。以下是一些常見的EEPROM編程錯誤及其解決方案: 常見
    的頭像 發(fā)表于 12-16 17:08 ?1412次閱讀

    VSS遇到的常見錯誤及解決方法

    Visual SourceSafe(VSS)是一個版本控制系統(tǒng),由微軟開發(fā),用于跟蹤文件和項目的歷史記錄。盡管VSS已經有些過時,但仍有一些團隊在使用它。以下是一些VSS用戶可能遇到的常見錯誤及其
    的頭像 發(fā)表于 12-13 16:08 ?379次閱讀

    電子電器氣密性檢測儀使用方法:操作中的常見錯誤與糾正

    電子電器氣密性檢測儀是確保產品質量的關鍵設備,但在使用過程中,操作人員常犯一些錯誤,導致測試結果不準確或儀器損壞。以下是一些常見的操作錯誤及其糾正
    的頭像 發(fā)表于 11-29 11:20 ?255次閱讀
    電子電器氣密性檢測儀使用<b class='flag-5'>方法</b>:操作中的<b class='flag-5'>常見</b><b class='flag-5'>錯誤</b>與糾正

    C語言數組應用計算機導論A第6講:數組

    C語言數組應用計算機導論A第6講:數組
    發(fā)表于 11-20 15:33 ?0次下載

    解讀版|Air780E軟件中C語言內存數組的神秘面紗!

    今天我們來揭開Air780E 軟件中 C 語言內存數組的神秘面紗,希望有所收獲。
    的頭像 發(fā)表于 11-17 10:00 ?313次閱讀
    解讀版|Air780E軟件中<b class='flag-5'>C</b><b class='flag-5'>語言</b>內存<b class='flag-5'>數組</b>的神秘面紗!

    aes加密的常見錯誤及解決方案

    的歸納以及相應的解決方案: 常見錯誤 編碼問題 : 在將字節(jié)數組轉換成字符串時,如果使用了不同的編碼格式,可能會導致解密后的數據出現亂碼。 密鑰長度問題 : AES算法支持128位、192位和256位三種密鑰長度。如果加密和解密
    的頭像 發(fā)表于 11-14 15:13 ?2109次閱讀

    常見傅里葉變換錯誤及解決方法

    傅里葉變換是一種數學工具,用于將信號從時域轉換到頻域,以便分析其頻率成分。在使用傅里葉變換時,可能會遇到一些常見錯誤。 1. 采樣定理錯誤 錯誤描述: 在進行傅里葉變換之前,沒有正確
    的頭像 發(fā)表于 11-14 09:42 ?1162次閱讀

    CAN總線常見錯誤及其解決方法

    錯誤碼,這些錯誤碼可以幫助我們診斷和解決問題。 1. 錯誤幀(Error Frame) 錯誤碼 :當CAN控制器檢測到一個幀的錯誤時,會發(fā)送
    的頭像 發(fā)表于 11-12 10:05 ?3935次閱讀

    服務器錯誤是怎么回事?常見錯誤原因及解決方法匯總

    服務器錯誤是怎么回事?最常見的原因分有六個,分別是:硬件問題、軟件問題、網絡問題、資源耗盡、數據庫、文件權限問題。可以根據以下具體錯誤原因進行辨別,并選擇適合的解決方法。關于
    的頭像 發(fā)表于 08-12 10:11 ?1627次閱讀

    PCB線路板制造中常見錯誤有哪些,如何避免?

    一站式PCBA智造廠家今天為大家講講避免常見pcb設計錯誤方法有哪些?避免常見PCB設計
    的頭像 發(fā)表于 06-07 09:15 ?555次閱讀

    嵌入式系統(tǒng)中C語言結構體的基礎實現與應用

    C語言中的數組只能允許程序員定義存儲相同類型數據。但是結構是C語言編程中允許您存儲不同數據類型的數據。
    發(fā)表于 03-12 14:29 ?560次閱讀
    嵌入式系統(tǒng)中<b class='flag-5'>C</b><b class='flag-5'>語言</b>結構體的基礎實現與應用

    串口通信常見錯誤和故障排除方法

    在進行串口通信時,確實可能會遇到一些常見錯誤和問題。
    的頭像 發(fā)表于 03-02 14:19 ?4258次閱讀

    C語言中的錯誤處理機制解析

    C 語言不提供對錯誤處理的直接支持,但是作為一種系統(tǒng)編程語言,它以返回值的形式允許您訪問底層數據。
    的頭像 發(fā)表于 02-26 11:19 ?564次閱讀
    主站蜘蛛池模板: 高清不卡日本v在线二区 | 国内精品手机在线观看视频 | 毛片不卡一区二区三区 | 午夜激情啪啪 | 色综合视频在线 | 亚洲欧美高清在线 | 羞羞漫画喷水漫画yy漫画 | 1000部啪啪未满十八勿入中国 | 欧美天天爽 | 深点再深一点好爽好多水 | 色吧五月婷婷 | 中文字幕精品一区影音先锋 | 天堂伊人| 亚洲色四在线视频观看 | 中文字幕二区 | 国产精品爱久久久久久久三级 | 操片免费| 色一欲一性一乱一区二区三区 | 日本大片黄色 | 深夜偷偷看视频在线观看 | 国产精品黄页网站在线播放免费 | 天堂资源在线观看 | 淫操 | 好男人社区www的视频免费 | 免费大片黄国产在线观看 | 日韩在线三级视频 | 久久久久久天天夜夜天天 | 免费在线视频你懂的 | 高h道具触手play肉男男 | 瑟瑟网站免费 | 狠狠色噜狠狠狠狠色综合久 | 丁香婷婷啪啪 | 亚洲国产一区二区三区在线观看 | 色婷婷一区二区三区四区成人网 | 国产人成午夜免费噼啪视频 | 国产chinesetube | 免费欧美| 成人黄色免费观看 | 美女视频黄又黄又免费高清 | 91福利国产在线观看网站 | 狠狠色噜噜狠狠狠狠888奇米 |