指針和多維數組
數組名是特殊的指針
數組是一個特殊的指針,多維數組也是更為複雜的數組,它們的關係是什麼樣的呢?
我們通過一個簡單的例子來比較形象的瞭解指針和多維數組:
int a[2][3];這是一個2*3的二維數組,首先我們清楚
數組名就是指向數組首元素的常量指針(它不可以指向其他部分,可以對指向的元素進行任意修改);其次C語言中所謂的多維數組,即是數組的數組,2*3的二維數組,本質上為2個有包含3個int的數據的數組。所以現在我們就可以解釋a的含義:
a == &a[0]那麼對於
a[0]也有
a[0] == &a[0][0]這時候我們就也可以得到另一個特殊的結論:
a == a[0],字面上看起來很難理解,這是因為對於一個指針它指向一個元素有兩個要素:第一為這個元素的首地址,第二為這個元素的類型(這也是我們在使用指針所必要要求的必須指向與它類型相同的元素),所以a是一個指向包含3個int元素的數組指針,a[0]是指向int元素的指針。在比較兩者時即比較首地址,無疑都是這個二維數組的首地址。
#include <stdio.h>
int main (void) {
int a[2][3];
if (a == &a[0])
printf("yes!\n");
if (a[0] == &a[0][0])
printf("yes!\n");
if (a == a[0])
printf("yes!");
return 0;
}
但是兩者仍然有差別,這種差別是在類型上的,也可謂是根本上的,通過指針的增加運算我們可以看到他們的不同:
#include <stdio.h>
int main (void) {
int a[2][3];
int *p = a;
int *pp = a[0];
if (a == a[0])
printf("yes!\n");
if (a+1 == a[0]+1)
printf("yes!\n");
else {
printf("no!\n");
printf("a = %p\n", a);
printf("p = %p\n", a+1);
printf("pp = %p", a[0]+1);
}
return 0;
}
/**
yes!
no!
a = 0061FF00
p = 0061FF0C
pp = 0061FF04
因為a為int (*)[3]類型,所以a+1移動了3*4=12個儲存單元,末位為C;a[0]為int *類型,所以a[0]+1移動了4個單元,這時候它們不再相等。
**/
通過指針指向多維數組
因為C語言要求指針在指向一個元素時類型必須同元素一致,所以我們想使用指針指向數組時不能簡單使用指向
int類型的指針。例如對於二維數組
a[2][3]。
int main (void) {
int a[2][3];
int (*p)[3] = a;
// int (*p1)[2] = a;這樣是不對的,因為C語言二維數組的聲明意義為2個長度為3的整型數組而不是相反的
return 0;
}
我們使用
int (*p)[3]而不是int *p[3],因為前者表示指向含有三個整數數組的指針,後者為含有3個整型指針的數組。我們也能通過解引用這樣的指針對於數組內容進行訪問。
我們通過討論數組名這個特殊的指針來了解指向多維數組的指針,
a == &a[0],所以*a = a[0]為第一個指向長度為3數組的指針;a[0] == &a[0][0],所以*a[0] = a[0][0]這樣我們就訪問了二維數組的第一個元素,所以**a == a[0][0],我們可以通過多次解引用對多維數組元素進行訪問,對於二維數組a[1][2]等價於*(*(a+1)+2)但是通過這樣對一個數組進行訪問往往會造成費解,而且有時候會出現不安全的現象:
#include <stdio.h>
int main (void) {
int a = 20;
const int b = 30;
int *p1 = &a;
const int *p2 = &b;// 指向常量的指針指向常量
const int **pp2;// 指向 指向常量的指針 的指針
// p1 = p2;// 使用普通指針指向指向常量的指針這樣的行為並不可行!
p2 = p1;// 把普通指針賦給指向常量的指針時時沒有問題的
// 下面是一種值得警惕的情況
printf("b = %d\n", b);
pp2 = &p1;// 這樣的行為也是不安全的,稱為為嵌套指針類型賦值,這樣會使得const修飾符失效
*pp2 = &b;
*p1 = 10;
printf("b = %d", b);
return 0;
}
/**
b = 30
b = 10
**/
我們驚奇發現b竟然也被修改了!因為我們讓pp2指向指針p1。然後因為pp2是指向常量的指針,所以*pp2也可以指向常量b,但是其實*pp2是p1!這時候我們就能通過p1修改常量b的值,這樣行為是很危險的!所以不要使用嵌套指針。