動態記憶體配置詳細懶人包

即使你知道你想利用的空間大小,但是如果因為某種特殊原因空間利用的大小有增加或者減少,你又必須重新去修改程式,擴大陣列的儲存範圍。 這種分配固定大小的記憶體分配方法稱之為靜態記憶體分配。 但是這種記憶體分配的方法存在比較嚴重的缺陷,特別是處理某些問題時:在大多數情況下會浪費大量的記憶體空間,在少數情況下,當你定義的陣列不夠大時,可能引起下標越界錯誤,甚至導致嚴重後果。 比較彈性的處理方法是:程式撰寫的時候不設定陣列的大小,而在執行時才以動態的方式指定、配置和使用這個陣列,例如讓使用者由鍵盤輸入它所需要的陣列大小,這時才決定配置所需的記憶體。 動態記憶體配置 動態記憶體配置,是由我們明確地以「malloc」等指令來取得記憶體空間,並以「free」釋放不再需要的記憶體空間。

動態記憶體配置

定長分配通常被稱為記憶體池分配,使用一個連結串列來儲存空閒記憶體塊資訊(通常每塊記憶體大小相同)。 通常,記憶體是從一個被稱為堆的記憶體池中分配出來的。 高階語言封裝了記憶體位址的概念,記憶體通常是通過指標來間接存取的。 分配演算法經常將組織分配釋放組塊等操作封裝成抽象的介面供上層函式呼叫。 在函式結束後還以指標存取堆疊上的區域變數,以指標 (或是複製的指標) 存取已經用 free() 函式釋放了的記憶體區段。 由上面的討論, 大家應該可以瞭解動態地記憶體配置可以使程式的彈性大大提高, 這也是 C 語言中為什麼要使用指標變數的一個很大的原因。

動態記憶體配置: 動態記憶體配置與字串

在電腦科學中, 動態記憶體分配(Dynamic memory allocation)又稱為堆記憶體分配,是指電腦程式在執行期中分配使用記憶體。 它可以當成是一種分配有限記憶體資源所有權的方法。 一般,用static修飾的變數,全域性變數位於靜態資料區。 函式呼叫過程中的引數,返回地址,EBP和區域性變數都採用棧的方式存放。

動態記憶體配置

動態配置的記憶體其生命週期完全由程式設計者來控制:其生成在 malloc() 函式, 終結在 free() 函式, 可以在任何看得到此記憶體位址的函式內存取此區域記憶體的變數內容, 不像區域性變數 只有在開始執行一函式時才生成, 函式一完畢立刻就終結, 不能再被使用。 在C語言中,區域變數與區塊變數是以自動的方式管理。 每當變數被宣告後,就會自動地在記憶體中配置適合的空間供其使用;當變數所在的函式或區塊結束時,所配置的記憶體空間就會被釋放。 所謂動態記憶體分配就是指在程式執行的過程中動態地分配或者回收儲存空間的分配記憶體的方法。

動態記憶體配置: 動態記憶體分配

以此種方式配置的記憶體空間是不會自動被釋放的,如果我們沒有在程式中使用「free」來釋放,則其生命週期將一直持續到程式結束為止。 通常都是以指標來存取這些動態配置的記憶體空間,我們必須小心的以指標來操作這些指向動態配置的記憶體空間,假設在程式中,沒有任何指標指向一個動態配置的記憶體空間,那麼該空間將無法被使用也無法被釋放,我們將此現像稱為記憶體洩漏。 C 語言中因為有指標的設計, 因此在函式傳遞參數時一律使用傳值的方法, 若是遇見函式內只需要某一參數的數值時當然就沒有問題, 動態記憶體配置 只要將變數的內容拷貝到函數的參數變數內即可, 若是遇見函式需要藉由參數傳某一數值回呼叫函式, 或是不希望浪費時間拷貝變數內資料的話, 只要將變數的位址藉由傳值的機制傳入函式, 函式內部即可利用此位址直接存取呼叫端函式內的變數。

動態記憶體配置

所謂的程式設計,就是透過程式碼對這些值進行邏輯上的操作,以滿足特定的應用目的。 在程式執行時,變數所代表的值,必須存在於記憶體內,才能進行各式操作。 由於記憶體是有限的,所以變數所對應的記憶體空間,也需要有妥善的方法管理,C語言在這方面可分成三種處理方法:自動、靜態與動態。 從這個角度來看,宣告在main()函式內的變數,其記憶體空間是從其宣告開始進行配置,一直到main()函式結束(也就是程式結束時),才會被釋放。 動態記憶體配置 對於程式中存在的其它函式而言,函式內所宣告的變數的記憶體空間,也是從宣告開始進行配置,但其所在的函式結束(或返回時),就會被釋放。

