c內存存儲結構
1. C語言運行的內存要求是哪三個是不是程序代碼區,靜態存儲區和動態存儲區。求高人路過
一個由c/C++編譯的程序佔用的內存分為以下幾個部分
1、棧區(stack)— 由編譯器自動分配釋放 ,存放函數的參數值,局部變數的值等。其操作方式類似於數據結構中的棧。2、堆區(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表,呵呵。3、全局區(靜態區)(static)—,全局變數和靜態變數的存儲是放在一塊的,初始化的全局變數和靜態變數在一塊區域, 未初始化的全局變數和未初始化的靜態變數在相鄰的另一塊區域。 - 程序結束後有系統釋放 4、文字常量區—常量字元串就是放在這里的。 程序結束後由系統釋放5、程序代碼區—存放函數體的二進制代碼。
2. C語言內存管理機制--malloc/calloc/free原理與實現
一、C程序的存儲空間布局
在C程序中,存儲空間布局通常分為棧和堆兩種類型。棧用於函數調用時的局部變數存儲,其大小由編譯器自動管理,遵循後進先出(LIFO)原則。堆用於動態內存分配,可以由程序在運行時動態地請求和釋放內存。
二、Heap內存模型
在堆內存中,malloc所申請的內存主要從堆區域分配。Linux內核通過維護一個break指針來管理堆空間。這個指針指向堆空間的某個地址,從堆起始地址(Heap』s Start)到break之間的地址空間為映射好的(虛擬地址與物理地址的映射,通過MMU實現),可以供進程訪問。從break向上,是未映射的地址空間,訪問這些空間會導致程序報錯。
三、調整break:brk()和sbrk()
break指針最初位於bss段的末尾之後,當break指針升高時,程序可以訪問新分配區域內的任何內存地址,而此時物理內存頁尚未分配,內存會在進程首次試圖訪問這些虛擬內存地址時自動分配新的物理內存頁。
Linux通過brk和sbrk系統調用操作break指針。brk()將break指針設置為指定位置,地址四捨五入到下一個內存頁的邊界處。sbrk()將break指針在原有地址基礎上增加指定的大小。sbrk(0)返回當前break指針的位置。系統對進程所分配的資源有限,包括映射的內存空間。
四、malloc
malloc函數用於在系統中動態分配連續的可用內存。它要求內存大小至少為指定的位元組數,返回指向內存塊起始地址的指針,多次調用不重疊分配地址,實現內存分配和釋放。malloc函數的返回值總是位元組對齊,適合高效訪問C語言數據結構。
五、初探實現malloc
一個簡單實現的malloc函數直接從未映射區域劃出內存,但忽略了記錄分配的內存塊信息,導致內存釋放時無法確定釋放的大小,需要額外數據結構記錄塊信息。
六、正式實現malloc
實現一個完整的malloc需要一個數據結構組織堆內存,每個內存塊包含元信息(大小、空閑狀態、指針)和實際數據區域。查找合適的內存塊、分配新的塊、分裂塊等操作需實現相應函數。
七、calloc的實現
calloc函數用於給一組相同對象分配內存,並初始化它們。實現只需兩次調用malloc,一次分配內存,另一次初始化。
八、free的實現
free函數需要驗證地址的有效性,並解決碎片問題。實現策略包括合並相鄰空閑內存塊,確保釋放的地址與未映射區域之間是空閑的。
九、realloc的實現
realloc函數調整已分配內存的大小。實現包括復制現有內存、調整大小、釋放舊內存等操作。
十、總結
通過上述機制,C語言提供內存管理功能,允許程序動態分配和釋放內存。優化空間和實際應用的內存管理策略如Linux內核夥伴演算法、STL空間配置器等提供了更高效的實現。
3. C語言中float,double等類型,在內存中的結構
從存儲結構和演算法上來講,double和float是一樣的,不一樣的地方僅僅是float是32位的,double是64位的,所以double能存儲更
高的精度。
任何數據在內存中都是以二進制(0或1)順序存儲的,每一個1或0被稱為1位,而在x86CPU上一個位元組是8位。比如一個16位(2
位元組)的short int型變數的值是1000,那麼它的二進製表達就是:00000011 11101000。由於Intel CPU的架構原因,它是按位元組倒
序存儲的,那麼就因該是這樣:11101000 00000011,這就是定點數1000在內存中的結構。
目前C/C++編譯器標准都遵照IEEE制定的浮點數表示法來進行float,double運算。這種結構是一種科學計數法,用符號、指數和
尾數來表示,底數定為2——即把一個浮點數表示為尾數乘以2的指數次方再添上符號。下面是具體的規格:
````````符號位 階碼 尾數 長度
float 1 8 23 32
double 1 11 52 64
臨時數 1 15 64 80
由於通常C編譯器默認浮點數是double型的,下面以double為例:
共計64位,摺合8位元組。由最高到最低位分別是第63、62、61、……、0位:
最高位63位是符號位,1表示該數為負,0正;
62-52位,一共11位是指數位;
51-0位,一共52位是尾數位。
按照IEEE浮點數表示法,下面將把double型浮點數38414.4轉換為十六進制代碼。
把整數部和小數部分開處理:整數部直接化十六進制:960E。小數的處理:
0.4=0.5*0+0.25*1+0.125*1+0.0625*0+……
實際上這永遠算不完!這就是著名的浮點數精度問題。所以直到加上前面的整數部分算夠53位就行了(隱藏位技術:最高位的1
不寫入內存)。
如果你夠耐心,手工算到53位那麼因該是:38414.4(10)=1001011000001110.(2)
科學記數法為:1.001……乘以2的15次方。指數為15!
於是來看階碼,一共11位,可以表示範圍是-1024 ~ 1023。因為指數可以為負,為了便於計算,規定都先加上1023,在這里,
15+1023=1038。二進製表示為:100 00001110
符號位:正—— 0 !
合在一起(尾數二進制最高位的1不要):
01000000 11100010 11000001 11001101 01010101 01010101 01010101 01010101
按位元組倒序存儲的十六進制數就是:
55 55 55 55 CD C1 E2 40
4. C語言求救~~順式存儲和鏈式存儲結構區別
鏈式存儲結構在邏輯上是連續的,但在物理上則是離散的,它能夠靈活地連接零散的存儲單元,從而提高了空間利用率。相反,順序存儲結構在邏輯和物理上均保持連續,這使得它需要連續的存儲空間,小空間無法被有效利用,導致空間浪費。
鏈式存儲結構通過鏈接多個零碎的小空間,形成了邏輯上的連續性,這使得它非常適合處理動態變化的數據結構,如鏈表、樹和圖等。順序存儲結構則更適合靜態數據的存儲,因為它們要求連續的存儲空間,這樣可以避免頻繁的內存分配與釋放。
雖然順序存儲結構在存儲相同內容時,其佔用的空間通常會比鏈式存儲結構更少,但這並不意味著它總是更優的選擇。鏈式存儲結構的優勢在於能夠動態調整存儲空間,而順序存儲結構則在訪問速度上可能更為高效。
鏈式存儲結構通過指針來實現空間的鏈接,而順序存儲結構則依賴於數組或連續的內存塊。鏈式存儲結構的靈活性使其在處理大量動態數據時更具優勢,而順序存儲結構則在處理大量靜態數據時更為高效。
總的來說,鏈式存儲結構和順序存儲結構各有其適用場景。鏈式存儲結構更適合處理動態變化的數據,而順序存儲結構則在訪問速度和空間利用率方面更具優勢。選擇哪種存儲結構,需要根據具體的應用場景和需求來決定。