1. 程式人生 > 實用技巧 >陣列地址,陣列首地址與陣列首元素地址的區別

陣列地址,陣列首地址與陣列首元素地址的區別

理清概念

C++中的int*int**int&int*&int *a[]int(*a)[]

int a;        //a是一個int型【變數】
int *a;       //a是一個指向int型變數的【指標】
int **a;      //a是一個指向一個指向int型變數指標的指標,也就是【二級指標】
int &a;       //a是一個【普通變數型引用】,若int &a = i;則a是變數i的一個別名,&a=&i,即a和i的地址一樣
int *&a;      //a是一個【指標變數型引用】,若int *&a = i;則a是指標i的一個引用
int a[2]; //a是一個含有兩個int型變數的【陣列】 int *a[2]; //a是一個【指標陣列】,陣列a裡存放的是兩個int型指標 int (*a)[2]; //a是一個【陣列指標】,a指向一個含有兩個int型變數的陣列

尤其是最後兩個。

程式碼測試

靜態陣列

靜態陣列在程式編譯階段即確定陣列的大小並完成固定大小的記憶體分配,所以陣列長度必須是常量,而不能是不確定值的變數

#include<stdio.h>
int main () {
         int arr[5]={1,2,3,4,5};
         int *p1;
         int
(*p2)[5]; p1 = arr; p2 = &arr; printf("sizeof(arr) = %d\n", sizeof(arr)); //sizeof(arr) = 20 printf("&arr = %d\n", &arr); //&arr = 6422276 printf("arr = %d\n", arr); //arr = 6422276 printf("&arr[0] = %d\n", &arr[0]); //&arr[0] = 6422276
printf("sizeof(p1) = %d\n", sizeof(p1)); //sizeof(p1) = 4 printf("p1 = %d\n", p1); //p1 = 6422276 printf("*p1 = %d\n",*p1); //*p1 = 1 printf("sizeof(p2) = %d\n", sizeof(p2)); //sizeof(p2) = 4 printf("p2 = %d\n", p2); //p2 = 6422276 printf("*p2 = %d\n", *p2); //*p2 = 6422276 printf("**p2 = %d\n", **p2); //**p2 = 1 printf("&arr + 1 = %d\n", &arr + 1); //&arr + 1 = 6422296 printf("arr + 1 = %d\n", arr + 1); //arr + 1 = 6422280 printf("&arr[0] + 1= %d\n", &arr[0] + 1); //&arr[0] + 1= 6422280 printf("p1+ 1 = %d\n", p1 + 1); //p1+ 1 = 6422280 printf("*(p1 + 1) = %d\n", *(p1 + 1)); //*(p1 + 1) = 2 printf("p2 + 1 = %d\n", p2 + 1); //p2 + 1 = 6422296 printf("*(p2 + 1) = %d\n", *(p2 + 1)); //*(p2 + 1) = 6422296 printf("*p2 + 1 = %d\n", *p2 + 1); //*p2 + 1 = 6422280 printf("**(p2 + 1) = %d\n", **(p2 + 1)); //**(p2 + 1) = 6422276 printf("*(*p2 + 1) = %d\n", *(*p2 + 1)); //*(*p2 + 1) = 2 return 0; }

分析

【0】陣列arr長度為5,型別是int;在測試系統中,1個int為4個位元組,1個位元組8位對應1個記憶體地址編號,起始地址為6422276(包含),結束地址為6422276 + 4 * 5 = 6422296(不包含)。

【1】數值上看陣列地址&arr = 陣列首地址arr = 陣列首元素地址&arr[0] = 6422276

【2】p1指標變數儲存的是陣列首地址p1 = arr;;p2指標變數儲存的是陣列地址p2 = &arr;。所以p1指向陣列首元素:*p1 =1,p2指向陣列首地址:*p2 =6422276

【3】陣列地址&arr加一,直接移動到下一個陣列地址:&arr + 1 = 6422296

【4】陣列首地址arr加一,直接移動到陣列下一個元素地址:arr + 1 = 6422280。陣列首元素地址加一結果同。

【5】p1指標加一,同陣列首地址(首元素地址),直接移動到陣列下一個元素地址:p1+ 1 = 6422280

【6】p2指標加一,同陣列地址,直接移動到下一個陣列地址:p2 + 1= 6422296

【7】靜態陣列中,陣列名在進行地址操作時,&arr和arr值雖相同,但意義不同&arr移動的單位是整個陣列,而arr移動的單位是陣列元素!!!

動態記憶體分配

所謂動態分配,即程式執行前並不確定陣列的大小,也不實際分配記憶體。在程式執行後,根據實際情況確定大小並動態分配記憶體。所以陣列定義改成根據輸入值n確定大小,並進行記憶體分配:

int n;
scanf("%d", &n); // 5
int *arr = new int[n];
arr[0] = 1 ,arr[1] = 2, arr[2] = 3, arr[4], arr[5];

儲存區域記憶體中的棧區編譯完成即分配好且大小固定)變成了堆區執行時動態分配,大小不固定)

所以後續程式碼不隨之改動的話,直接後果是報錯

int (*p2)[5];
p2 = &arr; //error: cannot convert 'int**' to 'int (*)[5]' in assignment 

顯然,此時的p2與&arr並不匹配。所以此時刪掉p1和p2,直接測試arr指標即可:

#include<stdio.h>
int main () {
         int n;
         scanf("%d", &n);
         int *arr = new int[n];
         arr[0] = 1 ,arr[1] = 2, arr[2] = 3, arr[4], arr[5];
         printf("sizeof(&arr) = %d\n", sizeof(&arr)); //sizeof(&arr) = 4
         printf("sizeof(arr) = %d\n", sizeof(arr)); //sizeof(arr) = 4

         printf("&arr = %d\n", &arr); //&arr = 6422296
         printf("arr = %d\n", arr); //arr = 15605496
         printf("&arr[0] = %d\n", &arr[0]); //&arr[0] = 15605496

         printf("*&arr = %d\n", *&arr); //*&arr = 15605496
         printf("*arr = %d\n", *arr); //*arr = 1
         printf("*&arr[0] = %d\n", *&arr[0]); //*&arr[0] = 1
         printf("arr[0] = %d\n", arr[0]); //arr[0] = 1

         printf("&arr + 1 = %d\n", &arr + 1); //&arr + 1 = 6422300
         printf("arr + 1 = %d\n", arr + 1); //arr + 1 = 15605500
         printf("&arr[0] + 1= %d\n", &arr[0] + 1); //&arr[0] + 1= 15605500

         printf("*(&arr + 1) = %d\n", *(&arr + 1)); //*(&arr + 1) = 5
         printf("*(arr + 1) = %d\n", *(arr + 1)); //*(arr + 1) = 2
         printf("*(&arr[0] + 1) = %d\n", *(&arr[0] + 1)); //*(&arr[0] + 1) = 2
         printf("*&arr + 1 = %d\n", *&arr + 1); //*&arr + 1 = 15605500
         printf("*arr + 1 = %d\n", *arr + 1); //*arr + 1 = 2
         printf("*&arr[0] + 1 = %d\n", *&arr[0] + 1); //*&arr[0] + 1 = 2

         return 0;
 }

分析

【1】與靜態陣列的結果相比,此時最大區別出現了:陣列地址&arr 不等於 陣列首地址arr。可以這麼理解,arr本身是一個指標,指向堆區中該陣列分配的記憶體首地址,即arr的值是該陣列首地址。而儲存這個地址的指標變數arr,它本身所在的記憶體地址即&arr。通俗地講,我們根據&arr找到arr這個指標,再根據arr的值找到arr這個陣列的儲存位置(記憶體地址)。

【2】陣列首地址與陣列首元素的地址仍然一致:arr = &arr[0]。而*&arr = arr,*arr = arr[0]。

【3】arr加一,移動到陣列下一個元素,arr[0]結果同。

【4】&arr加一,移動到下一個變數地址(上例為6422296->6422300)。