動態記憶體配置: 靜態與動態資料結構

在 Visual C 中可以用特殊的 alloc 函式自堆疊上配置記憶體, 此種記憶體和區域變數 一樣, 可以不需要以 free() 函式釋放, 一旦結束此函式即自動釋放此段記憶體。 另外像文書編輯程式、 或是影像編輯應用程式通常不曉得要編輯的文件或是影像有多大, 因此通常以動態配置來取得存放這些資料的記憶體。 動態分配的記憶體在被程式設計師明確釋放或被垃圾回收之前一直有效。 與靜態記憶體分配的區別在於沒有一個固定的生存期。

當記憶體塊比要分配的長度大兩倍以上,記憶體塊平均分裂成兩塊。 選中其中一半,重複這個過程(檢查長度,滿足條件則分裂)直到記憶體塊剛好等於需要的長度。 &x 及 &y 分別可以取得變數 x 所使用的二個位元組記憶體中第一個位元組的位址及變數 y 所使用的四個位元組記憶體中第一個位元組的位址。 製作資料結構例如︰串列 ,樹 ,不規則的多維陣列 動態記憶體配置 (Triangular, Sparse…)…。

動態記憶體配置: 必須成對執行︰

如此一來,這個程式就毫無彈性可言,因為任何想要使用這個程式的人都必須修改原始碼、重新編譯、才能正確執行它的需求。 若 x,y 為不同型態的指標變數則 x-y 未定義, x 與 y 同為指標變數時,x+y 亦無定義。 X 雖說是一個陣列, 但是在 C 語言中其實是一個指標常數, 在使用 scnaf() 函式時要求在變數前加一個 & 符號其實是在取得變數 x 的位址 (指標)。 在這種分配方式下,記憶體從一個2的N次冪大的記憶體塊中分配。

  • 靜態分配是編譯器完成的,比如區域性變數的分配。
  • 當記憶體塊比要分配的長度大兩倍以上,記憶體塊平均分裂成兩塊。
  • 記錄下此區段第 20 個整數變數的位址的話, 這也算是複製指標, 雖然不能夠藉由 free 直接釋放該段記憶體 free (iPtr-20) 還是可以成功的, iPtr1 也可以存取記憶體區塊內任意的元素, 也就是該段記憶體區塊上有多個指標指於其上, 必須非常小心地處理, 否則很容易有 dangling reference 的錯誤。
  • 從這個角度來看,宣告在main()函式內的變數,其記憶體空間是從其宣告開始進行配置,一直到main()函式結束(也就是程式結束時),才會被釋放。
  • 比較彈性的處理方法是:程式撰寫的時候不設定陣列的大小,而在執行時才以動態的方式指定、配置和使用這個陣列,例如讓使用者由鍵盤輸入它所需要的陣列大小,這時才決定配置所需的記憶體。
  • 由上面的討論, 大家應該可以瞭解動態地記憶體配置可以使程式的彈性大大提高, 這也是 C 語言中為什麼要使用指標變數的一個很大的原因。
  • 通常都是以指標來存取這些動態配置的記憶體空間,我們必須小心的以指標來操作這些指向動態配置的記憶體空間,假設在程式中,沒有任何指標指向一個動態配置的記憶體空間,那麼該空間將無法被使用也無法被釋放,我們將此現像稱為記憶體洩漏。
  • 如此一來,這個程式就毫無彈性可言,因為任何想要使用這個程式的人都必須修改原始碼、重新編譯、才能正確執行它的需求。

在靜態資料結構中,由於資料所佔用的空間大小及資料數目要事先宣告,因此,在執行時,空間的大小及資料數目是不會改變的(因為利用陣列結構)。 以上四點使得 PASCAL 或是 C 語言中都有指標的設計, JAVA 語言中亦有類似的 reference(參考)之設計。 由上節的討論可以得知, C 語言中指標最主要的目的就是提供程式設計者一種間接存取資料或程式碼的抽象方式, 使得程式碼的彈性大增。 藉由 iPtr 是否為 0 可以知道 iPtr 是否目前指向 一個程式可以使用的記憶體區段, 在配置新的記憶體之前必須檢查一下, 以確保不會造成 memory leakage, 在釋放掉此記憶體區段以後必須立刻麼指標設為 0, 以避免不慎誤用 。

動態記憶體配置: 記憶體的動態配置

