對於一維數組a[i](a[i]類型不為char),a表示數組的首地址,即a=&a[0]。
int a[10];
cout<<a<<endl;
cout<<&a[0]<<endl;//兩者相同,都表示數組a的首地址。
cout<<*a<<endl;
cout<<a[0]<<endl;//兩者相同,都表示數組a的首元素a[0]。
對於字符串數組,使用輸出數組名稱指令則會直接輸出整個字符串數組。
char str[10]={'1','2','3','4'};
cout<<str<<endl;//輸出整個字符串
cout<<&str[0]<<endl;//輸出整個字符串
cout<<*str<<endl;//輸出首元素
cout<<(char *)str<<endl;//輸出整個字符串
cout<<(int *)str<<endl;//輸出字符串首地址
cout<<(void *)str<<endl;//輸出字符串首地址
cout<<&str[1]<<endl;//輸出234
綜上,cout遇到輸出字符類型的地址時,不會輸出地址,而是輸出該地址上的字符。所以如果想輸出字符串數組的地址,需要把指針改為其他類型,如char或int。
指針存在類型 ,如int *p,p是int類型的指針,不可以指向double類型的地址
int *p p=p+1 加上了一個int的字節,即加了四個字節。
char *p p=p+1 加上了一個char的字節,即加了一個字節。
int a[10]={1,2,3};
cout<<*a<<endl;//結果為1
cout<<*(a+1)<<endl;//結果為2
指針存在着運算,此處說明一維數組分配的是一段連續的內存,可以通過某種運算公式得到地址。如要求a[5],地址即為a+5。
對於二維數組,以a[10][20]為例,其實分配的內存也是連續的一段,故可以通過某個固定的運算公式來得到地址。
如要求a[5][5],地址即為a+5*20+5。其中20為第二維的長度。
對多維數組也是如此。很容易發現,地址的計算與一維的數目無關,這也是為何將數組作為參數被函數調用時不需要寫明第一維的長度,但需寫明除第一維外所有維度長度的原因。
二維數組的數組名也是表示數組的地址,但與一維數組不同的是,它表示的數組中的每一個元素都是一個數組的地址。
int a[10][20];
a[0][0]=1;
cout<<(*a)<<endl;//輸出a[0],即a[0][0]的地址
cout<<*(*a)<<endl;//輸出a[0][0]
cout<<*a[0]<<endl;//輸出a[0][0]
在數組a中,每一個元素a[i]都代表着一個數組的地址,對應着二維數組的一行。因此,a與一維數組的首地址不同,如果想用一個指針p指向a,不可以運用與一維數組相同的方式。
int a[10][20];
//int *p=a; 編譯報錯
int (*q)[20]=a;//編譯成功
int (*t)[20]=&a[0];//編譯成功
int *p=a[0];//編譯成功,此時p與q指向的地址相同,都為a[0]
此處的(*q)[20]意在告訴編譯器,a所指向的數組中的元素都是一個長度為20的數組。
int a[10][20];
int (*q)[20]=a;
cout<<q<<endl;//0x61faf0
cout<<q+1<<endl;//0x61fb40
cout<<a[0]<<endl;//0x61faf0
cout<<a[0]+1<<endl;//0x61faf4
指針q的移動均是跨行移動,因為a在其指向的數組上,a[1]與a[2]之間分配的內存剛好相差一個第二維的長度,因此q每加1,相當於增加了20*4個字節,在十六進制下為50。而a[0]每移動1,其地址增加4個字節。
指針數組+二重指針
定義:
如果一個數組中的所有元素保存的都是指針,那么我們就稱它為指針數組。
指針數組的定義形式一般為:
dataType *arrayName[length];
注意區別指向二維數組的指針(在上文為a)的定義為
dataType (*arrayName)[length]
int a=1,b=2,c=3;
int *p[5]={&a,&b,&c};//相當於p[0]=&a
cout<<*(p[1]);//輸出2
對於指針數組,同樣是一個數組,如果想要再使用一個指針p指向該數組的首地址,那指針p即是指針數組的指針,即是一個二重指針。
對二重指針的定義為
dataType **(arrayName);
具體使用舉例
int a=1,b=2,c=3;
int *p[5]={&a,&b,&c};//相當於p[0]=&a
int **q=p;
cout<<*(q)<<endl;
cout<<p[0]<<endl;//兩者輸出結果相同
需要注意的是:
二重指針代表着這個指針指向的數組的類型是一個指針數組,即是數組中的每一個元素都是一個指針。
而二維數組中,數組名a作為地址,對應的數組的每一個元素是二維數組每一行的首地址(可認為是地址數組)。
故不可直接用二重指針指向a所在的地址。
int a[10][20];
int (* q)[20]=a;//正確
int **p=a;//錯誤
指針數組中的每一個指針指向地址時是相互獨立的。
上文中a指向的數組中a[1]、a[2]是對應的二維數組的每一行的地址。我們可以對每一行分別用一個指針指向這一行的首地址,將一個二維數組所用的指針放進一個數組中,就得到了一個指針數組。
如果先定義了二維數組,再用指針數組去指向每一行的首地址,那么指針數組中的指針指向的地址便是連續的。
int *p[3];
int a[3][2];
for(register int i=0;i<3;i++){
p[i]=a[i];//p[i]=&a[i][0];
}
cout<<p[0]<<" "<<p[1]<<" "<<p[2]<<endl;
//輸出0x61fe00 0x61fe08 0x61fe10
但如果先定義了指針數組,再讓每一個指針去指向一個一維數組從而構成一個二維數組,那么每一個指針的內存分配就不一定連續。
int *q[5];
int a[2],b[2],c[2];
q[0]=a;
q[1]=b;
q[2]=c;
cout<<q[0]<<" "<<q[1]<<" "<<q[2]<<endl;
//輸出0x61fde8 0x61fde0 0x61fdd8
舉一些函數對二維數組調用的例子
void BubbleSort(char a[10][20]);//正確
void Bubble(char a[][20], int n);//正確
void Bubble(char a[10][], int m);//錯誤,關鍵在除第一維之外的維度
void Bubble(char * a[10], int m);//正確
void Bubble(char a[][], int n, int m);//錯誤,理由如上
void Bubble(char ** a, int n, int m);//正確
void Bubble(char * a[], int n, int m);//正確,第一維不需要
上文中第4、6、7種調用方法與第1、2種所用的內存分配方法不同,在調用時有着不同的調用方式。
void dfs(char **a){
return;
}
void dfs1(char *a[]){
return;
}
int main(){
char *p[5];
dfs(p);
dfs1(p);
}
指針的內容較為繁雜,故寫下這篇文章便於自身理解,也希望各位讀者可以對其提出寶貴的意見。