1.陣列的元素儲存於記憶體中連續的位置上。當乙個陣列被宣告時,它所需要的內存在編譯時就被分配。
2.但是我們也可以使用動態記憶體分配在執行時為它分配記憶體。
3.為什麼使用動態記憶體分配
1>當使用陣列時,必須用乙個常量來指定陣列的長度。但是,有時候,陣列的長度常常在執行時才知道。因此,在某些情況下,我們通常採取宣告乙個較大的陣列,它可以容納可能出現的最多元素。
2>該方法的優點是:簡單。
3>它的缺點是:
ø 這種宣告在程式中引入了人為的限制,如果程式需要使用的元素數量超過了宣告的長度,它就無法處理這種情況。要避免這種情況,最簡單的方法就是把陣列宣告的更大一些。
ø 如果程式實際需要的元素數量比較少時,巨型陣列的絕大部分記憶體空間都被浪費了。
ø 如果輸入的資料超過了陣列的容納範圍時,程式必須以一種合理的方式作出響應。
1.c函式庫提供了兩個函式,malloc和free,分別用於執行動態記憶體分配和釋放。這些函式維護乙個可用記憶體。
2.當乙個程式另外需要一些記憶體時,它就呼叫malloc函式,malloc從記憶體池中提取一塊合適的記憶體。並向該程式返回乙個指向這塊記憶體的指標。這塊記憶體此時並沒有以任何方式進行初始化。如果要對其進行初始化,要麼自己動手進行初始化,要麼使用calloc()函式。當一塊以前分配的記憶體不在使用時,程式呼叫free函式把它歸還給記憶體池供以後使用。
3.這兩個函式的原型如下,都在標頭檔案stdlib.h中宣告
1>void*malloc(size_t size);
2>void free(void *pointer)
4.malloc的引數就是需要分配的記憶體位元組數。如果記憶體池中的可用記憶體可以滿足這個需求,malloc就返回乙個指向被分配的記憶體塊起始位置的指標。
1>malloc所分配的是一塊連續的記憶體。例如:如果請求分配100個位元組的記憶體,那麼它實際分配的記憶體就是100個連續的位元組,並不會分開位於兩塊或多塊不同的記憶體。同時,malloc實際分配的記憶體有可能比你請求的稍微多一點。但是這時由編譯器定義的。
2>如果記憶體池是空的,或者它的可用記憶體無法滿足要求時。在該情況下,malloc()函式向作業系統請求,要求得到更多地記憶體,並在這塊記憶體上執行分配任務。如果作業系統無法向malloc提供更多的記憶體,malloc就返回乙個null指標。因此,要對每個從malloc返回的指標都進行檢查,確保它並非null是非常重要的。
5.free的引數必須要麼是null,要麼是乙個先前從malloc,calloc或realloc返回的數值。想free傳遞乙個null引數不會產生任何效果。
6.malloc並不知道請求的記憶體需要儲存的是整型、浮點值、結構還是陣列。malloc返回乙個型別為void *的指標。在標準中表示乙個void *型別的指標可以轉換為其他任何型別的指標。因此,在使用前,要進行強制型別轉換。
1.還有兩個記憶體分配函式,calloc和realloc。它們的原型如下:
void*calloc(size_tnum_elements,size_t element_size);
voidrealloc(void *ptr,size_t new_size);
2.calloc也用於分配記憶體。malloc和calloc之間的區別是後者在返回指向記憶體的指標之前把它初始化為0。但如果程式只是想把一些值儲存到陣列中,那麼這個初始化過程純屬浪費時間。
3.calloc和malloc之間另乙個較小的區別是它們請求記憶體數量的方式不同。calloc的引數包括所需元素的數量和每個元素的位元組數。根據這些值,它能夠計算出總共需要分配的記憶體。
4.realloc函式用於修改乙個原先已經分配的記憶體塊大小。
1>使用這個函式,你可以使一塊記憶體擴大或縮小。如果它用於擴大乙個記憶體塊,那麼這塊記憶體原先的內容依然保留,新增加的記憶體新增到原先記憶體塊的後面,新記憶體並未以任何方法進行初始化。
2>如果它用於縮小一塊記憶體塊,該記憶體塊尾部的部分記憶體便被拿掉,剩餘部分記憶體的原先內容依然保留。
3>如果原先的記憶體塊無法改變大小,realloc將分配另一塊正確大小的記憶體,並把原先那塊記憶體的內容複製到新的塊上。因此,在使用realloc之後,就不能再使用指向舊記憶體的指標,而是應該該用realloc所返回的新指標。
4>如果realloc函式的第乙個引數是null,那麼它的行為就和malloc一模一樣。
1.使用malloc分配一塊記憶體
int *pi; ….
pi = malloc(100);
if (pi == null)
符號null定義於stdio.h,它實際上是字元值常量0。
1>如果記憶體分配成功,那麼得到了乙個指向100個位元組的指標。在整型為4個位元組的機器上,這塊記憶體將被當作25個整型元素的陣列,因為pi是乙個指向整型的指標。
2>但是,使用上面的程式可移植性較差:
可以使用如下的方法:
pi = malloc(25 *sizeof(int));
使用該方法,即使在整數長度不同的機器上,它也能獲得正確的結果。
3>已經有了指標,,如何使用這塊記憶體呢。可以使用間接訪問和指標運算來訪問陣列的不同整數字置,下面通過迴圈來給新分配的陣列的每個元素都初始化為0.
int *pi2,i; ……
pi2 = pi;
for(i = 0;i <25;i++)
*pi2++=0;
我們也可以使用小標來運算。
int i;
…..for( i=0;i<25;i++)
pi[i] = 0;
1.使用動態記憶體分配的程式中,常常會出現很多錯誤。
1>對null指標進行解引用操作
2>對分配的記憶體進行操作時越過邊界
3>釋放並非動態分配的記憶體
4>試圖釋放一塊動態分配的記憶體的一部分以及一塊記憶體被釋放之後被繼續使用。
說明:
² 動態分配最常見的錯誤就是忘記檢查所請求的記憶體是否成功分配。
² 2.動態記憶體分配的第二大錯誤**是操作記憶體時超出了分配記憶體的邊界。
2.當你使用free時,可能出現各種不同的錯誤。
1>傳遞給free的指標必須是乙個從malloc、calloc或realloc函式返回的指標。
2>傳遞給free函式乙個指標,讓它釋放一塊並非動態分配的記憶體可能導致程式立即終止或在晚些時候終止。
3>試圖釋放一塊動態分配記憶體的一部分也有可能引起類似問題。
eg:/**
***get 10 integers
**/pi =malloc(10*sizeof(int )); ….
/***僅釋放後5個整數,前面的5個數不釋放 */
free(pi + 5);
說明:² 釋放一塊記憶體的一部分是不允許的。動態分配的記憶體必須整塊一起釋放。但是,realloc函式可以縮小一塊動態分配的記憶體,有效地釋放它尾部的部分記憶體。
4>不要訪問已經被free函式釋放了的記憶體。假定對乙個指向動態分配的記憶體的指標進行了複製,而且這個指標的幾份拷貝分散於程式各處。你無法保證當你使用其中乙個指標時它所指向的記憶體是不是已被另乙個指標釋放。還要確保程式中所有使用這塊記憶體的地方在這塊記憶體釋放之前停止對它的使用。
5>當動態分配的記憶體不再需要使用時,應該被釋放,這樣可以被重新分配使用。分配記憶體但在使用完畢後不釋放將引起記憶體洩漏(memory leak)。
總結:1.當陣列被宣告時,必須在編譯時知道它的長度。動態記憶體分配允許程式為乙個長度在執行時才知道的陣列分配記憶體空間。
2.malloc和calloc函式都用於動態分配一塊記憶體,並返回乙個指定該塊記憶體的指標。
1>malloc的引數就是需要分配的記憶體的位元組數。
2>calloc的引數是需要分配的元素個數和每個元素的長度。calloc函式在返回前把記憶體初始化為零。malloc函式返回時記憶體並未以任何方式進行初始化。
3>呼叫realloc函式可以改變一塊已經動態分配的記憶體的大小。增加記憶體塊大小有時有可能採取的方法是把原來記憶體塊上的所有資料複製到乙個新的、更大的記憶體塊上。當乙個動態分配的記憶體塊不再使用時,應該呼叫free函式把它歸還給可用記憶體池,記憶體釋放後便不能再被訪問。
3.如果請求的記憶體分配失敗,malloc、malloc和readlloc函式返回的將是乙個null指標。
4.錯誤的訪問分配記憶體之外的區域所引起的後果類似越界訪問乙個陣列,但這個錯誤還能破壞可用記憶體池,導致程式失敗。
5.如果乙個指標不是從早先的malloc、calloc或realloc函式返回的,它是不能作為引數傳遞給free函式的。
動態記憶體分配
在c 中建立乙個物件時,我們必須要為這個物件申請一塊記憶體,而且要用建構函式對這塊記憶體進行初始化。c 中的new和delete相對於c的庫函式malloc和free在這方面有很大的優勢,所以我們主要講的是運算子new和delete。當用new來建立乙個物件時,它會自動在堆裡為物件分配記憶體並且為這...
動態記憶體分配
為什麼使用動態記憶體分配?c語言中的一切操作都是基於記憶體的 變數和陣列都是記憶體的別名,如何分配這些記憶體由編譯器在編譯期間決定 定義陣列的時候必須指定陣列唱的 而陣列長度是在編譯期就必須決定的 需求 程式執行的過程中,可能需要使用一些額外的記憶體空間 malloc和free malloc和fre...
動態記憶體分配
c的儲存類別有4種 自動的 auto 靜態的 statics 暫存器的 register 外部的 extern 全域性變數時分配在記憶體中的靜態儲存區 靜態區域性變數屬於靜態儲存類別,在靜態儲存區內分配儲存單元,是在編譯時賦初值的,只賦初值一次,在程式執行時它已有初值,以後每次呼叫函式時不再重新賦初...