程序的每個執行緒都有私有的“棧”,所以每個執行緒雖然程式碼一樣,但本地變數的資料都是互不干擾。 一個堆疊可以透過“基地址”和“棧頂”地址來描述。 全域性變數和靜態變數分配在靜態資料區,本地變數分配在動態資料區,即堆疊中。 C 程式可以分很多的模組來製作, 個別模組由不同的人來製作, 剛才這一段程式除了可以處理自己模組內的變數, 也可以處理別的模組裡的變數, 只要該變數的型態是 double 就可以了, 程式在撰寫的時候, 很明顯地我們對想要處理的資料做了一種一般化的處理, 我們並不是假設要處理的資料存放在某一個特定的變數裡, 而是假想說要處理的資料位於任何一個型態為 double 的變數內。 這個情況就好像你擬定一個推銷的策略時, 不會是只針對某一個特定的人, 而會做最起碼的一般化, 至少針對某一個特殊族群是有用的。 而在動態資料結構中,資料所佔用之空間大小及資料數目不必事先宣告,在執行時視實際需要而動態的增加或減少(因為利用串列結構)。

但是,在使用陣列的時候,總有一個問題困擾著我們:陣列應該有多大? 動態記憶體配置 在很多的情況下,你並不能確定要使用多大的陣列,比如上例,你可能並不知道我們要定義的這個陣列到底有多大,那麼你就要把陣列定義得足夠大。 這樣,你的程式在執行時就申請了固定大小的你認為足夠大的記憶體空間。

動態記憶體配置: 指標與 C 語言中函式的參數傳遞

資料區 ︰ 全域變數, static 變數,常數。 堆疊區 ︰ 區域變數 , 函式參數,暫時變數。 在第12章的12.4節,我們首次介紹了區域變數與全域變數的概念,本章將進一步說明變數的生命週期與可視範圍,最後並將介紹C語言的程式的記憶體佈局。

動態記憶體配置

C 語言中指標 (或稱指標常數) 就是是記憶體位址, 指標變數就是存放記憶體位址的變數, 記憶體位址是什麼東東呢? 在 CPU裡 頭替每一個記憶體位元組指定一個序號, 以便用來存取該位元組內存放的資料, 序號就好像我們家的門牌號碼讓郵差可以分辨哪些信放進哪一個信箱一樣, 所以我們稱這個序號為記憶體位址。 在程式中的變數,其實只是一個符號,用以代表某個值。

動態記憶體配置: C 語言中指標結合陣列的宣告相當隱晦,容易錯誤

動態記憶體分配不象陣列等靜態記憶體分配方法那樣需要預先分配儲存空間,而是由系統根據程式的需要即時分配,且分配的大小就是程式要求的大小。 記錄下此區段第 20 個整數變數的位址的話, 這也算是複製指標, 雖然不能夠藉由 free 直接釋放該段記憶體 free (iPtr-20) 還是可以成功的, iPtr1 也可以存取記憶體區塊內任意的元素, 也就是該段記憶體區塊上有多個指標指於其上, 必須非常小心地處理, 否則很容易有 dangling reference 的錯誤。 “棧”和“堆”是兩種不同的動態資料區,棧是一種線性結構,堆是一種鏈式結構。

  • &x 及 &y 分別可以取得變數 x 所使用的二個位元組記憶體中第一個位元組的位址及變數 y 所使用的四個位元組記憶體中第一個位元組的位址。
  • 但是這種記憶體分配的方法存在比較嚴重的缺陷,特別是處理某些問題時:在大多數情況下會浪費大量的記憶體空間,在少數情況下,當你定義的陣列不夠大時,可能引起下標越界錯誤,甚至導致嚴重後果。
  • 由上節的討論可以得知, C 語言中指標最主要的目的就是提供程式設計者一種間接存取資料或程式碼的抽象方式, 使得程式碼的彈性大增。
  • 在很多的情況下,你並不能確定要使用多大的陣列,比如上例,你可能並不知道我們要定義的這個陣列到底有多大,那麼你就要把陣列定義得足夠大。
  • 寫 qsort() 函式的人只要訂下這個比較大小函式的規格後就可以利用函式指標變數 pfnCompare 放心地寫他自己的 qsort() 了。
  • 藉由 iPtr 是否為 0 可以知道 iPtr 是否目前指向 一個程式可以使用的記憶體區段, 在配置新的記憶體之前必須檢查一下, 以確保不會造成 memory leakage, 在釋放掉此記憶體區段以後必須立刻麼指標設為 0, 以避免不慎誤用 。

香港SEO服務由 Featured 提供

Similar Posts