⑴ 不同編譯器為什麼對數據分配的存儲單元大小不同,分配的大小與程序運行有關嗎
額,不同的編譯器對同一種類型變數分配的存儲單元大小不同。。。不同就不同了。。。沒有為什麼。。。畢竟當初沒有統一的標准。不過都是微小的差別,影響不大。我們不需要知道為什麼不同,只要知道它們分配的確實不同就行了。
分配的大小與程序運行有關的。同樣是一個int型,在VC下被分配4位元組,在TC下被分配2位元組。實際程序運行的時候,也是前者吃掉4位元組的內存,後者吃掉2位元組的內存。
⑵ c語言哪些占程序空間哪些占內存空間
一個由C/C++編譯的程序佔用的內存分別為以下四個部分:
程序代碼區:存放程序的二進制代碼。
靜態數據區:存放程序運行期間用到的數據。其存儲空間是在編譯時分配的,在整個程序執行期間靜態數據區中的數據一直存在,程序結束後由系統釋放。
動態內存區(也稱棧):也存放程序運行期間用到的數據,其存儲空間在程序運行期間由編譯器自動分配釋放,其生命周期短於程序的運行期。
堆區:由程序員分配釋放,若程序員不釋放,程序結束時可能由系統回收。
以上內容抄自課本《C語言與程序設計》(電子工業出版社)
⑶ C語言問題:內存的分配方式有哪幾種
1、靜態存儲區分配
內存分配在程序編譯之前完成,且在程序的整個運行期間都存在,例如全局變數、靜態變數等。
2、棧上分配
在函數執行時,函數內的局部變數的存儲單元在棧上創建,函數執行結束時這些存儲單元自動釋放。
3、堆上分配
堆分配(又稱動態內存分配)。程序在運行時用malloc或者new申請內存,程序員自己用free或者delete釋放,動態內存的生存期由我們自己決定。
(3)程序分配內存和編譯器分配內存擴展閱讀
棧上分配數組
#include<iostream>
usingnamespacestd;
voidmain()
{
int**arr=NULL;//int型二維數組
introws,columns;
cin>>rows;//2
cin>>columns;//3
//請在此處編寫代碼,根據rows和columns在棧上分配一個數組arr
...你的代碼...
//賦值給數組元素
for(introwIndex=0;rowIndex<rows;rowIndex++)
{
for(intcolumnIndex=0;columnIndex<columns;columnIndex++)
{
arr[rowIndex][columnIndex]=columnIndex+(rowIndex+1)*1000+1;
}
}
//列印每個數組元素
for(rowIndex=0;rowIndex<rows;rowIndex++)
{
for(intcolumnIndex=0;columnIndex<columns;columnIndex++)
{
printf("%d",arr[rowIndex][columnIndex]);
}
printf(" ");
}
}
⑷ 編譯時分配內存和運行時分配內存
編譯其實只是一個掃描過程,進行詞法語法檢查,代碼優化而已,編譯程序越好,程序運行的時候越高效。
我想你說的「編譯時分配內存」是指「編譯時賦初值」,它只是形成一個文本,檢查無錯誤,並沒有分配內存空間。
當你運行時,系統才把程序導入內存。一個進程(即運行中的程序)在主要包括以下五個分區:
棧、堆、bss、data、code
代碼(編譯後的二進制代碼)放在code區,代碼中生成的各種變數、常量按不同類型分別存放在其它四個區。系統依照代碼順序執行,然後依照代碼方案改變或調用數據,這就是一個程序的運行過程。
⑸ c語言中編譯系統和操作系統誰為變數分配相應的存儲空間
編譯系統將程序編譯成可執行代碼
操作系統執行程序,按照可執行代碼需求為程序分配代碼空間、常量空間、變數空間、堆棧空間,然後執行程序。
⑹ 操作系統執行可執行程序時,內存分配是怎樣的
如果是集顯,執行程序時需要調動集顯,有一部分的物理內存會被分配給集顯來使用,如果是獨顯,那就沒問題了,獨顯自己帶有內存,不需要共享(部分顯卡除外,有些性能強勁的顯卡可以分享內存,增加性能),這時候的內存就是你系統所能識別的內存。
從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變數,static變數。
從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc或new申請任意多少的內存,程序員自己負責在何時用free或delete釋放內存。動態內存的生存期由我們決定,使用非常靈活,但問題也最多。
(6)程序分配內存和編譯器分配內存擴展閱讀:
C++的內存分配:
根據C++的語法規范,定義數組時數組長度必須用常量而不能用變數表示,此時可以使用動態內存分配解決這一問題。
動態內存分配是指在程序運行時為程序中的變數分配內存空間,它完全由應用程序自己進行內存的分配和回收。
程序運行時,特別要注意的是內存的分配。有以下六個地方都可以保存數據。
⑺ 操作系統執行可執行程序時,內存分配是怎樣的
在操作系統中,一個進程就是處於執行期的程序(當然包括系統資源),實際上正在執行的程序代碼的活標本。那麼進程的邏輯地址空間是如何劃分的呢?
圖1做了簡單的說明(Linux系統下的):
圖一
左邊的是UNIX/LINUX系統的執行文件,右邊是對應進程邏輯地址空間的劃分情況。
一般認為在c中分為這幾個存儲區: 1. 棧 --有編譯器自動分配釋放 2. 堆 -- 一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收 3. 全局區(靜態區) -- 全局變數和靜態變數的存儲是放在一塊的,初始化的全局變數和靜態變數在一塊區域,未初始化的全局變數和未初始化的靜態變數在相鄰的另一塊區域。程序結束釋放。 4. 另外還有一個專門放常量的地方。程序結束釋放。 在函數體中定義的變數通常是在棧上,用malloc, calloc, realloc等分配內存的函數分配得到的就是在堆上。在所有函數體外定義的是全局量,加了static修飾符後不管在哪裡都存放在全局區(靜態區),在所有函數體外定義的static變數表示在該文件中有效,不能extern到別的文件用,在函數體內定義的static表示只在該函數體內有效。另外,函數中的"adgfdf"這樣的字元串存放在常量區。比如:代碼:
int a = 0; //全局初始化區
char *p1; //全局未初始化區
main(){
int b; //棧
char s[] = "abc"; //棧
char *p2; //棧
char *p3 = "123456"; //123456 在常量區,p3在棧上。
static int c = 0; //全局(靜態)初始化區
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);//分配得來得10和20位元組的區域就在堆區。
strcpy(p1, "123456");//123456 放在常量區,編譯器可能會將它與p3所指向 的"123456"優化成一塊。
}
還有就是函數調用時會在棧上有一系列的保留現場及傳遞參數的操作。 棧的空間大小有限定,vc的預設是2M。棧不夠用的情況一般是程序中分配了大量數組和遞歸函數層次太深。有一點必須知道,當一個函數調用完返回後它會釋放該函數中所有的棧空間。棧是由編譯器自動管理的,不用你操心。 堆是動態分配內存的,並且你可以分配使用很大的內存。但是用不好會產生內存泄漏。並且頻繁地malloc和free會產生內存碎片(有點類似磁碟碎片),因為c分配動態內存時是尋找匹配的內存的。而用棧則不會產生碎片。 在棧上存取數據比通過指針在堆上存取數據快些。 一般大家說的堆棧和棧是一樣的,就是棧(stack),而說堆時才是堆heap. 棧是先入後出的,一般是由高地址向低地址生長。
堆(heap)和堆棧(stack)的區別
2.1申請方式stack:由系統自動分配。 例如,聲明在函數中一個局部變數 int b; 系統自動在棧中為b開辟空間heap:需要程序員自己申請,並指明大小,在c中malloc函數
如p1 = (char *)malloc(10);
在C++中用new運算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在棧中的。
2.2 申請後系統的響應棧:只要棧的剩餘空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。堆:首先應該知道操作系統有一個記錄空閑內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閑結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閑鏈表中。
2.3
2.4申請效率的比較:棧由系統自動分配,速度較快。但程序員是無法控制的。堆是由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便.另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,他不是在堆,也不是在棧是直接在進程的地址空間中保留一快內存,雖然用起來最不方便。但是速度快,也最靈活。
2.5堆和棧中的存儲內容棧: 在函數調用時,第一個進棧的是主函數中後的下一條指令(函數調用語句的下一條可執行語句)的地址,然後是函數的各個參數,在大多數的C編譯器中,參數是由右往左入棧的,然後是函數中的局部變數。注意靜態變數是不入棧的。當本次函數調用結束後,局部變數先出棧,然後是參數,最後棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。堆:一般是在堆的頭部用一個位元組存放堆的大小。堆中的具體內容有程序員安排。
2.6存取效率的比較
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在運行時刻賦值的;
而bbbbbbbbbbb是在編譯時就確定的;
但是,在以後的存取中,在棧上的數組比指針所指向的字元串(例如堆)快。
比如:#include <...>
void main(){
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
對應的匯編代碼
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一種在讀取時直接就把字元串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到edx中,在根據edx讀取字元,顯然慢了。
2.7小結:堆和棧的區別可以用如下的比喻來看出:使用棧就象我們去飯館里吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等准備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。使用堆就象是自己動手做喜歡吃的菜餚,比較麻煩,但是比較符合自己的口味,而且自由度大。堆和棧的區別主要分:操作系統方面的堆和棧,如上面說的那些,不多說了。還有就是數據結構方面的堆和棧,這些都是不同的概念。這里的堆實際上指的就是(滿足堆性質的)優先隊列的一種數據結構,第1個元素有最高的優先權;棧實際上就是滿足先進後出的性質的數學或數據結構。雖然堆棧,堆棧的說法是連起來叫,但是他們還是有很大區別的,連著叫只是由於歷史的原因。
申請大小的限制棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閑內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。一、預備知識—程序的內存分配一個由c/C++編譯的程序佔用的內存分為以下幾個部分
1、棧區(stack)— 由編譯器自動分配釋放 ,存放函數的參數值,局部變數的值等。其操作方式類似於數據結構中的棧。2、堆區(heap)— 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表,呵呵。3、全局區(靜態區)(static)—全局變數和靜態變數的存儲是放在一塊的,初始化的全局變數和靜態變數在一塊區域, 未初始化的全局變數和未初始化的靜態變數在相鄰的另一塊區域。 - 程序結束後有系統釋放4、文字常量區 —常量字元串就是放在這里的。 程序結束後由系統釋放5、程序代碼區(text)—存放函數體的二進制代碼。
⑻ 我們經常看到書上面說的 某某變數的內存單元是編譯器在編譯時候分配的 是什麼意思
所謂在編譯期間分配空間指的是靜態分配空間(相對於用new動態申請空間),如全局變數或靜態變數(包括一些復雜類型的常量),它們所需要的空間大小可以
明確計算出來,並且不會再改變,因此它們可以直接存放在可執行文件的特定的節里(而且包含初始化的值),程序運行時也是直接將這個節載入到特定的段中,不
必在程序運行期間用額外的代碼來產生這些變數。
其實在運行期間再看「變數」這個概念就不再具備編譯期間那麼多的屬性了(諸如名稱,類型,作用
域,生存期等等),對應的只是一塊內存(只有首址和大小),
所以在運行期間動態申請的空間,是需要額外的代碼維護,以確保不同變數不會混用內存。比如寫new表示有一塊內存已經被佔用了,其它變數就不能再用它了;
寫delete表示這塊內存自由了,可以被其它變數使用了。(通常我們都是通過變數來使用內存的,就編碼而言變數是給內存塊起了個名字,用以區分彼此)
內存申請和釋放時機很重要,過早會丟失數據,過遲會耗費內存。特定情況下編譯器可以幫我們完成這項復雜的工作(增加額外的代碼維護內存空間,實
現申請和釋 放)。從這個意義上講,局部自動變數也是由編譯器負責分配空間的。進一步講,內存管理用到了我們常常掛在嘴邊的堆和棧這兩種數據結構。
最後對於「編譯器分配空間」這種不嚴謹的說法,你可以理解成編譯期間它為你規劃好了這些變數的內存使用方案,這個方案寫到可執行文件裡面了(該文件中包含若干並非出自你大腦衍生的代碼),直到程序運行時才真正拿出來執行。
⑼ 如何分配內存啊
內存分配方式
內存分配方式有三種:
(1) 從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變數,static變數。
(2) 在棧上創建。在執行函數時,函數內局部變數的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集中,效率很高,但是分配的內存容量有限。
(3) 從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc或new申請任意多少的內存,程序員自己負責在何時用free或delete釋放內存。動態內存的生存期由我們決定,使用非常靈活,但問題也最多。
常見的內存錯誤及其對策
發生內存錯誤是件非常麻煩的事情。編譯器不能自動發現這些錯誤,通常是在程序運行時才能捕捉到。而這些錯誤大多沒有明顯的症狀,時隱時現,增加了改錯的難度。有時用戶怒氣沖沖地把你找來,程序卻沒有發生任何問題,你一走,錯誤又發作了。
常見的內存錯誤及其對策如下:
u 內存分配未成功,卻使用了它。
編程新手常犯這種錯誤,因為他們沒有意識到內存分配會不成功。常用解決辦法是,在使用內存之前檢查指針是否為NULL。如果指針p是函數的參數,那麼在函數的入口處用assert(p!=NULL)進行檢查。如果是用malloc或new來申請內存,應該用if(p==NULL) 或if(p!=NULL)進行防錯處理。
u 內存分配雖然成功,但是尚未初始化就引用它。
犯這種錯誤主要有兩個起因:一是沒有初始化的觀念;二是誤以為內存的預設初值全為零,導致引用初值錯誤(例如數組)。
內存的預設初值究竟是什麼並沒有統一的標准,盡管有些時候為零值,我們寧可信其無不可信其有。所以無論用何種方式創建數組,都別忘了賦初值,即便是賦零值也不可省略,不要嫌麻煩。
u 內存分配成功並且已經初始化,但操作越過了內存的邊界。
例如在使用數組時經常發生下標「多1」或者「少1」的操作。特別是在for循環語句中,循環次數很容易搞錯,導致數組操作越界。
u 忘記了釋放內存,造成內存泄露。
含有這種錯誤的函數每被調用一次就丟失一塊內存。剛開始時系統的內存充足,你看不到錯誤。終有一次程序突然死掉,系統出現提示:內存耗盡。
動態內存的申請與釋放必須配對,程序中malloc與free的使用次數一定要相同,否則肯定有錯誤(new/delete同理)。
u 釋放了內存卻繼續使用它。
有三種情況:
(1)程序中的對象調用關系過於復雜,實在難以搞清楚某個對象究竟是否已經釋放了內存,此時應該重新設計數據結構,從根本上解決對象管理的混亂局面。
(2)函數的return語句寫錯了,注意不要返回指向「棧內存」的「指針」或者「引用」,因為該內存在函數體結束時被自動銷毀。
(3)使用free或delete釋放了內存後,沒有將指針設置為NULL。導致產生「野指針」。
⑽ 編譯時分配內存和運行時分配內存的理解,麻煩講解下
編譯時無所謂分配內存,程序在載入後才佔用內存,不知道你說的是不是說編譯生成的目標文件所佔的空間,目標文件里的各個段.bss .data .text等都要佔據一定空間,而運行時隨時都在分配內存,堆棧都是內存。
不管是局部的還是全局靜態變數,都會佔用目標文件的空間,但是也可以不初始化,不初始化的保存在.bss段,初始化的保存在.data段。