1. 程式人生 > >c語言中記憶體的動態分配與釋放(多維動態陣列構建)

c語言中記憶體的動態分配與釋放(多維動態陣列構建)

一. 靜態陣列與動態陣列
   靜態陣列比較常見,陣列長度預先定義好,在整個程式中,一旦給定大小後就無法再改變長度,靜態陣列自己自動負責釋放佔用的記憶體。
   動態陣列長度可以隨程式的需要而重新指定大小。動態陣列由記憶體分配函式(malloc)從堆(heap)上分配儲存空間,只有當程式執行了分配函式後,才為其分配記憶體,同時由程式設計師自己負責釋放分配的記憶體(free)。

二. 為什麼要使用動態陣列?
    在實際的程式設計中,往往會發生這種情況,即所需的記憶體空間取決於實際輸入的資料,而無法預先確定。對於這種問題,用靜態陣列的辦法很難解決。為了解決上述問題,c語言提供了一些記憶體管理函式,這些記憶體管理函式結合指標可以按需要動態地分配記憶體空間,來構建動態陣列,也可把不再使用的空間回收待用,為有效地利用記憶體資源提供了手段。

三. 動態陣列與靜態陣列的比較
    對於靜態陣列,其建立非常方便,使用完也無需釋放,要引用也簡單,但是建立後無法改變其大小是其致命弱點!   
    對於動態陣列,其建立麻煩,使用完必須由程式設計師自己釋放,否則嚴重會引起記憶體洩露。但其使用非常靈活,能根據程式需要動態分配大小。

四. 如何構建動態陣列?
    構建動態陣列時,我們遵循下面的原則:
    申請的時候從外層往裡層,逐層申請;
    釋放的時候從裡層往外層,逐層釋放;

五. 構建動態陣列所需指標
    對於構建一維動態陣列,需要一維指標;   
    對於二維,則需要一維,二維指標;   
    對於三維,需要一,二,三維指標;   
    依此類推。

六. 動態記憶體分配與釋放函式

 

/*動態記憶體分配與釋放函式*/

void *malloc(unsigned int size);

void *calloc(unsigned int num, unsigned int size);

void *realloc(void *p,unsigned int size);

void free(void *p);
說明:
(1)
malloc()函式成功:返回所開闢空間首地址;失敗:返回空指標;功能:向系統申請size位元組堆的空間;
calloc()成功:返回所開闢空間首地址;失敗:返回空指標;功能:按型別向系統申請num個size位元組堆的空間;
realloc()成功:返回所開闢空間首地址;失敗:返回空指標;功能:將p指向的空間變為個size位元組堆的空間;
free()沒有返回值,釋放p指向的堆空間;
(2) 
規定為void *型別,這並不是說該函式呼叫後無返回值,而是返回一個結點的地址,該地址的型別為void(無型別或型別不確定),即一段儲存區的首址,其具體型別無法確定,只有使用時根據各個域值資料再確定。可以用強制轉換的方法將其轉換為別的型別。例如:


double *pd = NULL; 
pd = (double *)calloc(10, sizeof(double));
表示將向系統申請10個連續的double型別的儲存空間,並用指標pd指向這個連續的空間的首地址。並且用(double)對calloc()的返回型別進行轉換,以便把double型別資料的地址賦值給指標pd。
(3)
使用sizeof的目的是用來計算一種型別的佔有的位元組數,以便適合不同的編譯器。
(4)檢查動態記憶體是否分配成功
由於動態分配不一定成功,為此要附加一段異常處理程式,不致程式執行停止,使使用者不知所措。通常採用這樣的異常處理程式段:


if (p == NULL) /* 或者if(!p)*/

{

    printf("動態申請記憶體失敗!\n");

    exit(1); //異常退出

} 

(5)這四個函式標頭檔案均包含在<stdlib.h>中。   
(6)分配的堆空間是沒有名字的,只能通過返回的指標找到它。   
(7)絕不能對非動態分配儲存塊使用free。也不能對同一塊記憶體區同時用free釋放兩次,如:


