對數組進行malloc動態分配的一些總結


筆者在處理程序奔潰問題的時候,遇到棧溢出的情況,棧溢出最常見的情況是:迭代調用和數組過大。數組占用占空間,所以改為了malloc方式放在堆上。想想,就想整理一下關於對多維數組的動態分配問題。

 

一,堆和棧的先關問題

首先,必須了解一下堆和棧的問題,可參考網上文章 ,現在稍微總結一下:

棧區(stack),由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧;堆區(heap),一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表;全局區(靜態區)(static),全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域,程序結束后由系統釋放;文字常量區,常量字符串就是放在這里的,程序結束后由系統釋放 ;程序代碼區,存放函數體的二進制代碼。

 

二,多維數組的malloc內存動態分配

對於一些需要放在堆上的數組,或者維數未知的數組,我們可以直接定義指針,在進行對其內存分配。

 

1,C語言動態分配二維數組


(1) 已知第二維

char (*a)[N];//指向數組的指針  
  
a = (char (*)[N])malloc(sizeof(char) * N * m);  
printf("%d\n", sizeof(a));//4,指針  
printf("%d\n", sizeof(a[0]));//N,一維數組  
  
free(a);  

 

(2) 已知第一維

char* a[M];//指針的數組  
int i;  
for(i=0; i<M; i++)  
  a[i] = (char *)malloc(sizeof(char) * n);  
printf("%d\n", sizeof(a));//4*M,指針數組  
printf("%d\n", sizeof(a[0]));//4,指針  
  
for(i=0; i<M; i++)  
    free(a[i]);

 

(3) 已知第一維,一次分配內存(保證內存的連續性)

char* a[M];//指針的數組  
int i;  
  
a[0] = (char *)malloc(sizeof(char) * M * n);  
for(i=1; i<M; i++)  
  a[i] = a[i-1] + n;  
printf("%d\n", sizeof(a));//4*M,指針數組  
printf("%d\n", sizeof(a[0]));//4,指針  
  
free(a[0]); 

 

(4) 兩維都未知

char **a;  
int i;  
  
a = (char **)malloc(sizeof(char *) * m);//分配指針數組  
for(i=0; i<m; i++)  
{  
  a[i] = (char *)malloc(sizeof(char) * n);//分配每個指針所指向的數組  
}  
  
printf("%d\n", sizeof(a));//4,指針  
printf("%d\n", sizeof(a[0]));//4,指針  
  
for(i=0; i<m; i++)  
{  
  free(a[i]);  
}  
free(a);

 

(5) 兩維都未知,一次分配內存(保證內存的連續性)

char **a;  
int i;  
a = (char **)malloc(sizeof(char *) * m);//分配指針數組  
a[0] = (char *)malloc(sizeof(char) * m * n);//一次性分配所有空間  
for(i=1; i<m; i++)  
{  
    a[i] = a[i-1] + n;  
}  
  
printf("%d\n", sizeof(a));//4,指針  
printf("%d\n", sizeof(a[0]));//4,指針  
free(a[0]);  
free(a);

 

2,C++動態分配二維數組


(1) 已知第二維

char (*a)[N];//指向數組的指針  
a = new char[m][N];  
  
printf("%d\n", sizeof(a));//4,指針  
printf("%d\n", sizeof(a[0]));//N,一維數組  
  
delete[] a; 

 

(2) 已知第一維

char* a[M];//指針的數組  
for(int i=0; i<M; i++)  
    a[i] = new char[n];  
  
printf("%d\n", sizeof(a));//4*M,指針數組  
printf("%d\n", sizeof(a[0]));//4,指針  
  
for(i=0; i<M; i++)  
    delete[] a[i];  

 

(3) 已知第一維,一次分配內存(保證內存的連續性)

char* a[M];//指針的數組  
a[0] = new char[M*n];  
for(int i=1; i<M; i++)  
a[i] = a[i-1] + n;  
  
printf("%d\n", sizeof(a));//4*M,指針數組  
printf("%d\n", sizeof(a[0]));//4,指針  
  
delete[] a[0];

 

(4) 兩維都未知

char **a;  
a = new char* [m];//分配指針數組  
for(int i=0; i<m; i++)  
{  
  a[i] = new char[n];//分配每個指針所指向的數組  
}  
  
printf("%d\n", sizeof(a));//4,指針  
printf("%d\n", sizeof(a[0]));//4,指針  
  
for(i=0; i<m; i++)  
  delete[] a[i];  
delete[] a;  

 

(5) 兩維都未知,一次分配內存(保證內存的連續性)

char **a;  
a = new char* [m];  
a[0] = new char[m * n];//一次性分配所有空間  
for(int i=1; i<m; i++)  
{  
a[i] = a[i-1] + n;//分配每個指針所指向的數組  
}  
  
printf("%d\n", sizeof(a));//4,指針  
printf("%d\n", sizeof(a[0]));//4,指針  
  
delete[] a[0];  
delete[] a; 

 

多說一句:new和delete要注意配對使用,即有多少個new就有多少個delete,這樣才可以避免內存泄漏!

 

3,靜態二維數組作為函數參數傳遞


如果采用上述幾種方法動態分配二維數組,那么將對應的數據類型作為函數參數就可以了。這里討論靜態二維數組作為函數參數傳遞,即按照以下的調用方式:
int a[2][3];
func(a);


C語言中將靜態二維數組作為參數傳遞比較麻煩,一般需要指明第二維的長度,如果不給定第二維長度,則只能先將其作為一維指針傳遞,然后利用二維數組的線性存儲特性,在函數體內轉化為對指定元素的訪問。
首先寫好測試代碼,以驗證參數傳遞的正確性:


(1) 給定第二維長度

void func(int a[][N])  
{  
    printf("%d\n", a[1][2]);  
} 

 

(2) 不給定第二維長度

void func(int* a)  
{  
  printf("%d\n", a[1 * N + 2]);//計算元素位置  
} 

 

注意:使用該函數時需要將二維數組首地址強制轉換為一維指針,即func((int*)a);

 

 

三,關於數組與指針相互memcpy的問題

 

筆者只舉個例子:

unsigned char  Buffer1[5][8]=         
{
    {1,2,3,4,5,6,7,8},
    {1,2,3,4,5,6,7,8},
    {1,2,3,4,5,6,7,8},
    {1,2,3,4,5,6,7,8},
    {1,2,3,4,5,6,7,8},
};

unsigned char *Buffer2 = NULL;
int bufer_index = 0;

Buffer2 = (unsigned char *)malloc(sizeof(unsigned char) * 5 * 8);

memset(Buffer2, 0, sizeof(Buffer2));
for (bufer_index = 0; bufer_index < 5; bufer_index++)
{
  memcpy(Buffer2 + (bufer_index * 8), Buffer1[bufer_index], 8 * sizeof(unsigned char));
}

 

memcpy回來:

for (bufer_index = 0; bufer_index < 5; bufer_index++)
{
    memcpy(Buffer[bufer_index], Buffer2 + (bufer_index * 8), 8 * sizeof(unsigned char));                    
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM