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

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C程序中常見(jiàn)的與內(nèi)存相關(guān)的錯(cuò)誤及其解決辦法

STM32嵌入式開(kāi)發(fā) ? 來(lái)源:STM32嵌入式開(kāi)發(fā) ? 2023-06-14 17:13 ? 次閱讀

對(duì)C語(yǔ)言入門(mén)程序員來(lái)說(shuō),管理和使用虛擬存儲(chǔ)器可能是個(gè)困難的,容易出錯(cuò)的任務(wù)。與存儲(chǔ)器有關(guān)的錯(cuò)誤屬于那些最令人驚恐的錯(cuò)誤,因?yàn)樗鼈兘?jīng)常在時(shí)間和空間上,都在距錯(cuò)誤源一段距離之后,才表現(xiàn)出來(lái)。

將錯(cuò)誤的數(shù)據(jù)編寫(xiě)到錯(cuò)誤的位置,你的程序可能在最終失敗之前運(yùn)行了好幾個(gè)小時(shí),且使程序中止的位置距離錯(cuò)誤的位置已經(jīng)很遠(yuǎn)了。

1、間接引用壞指針

在進(jìn)程的虛擬地址空間中有較大的漏洞,沒(méi)有映射到任何有意義的數(shù)據(jù)。如果我們?cè)噲D間接引用一個(gè)指向這些洞的指針,那么操作系統(tǒng)就會(huì)以段異常終止我們的程序。

而且,虛擬存儲(chǔ)器的某些區(qū)域是只讀的。試圖寫(xiě)這些區(qū)域?qū)⒃斐梢员Wo(hù)異常終止這個(gè)程序。

間接引用壞指針的一個(gè)常見(jiàn)示例是經(jīng)典的scanf錯(cuò)誤。假設(shè)我們想要使用scanf從stdin讀一個(gè)整數(shù)到變量。做這件事情正確的方法是傳遞給scanf一個(gè)格式串和變量的地址:

ea36476a-0a92-11ee-962d-dac502259ad0.png ????

然而,對(duì)于c語(yǔ)言程序員初學(xué)者而言,很容易傳遞val的內(nèi)容,而不是它的地址:

ea4a0b38-0a92-11ee-962d-dac502259ad0.png ????

在這種情況下,scanf將把val的內(nèi)容解釋為一個(gè)地址,并試圖將一個(gè)字寫(xiě)到這個(gè)位置。在最好的情況下,程序立即以異常終止。

在最糟糕的情況下,val的內(nèi)容對(duì)應(yīng)于虛擬存儲(chǔ)器的某個(gè)合法的讀/寫(xiě)區(qū)域,于是我們就覆蓋了存儲(chǔ)器,這通常會(huì)在相當(dāng)以后造成災(zāi)難性的、令人困惑的后果。

2、讀未初始化的存儲(chǔ)器

雖然.bss存儲(chǔ)器位置(諸如未初始化的全局C變量)總是被加載器初始化為零,但是對(duì)于堆存儲(chǔ)器卻并不是這樣的。一個(gè)常見(jiàn)的錯(cuò)誤就是假設(shè)堆存儲(chǔ)器被初始化為零:

ea61e03c-0a92-11ee-962d-dac502259ad0.png ????

在這個(gè)示例中,程序員不正確地假設(shè)向量y被初始化為零。正確的實(shí)現(xiàn)方式是在for循環(huán)時(shí)將y[i]設(shè)置為零,或使用calloc。

3、允許棧緩沖區(qū)溢出

如果一個(gè)程序不檢查輸入串的大小就寫(xiě)入棧中的目標(biāo)換成區(qū),那么這個(gè)程序就會(huì)有緩沖區(qū)溢出錯(cuò)誤。例如,下面的函數(shù)就有緩沖區(qū)錯(cuò)誤,因?yàn)間ets函數(shù)拷貝一個(gè)任意長(zhǎng)度的串到緩沖區(qū)。為了糾正這個(gè)錯(cuò)誤,我們必須使用fgets函數(shù),這個(gè)函數(shù)限制了輸入串的大小:

ea77efda-0a92-11ee-962d-dac502259ad0.png

4、假設(shè)指針和它們指向的對(duì)象是相同大小的

一種常見(jiàn)的錯(cuò)誤是假設(shè)指向?qū)ο蟮闹羔樅退鼈兯赶虻膶?duì)象是相同大小的:

ea8547ca-0a92-11ee-962d-dac502259ad0.png ????

這里的目的是創(chuàng)建一個(gè)由n個(gè)指針組成的數(shù)組,每個(gè)指針都指向一個(gè)包含m個(gè)int的數(shù)組。然而,因?yàn)槌绦騿T將int **A = (int **)malloc(n * sizeof(int));中將sizeof(int)寫(xiě)成了sizeof(int),代碼實(shí)際創(chuàng)建的是一個(gè)int的數(shù)組。這段代碼只有在int和指向int的指針大小相同的機(jī)器上運(yùn)行良好。

但是,如果我們?cè)谙馎lpha這樣的機(jī)器上運(yùn)行這段代碼,其中指針大于int,那么在for(i = 0; i < n; i++)? A[i] = (int *)malloc(m * sizeof(int));將寫(xiě)到超過(guò)A數(shù)組末端的地方。因?yàn)檫@些字中的一個(gè)很可能是分配塊的邊界標(biāo)記腳部,所以我們可能不會(huì)發(fā)現(xiàn)這個(gè)錯(cuò)誤,而沒(méi)有任何明顯的原因。

5、造成錯(cuò)位錯(cuò)位

錯(cuò)位錯(cuò)誤是另一種很常見(jiàn)的覆蓋錯(cuò)誤發(fā)生的原因:

ea991b7e-0a92-11ee-962d-dac502259ad0.png ????

這是前面程序的另一個(gè)版本。這里我們創(chuàng)建了一個(gè)n個(gè)元素的指針數(shù)組,但是隨后試圖初始化這個(gè)數(shù)組的n+1個(gè)元素,在這個(gè)過(guò)程中覆蓋了A數(shù)組后面的某個(gè)存儲(chǔ)器。

6、引用指針,而不是它所指向的對(duì)象

如果我們不太注意C操作符的優(yōu)先級(jí)和結(jié)合性,我們就會(huì)錯(cuò)誤地操作指針,而不是期望操作指針?biāo)赶虻膶?duì)象。比如,考慮下面的函數(shù),其目的是刪除一個(gè)有*size項(xiàng)的二叉堆里的第一項(xiàng),然后對(duì)剩下的*size-1項(xiàng)重新建堆。

eaa59a70-0a92-11ee-962d-dac502259ad0.png ???

*size—目的是減少size指針指向的整數(shù)的值。然而,因?yàn)橐辉?運(yùn)算符優(yōu)先級(jí)相同,從右向左結(jié)合,所以代碼實(shí)際減少的是指針自己的值,而不是它所指向的整數(shù)的值。

如果幸運(yùn)的話,程序會(huì)立即失敗,但是更有可能發(fā)生的是,當(dāng)程序在它執(zhí)行過(guò)程的很后面產(chǎn)生一個(gè)不正確的結(jié)果時(shí),我們只能在那里抓腦袋了。這里的原則是如果你對(duì)優(yōu)先級(jí)和結(jié)合性有疑問(wèn),就使用括號(hào)。使用表達(dá)式(*size)--。

7、誤解指針運(yùn)算

另一種常見(jiàn)的錯(cuò)誤是忘記了指針的算術(shù)操作是以它們指向的對(duì)象的大小為單位來(lái)進(jìn)行的,而這種大小單位并不一定是字節(jié)。例如,下面函數(shù)的目的是掃描一個(gè)int的數(shù)組,并返回一個(gè)指針,指向val的首次出現(xiàn):

eaadef90-0a92-11ee-962d-dac502259ad0.png

8、引用不存在的變量

沒(méi)有太多經(jīng)驗(yàn)的C程序員不理解棧的規(guī)則,有時(shí)會(huì)引用不再合法的本地變量,如下列所示:

eac44b8c-0a92-11ee-962d-dac502259ad0.png ????

這個(gè)函數(shù)返回一個(gè)指針,指向棧里的一個(gè)局部變量,然后彈出它的棧幀。盡管p仍然指向一個(gè)合法的存儲(chǔ)器地址,但是它已經(jīng)不再指向一個(gè)合法的變量了。

當(dāng)以后在程序中調(diào)用其他函數(shù)時(shí),存儲(chǔ)器將重用它們的幀棧。后來(lái),如果程序分配某個(gè)值給*p,那么它可能實(shí)際正在修改另一個(gè)函數(shù)的幀棧中的一個(gè)條目,從而帶來(lái)潛在地災(zāi)難性的、令人困惑的后果。

9、引用空閑堆塊中的數(shù)據(jù)

一個(gè)相似的錯(cuò)誤是引用已被釋放了的堆塊中的數(shù)據(jù)。如下面的示例,示例中分配了一個(gè)整數(shù)數(shù)組x,之后釋放了塊x,最后又引用了它。

ead02362-0a92-11ee-962d-dac502259ad0.png

10、引起存儲(chǔ)器泄漏

存儲(chǔ)器泄漏是緩慢、隱形的殺手,當(dāng)程序員不小心忘記釋放已分配塊,而在堆里創(chuàng)建了垃圾時(shí),會(huì)發(fā)生這種問(wèn)題。例如,下面的函數(shù)分配了一個(gè)堆塊x,然后不釋放它就返回。

eae5f37c-0a92-11ee-962d-dac502259ad0.png ????

如果leak經(jīng)常被調(diào)用,堆里就會(huì)充滿(mǎn)了垃圾,最糟糕的情況下,會(huì)占有整個(gè)虛擬地址空間。對(duì)于像守護(hù)進(jìn)程和服務(wù)器這樣的程序來(lái)說(shuō),存儲(chǔ)器泄漏是特別嚴(yán)重的,根據(jù)定義這些程序是不會(huì)終止的。




審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 存儲(chǔ)器
    +關(guān)注

    關(guān)注

    38

    文章

    7496

    瀏覽量

    163927
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7605

    瀏覽量

    137003
  • 虛擬機(jī)
    +關(guān)注

    關(guān)注

    1

    文章

    918

    瀏覽量

    28232

原文標(biāo)題:C程序中常見(jiàn)的與內(nèi)存相關(guān)的錯(cuò)誤

文章出處:【微信號(hào):c-stm32,微信公眾號(hào):STM32嵌入式開(kāi)發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    C程序中常見(jiàn)的與內(nèi)存相關(guān)錯(cuò)誤

    對(duì)C語(yǔ)言入門(mén)程序員來(lái)說(shuō),管理和使用虛擬存儲(chǔ)器可能是個(gè)困難的,容易出錯(cuò)的任務(wù)。與存儲(chǔ)器有關(guān)的錯(cuò)誤屬于那些最令人驚恐的錯(cuò)誤,因?yàn)樗鼈兘?jīng)常在時(shí)間和空間上,都在距
    發(fā)表于 06-14 17:13 ?358次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>程序</b><b class='flag-5'>中常見(jiàn)</b>的與<b class='flag-5'>內(nèi)存</b><b class='flag-5'>相關(guān)</b>的<b class='flag-5'>錯(cuò)誤</b>

    聲卡硬件維修的常見(jiàn)問(wèn)題及解決辦法

    聲卡硬件維修的常見(jiàn)問(wèn)題及解決辦法 常見(jiàn)故障一:聲卡無(wú)聲   出現(xiàn)這種故障常見(jiàn)的原因有:
    發(fā)表于 02-23 14:25 ?2558次閱讀

    垂直熱風(fēng)整平中常見(jiàn)問(wèn)題解決辦法

    垂直熱風(fēng)整平中常見(jiàn)問(wèn)題解決辦法   熱風(fēng)整平又叫噴錫,它的工作原理是利用熱風(fēng)將印制板表面及孔內(nèi)多余焊料去掉,剩余焊料均
    發(fā)表于 03-02 09:35 ?793次閱讀

    開(kāi)發(fā)中常遇電磁兼容EMC問(wèn)題及解決辦法

    開(kāi)發(fā)中常遇電磁兼容EMC問(wèn)題及解決辦法 下面產(chǎn)品開(kāi)發(fā)中常見(jiàn)的一些EMC問(wèn)題: 一
    發(fā)表于 04-17 11:32 ?736次閱讀

    物理內(nèi)存使用率高的原因及解決辦法

    主要講解的就是物理內(nèi)存使用率高的原因以及他的解決辦法。導(dǎo)致物理內(nèi)存使用率高有幾種可能,而最常見(jiàn)的則有兩種:一是安裝不好的程序,
    發(fā)表于 05-03 17:14 ?9380次閱讀
    物理<b class='flag-5'>內(nèi)存</b>使用率高的原因及<b class='flag-5'>解決辦法</b>

    Absinthe2.0越獄iOS5.1.1常見(jiàn)錯(cuò)誤解決辦法

    Absinthe2.0越獄中可能會(huì)遇到一些問(wèn)題,本內(nèi)容介紹了Absinthe2.0越獄iOS5.1.1常見(jiàn)錯(cuò)誤解決辦法
    發(fā)表于 09-12 15:03 ?4712次閱讀

    Matlab編程常見(jiàn)錯(cuò)誤解決辦法

    Matlab編程常見(jiàn)錯(cuò)誤解決辦法求人不如求己
    發(fā)表于 03-16 15:58 ?0次下載

    一文知道Zynq平臺(tái)運(yùn)行SDK程序錯(cuò)誤解決辦法

    Zynq平臺(tái)運(yùn)行SDK程序錯(cuò)誤解決辦法,具體的跟隨小編一起來(lái)了解一下。
    的頭像 發(fā)表于 07-14 06:05 ?8125次閱讀

    KEIL C編譯器中常見(jiàn)的警告與錯(cuò)誤信息的詳細(xì)解決辦法資料概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是KEIL C編譯器中常見(jiàn)的警告與錯(cuò)誤信息的詳細(xì)解決辦法資料概述。
    發(fā)表于 11-07 17:43 ?14次下載

    內(nèi)存條兼容異常問(wèn)題的原因及其解決辦法

    經(jīng)常使用電腦的朋友都知道,電腦如果出現(xiàn)滴滴聲的 電腦開(kāi)機(jī) 故障就是內(nèi)存條出現(xiàn)了問(wèn)題。但是如果類(lèi)似迅雷等軟件突然出現(xiàn)問(wèn)題時(shí),大多數(shù)朋友可能就不會(huì)想到是由于內(nèi)存出現(xiàn)了兼容性的問(wèn)題了。下面,我就向大家介紹一下內(nèi)存條兼容異常問(wèn)題的原因
    發(fā)表于 06-14 10:53 ?1.1w次閱讀

    C語(yǔ)言常見(jiàn)內(nèi)存錯(cuò)誤及解決方法

      本文將帶您了解一些良好的和內(nèi)存相關(guān)的編碼實(shí)踐,以將內(nèi)存錯(cuò)誤保持在控制范圍內(nèi)。內(nèi)存錯(cuò)誤
    的頭像 發(fā)表于 02-14 13:10 ?3307次閱讀

    java內(nèi)存溢出的幾種原因和解決辦法

    內(nèi)存,但是如果程序中存在內(nèi)存泄漏(Memory Leak)或者使用不當(dāng)?shù)臄?shù)據(jù)結(jié)構(gòu)等問(wèn)題,仍然有可能導(dǎo)致內(nèi)存溢出。下面將詳細(xì)介紹Java內(nèi)存
    的頭像 發(fā)表于 11-23 14:44 ?6209次閱讀

    codeblocks環(huán)境錯(cuò)誤解決辦法

    CodeBlocks是一款常用的集成開(kāi)發(fā)環(huán)境,用于編寫(xiě)、編譯和調(diào)試C、C++等程序。然而,有時(shí)在使用CodeBlocks時(shí)可能會(huì)遇到一些錯(cuò)誤或問(wèn)題。本文將為你提供一些
    的頭像 發(fā)表于 11-26 09:37 ?7258次閱讀

    常見(jiàn)MCU故障及解決辦法

    微控制器單元(MCU)是現(xiàn)代電子設(shè)備中的核心組件,負(fù)責(zé)處理和控制各種功能。然而,由于各種原因,MCU可能會(huì)出現(xiàn)故障。以下是一些常見(jiàn)的MCU故障及其解決辦法: 1. 電源問(wèn)題 故障現(xiàn)象: MCU無(wú)法
    的頭像 發(fā)表于 11-01 13:41 ?1957次閱讀

    RS232串口通信中常見(jiàn)問(wèn)題及解決辦法

    RS232串口通信中常見(jiàn)問(wèn)題及解決辦法主要包括以下幾個(gè)方面: 一、物理連接問(wèn)題 問(wèn)題 :串口線未插穩(wěn)或接口松動(dòng)。 解決辦法 :重新插拔串口線,確保連接牢固。同時(shí)檢查插頭和針腳是否損壞,如有損壞需更換
    的頭像 發(fā)表于 11-21 09:32 ?1419次閱讀