free(p);

free(p);
(8)呼叫 free()時, 傳入指標指向的記憶體被釋放, 但呼叫函式的指標值可能保持不變, 因為p是作為形參而傳遞給了函式。嚴格的講, 被釋放的指標值是無效的, 因為它已不再指向所申請的記憶體區。這時對它的任何使用便可能會可帶來問題。所以在釋放一個指標指向的記憶體後,將該指標賦值為0,避免該指標成為野指標:


int *p = (int *)malloc(sizeof(int));

free(p); /*釋放p指向記憶體*/

p = 0; /*或者 p = NULL,釋放p指向的記憶體後,將p指標賦值為0,避免p指標成為野指標*/
(9)malloc與calloc的區別,對於用malloc分配的記憶體區間,如果原來沒有被使用過,則其中的每一位可能都是0;反之,如果這部分記憶體空間曾經被分配、釋放和重新分配,則其中可能遺留各種各樣的資料。也就是說,使用malloc()函式的程式開始時(記憶體空間還沒有被重新分配)能正常執行,但經過一段時間後(記憶體空間已被重新分配)可能會出現問題,因此在使用它之前必須先進行初始化(可用memset函式對其初始化為0),但呼叫calloc()函式分配到的空間在分配時就已經被初始化為0了。當你在calloc()函式和malloc()函式之間作選擇時,你需考慮是否要初始化所分配的記憶體空間,從而來選擇相應的函式。
六.動態陣列構建過程
以三維整型陣列為例int array[x][y][z]
先遵循從外到裡,逐層申請的原則:
最外層的指標就是陣列名array,他是一個三維指標,指向的是array[],array[]是二維指標,所以給array申請記憶體空間需要一個三維指標int *** p;


/*給三維陣列array[x][y][z]動態分配記憶體*/

int *** p = (int ***)malloc(x * sizeof(int **)); 
/*或者如下*/
array = (int ***)malloc(x * sizeof(int **))

/*指標p指向的是array三維陣列的第一維,有x個元素,所以要sizeof(x * (int **))*/
次層指標是array[],它是一個二維指標,指向的是array[][],array[][]是一維指標:


int i, j;

for (i = 0; i < x; i++)

