C/C++語言變量聲明內存分配

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <span?style="font-family:?Verdana,?Arial,?Helvetica,?sans-serif;?">一個由c/C++編譯的程序占用的內存分為以下幾個部分</span>??

1、棧區(stack)— 程序運行時由編譯器自動分配,存放函數的參數值,局部變量的值等。其操作方式類似于數據結構中的棧。程序結束時由編譯器自動釋放。
2、堆區(heap) — 在內存開辟另一塊存儲區域。一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似于鏈表。
3、全局區(靜態區)(static)—編譯器編譯時即分配內存。全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的

另一塊區域。 - 程序結束后由系統釋放
4、文字常量區 —常量字符串就是放在這里的。 程序結束后由系統釋放
5、程序代碼區—存放函數體的二進制代碼。

例子程序
這是一個前輩寫的,非常詳細

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. //main.cpp??
  2. int?a?=?0;?全局初始化區??
  3. char?*p1;?全局未初始化區??
  4. main()??
  5. {??
  6. int?b;//?棧??
  7. char?s[]?=?"abc";?//棧??
  8. char?*p2;?//棧??
  9. char?*p3?=?"123456";?//"123456/0"在常量區,p3在棧上。??
  10. static?int?c?=0;?//全局(靜態)初始化區??
  11. p1?=?(char?*)malloc(10);??
  12. p2?=?(char?*)malloc(20);??
  13. //分配得來得10和20字節的區域就在堆區。??
  14. strcpy(p1,?"123456");?//123456/0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。??
  15. }??

===============

C語言程序的內存分配方式
1.內存分配方式
  內存分配方式有三種:
  [1]從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量,static變量。
  [2]在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置于處理器的指令集中,效率很高,但是分配的內存容

量有限。
  [3]從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc或new申請任意多少的內存,程序員自己負責在何時用free或delete釋放內存。動態內存的生存期由程序員決定,使用非常靈活,但

如果在堆上分配了空間,就有責任回收它,否則運行的程序會出現內存泄漏,頻繁地分配和釋放不同大小的堆空間將會產生堆內碎塊。
2.程序的內存空間
  一個程序將操作系統分配給其運行的內存塊分為4個區域,如下圖所示。
  一個由C/C++編譯的程序占用的內存分為以下幾個部分,
  1、棧區(stack)—  由編譯器自動分配釋放 ,存放為運行函數而分配的局部變量、函數參數、返回數據、返回地址等。其操作方式類似于數據結構中的棧。
  2、堆區(heap) —  一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。分配方式類似于鏈表。
  3、全局區(靜態區)(static)—存放全局變量、靜態數據、常量。程序結束后由系統釋放。
  4、文字常量區 —常量字符串就是放在這里的。 程序結束后由系統釋放。
  5、程序代碼區—存放函數體(類成員函數和全局函數)的二進制代碼。
  下面給出例子程序,

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. int?a?=?0;?//全局初始化區??
  2.   char?*p1;?//全局未初始化區??
  3.   int?main()?{??
  4.   int?b;?//棧??
  5.   char?s[]?=?"abc";?//棧??
  6.   char?*p2;?//棧??
  7.   char?*p3?=?"123456";?//123456在常量區,p3在棧上。??
  8.   static?int?c?=0;//全局(靜態)初始化區??
  9.   p1?=?new?char[10];??
  10.   p2?=?new?char[20];??
  11.   //分配得來得和字節的區域就在堆區。??
  12.   strcpy(p1,?"123456");?//123456放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。??
  13.   }??

3.堆與棧的比較
  3.1申請方式
  stack: 由系統自動分配。 例如,聲明在函數中一個局部變量 int b; 系統自動在棧中為b開辟空間。
  heap: 需要程序員自己申請,并指明大小,在C中malloc函數,C++中是new運算符。
  如p1 = (char *)malloc(10); p1 = new char[10];
  如p2 = (char *)malloc(10); p2 = new char[20];
  但是注意p1、p2本身是在棧中的。
  3.2申請后系統的響應
  棧:只要棧的剩余空間大于所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。
  堆:首先應該知道操作系統有一個記錄空閑內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大于所申請空間的堆結點,然后將該結點從空閑結點鏈表中刪除,并將該結

點的空間分配給程序。
  對于大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。
  由于找到的堆結點的大小不一定正好等于申請的大小,系統會自動的將多余的那部分重新放入空閑鏈表中。
  3.3申請大小的限制
  棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之

是一個編譯時就確定的常數),如果申請的空間超過棧的剩余空間時,將提示overflow。因 此,能從棧獲得的空間較小。
  堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由于系統是用鏈表來存儲的空閑內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計算機系統

