數組和auto的問題。

數組和auto的問題。

寫在前面的話:可以先看看文章末尾的總結,如果可以明白答案就不必浪費時間。如果想看內容建議先了解一下數組指針的問題,比如大概知道 int(*)[][]、int **、int(*)[]這些都代表什麼。

  • 問題起源:

在看書時學習了範圍for,於是乎就操作一下

int arr[5]={1,2,3,4,5};
for(auto i:arr)
    cout<<i<<endl;

跑了一下感覺挺舒服,減少代碼長度,看起來也很簡潔,而且不用考率數組越界等什麼亂七八糟的問題。那麼一個二維數組的範圍for怎麼寫呢?我抖了個激靈大手一揮寫下下面的代碼

int arrt[2][3]={1,2,3,4,5,6};
for(auto i:arr)
    for(auto j: i)
        cout<<j<<endl;

感覺自己很機智,巧用i來做內層範圍,然而編譯一下……bang~炸了。網上搜了一下說要這麼寫

int arrt[2][3]={1,2,3,4,5,6};
for(auto &i:arr)
    for(auto j: i)
        cout<<j<<endl;

why?僅僅相差一個&(引用),就導致不同的結果。Google一番,各種花式解決問題,但是根本不能說明其到底爲什麼錯誤。各種分析含糊其詞有甚者大談特談int**類型。好吧,幸好我讀了一點點書,不然就信了他們的鬼話。於是就只能自己慢慢往出來試了。(我承認博客有錯誤是正常的,每個人在初學的時候都有理解不透徹的時候,但是在查找很久仍然沒有找到結果的我心裏很難受,忍不住想要吐槽……這就像現在正在看這個博客的你一樣,心裏在大罵這個博主戲精一個,廢話真多,說了這麼多還沒講到重點,浪費我時間……)好好好,廢話就不說了我們開始來思考這個問題。

  • 多維數組範圍for循環遍歷時,外層循環變量爲什麼要引用。
    • 這個問題的本質是auto一個數組會是什麼結果
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
    int arrt[2][3]={1,2,3,4,5,6};//ok,這是一個二維數組,下面讓我們看看arrt到底是個什麼玩意
    int (*p0)[2][3]=&arrt;//可以看到arrt這個變量的地址是一個int(*)[2][3]型,並不是什麼int**,可以用一個這樣的指針指向這樣的數組。
    int (*p1)[3]=arrt;//arrt是一個二維數組,他的數組名錶示一個他裏面的第一個一維數組的首地址,可以用一個類型int(*)[3](長度爲三的一維數組指針)來指向他。
    int *p2 =arrt[0];//arrt[0]這是一個一維數組,他表示一維數組的第一個元素的首地址(int *),自然可以讓int *來指向他。
//搞清楚這些,我們來看看auto一個數組有什麼結果(可以和上面對比)
    auto &art0=arrt;//q0,一個二位數組(別名)
    auto q0=&arrt;  //q1,一個int(*)[2][3](指向一個兩行三列的數組指針)
    auto q1=arrt;   //q2,一個int(*)[3](指向一個長度爲三的一維數組指針)
    auto q2=arrt[0];//q3,一個int *(指向一個int型)
/*  這裏我們可以看出:aout加上&,結果是引用一個數組
                   auot不加&,結果是其對應的指針
    這就是問題的關鍵,一個是 數組,一個是指針。下面是打印他們的類型。
*/
    cout <<"arrt=  "<<typeid(arrt).name()<<endl;
    cout <<"p0  =  "<<typeid(p0).name()<<endl;
    cout <<"p1  =  "<<typeid(p1).name()<<endl;
    cout <<"p2  =  "<<typeid(p2).name()<<endl;
    cout <<"art0=  "<<typeid(art0).name()<<endl;
    cout <<"q0  =  "<<typeid(q0).name()<<endl;
    cout <<"q1  =  "<<typeid(q1).name()<<endl;
    cout <<"q2  =  "<<typeid(q2).name()<<endl;
}

這裏寫圖片描述

  • 理清楚上面的東西后我們就可以繼續分析最上面範圍for 裏的 i 的類型
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
    int arrt[2][3]={1,2,3,4,5,6};//ok,依然這是一個二維數組
    /***
    for(auto i:arrt)
    這裏是要把arrt的第一個元素拿出來對i進行初始化,具體看下面
    */
    for(auto i:arrt)//auto i=arrt[0];
    {
        cout <<typeid(i).name()<<endl;
        //arrt中有兩個成員所以循環兩次
    }
    for(auto &i:arrt)//auto &i=arrt[0];
    {
        cout <<typeid(i).name()<<endl;
        //arrt中有兩個成員所以循環兩次
    }
    /***
    有了上面的分析,我們很容易知道,第一個i是一個指針(int *)
                               第二個i是一個數組(引用)
    而在範圍for循環裏面的範圍(只能是一個集合,例如數組,string,vector……)是不允許是一個指針的。
    所以編譯器自然就會報錯。
    */
}

這裏寫圖片描述
OK!大功告成,終於把你們忽悠的看到這裏了……嘿~
總結一下,其實就是不加&,i是一個int * 指針,就不能作爲下一次範圍for 的範圍。加了&就是引用一個數組,就可以作爲下一次範圍for 的範圍。
最後吐槽寫一篇博客好**累啊,好**麻煩啊。青山不改綠水長流,各位看客咱們有緣再見。
對了如果有朋友覺得上面的知識有問題,有困惑敬請留言,一起討論學習~。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章