{

    array[i] = (int **)malloc(y * sizeof(int *));

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


int i, j;

for (i = 0; i < x; i++)

{

    for (j = 0; j < y; j++)

    {

        array[i][j] = (int *)malloc(z * sizeof(int));

    }

}
綜合以上三步:


/*動態構建三維陣列記憶體分配函式*/

/*

 * pArr: 指向三維陣列首地址

 * x: 三維陣列第一維元素個數

 * y: 三維陣列第二維元素個數

 * z: 三維陣列第三維元素個數

 */
void Create3DActiveArray(int ***pArr, int x, int y, int z)
{

    int i, j, k;

    pArr = (int ***)malloc(x * sizeof(int **));


    for (i = 0; i < x; i++)

    {

        pArr[i] = (int **)malloc(y * sizeof(int *));
        for (j = 0; j < y; j++)

        {

           pArr[i][j] = (int *)malloc(z * sizeof(int));

           for (k = 0; k < z; k++)

           {

              pArr[i][j][k] = i + j + k;

           }

        }

    }
}
記憶體釋放函式:


void Free3DActiveArray(int ***pArr, int x, int y)

{

    int i, j, k;

    for (i = 0; i < x; i++)

    {

        for (j = 0; j < y; j++)

        {

            free(pArr[i][j]);

            pArr[i][j] = 0;

        }

        free(pArr[i]);

        pArr[i] = 0;

    }

    free(pArr);

   

}

 

/*

    2012年2月29日 12:00:32

    目的:多維陣列構建和釋放,這裡以構建一個動態3維陣列為例

*/

 

#include <stdio.h>

#include <malloc.h>

 

void Malloc3DActiveArray(int *** pArr, int x, int y, int z);

void Free3DActiveArray(int *** pArr, int x, int y);

//void Display3DArray(int *** pArr, int x, int y, int z);

 

 

int main(void)

{

    int x, y, z;

    int *** array = NULL;

 

    printf("輸入一維長度: ");

    scanf("%d",&x);

    printf("輸入二維長度: ");

    scanf("%d",&y);

    printf("輸入三維長度: ");

    scanf("%d",&z);

 

    Malloc3DActiveArray(array, x, y, z);

    Free3DActiveArray(array, x, y);

    array = NULL;

 

    return 0;

}

 

void Malloc3DActiveArray(int *** pArr, int x, int y, int z)

{

    int i, j, k;

    pArr = (int ***)malloc(x * sizeof(int **));

 

    for (i = 0; i < x; i++)

    {

        pArr[i] = (int **)malloc(y * sizeof(int *));

        for (j = 0; j < y; j++)

        {

            pArr[i][j] = (int *)malloc(z * sizeof(int));

            for (k = 0; k < z; k++)

            {

                pArr[i][j][k] = i + j + k + 1;

                printf("%d ", pArr[i][j][k]);

            }

            printf("\n");

        }

        printf("\n");

    }

}

 

void Free3DActiveArray(int *** pArr, int x, int y)

{

    int i, j;

    for (i = 0; i < x; i++)

    {

        for (j = 0; j < y; j++)

        {

            free(pArr[i][j]);

            pArr[i][j] = 0;

        }

 

        free(pArr[i]);

        pArr[i] = 0;

    }

    free(pArr);

}


/*

    2012年2月29日 12:32:02

    功能:動態構建4維陣列,學習動態構建多維陣列,並釋放多維陣列

*/

 

#include <stdlib.h>

#include <stdio.h>

 

int main()

{

    int n1,n2,n3,n4;

    int ****array;

    int i,j,k,m;

 

    puts("輸入一維長度:");

    scanf("%d",&n1);

    puts("輸入二維長度:");

    scanf("%d",&n2);

    puts("輸入三維長度:");

    scanf("%d",&n3);

    puts("輸入四維長度:");

    scanf("%d",&n4);

 

    array = (int ****)malloc(n1 * sizeof(int***));//第一維

 

    for (i = 0; i < n1; i++)

    {

        array[i] = (int***)malloc(n2 * sizeof(int**)); //第二維

        for (j = 0; j < n2; j++)

        {

            array[i][j] = (int**)malloc(n3 * sizeof(int*)); //第三維

            for (k = 0; k < n3; k++)

            {

                array[i][j][k] = (int *)malloc(n4 * sizeof(int));//第四維

                for (m = 0; m < n4; m++)

                {

                    array[i][j][k][m] = i + j + k + m + 1;

                    printf("%d\t", array[i][j][k][m]);

                }

                printf("\n");

            }

            printf("\n");

        }

        printf("\n");

    }

 

    for (i = 0; i < n1; i++)

    {

        for (j = 0; j < n2; j++)

        {

            for (k = 0; k < n3; k++)

            {

                free(array[i][j][k]);//釋放第四維指標

                array[i][j][k] = 0;

            }

 

            free(array[i][j]);//釋放第三維指標

            array[i][j] = 0;

        }

 

        free(array[i]);//釋放第二維指標

        array[i] = 0;

    }

 

    free(array);//釋放第一維指標

    array = NULL;

 

    return 0;

}

 

/*

    在vc++6.0中輸出結果為:

    -----------------------------------

    輸入一維長度:

    1

    輸入二維長度:

    2

    輸入三維長度:

    3

    輸入四維長度:

    4

    1 2 3 4

    2 3 4 5

    3 4 5 6

 

    2 3 4 5

    3 4 5 6

    4 5 6 7

    Press any key to continue

*/