當前位置:
首頁 > 知識 > C 語言動態數組

C 語言動態數組

在實際的編程中,往往會發生這種情況,即所需的內存空間取決於實際輸入的數據,而無法預先確定。對於這種問題,用靜態數組的辦法很難解決。為了解決上述問題,C語言提供了一些內存管理函數,這些內存管理函數結合指針可以按需要動態地分配內存空間,來構建動態數組,也可把不再使用的空間回收待用,為有效地利用內存資源提供了手段。

動態數組,是相對於靜態數組而言。靜態數組的長度是預先定義好的,在整個程序中,一旦給定大小後就無法改變。而動態數組則不然,它可以隨程序需要而重新指定大小。動態數組的內存空間是從堆(heap)上分配(即動態分配)的。是通過執行代碼而為其分配存儲空間。當程序執行到這些語句時,才為其分配。程序員自己負責釋放內存。

為什麼要使用動態數組?

在實際的編程中,往往會發生這種情況,即所需的內存空間取決於實際輸入的數據,而無法預先確定。對於這種問題,用靜態數組的辦法很難解決。為了解決上述問題,C語言提供了一些內存管理函數,這些內存管理函數結合指針可以按需要動態地分配內存空間,來構建動態數組,也可把不再使用的空間回收待用,為有效地利用內存資源提供了手段。

動態數組與靜態數組的對比

對於靜態數組,其創建非常方便,使用完也無需釋放,要引用也簡單,但是創建後無法改變其大小是其致命弱點!

對於動態數組,其創建麻煩,使用完必須由程序員自己釋放,否則嚴重會引起內存泄露。但其使用非常靈活,能根據程序需要動態分配大小。

如何構建動態數組

遵循原則

申請的時候從外層往裡層,逐層申請;

釋放的時候從裡層往外層,逐層釋放。

構建所需指針

對於構建一維動態數組,需要一維指針;

對於二維,則需要一維,二維指針;

三維需要一,二,三維指針;

依此類推。

構建所需函數

函數原型返 回功能說明void *malloc(unsigned int size);成功:返回所開闢 空間首地址 失敗:返回空指針向系統申請 size位元組的 堆空間void *calloc(unsigned int num, unsigned int size);成功:返回所開闢 空間首地址 失敗:返回空指針按類型申請 num個size字 節的堆空間void free(void *p);無返回值釋放p指向 的堆空間void *realloc(void *p,unsigned int size);成功:返回新開闢 空間首地址 失敗:返回空指針將p指向的 堆空間變為 size

說明:

  • (1)規定為 void * 類型,這並不是說該函數調用後無返回值,而是返回一個結點的地址,該 地址的類型為void(無類型或類型不確定),即一段存儲區的首址,其具體類型無法確定,只有使 用時根據各個域值數據再確定。可以用強制轉換的方法將其轉換為別的類型。例如:double *pd=NULL; pd=(double *)calloc(10,sizeof(double)); 表示將向系統申請10個連續的 double類型的存儲空間,並用指針pd指向這個連續的空間的首地址。並且用(double)對calloc( ) 的返回類型進行轉換,以便把double類型數據的地址賦值給指針pd。
  • (2)使用sizeof的目的是用來計算一種類型的佔有的位元組數,以便適合不同的編譯器。
  • (3)由於動態分配不一定成功,為此要附加一段異常處理程序,不致程序運行停止,使用戶 不知所措。通常採用這樣的異常處理程序段: if(p==NULL) /* 或者if(!p)*/ { printf("動態申請內存失敗!
    "); exit(1); //異 常退出 }
  • (4)這四個函數頭文件均包含在中。
  • (5)分配的堆空間是沒有名字的 只能通過返回的指針找到它。
  • (6)絕不能對非動態分配存儲塊使用free。也不能對同一塊內存區同時用free釋放兩次。 如:free(p);free(p);
  • (7)調用 free() 時, 傳入指針指向的內存被釋放, 但調用函數的指針值可能保持不變, 因 為p是作為形參而傳遞給了函數。嚴格的講, 被釋放的指針值是無效的, 因為它已不再指向所申請 的內存區。這時對它的任何使用便可能會可帶來問題。

malloc與calloc的區別

對於用malloc分配的內存區間,如果原來沒有被使用過,則其中的每一位可能都是0;反之, 如果這部分內存空間曾經被分配、釋放和重新分配,則其中可能遺留各種各樣的數據。也就是說, 使用malloc()函數的程序開始時(內存空間還沒有被重新分配)能正常運行,但經過一段時間後(內 存空間已被重新分配)可能會出現問題,因此在使用它之前必須先進行初始化(可用memset函數 對其初始化為0),但調用calloc()函數分配到的空間在分配時就已經被初始化為0了。 當你在calloc()函數和malloc()函數之間作選擇時,你需考慮是否要初始化所分配的內存空 間,從而來選擇相應的函數。

具體構建方法

以三維整型數組array[n1][n2][n3]為例。

先遵循從外層到裡層,逐層申請的原則:

最外層指針是array,它是個三維指針,所指向的是array[],其為二維指針。所以給array

申請內存應:

array=(int***)calloc(n1,sizeof(int**));

次層指針是array[],它是個二維指針,所指向的是array[][],其為一維指針。所以給array[]

申請內存應:

for(i=0;i<n1;i++)
{
array[i]=(int**)calloc(n2,sizeof(int*));
}

最內層指針是array[][],它是個一維指針,所指向的是array[][][],其是個整型常量。所以給array[][]申請內存應:

for(i=0;i<n1;i++)
{
for(j=0;j<n2;j++)
{
array[i][j]=(int*)calloc(n3,sizeof(int));
}
}

當然,你可以把它們整合在一起為:

int i,j,k;
int n1,n2,n3;
int ***array;
scanf("%d%d%d",&n1,&n2,&n3);
array=(int***)calloc(n1,sizeof(int**));
for(i=0;i<n1;i++)
{
array[i]=(int**)calloc(n2,sizeof(int*));
for(j=0;j<n2;j++)
{
array[i][j]=(int*)calloc(n3,sizeof(int));
for(k=0;k<n3;k++)
{
array[i][j][k]=i+j+k+1;
}
}
}

最後不要忘了釋放這些內存,這要遵循釋放的時候從裡層往外層,逐層釋放的原則。

分析過程可參考上面的解答,這裡不再贅述。只給出代碼吧:

for(i=0;i<n1;i++)
{
for(j=0;j<n2;j++)
{
free(array[i][j]);//釋放第三維指針
}
}
for(i=0;i<n1;i++)
{
free(array[i]);//釋放第二維指針
}
free(array);//釋放第一維指針

其餘維的如四維創建過程大同小異,這裡不再贅述。

C 語言動態數組

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

對conda和pip的一點認識
打造Python的vim環境

TAG:程序員小新人學習 |