深刻理解C/C++二維數組

深刻理解C/C++二維數組

前言

原本覺得本身對二維數組的理解還能夠,沒感受有什麼,可是今天小夥伴問了一個問題感受迷惑了很久,因而決定細緻的記錄一下,一步一步的探究各類關於二維數組的問題,鞏固基礎。shell

二維數組的探究之旅(初級)

首先定義二維數組數組

int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

而後開始研究二維數組名和地址的關係spa

// 打印a a[0] 和 a[0][0]的地址
cout << "the value of a: " << a << endl;
cout << "the value of a[0]: " << a[0] << endl;
cout << "the address of a[0][0]: " << &a[0][0] << endl;
the value of a: 0x7ffe5b8c1ee0
the value of a[0]: 0x7ffe5b8c1ee0
the address of a[0][0]: 0x7ffe5b8c1ee0

就如各類資料說的那樣,能夠看出三個表達指向的是一個地址,繼續看指針

這裏看一下每一行\(a[i], 0\leq i<3\)code

for (int i = 0; i < 3; ++i)
    cout << "the value of a[" << i << "]" << " is " << a[i] << endl;
the value of a[0]is 0x7ffe5b8c1ee0
the value of a[1]is 0x7ffe5b8c1eec
the value of a[2]is 0x7ffe5b8c1ef8

打印的結果是每一行的首地址,能夠看出來每兩個地址之間差12個字節,也就是三個int的長度(每一個int是四個字節,大部分編譯器是這樣的)。這與咱們預期的是同樣的,畢竟是每行的首地址。索引

繼續走,咱們看到\(a, a[0], a[0][0]\)的地址是同樣的,都是最頭上的首地址,那麼這裏用這個地址推導進而顯示其餘位置的元素編譯器

// 由a[0]推出其餘,這裏以第1行第1列(0 base)爲例
cout << "the address of a[0+1]+1 " << "is " << a[0+1]+1 << endl;
cout << "the value of a[0+1]+1 " << "is " << *(a[0+1]+1) << endl;
cout << "the address of a[0]+4 " << "is " << a[0]+4 << endl;
cout << "the value of a[0]+4 " << "is " << *(a[0]+4) << endl;
the address of a[0+1]+1 is 0x7ffe5b8c1ef0
the value of a[0+1]+1 is 5
the address of a[0]+4 is 0x7ffe5b8c1ef0
the value of a[0]+4 is 5

前兩種行是經過加a[0]的索引獲得其餘行的首地址,而後再加偏移量獲得的,後兩行是直接計算偏移量獲得的。博客

繼續,由\(a[0][0]\)的地址推導編譯

// 由&a[0][0]推出其餘, 這裏以第1行第1列(0 base)爲例

cout << "the address of a[0][0]+4 " << "is " << &a[0][0]+4 << endl;
cout << "the value of a[0][0]+1 " << "is " << *(&a[0][0]+4) << endl;
the address of a[0][0]+4 is 0x7ffe5b8c1ef0
the value of a[0][0]+1 is 5

這裏和上面的第二中直接加偏移量的狀況是同樣的。class

由數組名獲得其餘元素

如今是讓人有點迷惑的地方,就是數組名a既然和\(a[0], a[0][0]\)指向的地址同樣,那麼是否用法也同樣呢?

咱們先來看看如何用a獲得\(a[1][1]\)

// 假設要求a[1][1](5)
cout << "a[1][1] inferred from a : " << *(*(a+1)+1) << endl;
a[1][1] inferred from a : 5

a+1指向的是\(a[1]\),這裏是第1行(0 base)的首地址,對它解引用獲得a[1]的地址,而後+1就獲得\(a[1][1]\)的地址了。

前面說a+1是指向地址的,那麼是否是意味a是一個二級指針呢?

int *p = a; // 不經過

實驗發現報錯,說明a不是一個指針類型,繼續看

int *p = *a;
cout << "the value of p is: " << p << endl;
cout << "the value of *p is: " << *p << endl;
cout << "the value of p+1 is: " << p+1 << endl;
cout << "the value of *(p+1) is: " << *(p+1) << endl;

cout << "a[1][1] inferred from p : " << *(p+1*3+1) << endl;
the value of p is: 0x7ffe5b8c1ee0
the value of *p is: 1
the value of p+1 is: 0x7ffe5b8c1ee4
the value of *(p+1) is: 2
a[1][1] inferred from p : 5

對a解引用後確實是一個地址,因此能夠定義指針,而且能夠用加偏移量的方式獲得\(a[1][1]\)

更爲有趣的是

cout << "a[1][1] inferred from p[] : " << p[1*3+1] << endl;
a[1][1] inferred from p[] : 5

指針p表現的居然像一個一維數組(由於直接按索引就能夠獲得元素),這裏也增長了一種新的取元素方式。這可能和[]的工做方式有關,這部分仍是沒弄明白,歡迎指導。

總結

這篇博客詳細的記錄了由二維數組名引出的各類細節,雖然還不完善,可是確實讓本身鞏固了基礎,之後估計應該不會倒在二維數組了……吧。

相關文章
相關標籤/搜索