1.數(shù)組的元素存儲于內(nèi)存中連續(xù)的位置上。當(dāng)一個數(shù)組被聲明時,它所需要的內(nèi)存在編譯時就被分配。
2.但是我們也可以使用動態(tài)內(nèi)存分配在運(yùn)行時為它分配內(nèi)存。
3.為什么使用動態(tài)內(nèi)存分配
1>當(dāng)使用數(shù)組時,必須用一個常量來指定數(shù)組的長度。但是,有時候,數(shù)組的長度常常在運(yùn)行時才知道。因此,在某些情況下,我們通常采取聲明一個較大的數(shù)組,它可以容納可能出現(xiàn)的最多元素。
2>該方法的優(yōu)點是:簡單。
3>它的缺點是:
這種聲明在程序中引入了人為的限制,如果程序需要使用的元素數(shù)量超過了聲明的長度,它就無法處理這種情況。要避免這種情況,最簡單的方法就是把數(shù)組聲明的更大一些。
如果程序?qū)嶋H需要的元素數(shù)量比較少時,巨型數(shù)組的絕大部分內(nèi)存空間都被浪費(fèi)了。
如果輸入的數(shù)據(jù)超過了數(shù)組的容納范圍時,程序必須以一種合理的方式作出響應(yīng)。
1.c函數(shù)庫提供了兩個函數(shù),malloc和free,分別用于執(zhí)行動態(tài)內(nèi)存分配和釋放。這些函數(shù)維護(hù)一個可用內(nèi)存。
2.當(dāng)一個程序另外需要一些內(nèi)存時,它就調(diào)用malloc函數(shù),malloc從內(nèi)存池中提取一塊合適的內(nèi)存。并向該程序返回一個指向這塊內(nèi)存的指針。這塊內(nèi)存此時并沒有以任何方式進(jìn)行初始化。如果要對其進(jìn)行初始化,要么自己動手進(jìn)行初始化,要么使用calloc()函數(shù)。當(dāng)一塊以前分配的內(nèi)存不在使用時,程序調(diào)用free函數(shù)把它歸還給內(nèi)存池供以后使用。
3.這兩個函數(shù)的原型如下,都在頭文件stdlib.h中聲明
1>void *malloc(size_t size);
2>void free(void *pointer)
4.malloc的參數(shù)就是需要分配的內(nèi)存字節(jié)數(shù)。如果內(nèi)存池中的可用內(nèi)存可以滿足這個需求,malloc就返回一個指向被分配的內(nèi)存塊起始位置的指針。
1>malloc所分配的是一塊連續(xù)的內(nèi)存。例如:如果請求分配100個字節(jié)的內(nèi)存,那么它實際分配的內(nèi)存就是100個連續(xù)的字節(jié),并不會分開位于兩塊或多塊不同的內(nèi)存。同時,malloc實際分配的內(nèi)存有可能比你請求的稍微多一點。但是這時由編譯器定義的。
2>如果內(nèi)存池是空的,或者它的可用內(nèi)存無法滿足要求時。在該情況下,malloc()函數(shù)向操作系統(tǒng)請求,要求得到更多地內(nèi)存,并在這塊內(nèi)存上執(zhí)行分配任務(wù)。如果操作系統(tǒng)無法向malloc提供更多的內(nèi)存,malloc就返回一個NULL指針。因此,要對每個從malloc返回的指針都進(jìn)行檢查,確保它并非NULL是非常重要的。
5.free的參數(shù)必須要么是NULL,要么是一個先前從malloc,calloc或realloc返回的數(shù)值。想free傳遞一個NULL參數(shù)不會產(chǎn)生任何效果。
6.malloc并不知道請求的內(nèi)存需要存儲的是整型、浮點值、結(jié)構(gòu)還是數(shù)組。Malloc返回一個類型為void *的指針。在標(biāo)準(zhǔn)中表示一個void *類型的指針可以轉(zhuǎn)換為其他任何類型的指針。因此,在使用前,要進(jìn)行強(qiáng)制類型轉(zhuǎn)換。
1.還有兩個內(nèi)存分配函數(shù),calloc和realloc。它們的原型如下:
void *calloc(size_t num_elements,size_t element_size);
void realloc(void *ptr,size_t new_size);
2.calloc也用于分配內(nèi)存。malloc和calloc之間的區(qū)別是后者在返回指向內(nèi)存的指針之前把它初始化為0。但如果程序只是想把一些值存儲到數(shù)組中,那么這個初始化過程純屬浪費(fèi)時間。
3.calloc和malloc之間另一個較小的區(qū)別是它們請求內(nèi)存數(shù)量的方式不同。calloc的參數(shù)包括所需元素的數(shù)量和每個元素的字節(jié)數(shù)。根據(jù)這些值,它能夠計算出總共需要分配的內(nèi)存。
4.realloc函數(shù)用于修改一個原先已經(jīng)分配的內(nèi)存塊大小。
1>使用這個函數(shù),你可以使一塊內(nèi)存擴(kuò)大或縮小。如果它用于擴(kuò)大一個內(nèi)存塊,那么這塊內(nèi)存原先的內(nèi)容依然保留,新增加的內(nèi)存添加到原先內(nèi)存塊的后面,新內(nèi)存并未以任何方法進(jìn)行初始化。
2>如果它用于縮小一塊內(nèi)存塊,該內(nèi)存塊尾部的部分內(nèi)存便被拿掉,剩余部分內(nèi)存的原先內(nèi)容依然保留。
3>如果原先的內(nèi)存塊無法改變大小,realloc將分配另一塊正確大小的內(nèi)存,并把原先那塊內(nèi)存的內(nèi)容復(fù)制到新的塊上。因此,在使用realloc之后,就不能再使用指向舊內(nèi)存的指針,而是應(yīng)該該用realloc所返回的新指針。
4>如果realloc函數(shù)的第一個參數(shù)是NULL,那么它的行為就和malloc一模一樣。
1.使用malloc分配一塊內(nèi)存
int *pi;
….
pi = malloc(100);
if (pi == NULL){
printf(“Outof memory!\n”);
exit(1);
}
符號NULL定義于stdio.h,它實際上是字符值常量0。
1>如果內(nèi)存分配成功,那么得到了一個指向100個字節(jié)的指針。在整型為4個字節(jié)的機(jī)器上,這塊內(nèi)存將被當(dāng)作25個整型元素的數(shù)組,因為pi是一個指向整型的指針。
2>但是,使用上面的程序可移植性較差:
可以使用如下的方法:
pi = malloc(25 *sizeof(int));
使用該方法,即使在整數(shù)長度不同的機(jī)器上,它也能獲得正確的結(jié)果。
3>已經(jīng)有了指針,,如何使用這塊內(nèi)存呢。可以使用間接訪問和指針運(yùn)算來訪問數(shù)組的不同整數(shù)位置,下面通過循環(huán)來給新分配的數(shù)組的每個元素都初始化為0.
int *pi2,i;
……
pi2 = pi;
for(i = 0;i <25;i++)
*pi2++=0;
我們也可以使用小標(biāo)來運(yùn)算。
int i;
…..
for( I=0;i<25;i++)
pi[i] = 0;
1.使用動態(tài)內(nèi)存分配的程序中,常常會出現(xiàn)很多錯誤。
1>對NULL指針進(jìn)行解引用操作
2>對分配的內(nèi)存進(jìn)行操作時越過邊界
3>釋放并非動態(tài)分配的內(nèi)存
4>試圖釋放一塊動態(tài)分配的內(nèi)存的一部分以及一塊內(nèi)存被釋放之后被繼續(xù)使用。
說明:
2 動態(tài)分配最常見的錯誤就是忘記檢查所請求的內(nèi)存是否成功分配。
2 2.動態(tài)內(nèi)存分配的第二大錯誤來源是操作內(nèi)存時超出了分配內(nèi)存的邊界。
2.當(dāng)你使用free時,可能出現(xiàn)各種不同的錯誤。
1>傳遞給free的指針必須是一個從malloc、calloc或realloc函數(shù)返回的指針。
2>傳遞給free函數(shù)一個指針,讓它釋放一塊并非動態(tài)分配的內(nèi)存可能導(dǎo)致程序立即終止或在晚些時候終止。
3>試圖釋放一塊動態(tài)分配內(nèi)存的一部分也有可能引起類似問題。
Eg:
/**
***Get 10 integers
**/
pi = malloc(10*sizeof(int ));
….
/*
**僅釋放后5個整數(shù),前面的5個數(shù)不釋放
*/
free(pi + 5);
說明:
2 釋放一塊內(nèi)存的一部分是不允許的。動態(tài)分配的內(nèi)存必須整塊一起釋放。但是,realloc函數(shù)可以縮小一塊動態(tài)分配的內(nèi)存,有效地釋放它尾部的部分內(nèi)存。
4>不要訪問已經(jīng)被free函數(shù)釋放了的內(nèi)存。假定對一個指向動態(tài)分配的內(nèi)存的指針進(jìn)行了復(fù)制,而且這個指針的幾份拷貝分散于程序各處。你無法保證當(dāng)你使用其中一個指針時它所指向的內(nèi)存是不是已被另一個指針釋放。還要確保程序中所有使用這塊內(nèi)存的地方在這塊內(nèi)存釋放之前停止對它的使用。
5>當(dāng)動態(tài)分配的內(nèi)存不再需要使用時,應(yīng)該被釋放,這樣可以被重新分配使用。分配內(nèi)存但在使用完畢后不釋放將引起內(nèi)存泄漏(memory leak)。
總結(jié):
1.當(dāng)數(shù)組被聲明時,必須在編譯時知道它的長度。動態(tài)內(nèi)存分配允許程序為一個長度在運(yùn)行時才知道的數(shù)組分配內(nèi)存空間。
2.malloc和calloc函數(shù)都用于動態(tài)分配一塊內(nèi)存,并返回一個指定該塊內(nèi)存的指針。
1>malloc的參數(shù)就是需要分配的內(nèi)存的字節(jié)數(shù)。
2>calloc的參數(shù)是需要分配的元素個數(shù)和每個元素的長度。calloc函數(shù)在返回前把內(nèi)存初始化為零。malloc函數(shù)返回時內(nèi)存并未以任何方式進(jìn)行初始化。
3>調(diào)用realloc函數(shù)可以改變一塊已經(jīng)動態(tài)分配的內(nèi)存的大小。增加內(nèi)存塊大小有時有可能采取的方法是把原來內(nèi)存塊上的所有數(shù)據(jù)復(fù)制到一個新的、更大的內(nèi)存塊上。當(dāng)一個動態(tài)分配的內(nèi)存塊不再使用時,應(yīng)該調(diào)用free函數(shù)把它歸還給可用內(nèi)存池,內(nèi)存釋放后便不能再被訪問。
3.如果請求的內(nèi)存分配失敗,malloc、malloc和readlloc函數(shù)返回的將是一個NULL指針。
4.錯誤的訪問分配內(nèi)存之外的區(qū)域所引起的后果類似越界訪問一個數(shù)組,但這個錯誤還能破壞可用內(nèi)存池,導(dǎo)致程序失敗。
5.如果一個指針不是從早先的malloc、calloc或realloc函數(shù)返回的,它是不能作為參數(shù)傳遞給free函數(shù)的。
聯(lián)系客服