版權聲明:原創文章,轉載請注明出處。
1. 一維數組名與指針
對於一維數組來說,數組名就是指向該數組首地址的指針,對於:
int array[10];
array就是該數組的首地址,如果我們想定義一個指向該數組的指針,我們可以用如下定義:
int *p;
然后令:
p = array;
那么指針p就指向了數組array的首地址,此時我們可以向操作array一樣操作p:
#include <stdio.h> int main(){ int array[10]= {1,2,3,4,5,6,7,8,9,10}; int *p = array; for(int i=0;i<10;i++){ printf("%d ",array[i]); } printf("\n"); for(int i=0;i<10;i++){ printf("%d ",p[i]); } printf("\n"); for(int i=0;i<10;i++){ printf("%d ",*(array+i)); } printf("\n"); for(int i=0;i<10;i++){ printf("%d ",*(p+i)); } printf("\n"); return 0; }
結果如下:
2. 多維數組名與指針
但是如果我們定義一個多維數組,如:
int arrays[2][2];
數組名arrays是數組元素的首地址,如果我們還用上面的那種定義:
int *p; p = arrays;
這樣p就指向了該多維數組的首地址,由於多維數組其實是數組的數組,所以多維數組的首地址就是一個地位的數組的首地址,即arrays[0],它是一個有2個元素的數組。因此我們可以將一維數組名賦值給int*型的指針,
#include <stdio.h> int main(){ int arrays[2][2] = {1,2,3,4}; int *p = arrays; for(int i=0;i<4;i++){ printf("%d ",p[i]); } printf("\n"); return 0; }
結果如下:
可以發現,編譯時發生警告:
我們之所以可以通過p來遍歷arrays中所有元素,是因為,數組本質上是按行優先存儲的。
我們可以通過兩次解引用獲取到數組中的某一個元素的值,有下式成立:
**arrays == *&arrays[0][0] == arrays[0][0]
如:
#include <stdio.h> int main(){ int arrays[2][2] = {1,2,3,4}; int *p = arrays; printf("%d == %d == %d\n",**arrays,*&arrays[0][0],arrays[0][0]); return 0; }
結果:
對於多維數組我們可以定義一個指向多維數組的指針:
int (*p)[2];
p = arrays;
這個括號是一定要加的,因為[]的優先級比較高(?)。
比較 int *p[2] 和 int (*p)[2] :
- int *p[2] 表示p是一個有2個元素的數組,數組中的每一個元素表示一個指向int型變量的指針;
- int (*p)[2] 表示p是一個指針,它指向一個數組,數組中的每個元素指向一個有2個元素的數組。
因此我們知道 int (*p)[2] 與arrays有同樣的數組結構,p就是arrays的一個別名,我們可以通過p來實現任何arrays能實現的操作:
#include <stdio.h> int main(){ int arrays[2][3] = {1,2,3,4,5,6}; int (*p)[3] = arrays; for(int i=0;i<2;i++){ for(int j=0;j<3;j++){ printf("%d ",p[i][j]); } printf("\n"); } return 0; }
結果如下:
3. 數組名和指針的區別
數組名和指針之間,經常會交替使用這兩個變量,例如把一個指針當成數組來使用,或者是把數組名賦值給指針,通過指針來訪問數組成員變量。
但是,數組名和指針畢竟是定義不同的變量,它們之間也有一定的區別和聯系。
理解數組名和指針的區別和聯系有助於我們正確使用C語言,即什么情況下該使用數組名,什么情況下該使用指針。
區別1:
數組名和指針取地址后的值不一樣:
- 數組名取地址得到的是數組名所指元素的地址。
- 對指針取地址得到的是指針變量自身的地址。
1)對於數組名:
#include <stdio.h> int main(){ int array[6] = {1,2,3,4,5,6}; printf("array = 0x%x\n",array); printf("&array[0] = 0x%x\n",&array[0]); printf("&array = 0x%x\n",&array); return 0; }
輸出結果如下:
我們已經知道,數組名即數組首元素的地址,因此array和&array[0]的值一樣,但是令我們驚奇的是,數組名的地址&array和和數組首元素的地址&array[0]也一樣。
2)對於指針:
#include <stdio.h> int main(){ int array[6] = {1,2,3,4,5,6}; int *p = array; printf("array = 0x%x\n",array); printf("&array[0] = 0x%x\n",&array[0]); printf("&array = 0x%x\n",&array); printf("\np = 0x%x\n",p); printf("&p = 0x%x\n",&p); return 0; }
結果如下:
可以發現指針的值和指針所在的地址是不同的。
區別2:
數組名是指針常量,指針是指針變量。
- 數組是固定大小的,數組一經定義,那么數組名就是一個指向數組首元素類型的常量指針,也就是說數組名是不允許更改的;
- 但是我們知道除非定義指針常量,否則指針變量是可以再賦值的。
區別3:
當對數組名使用sizeof時,得到的是數組所有元素所占的字節數,對指針sizeof得到的是指針類型的字節數。
#include <stdio.h> int main(){ int array[6] = {1,2,3,4,5,6}; int *p = array; printf("sizeof array = %d bytes\n",sizeof(array)); printf("sizeof pointer = %d bytes\n",sizeof(p)); return 0; }
輸出如下:
區別4:
對數組名取&和對指針取&的意義不同。
#include <stdio.h> int main(){ int array[6] = {1,2,3,4,5,6}; int *p = array; printf("&array = 0x%x\n",&array); printf("&array + 1 = 0x%x\n\n",&array + 1); printf("&p = 0x%x\n",&p); printf("&p + 1 = 0x%x\n",&p + 1); return 0; }
輸出如下:
上圖可以看到對array取地址后加一,增大了24個字節,恰好是數組的大小;而對指針p取地址后加一,只增大了8個字節,恰好是一個指針類型所占的字節數。
4. 總結
- 數組名代表了一個指向數組首元素的指針常量,一經定義,不可更改;指針是指針變量,定義之后仍可更改,其類型在定義時確定。
- 當出現 sizeof 和 & 操作符時,數組名不再當成指向一個元素的指針常量來使用,而指針仍當成指向一個元素的指針變量來使用。
- 對於使用指針和數組下標的選擇:
- 系統在使用數組下標對數組成員變量進行訪問時,開銷比較大,指針的訪問效率是遠遠大於數組名的訪問效率的;
- 但是只有在指針正確訪問時,使用指針才比下標法更有效率;
- 下標法更加容易理解,在可讀性方面,也更加的具有優勢。
參考資料:
- https://blog.csdn.net/findgeneralgirl/article/details/78501734
- https://blog.csdn.net/dream_follower/article/details/80356754