動態建立陣列
在很多情況下,我們不知道所要建立陣列的大小,而是想根據需求動態的建立陣列。但是通常使用 int arr[n] 這樣的寫法編譯器會報錯,因為n是變數。例如以下程式碼
int n = 10;
int a[n];
對於這種情況我們可以用以下的方法解決。
一、建立動態陣列
用到的標頭檔案:# include <stdlib.h>
用到的函式:malloc() sizeof()
用法如下:
int n = 10;
int *p = (int*) malloc (n * sizeof(int));//建立可以存放是個int型資料的陣列
解釋:
1、malloc()函式的形參是要分配的位元組數,注意是位元組數,不是單元數。
2、malloc函式返回的是一個無型別的首地址,因此必須在malloc函式前加上型別強轉,轉換為自己需要的資料型別
3、因為malloc函式只負責分配記憶體,所以我們需要自己定義相應的型別變數來接收malloc分配的記憶體,注意malloc函式返回的 是分配記憶體的首地址,所以接收的變數也應該是相應的指標型別
注意:動態陣列記憶體是在堆區分配,堆區有2G記憶體
當分配完成之後,使用完全和陣列用法相同,如下:
void DynamicArray() { int n = 10; int *p = (int*) malloc (n * sizeof(int));//建立可以存放是個int型資料的陣列 //陣列賦值 for(int i=0;i<n;i++) { p[i] = i; } //陣列列印 for(int i=0;i<n;i++) { printf("%d ",p[i]); } }
二、記憶體的釋放
用到的函式:free()
用法:
free(p);
如果不對在堆區分配的記憶體進行釋放,會導致記憶體洩漏,記憶體洩露一般不容易查不容易修改,因此在程式設計過程中一定注意要釋放記憶體。
三、動態建立並初始化陣列
用到的函式:calloc()
calloc函式有兩個形參,第一個是元素的數目,第二個是每個元素的位元組數
calloc函式將陣列每個元素初始化為0
用法:
int n = 10; int *p = (int*) calloc(n,sizeof(int)); for(int i=0;i<n;i++) { printf("%d ",p[i]); } free(p);
四、陣列擴容
有時候動態陣列分配過程中會發生陣列大小不夠的問題,我們就需要對陣列進行擴容
用到的函式:realloc()
realloc函式第一個形參是:對以前指定的指標記憶體塊
realloc函式第二個形參是:新的大小 (以位元組為單位)。
realloc函式返回的也是無型別的地址,因此自己定義相應的型別變數來接收realloc分配的記憶體
用法:
int n = 10;
int *p = (int*) malloc (n * sizeof(int));//建立可以存放是個int型資料的陣列
//陣列賦值
for(int i=0;i<n;i++)
{
p[i] = i;
}
//擴容
p = (int*) realloc (p,sizeof(int)*20);
//陣列列印
for(int i=0;i<n;i++)
{
printf("%d ",p[i]);
}
//釋放記憶體
free(p);
五、free函式容易引起崩潰的解決
在堆區分配的記憶體塊中都有一個頭標記和尾標記,頭標記在記憶體塊首地址向前偏移一點的位置處,尾地址在記憶體塊末尾篇後一點處,所有free崩潰的原因都是因為free函式找不到記憶體塊的頭或尾。共有以下幾種情況
1、越界(如下程式碼)
int n = 10;
int *p = (int*) malloc (n * sizeof(int));//建立可以存放是個int型資料的陣列
//陣列賦值
for(int i=0;i<n*2;i++)
{
p[i] = i;
}
free(p);
此段程式碼陣列值定義了10個單元格,而在賦值過程中卻迴圈了20次,在賦值過程中破壞了記憶體塊尾部標記,導致free函式找不到尾標記,程式崩潰。
2、指標移動(如下程式碼)
int n = 10;
int *p = (int*) malloc (n * sizeof(int));//建立可以存放是個int型資料的陣列
//陣列賦值
for(int i=0;i<n;i++)
{
p[i] = i;
p++;
}
free(p);
此段程式碼,陣列在賦值過程中採用指標移動賦值,導致賦值結束指標變數p沒有指向記憶體塊頭部,free函式找不到記憶體塊頭標記,程式崩潰。
3、重複釋放(程式碼如下)
int n = 10;
int *p = (int*) malloc (n * sizeof(int));//建立可以存放是個int型資料的陣列
//陣列賦值
for(int i=0;i<n;i++)
{
p[i] = i;
}
int *q = p;
free(p);
free(q);
此段程式碼,p和q指向同一個記憶體塊,因此就等於對一個記憶體塊free了兩次,在第一次free過程中沒有問題,而在第二次free是就找不到頭標記和尾標記,程式崩潰
4、釋放棧記憶體(程式碼如下)
int a[10];
free(a);
此段程式碼,在棧中定義了一個數組,棧中的記憶體塊不存在頭標記和尾不標記,因此free函式找不到頭標記和尾標記,程式崩潰。