中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。
  3.4申請效率的比較
  棧由系統自動分配,速度較快。但程序員是無法控制的。
  堆是由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便。
  另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,他不是在堆,也不是棧,而是直接在進程的地址空間中保留一快內存,雖然用起來最不方便。但是速度快,也最靈活。
  3.5堆和棧中的存儲內容
  棧:在函數調用時,第一個進棧的是主函數中后的下一條指令(函數調用語句的下一條可執行語句)的地址,然后是函數的各個參數,在大多數的C編譯器中,參數是由右往左入棧的,然后是函數中

的局部變量。注意靜態變量是不入棧的。
  當本次函數調用結束后,局部變量先出棧,然后是參數,最后棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。
  堆:一般是在堆的頭部用一個字節存放堆的大小。堆中的具體內容有程序員安排。
  3.6存取效率的比較

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. char?s1[]?=?"a";??
  2. char?*s2?=?"b";??

a是在運行時刻賦值的;而b是在編譯時就確定的;但是,在以后的存取中,在棧上的數組比指針所指向的字符串(例如堆)快。 比如

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. int main(){??
  2.   char?a?=?1;??
  3.   char?c[]?=?"1234567890";??
  4.   char?*p?="1234567890";??
  5.   a?=?c[1];??
  6.   a?=?p[1];??
  7.   return?0;??
  8.   }??

對應的匯編代碼
[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. 10:?a?=?c[1];??
  2.   00401067?8A?4D?F1?mov?cl,byte?ptr?[ebp-0Fh]??
  3.   0040106A?88?4D?FC?mov?byte?ptr?[ebp-4],cl??
  4.   11:?a?=?p[1];??
  5.   0040106D?8B?55?EC?mov?edx,dword?ptr?[ebp-14h]??
  6.   00401070?8A?42?01?mov?al,byte?ptr?[edx+1]??
  7.   00401073?88?45?FC?mov?byte?ptr?[ebp-4],al??

第一種在讀取時直接就把字符串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到edx中,再根據edx讀取字符,顯然慢了。

3.7小結
  堆和棧的主要區別由以下幾點:
  1、管理方式不同;
  2、空間大小不同;
  3、能否產生碎片不同;
  4、生長方向不同;
  5、分配方式不同;
  6、分配效率不同;
  管理方式:對于棧來講,是由編譯器自動管理,無需我們手工控制;對于堆來說,釋放工作由程序員控制,容易產生memory leak。
  空間大小:一般來講在32位系統下,堆內存可以達到4G的空間,從這個角度來看堆內存幾乎是沒有什么限制的。但是對于棧來講,一般都是有一定的空間大小的,例如,在VC6下面,默認的棧空間大

小是1M。當然,這個值可以修改。
  碎片問題:對于堆來講,頻繁的new/delete勢必會造成內存空間的不連續,從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個問題,因為棧是先進后出的隊列,他們是如此的一

一對應,以至于永遠都不可能有一個內存塊從棧中間彈出,在他彈出之前,在他上面的后進的棧內容已經被彈出,詳細的可以參考數據結構。
  生長方向:對于堆來講,生長方向是向上的,也就是向著內存地址增加的方向;對于棧來講,它的生長方向是向下的,是向著內存地址減小的方向增長。
  分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部變量的分配。動態分配由malloca函數進行分配,但是棧的動態分

配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。
  分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的

,它的機制是很復雜的,例如為了分配一塊內存,庫函數會按照一定的算法(具體的算法可以參考數據結構/操作系統)在堆內存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由于內

存碎片太多),就有可能調用系統功能去增加程序數據段的內存空間,這樣就有機會分 到足夠大小的內存,然后進行返回。顯然,堆的效率比棧要低得多。
  從這里我們可以看到,堆和棧相比,由于大量new/delete的使用,容易造成大量的內存碎片;由于沒有專門的系統支持,效率很低;由于可能引發用戶態和核心態的切換,內存的申請,代價變得更

加昂貴。所以棧在程序中是應用最廣泛的,就算是函數的調用也利用棧去完成,函數調用過程中的參數,返回地址, EBP和局部變量都采用棧的方式存放。所以,我們推薦大家盡量用棧,而不是用堆。
  雖然棧有如此眾多的好處,但是由于和堆相比不是那么靈活,有時候分配大量的內存空間,還是用堆好一些。
  無論是堆還是棧,都要防止越界現象的發生(除非你是故意使其越界),因為越界的結果要么是程序崩潰,要么是摧毀程序的堆、棧結構,產生以想不到的結果。
4.new/delete與malloc/free比較
  從C++角度上說,使用new分配堆空間可以調用類的構造函數,而malloc()函數僅僅是一個函數調用,它不會調用構造函數,它所接受的參數是一個unsigned long類型。同樣,delete在釋放堆空間之

