數組與指針之間關系的理解


本篇討論數組與指針之間的關系,分別以一維數組與二維數組為例進行說明。

一. 一維數組。

首先,讓我們明確以下兩點:

第一,數組名是一個固定的東西,它只能代表一個數組,也就是說,不允許這個數組名在后面又去表示另一個數組。

第二,數組名是一個指針,並且是一個常量指針。

現有一條語句: array[2] { 0, 1 },這條語句定義了一個數組,數組名是 array,該數組包含 2 個元素,其值分別為 0 和 1。我們訪問數組元素通過[ ] 運算符,比如 array[ 0 ] ,它的值就是 0 。這個 array ,也就是數組名,實質上是一個指針,它指向這個數組第一個元素的首地址。通過下面代碼,我們可以清楚的知道,array 的地址和 array[ 0 ]的地址是一樣的。

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main() {
 5     int a[2] { 0, 1 };
 6     cout << "a address : " << &a << endl;
 7     cout << "a[0] address : " << &a[0] << endl;
 8     
 9     return 0;
10 }

二. 二維數組

二維數組,我們可以把它看作一個矩陣,由行列組成。現有一條語句 array_2d [ 2 ] [ 3 ] ,這條語句聲明了一個二維數組,它有兩行三列共 6 個元素。我們換一個角度,不要把它看成一個整體,而是看成 2 個 一維數組的組合,每個一維數組有 3 個元素。這兩個一維數組的首元素分別是 array_2d [ 0 ] [ 0 ] , array_2d [ 1 ] [ 0 ]。為了更清楚的查看結果,請看以下代碼:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main() {
 5     int a[2] { 0, 1 };
 6     int b[2][3] { { 1, 2, 3 }, { 3, 2, 1 } };
 7     cout << "a address : " << &a << endl;
 8     cout << "a[0] address : " << &a[0] << endl;
 9 
10     cout << "b address : " << &b << endl;
11     cout << "b[0] address : " << &b[0] << endl;
12     cout << "b[1] address : " << &b[1] << endl;
13     cout << "b[0][0] address : " << &b[0][0] << endl;
14     cout << "b[1][0] address : " << &b[1][0] << endl;
15 
16     return 0;
17 }

這段代碼的運行結果如下:

1. a 和 a[ 0 ] 的地址一樣。

2.  b 與 b[ 0 ] 以及 b[ 0 ][ 0 ]這三者的地址一樣。

這表明數組名是數組首元素的地址,不論數組是一維還是二維,都遵循這個規律。

三. 當動態分配內存時,數組名與首元素地址是什么關系?

很多時候,之間定義固定長度的數組,並不能達到我們想要的效果,因此需要動態分配內存。請看如下代碼:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main() {
 5     int* new_array = new int[5];
 6     int** new_array_2d = new int* [5];
 7     for (int i = 0; i < 5; ++i) {
 8         new_array_2d[i] = new int[5];
 9     }
10 
11     cout << "New_array address : " << &new_array << endl;
12     cout << "New_array[0] address : " << &new_array[0] << endl;
13     cout << "New_array_2d address : " << &new_array_2d << endl;
14     cout << "New_array_2d[0] address : " << &new_array_2d[0] << endl;
15     cout << "New_array_2d[0][0] address : " << &new_array_2d[0][0] << endl;
16 
17     return 0;
18 }

在第 5 行,我們動態分配了一個元素個數為 5 的數組, new 運算符返回了首地址,並賦值給指針 new_array,現在 new_array 可以理解為該數組的名字。數組元素也可以通過 [ ] 運算符來訪問。

但是代碼的運行結果如下:

1. new_array 的地址不是 new_array [ 0 ] 的地址。

2. new_array_2d 的地址, new_array_2d [ 0 ] 的地址, new_array_2d [ 0 ] [ 0 ] 的地址,互不相同。

通過上面的結果我們可以清楚的知道,在動態分配內存時,數組名(即指針)的地址,與數組元素的地址無關。

代碼中有幾處需要解釋:

第一,new 運算符返回的是一個地址,因此需要用一個指針變量保存。

第二,new運算符分配連續空間時,指針同樣保存的是首地址。

第三,在二維數組動態分配的時候,用到了二級指針,因此你會看到 int** x這種寫法。指針變量里存儲的是地址,當這個指針指向的數據是 int 型,就寫成 int* x,而當這個指針指向另外一個指針時,自然就應該寫成 int** x(可以將 int 和第一個星號看成一個整體,表示指針數據類型,將第二個星號和變量名看成普通的變量聲明即可)。前面說過,可以將二維數組看成行列的組合,那么在動態分配二維數組時,先將所有行的地址,當作一個豎着的數組,這個豎着的數組的首地址,賦值給二維數組的名字(即第 6 行定義的二級指針 x ),然后再循環地為每個行(可以看成橫着的數組)分配空間。這個豎着的數組保存了所有首地址,其中的每個元素分別指向每一個橫着的數組,每個橫着的數組保存的真正的元素值。

第四,由三可知,第 6 行代碼右邊就是豎着的數組,其中的每個元素都是指針,因此這個數組是指針數組,應該用 new int* [ ]。而第 7 行到第 9 行里循環分配的空間是橫着的數組,里面每個元素是一個整數,因此寫為 new int [ ] 。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM