錯誤內存【讀書筆記】C程序中常見的內存操作有關的典型編程錯誤

題記:寫這篇博客要主是加深自己對錯誤內存的認識和總結實現算法時的一些驗經和訓教,如果有錯誤請指出,萬分感謝。

? ? ? ? ?對C/C++程序員來講,內存管理是個不小的挑戰,絕對值得慎之又慎,否則讓由上萬行代碼構成的模塊跑起來后才出現內存崩潰,是很讓人痛苦的。因為崩潰的位置在時間和空間上,通常是在距真正的錯誤源一段距離以后才表現出來。頭幾天線上模塊因堆內存寫越界1個字節引起各種詭異崩潰,定位問題過程當中的折騰仍歷歷在目,今天讀到《深刻理解計算機系統》第9章-虛擬存儲器,發明書中總結了C程序中常見的內存操縱有關的10種典型編程錯誤,總結的比擬全面。故作為筆記,記載于此。

????1. 間接引用無效指針
? ? ? ? 進程虛擬地址空間的某些地址范圍可能沒有映射到任何有意義的數據,如果我們試圖間接引用一個指向這些地址的指針,則操縱系統會以Segment Fault終止進程。而且,虛擬存儲器的某些區域是只讀的(如.text或.rodata),試圖寫這些區域會以掩護異常中止當前進程。
? ? ? ? 如從stdin讀取一個int變量時,scanf("%d", &val)是準確用法,若誤寫為scanf("%d", val)時,val的值會被解釋為一個地址,并試圖向該地址寫數據。在最好的情況下,進程立即異常中止。在最壞的情況下,val的值恰好對應于虛擬存儲器的某個正當的具有讀/寫權限的內存區域,于是該內存單元會被改寫,而這通常會在相當長的一段時間后形成災難性的、令人困惑的后果。

????2. 讀未初始化的存儲器
? ? ? ? C語言的malloc并不負責初始化申請到的內存區域,因此,常見的錯誤是假設堆存儲器被初始化為0,例如:

int * foo(int **A, int *x, int n){int i, j;int * y = (int *)Malloc(n * sizeof(int));for(i = 0; i < n; i++) {for(j = 0; j < n; j++){y[i] += A[i][j] * x[j];}}return y;}

? ? ? ? ? ?上述代碼中,錯誤地假設了y被初始化為0。準確的實現方式是顯式將y[i]置為0或者應用calloc。

????3. 棧緩沖區溢出
? ? ? ? ?例如:

char buf[5];sprintf(buf, "%s", "hello world");

? ? ? ? ? ?

????上面的代碼致使棧緩沖區溢出,安全的做法是:1)根據需求定義適合的buffer;2)采取snprintf(buf, sizeof(buf), "%s", "hello world")來實時截斷。

????4. 誤以為指針與其指向的對象是雷同巨細的
? ? ? ? 例如:

int **makeArray(int n, int m){int i;int **A = (int **)Malloc(n*sizeof(int));   // 這里錯誤地以為int *與int兩種變量類型具有雷同的sizefor(i = 0; i < n; i++) {A[i] = (int *)Malloc(m * sizeof(int));}return A;}

????? ? ? ? 上述代碼目的是創立一個由n個指針構成的數組,每一個指針均指向一個包含m個int的數組,但誤將sizeof(int *)寫成sizeof(int)。這段代碼只有在int和int *的size雷同的機器上運行良好。如果在像Core i7這樣的機器上運行這段代碼,由于指針變量的size大于sizeof(int),則會引發代碼中的for循環寫越界。因為這些字中的一個很多是已分配塊的邊界標記腳部,所以我們可能不會立即發明這個錯誤,直到進程運行很久釋放這個內存塊時,此時,分配器中的合并代碼會戲劇性地失敗,而沒有任何明顯的原因。這是"在遠處起作用"(action at distance)的一個隱秘示例,這類"在遠處起作用"是與存儲器有關的編程錯誤的典型情況。

????5. 形成錯位錯誤
? ? ? ? ?錯位(Off-by-one)錯誤是另一種常見的覆蓋錯誤來源:

每日一道理
全部世界,因為有了陽光,城市有了生機;細小心靈,因為有了陽光,內心有了舒暢。明媚的金黃色,樹叢間小影成像在葉片上泛有的點點破碎似的金燦,海面上直射反映留有的隨波浪層層翻滾的碎片,為這大自然創造了美景,惹人醉的溫馨之感,濃濃暖意中夾雜著的明朗與柔情,讓雨過天晴后久違陽光的心靈重新得到了滋潤!
int ** makeArray(int n, int m){int i;int **A = (int **)Malloc(n * sizeof(int *));for(i = 0; i <= n; i++) {A[i] = (int *)Malloc(m * sizeof(int));}return A;}

? ? ? ? ?

????很明顯,for循環次數分歧預期,致使寫越界。榮幸的話,進程會立即崩潰;不幸的話,運行很長時間才拋出各種詭異問題。

????6. 引用指針,而不是它所指向的對象
? ? ? ? 如果不注意C操縱符的優先級和結合性,就會錯誤地操縱指針,而不是指針所指向的對象。
? ? ? ? 比如上面的函數,其目的是刪除一個有*size項的二叉堆里的第一項,然后對剩下的*size-1項重建堆:

int * binheapDelete(int **binheap, int *size){int *packet = binheap[0];binheap[0] = binheap[*size - 1];*size--;  // 此處應該為(*size)--heapify(binheap, *size, 0);return (packet);}

????? ? ? ?上述代碼中,由于--和*優先級雷同,從右向左結合,所以*size--其實增加的是指針自己的值,而非其指向的整數的值。因此,服膺:當你對優先級和結合性有疑問時,就應該應用括號。

????7. 誤解指針運算
? ? ? ? 在C/C++中,指針的算術操縱是以它們指向的對象的巨細為單位來進行的。例如上面函數的功能是掃描一個int的數組,并返回一個指針,指向val的初次出現:

int * search(int *p, int val){while(*p && *p != val) {p += sizeof(int); // 此處應該為p++,否則p += 4會致使大部分元素被跳過}}

????8. 引用不存在的變量

? ? ? ? ? ?

????C/C++新手不理解棧的規矩時,可能會引用不再正當的當地變量,例如:

int * stackref(){int val;return &val;}

????? ? ? ? 函數返回的指針(假設為p)指向棧中的局部變量,但該變量在函數返回后隨著stackref棧幀的銷毀已經不再有效。也即:盡管函數返回的指針p仍然指向一個正當的存儲器地址,但它已經不再指向一個正當的變量了。當程序后續調用其它函數時,存儲器將重用剛才銷毀棧幀處的存儲器區域。再后來,如果程序分配某個值給*p,那么它可能實際上正在修改另一個函數棧幀中的數據,從而潛在地帶來災難性的、令人困惑的后果。

????9. 引用閑暇堆塊中的數據
? ? ? ? 典型的錯誤為:引用已經被釋放了的堆塊中的數據,例如:

int * heapref(int n, int m){int i;int *x, *y;x = (int *)Malloc(n * sizeof(int));/*  各種操縱 */free(x);y = (int *)Malloc(m * sizeof(int));for(i = 0; i < m; i++) {y[i] = x[i]++;  // 此處的x之前已經被釋放了!}}

????10. 內存泄露
? ? ? ?內存泄露是遲緩、隱性的殺手,當程序員忘記釋放已分配塊時會產生這類問題,例如:

void leak(int n){int *x = (int *)Malloc(n * sizeof(int));return;}

????? ? ? ?如果leak在程序全部生命周期內只調用數次,則問題還不是很嚴峻(但還是會浪費存儲器空間),因為隨著進程結束,操縱系統會回收這些內存空間。但如果leak()被經常調用,那就會產生嚴峻的內存泄露,最壞的情況下,會占用全部虛擬地址空間。對于像守護進程和服務器這樣的程序來講,內存泄露是嚴峻的bug,必須加以看重。

????【參考資料】
《深刻理解計算機系統》第9章 — 虛擬存儲器

????============== EOF ==================

????

文章結束給大家分享下程序員的一些笑話語錄: 一個合格的程序員是不會寫出 諸如 “摧毀地球” 這樣的程序的,他們會寫一個函數叫 “摧毀行星”而把地球當一個參數傳進去。

--------------------------------- 原創文章 By
錯誤和內存
---------------------------------

轉載于:https://www.cnblogs.com/xinyuyuanm/p/3150400.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/259647.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/259647.shtml
英文地址,請注明出處:http://en.pswp.cn/news/259647.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring_HelloWord

環境&#xff1a;IntelliJ 14 &#xff1b; jdk1.8 Spring操作步驟 1.新建項目---Spring Batch2.IntelliJ會自動加載jar包3.現在就可以在src目錄下寫Java類文件了4.將相應的類部署在XML配置文件spring-config.xml中 &#xff08;Eclipse需要手動創建&#xff0c;貌似名為bean.x…

java 按鈕組_java中創建一個按鈕組,有10個按鈕,分別寫著0,1,2,,3。。。。9

展開全部用Java創建按鈕組32313133353236313431303231363533e59b9ee7ad9431333332643966的程序如下:import java.awt.GridLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JButton;import javax.swing.JFrame;public class…

Starling 2D框架簡介

本系列是對Introducing Starling pdf的翻譯&#xff0c;下文是對adobe開發人員中心的一片日志的轉載&#xff0c;地址為http://www.adobe.com/cn/devnet/flashplayer/articles/introducing_Starling.html Starling 是在 Stage3D APIs 基礎上開發的一種 ActionScript 3 2D 框架&…

基本數據結構——棧

棧的特征是后進先出&#xff08;last-in, first-out, LIFO&#xff09;。棧上的插入操作稱為壓入&#xff08;PUSH&#xff09;&#xff0c;刪除操作稱為彈出&#xff08;POP&#xff09;。 下面使用一個數組S[n]來實現一個最多容納n個元素的棧。定義一個屬性指向最新插入的元素…

Android AutoCompleteTextView控件實現類似百度搜索提示,限制輸入數字長度

Android AutoCompleteTextView 控件實現類似被搜索提示&#xff0c;效果如下 1.首先貼出布局代碼 activity_main.xml&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res…

Centos/RHEL上查看主板型號

老是搞忘記&#xff0c;專門做個記錄&#xff1a; [rootmedia ~]# dmidecode | grep "Product Name" Product Name: To be filled by O.E.M.Product Name: B75M-D3V 修改默認語言&#xff1a;[chenshouyongmedia ~]$ cat /etc/sysconfig/i18n LANG"en_US.UTF-8…

java即時聊天系統畢業_(完整版)基于Java即時聊天系統的設計與實現畢業論文設計...

目錄1 前言...................................................................................................................................1.1 課題選題背景...................................................................................................…

杭電 1284 錢幣兌換問題【完全背包求方案總數】

解題思路&#xff1a;因為對于完全背包的狀態轉移方程f[v]max(f[v],f[v-c[i]]w[i])已經記錄了所有背包組成的方案&#xff0c;只不過通常問的是求最大值&#xff0c;現在要求方案總數 即為 f[v]sum(f[v],f[v-c[i]w[i]]), Problem Description在一個國家僅有1分&#xff0c;2分&…

java與算法_Java與算法之(1) - 冒泡排序

冒泡排序法的原理是&#xff0c;每次比較相鄰的兩個元素&#xff0c;如果它們的順序錯誤就把它們交換過來。例如對4 3 6 2 7 1 5這7個數字進行從小到大的排序&#xff0c;從最左側開始&#xff0c;首先比較4和3因為是從小到大排序&#xff0c;4和3的順序顯然是錯誤的&#xff0…

Js+XML 操作

我的xml文件Login.xml如下. <?xml version"1.0" encoding"utf-8" ?><Login><Character><C Text"熱血"Value"0"></C><C Text"弱氣"Value"1"></C><C Text"激情…

Java(Android)線程池

1、new Thread的弊端執行一個異步任務你還只是如下new Thread嗎&#xff1f; [java] view plaincopy new Thread(new Runnable() { Override public void run() { // TODO Auto-generated method stub } }).start(); 那你就out太多了&#xff0c;n…

JQuery鏈式操作簡單的菜單列表

看到這個簡單的菜單demo&#xff0c;也是為了再看看JQuery對DOM的操作&#xff0c;一直都記不牢&#xff0c;特別是siblings&#xff08;&#xff09;這個總是想不起來。 這次再過一遍JQuery&#xff0c;不管簡單的還是復雜的demo 還是堅持練習一遍吧&#xff01;只為記錄&…

java 網絡編程實驗_Java網絡編程入門實驗一涉及點

1.http://www.cr173.com/html/20128_all.html 【wireshark怎么抓包、wireshark抓包詳細圖文教程】2.http://blog.csdn.net/huangjin0507/article/details/51678858 【HTTP協議1&#xff1a;工作原理】3.https://www.cnblogs.com/1666818961-lxj/p/7210021.html 【網絡常用端口號…

node.js async流程控制器--queue(隊列)

queue流程控制器是一個并行的流程控制器,但是它與parallel的區別在于queue可以控制一次執行幾個函數,而parallel只是讓所有函數并行執行. 例子如下: var q async.queue(function (obj,cb) {setTimeout(function () {console.log(obj);cb(); },obj.time) },1)for (var i 0; i&…

利用JS實現點擊上一周或下一周卻換

1.頁面加載顯示當前年份的第幾周 效果如圖&#xff1a; html代碼&#xff1a; <font size"2" color"black"> <input id"btnweek5" type"button" class"btn" value"上周" οnclick"EduCommissio…

centos7網卡編輯_CentOS7修改網卡為eth0

1.編輯網卡信息[rootlinux-node2~]#cd /etc/sysconfig/network-scripts/ #進入網卡目錄[rootlinux-node2network-scripts]# mv ifcfg-eno16777728 ifcfg-eth0 #重命名網卡名稱[rootlinux-node2 network-scripts]#cat ifcfg-eth0 #編輯網卡信息TYPEEthernetBOOTPROTOstaticDEFR…

C# 微支付退款申請接口 V3.3.6

/// <summary>/// 微支付退款申請/// </summary>/// <param name"context"></param>/// <param name"returnMsg"></param>/// <returns></returns>public bool Refund(HttpContext context, ref string r…

[轉] 英語、計算機、互聯網與全球化

http://davidzhao.blog.51cto.com/4548102/1225732 轉載于:https://www.cnblogs.com/wowk/p/3169638.html

APNIC IP 庫

http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest轉載于:https://www.cnblogs.com/dlwj/p/6388162.html

java reference 傳引用_Java的引用(reference)---Roni

摘自《Java面向對象編程》一書,作者:孫衛琴 來源:www.javathinker.org在JDK1.2以前的版本中&#xff0c;當一個對象不被任何變量引用&#xff0c;那么程序就無法再使用這個對象。也就是說&#xff0c;只有對象處于可觸及狀態&#xff0c;程序才能使用它。這就像在日常生活中&am…