前會調用析構函數,而free函數則不會。

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. class?Time{??
  2.   public:??
  3.   Time(int,int,int,string);??
  4.   ~Time(){??
  5.   cout<<"call?Time’s?destructor?by:"<<name<<endl;??
  6.   }??
  7.   private:??
  8.   int?hour;??
  9.   int?min;??
  10.   int?sec;??
  11.   string?name;??
  12.   };??
  13.   Time::Time(int?h,int?m,int?s,string?n){??
  14.   hour=h;??
  15.   min=m;??
  16.   sec=s;??
  17.   name=n;??
  18.   cout<<"call?Time’s?constructor?by:"<<name<<endl;??
  19.   }??
  20.   int?main(){??
  21.   Time?*t1;??
  22.   t1=(Time*)malloc(sizeof(Time));??
  23.   free(t1);??
  24.   Time?*t2;??
  25.   t2=new?Time(0,0,0,"t2");??
  26.   delete?t2;??
  27.   system("PAUSE");??
  28.   return?EXIT_SUCCESS;??
  29.   }??
  30.   ??

結果:
  call Time’s constructor by:t2
  call Time’s destructor by:t2
  從結果可以看出,使用new/delete可以調用對象的構造函數與析構函數,并且示例中調用的是一個非默認構造函數。但在堆上分配對象數組時,只能調用默認構造函數,不能調用其他任何構造函數

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

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

相關文章

sql server數據庫實現保留指定位數小數的函數

有時候需要對一個特定的含有小數點的數字保留指定位數&#xff0c;比如“123.123600”。 在數據庫中以函數的形式實現如下&#xff1a; USE [數據庫名稱] GO /****** Object: UserDefinedFunction [dbo].[AvgLimit] Script Date: 2016/12/29 11:30:44 ******/ SET ANSI_NUL…

Centos7下安裝netstat

剛安裝centos7發想沒有查看端口的命令 netstat yum install net-tools轉載于:https://www.cnblogs.com/cuizhipeng/p/5329811.html

【pyqt5學習】——items view相關控件(list view、table view)

目錄 list view——列表視圖 table view——表格視圖 list view——列表視圖 PyQt5-高級控件使用&#xff08;QListView&#xff09; - ygzhaof_100 - 博客園QListView用于展示數據&#xff0c;子類是QListWidget。QlistView基于模型Mode&#xff0c;需要程序創建Model然后保…

變量定義和聲明的區別~~~概念上千萬不要栽跟頭!!!

變量的聲明有兩種情況&#xff1a; 1、一種是需要建立存儲空間的。例如&#xff1a;int a 在聲明的時候就已經建立了存儲空間。 2、另一種是不需要建立存儲空間的。 例如&#xff1a;extern int a 其中變量a是在別的文件中定義的。 聲明是向編譯器介紹名字&#xff0d;&…

解決Ajax不能跨域的方法

1. Ajax不能跨域請求的原因 同源策略(Same Origin Policy)&#xff0c;是一種約定&#xff0c;該約定阻止當前腳本獲取或者操作另一個域下的內容。所有支持Javascript的瀏覽器都支持同源策略&#xff0c;也就是說瀏覽器可以隔離來自不同源的內容&#xff0c;阻止跨域請求的發生…

【pyqt5學習】——containers相關控件(tab widget、scroll area、stack widget、tool box、MDI area、dock widget)

目錄 1、tab widget 2、scroll area 2.1 使用方法 Step1.拖入QScrollArea ?Step2.改變widget控件布局 ?Step3.設置scrollAreaWidgetContents大小 3、Tool Box 4、Stacked Widget 4.1 案例展示 5、frame 6、MDI AREA 7、dock widget 7.1 懸浮狀態 7.2 吸附狀態 conta…

Java使用原子類進行多線程的 i++ 操作示例

2019獨角獸企業重金招聘Python工程師標準>>> 使用AtomicInteger原子類進行 i 操作 可以有類似 synchronized 實現同步的效果。 原子操作是不能分割的整體&#xff0c;沒有其他線程能夠中斷或檢查正在原子操作中的變量。一個原子類型就是一個原子操作可用的類型&…

深入理解面向對象設計的七大原則

一&#xff0e;面向對象設計的七大原則是什么&#xff1f; 1.開放封閉原則 2.里氏轉換原則 3.依賴倒轉原則 4.組合/聚合原則 5.接口隔離原則 6.“迪米特”法則 7.單一職責原則 二&#xff0e;七大原則是什么含義&#xff1f; 序號 面向對象設計七大原則 偶的理解 1 …

