二維數(shù)組定義以及動(dòng)態(tài)分配空間
二維數(shù)組定義以及動(dòng)態(tài)分配空間
下面三種定義形式怎么理解?怎么動(dòng)態(tài)分配空間?
(1)、int **Ptr;
(2)、int *Ptr[ 5 ]; 我更喜歡寫(xiě)成 int* Prt[5];
(3)、int ( *Ptr )[ 5 ];
此文引自網(wǎng)上,出處不詳,但是覺(jué)得非常好。略改了一點(diǎn)。
多維數(shù)組一向很難,一般都采用一維數(shù)組,但是一旦要用到還真是頭疼。 閑話少說(shuō),這里我就以三個(gè)二維數(shù)組的比較來(lái)展開(kāi)討論:
(1)、int **Ptr;
(2)、int *Ptr[ 5 ]; 我更喜歡寫(xiě)成 int* Prt[5];
(3)、int ( *Ptr )[ 5 ];
以上三例都是整數(shù)的二維數(shù)組,都可以用形如 Ptr[ 1 ][ 1 ] 的 方式訪問(wèn)其內(nèi)容;但它們的差別卻是很大的。下面我從四個(gè)方面對(duì)它們進(jìn)行討論:
???? 一、內(nèi)容:
??????? 它們本身都是指針,它們的最終內(nèi)容都是整數(shù)。注意我這里說(shuō)的是最終內(nèi)容,而不是中間內(nèi)容,比如你寫(xiě) Ptr[ 0 ],對(duì)于三者來(lái)說(shuō),其內(nèi)容都是一個(gè)整數(shù)指針,即 int *;Ptr[1][1] 這樣的形式才是其最終內(nèi)容。
???? 二、意義:
??????? (1)、int **Ptr 表示指向"一群"指向整數(shù)的指針的指針。
??????? (2)、int *Ptr[ 5 ] 表示指向 5 個(gè)指向整數(shù)的指針的指針,或者說(shuō)Ptr有5個(gè)指向"一群"整數(shù)的指針,Ptr是這5個(gè)指針構(gòu)成的數(shù)組的地址。
??????? (3)、int ( *Ptr )[ 5 ] 表示指向"一群"指向 5 個(gè)整數(shù)數(shù)組的指針的指針。
???? 三、所占空間:
??????? (1)、int **Ptr 和 (3)、int ( *Ptr )[ 5 ] 一樣,在32位平臺(tái)里,都是4字節(jié),即一個(gè)指針。
??????? 但 (2)、int *Ptr[ 5 ] 不同,它是 5 個(gè)指針,它占5 * 4 = 20 個(gè)字節(jié)的內(nèi)存空間。
???? 四、用法:
??????? (1)、int **Ptr
??????? 因?yàn)槭侵羔樀闹羔?,需要兩次?nèi)存分配才能使用其最終內(nèi)容。首 先,Ptr = ( int ** )new int *[ 5 ];這樣分配好了以后,它和(2)的意義相同了;然后要分別對(duì) 5 個(gè)指針進(jìn)行內(nèi)存分配,例如:
?? Ptr[ 0 ] = new int[ 20 ];?
它表示為第 0 個(gè)指針?lè)峙?20 個(gè)整數(shù),分配好以后, Ptr[ 0 ] 為指向20個(gè)整數(shù)的數(shù)組。這時(shí)可以使用下標(biāo)用法 Ptr[ 0 ][ 0 ] 到Ptr[ 0 ][ 19 ] 了。
?????? 如果沒(méi)有第一次內(nèi)存分配,該 Ptr 是個(gè)"野"指針,是不能使用的,如果沒(méi)有第二次內(nèi)存分配,則 Ptr[ 0 ] 等也是個(gè)"野"指針,也是不能用的。當(dāng)然,用它指向某個(gè)已經(jīng)定義的地址則是允許的,那是另外的用法(類似于"借雞生蛋"的做法),這里不作討論(下同)。
?
例子:
C語(yǔ)言:
//動(dòng)態(tài)分配二維數(shù)組空間
{
?? m_iHight=10;//二維數(shù)組的高度
m_i;//二維數(shù)組的寬度
//動(dòng)態(tài)分配一個(gè)二維數(shù)組m_ppTable內(nèi)存空間
//其類型為int
?? //m_ppTable指向該數(shù)組
?? int **m_ppTable;
?? m_ppTable=new int *[m_iHight];
//動(dòng)態(tài)分配m_iHight個(gè)類型為int *的內(nèi)存空間
//分配的是行地址空間
?? for(int i=0;i
??????????? m_ppTable[i]= new int[m_iWidth];
?? //動(dòng)態(tài)分配m_iWidth個(gè)類型為int的內(nèi)存空間
//分配的是某行的數(shù)值空間
}
//由此分配的二維數(shù)組空間并非是連續(xù)的
//可以使用m_ppTable[row][col]來(lái)給該二維數(shù)組賦值
//其中 0<=row
//釋放所分配的內(nèi)存空間
{
??? for(int i=0;i
?????? delete[m_iWidth]m_ppTable[i]; //以行為單位釋放數(shù)值空間
??? delete [m_iHight]m_ppTable;????? //釋放行地址空間
}
int **a;
a=(int **)calloc(sizeof(int *),n);
for (i=0;i?? a[i]=(int *)calloc(sizeof(int),n);
這樣就可以了
使用的時(shí)候就和普通的二維數(shù)組一樣
最后用
for(i=0;i?? cfree(a[i]);
cfree(a);釋放內(nèi)存
就可以了
?????? (2)、int *Ptr[ 5 ]
?????? 這樣定義的話,編譯器已經(jīng)為它分配了 5 個(gè)指針的空間,這相當(dāng)于(1)中的第一次內(nèi)存分配。根據(jù)對(duì)(1)的討論可知,顯然要對(duì)其進(jìn)行一次內(nèi)存分配的。否則就是"野"指針。
?????? (3)、int ( *Ptr )[ 5 ]
?????? 這種定義我覺(jué)得很費(fèi)解,不是不懂,而是覺(jué)得理解起來(lái)特別吃力,也許是我不太習(xí)慣這樣的定義吧。怎么描述它呢?它的意義是"一群" 指針,每個(gè)指針都是指向一個(gè) 5 個(gè)整數(shù)的數(shù)組。
如果想分配 k 個(gè)指針,這樣寫(xiě): Ptr = ( int ( * )[ 5 ] ) new int[ 5 * k ]。
這是一次性的內(nèi)存分配。分配好以后,Ptr 指向一片連續(xù)的地址空間,
其中 Ptr[ 0 ] 指向第 0 個(gè) 5 個(gè)整數(shù)數(shù)組的首地址,Ptr[ 1 ] 指向第1個(gè)5個(gè)整數(shù)數(shù)組的首地址。
??? 綜上所述,我覺(jué)得可以這樣理解它們:
??? int ** Ptr
?
_______________________________________________________________
1. C語(yǔ)言動(dòng)態(tài)分配二維數(shù)組
(1)已知第二維
Code-1
char (*a)[N];//指向數(shù)組的指針
a = (char (*)[N])malloc(sizeof(char *) * m);
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//N,一維數(shù)組
free(a);
(2)已知第一維
Code-2
char* a[M];//指針的數(shù)組
int i;
for(i=0; i<M; i++)
a[i] = (char *)malloc(sizeof(char) * n);
printf("%dn", sizeof(a));//4*M,指針數(shù)組
printf("%dn", sizeof(a[0]));//4,指針
for(i=0; i<M; i++)
?? free(a[i]);
(3)已知第一維,一次分配內(nèi)存(保證內(nèi)存的連續(xù)性)
Code-3
char* a[M];//指針的數(shù)組
int i;
a[0] = (char *)malloc(sizeof(char) * M * n);
for(i=1; i<M; i++)
a[i] = a[i-1] + n;
printf("%dn", sizeof(a));//4*M,指針數(shù)組
printf("%dn", sizeof(a[0]));//4,指針
free(a[0]);
(4)兩維都未知
Code-4
char **a;
int i;
a = (char **)malloc(sizeof(char *) * m);//分配指針數(shù)組
for(i=0; i<m; i++)
{
a[i] = (char *)malloc(sizeof(char) * n);//分配每個(gè)指針?biāo)赶虻臄?shù)組
}
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//4,指針
for(i=0; i<m; i++)
{
free(a[i]);
}
free(a);
(5)兩維都未知,一次分配內(nèi)存(保證內(nèi)存的連續(xù)性)
Code-5
char **a;
int i;
a = (char **)malloc(sizeof(char *) * m);//分配指針數(shù)組
a[0] = (char *)malloc(sizeof(char) * m * n);//一次性分配所有空間
for(i=1; i<m; i++)
{
a[i] = a[i-1] + n;
}
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//4,指針
free(a[0]);
free(a);
2.C++動(dòng)態(tài)分配二維數(shù)組
(1)已知第二維
Code-6
char (*a)[N];//指向數(shù)組的指針
a = new char[m][N];
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//N,一維數(shù)組
delete[] a;
(2)已知第一維
Code-7
char* a[M];//指針的數(shù)組
for(int i=0; i<M; i++)
?? a[i] = new char[n];
printf("%dn", sizeof(a));//4*M,指針數(shù)組
printf("%dn", sizeof(a[0]));//4,指針
for(i=0; i<M; i++)
?? delete[] a[i];
(3)已知第一維,一次分配內(nèi)存(保證內(nèi)存的連續(xù)性)
Code-8
char* a[M];//指針的數(shù)組
a[0] = new char[M*n];
for(int i=1; i<M; i++)
a[i] = a[i-1] + n;
printf("%dn", sizeof(a));//4*M,指針數(shù)組
printf("%dn", sizeof(a[0]));//4,指針
delete[] a[0];
(4)兩維都未知
Code-9
char **a;
a = new char* [m];//分配指針數(shù)組
for(int i=0; i<m; i++)
{
a[i] = new char[n];//分配每個(gè)指針?biāo)赶虻臄?shù)組
}
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//4,指針
for(i=0; i<m; i++)
delete[] a[i];
delete[] a;
(5)兩維都未知,一次分配內(nèi)存(保證內(nèi)存的連續(xù)性)
Code-10
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;//分配每個(gè)指針?biāo)赶虻臄?shù)組
}
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//4,指針
delete[] a[0];
delete[] a;
多說(shuō)一句:new和delete要注意配對(duì)使用,即有多少個(gè)new就有多少個(gè)delete,這樣才可以避免內(nèi)存泄漏!
?
3.靜態(tài)二維數(shù)組作為函數(shù)參數(shù)傳遞
如果采用上述幾種方法動(dòng)態(tài)分配二維數(shù)組,那么將對(duì)應(yīng)的數(shù)據(jù)類型作為函數(shù)參數(shù)就可以了。這里討論靜態(tài)二維數(shù)組作為函數(shù)參數(shù)傳遞,即按照以下的調(diào)用方式:
int a[2][3];
func(a);
C語(yǔ)言中將靜態(tài)二維數(shù)組作為參數(shù)傳遞比較麻煩,一般需要指明第二維的長(zhǎng)度,如果不給定第二維長(zhǎng)度,則只能先將其作為一維指針傳遞,然后利用二維數(shù)組的線性存儲(chǔ)特性,在函數(shù)體內(nèi)轉(zhuǎn)化為對(duì)指定元素的訪問(wèn)。
首先寫(xiě)好測(cè)試代碼,以驗(yàn)證參數(shù)傳遞的正確性:
(1)給定第二維長(zhǎng)度
Code-11
void func(int a[][N])
{
printf("%dn", a[1][2]);
}
(2)不給定第二維長(zhǎng)度
Code-12
void func(int* a)
{
printf("%dn", a[1 * N + 2]);//計(jì)算元素位置
}
注意:使用該函數(shù)時(shí)需要將二維數(shù)組首地址強(qiáng)制轉(zhuǎn)換為一維指針,即func((int*)a);
1. C語(yǔ)言動(dòng)態(tài)分配二維數(shù)組
(1)已知第二維
Code-1
char (*a)[N];//指向數(shù)組的指針
a = (char (*)[N])malloc(sizeof(char *) * m);
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//N,一維數(shù)組
free(a);
(2)已知第一維
Code-2
char* a[M];//指針的數(shù)組
int i;
for(i=0; i<M; i++)
a[i] = (char *)malloc(sizeof(char) * n);
printf("%dn", sizeof(a));//4*M,指針數(shù)組
printf("%dn", sizeof(a[0]));//4,指針
for(i=0; i<M; i++)
?? free(a[i]);
(3)已知第一維,一次分配內(nèi)存(保證內(nèi)存的連續(xù)性)
Code-3
char* a[M];//指針的數(shù)組
int i;
a[0] = (char *)malloc(sizeof(char) * M * n);
for(i=1; i<M; i++)
a[i] = a[i-1] + n;
printf("%dn", sizeof(a));//4*M,指針數(shù)組
printf("%dn", sizeof(a[0]));//4,指針
free(a[0]);
(4)兩維都未知
Code-4
char **a;
int i;
a = (char **)malloc(sizeof(char *) * m);//分配指針數(shù)組
for(i=0; i<m; i++)
{
a[i] = (char *)malloc(sizeof(char) * n);//分配每個(gè)指針?biāo)赶虻臄?shù)組
}
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//4,指針
for(i=0; i<m; i++)
{
free(a[i]);
}
free(a);
(5)兩維都未知,一次分配內(nèi)存(保證內(nèi)存的連續(xù)性)
Code-5
char **a;
int i;
a = (char **)malloc(sizeof(char *) * m);//分配指針數(shù)組
a[0] = (char *)malloc(sizeof(char) * m * n);//一次性分配所有空間
for(i=1; i<m; i++)
{
a[i] = a[i-1] + n;
}
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//4,指針
free(a[0]);
free(a);
2.C++動(dòng)態(tài)分配二維數(shù)組
(1)已知第二維
Code-6
char (*a)[N];//指向數(shù)組的指針
a = new char[m][N];
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//N,一維數(shù)組
delete[] a;
(2)已知第一維
Code-7
char* a[M];//指針的數(shù)組
for(int i=0; i<M; i++)
?? a[i] = new char[n];
printf("%dn", sizeof(a));//4*M,指針數(shù)組
printf("%dn", sizeof(a[0]));//4,指針
for(i=0; i<M; i++)
?? delete[] a[i];
(3)已知第一維,一次分配內(nèi)存(保證內(nèi)存的連續(xù)性)
Code-8
char* a[M];//指針的數(shù)組
a[0] = new char[M*n];
for(int i=1; i<M; i++)
a[i] = a[i-1] + n;
printf("%dn", sizeof(a));//4*M,指針數(shù)組
printf("%dn", sizeof(a[0]));//4,指針
delete[] a[0];
(4)兩維都未知
Code-9
char **a;
a = new char* [m];//分配指針數(shù)組
for(int i=0; i<m; i++)
{
a[i] = new char[n];//分配每個(gè)指針?biāo)赶虻臄?shù)組
}
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//4,指針
for(i=0; i<m; i++)
delete[] a[i];
delete[] a;
(5)兩維都未知,一次分配內(nèi)存(保證內(nèi)存的連續(xù)性)
Code-10
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;//分配每個(gè)指針?biāo)赶虻臄?shù)組
}
printf("%dn", sizeof(a));//4,指針
printf("%dn", sizeof(a[0]));//4,指針
delete[] a[0];
delete[] a;
多說(shuō)一句:new和delete要注意配對(duì)使用,即有多少個(gè)new就有多少個(gè)delete,這樣才可以避免內(nèi)存泄漏!
3.靜態(tài)二維數(shù)組作為函數(shù)參數(shù)傳遞
如果采用上述幾種方法動(dòng)態(tài)分配二維數(shù)組,那么將對(duì)應(yīng)的數(shù)據(jù)類型作為函數(shù)參數(shù)就可以了。這里討論靜態(tài)二維數(shù)組作為函數(shù)參數(shù)傳遞,即按照以下的調(diào)用方式:
int a[2][3];
func(a);
C語(yǔ)言中將靜態(tài)二維數(shù)組作為參數(shù)傳遞比較麻煩,一般需要指明第二維的長(zhǎng)度,如果不給定第二維長(zhǎng)度,則只能先將其作為一維指針傳遞,然后利用二維數(shù)組的線性存儲(chǔ)特性,在函數(shù)體內(nèi)轉(zhuǎn)化為對(duì)指定元素的訪問(wèn)。
首先寫(xiě)好測(cè)試代碼,以驗(yàn)證參數(shù)傳遞的正確性:
(1)給定第二維長(zhǎng)度
Code-11
void func(int a[][N])
{
printf("%dn", a[1][2]);
}
(2)不給定第二維長(zhǎng)度
Code-12
void func(int* a)
{
printf("%dn", a[1 * N + 2]);//計(jì)算元素位置
}
注意:使用該函數(shù)時(shí)需要將二維數(shù)組首地址強(qiáng)制轉(zhuǎn)換為一維指針,即func((int*)a);