mybatis實戰教程(mybatis in action)之二:以接口的方式編程

前面一章&#xff0c;已經搭建好了eclipse,mybatis,mysql的環境&#xff0c;并且實現了一個簡單的查詢。請注意&#xff0c;這種方式是用SqlSession實例來直接執行已映射的SQL語句&#xff1a;session.selectOne("com.yihaomen.mybatis.models.UserMapper.selectUserByID&…

Linux內核分析06

進程的描述和進程的創建 一&#xff0c;進程的描述 進程控制塊PCB——task_struct &#xff08;進程描述符&#xff09;&#xff0c;為了管理進程&#xff0c;內核必須對每個進程進行清晰的描述&#xff0c;進程描述符提供了內核所需了解的進程信息。 struct task_struct數據結…

【pyqt5學習】——pyqt5中.qrc資源文件的創建與編寫

目錄 一、說明 二、安裝pyqt5以及相關工具&#xff08;pyqt5、pyuic、pqrcc&#xff09; 三、創建.ui文件 1、選中文件右鍵-external-pyqt5 打開GUI設計界面 2、創建一個界面&#xff08;內含四個等大label框&#xff09; 3、CTRLS保存 4、找到ui文件&#xff0c;右鍵--e…

zabbix3.0.4通過jmx監控tomcat

jdk下載頁面http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.htmlhttp://download.oracle.com/otn-pub/java/jdk/8u91-b14/jdk-8u91-linux-x64.rpm?AuthParam1462948138_871b75d4b1dd7155e8cbe4f23e5cd2cd腳本[rootNFS-WEB1 latest]# vim /e…

C#學習筆記——25個經典問題

1.靜態成員和非靜態成員的區別&#xff1f; 2.const 和 static readonly 區別&#xff1f; 3.extern 是什么意思&#xff1f; 4.abstract 是什么意思&#xff1f; 5.internal 修飾符起什么作用&#xff1f; 6.sealed 修飾符是干什么的&#xff1f; 7.override 和 o…

PHP的學習--RSA加密解密

PHP服務端與客戶端交互或者提供開放API時&#xff0c;通常需要對敏感的數據進行加密&#xff0c;這時候rsa非對稱加密就能派上用處了。 舉個通俗易懂的例子&#xff0c;假設我們再登錄一個網站&#xff0c;發送賬號和密碼&#xff0c;請求被攔截了。 密碼沒加密&#xff0c;那攻…

Swift學習

1、Swift網址 http://swiftdoc.org/ 2、 https://github.com/ipader/SwiftGuide 轉載于:https://www.cnblogs.com/superbobo/p/5329876.html

【pyqt5學習】——最新版:配置external tools(designer、pyuic、pqrcc)

目錄 1、pip install PyQt5 2、pip install pyqt5-tools 3、file-settings-tools-external tool 點擊加號定義工具名字&#xff0c;名字隨意便于區分即可 雙擊每一個工具名字&#xff0c;配置路徑&#xff08;注意每一個exe的路徑&#xff09; designer.exe pyuic.exe py…

Linux中vi命令詳解

最近vi用的多&#xff0c;很多技巧不知道&#xff0c;備注一份&#xff0c; vi編輯器是所有Unix及Linux系統下標準的編輯器&#xff0c;它的強大不遜色于任何最新的文本編輯器&#xff0c;這里只是簡單地介紹一下它的用法和一小部分指令。由于 對Unix及Linux系統的任何版本&…

C# 屬性和字段

以下的文章是摘錄的&#xff0c;作者已經不詳了。之所以摘錄&#xff0c;是因為這個概念很重要特別對于VFP程序員來說&#xff0c;這里構造屬性就與vfp的方法完全不同。c#的屬性融合了vfp的addproperty() 和屬性的access method和assign method 。不一而足使用屬性&#xff0c…

SEO優化---學會建立高轉化率的網站關鍵詞庫

想要優化好一個網站&#xff0c;行業的分析&#xff0c;以及關鍵詞的挖掘是必要的,有一定的關鍵詞排名了,但是轉化率和流量方面卻很不理想這種情況大部分是只注重了有指數的關鍵詞排名&#xff0c;而忽略了長尾關鍵詞和一些沒有指數但是可以帶來巨大流量的關鍵詞。 網站大部分的…

Monkey腳本編寫

腳本優勢&#xff1a;簡單、快捷、不需要借助任何工具&#xff0c;可以做簡單的性能測試 腳本缺點&#xff1a;只能簡單實現坐標、按鍵等基本操作&#xff0c;無邏輯性 腳本格式&#xff1a; 腳本API&#xff1a; 例子&#xff1a; 打開瀏覽器&#xff0c;輸入WWW.jikexueyuan.…