分類

展開全部 | 收合全部

分類

展開全部 | 收合全部

【C++ 觀念理解 #3】C++ 理解 for loop (迴圈) 為什麼有時候會有 * ,為什麼有時候會有 &

前言

這邊要來整理長期我在 C++ 感到困惑的一個問題,
就是為什麼有時候 for 迴圈 會有 &,有時候 for 迴圈 又沒有 &,
然後有時候沒有 & 也跑得過,有時候看範例卻又不是這樣寫。

直接看程式碼再來解釋

下面這一段程式碼是一個簡化後的例子,它可以用來解釋我目前困惑的所有問題。

我們單純的讓程式印出從 0 到 9,
也宣告了另外一個 arr 從 9 一路到 0。

#include <iostream>

using namespace std;

int main()
{

    for (int i = 0; i < 10; ++i)
    {
        cout << i;
    }
    cout << endl << "---------------------" << endl;

    int arr[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
    for (int i = 0; i < 10; ++i)
    {
        cout << arr[i];
    }
    cout << endl << "---------------------" << endl;

    for (int* it = std::begin(arr); it != std::end(arr); ++it){
        cout << it << ", "; // it: address      
        cout << *it << endl; // *it get value       
    }
    cout << endl << "---------------------" << endl;


    for (int &ele : arr)
    {
        cout << ele;
    }
    cout << endl << "---------------------" << endl;

    return 0;
}

結果

解釋區

上面的程式碼大致分為四段,讓我理解了非常多的事情,還有觀念混淆的地方

第一段 for loop 的例子,最單純的數值增加

for (int i = 0; i < 10; ++i)
{
    cout << i;
}

第一段例子是每一位學 c++ 新手都一定最早學到的例子,
他就是一個單純的數值增加,
但大部分開始混亂,都是從下面那幾個例子才開始出現的,例如我XD。

第二段 for loop 的例子,我們是在用 for 增加變數,透過變數去拿取物件

int arr[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
for (int i = 0; i < 10; ++i)
{
    cout << arr[i];
}

到這裡應該也還不算太混亂,就只是一個透過 array 的 index 去拿取對應的 arr 數值。

第三段 for loop 的例子 (重要),其實,我們是直接去地址拿值!

for (int* it = std::begin(arr); it != std::end(arr); ++it){
    cout << it << ", "; // it: address      
    cout << *it << endl; // *it get value       
}

讓我觀念開始混亂,就是從這個例子開始的,
碰到 array 數值的拿取,第二種寫法或是第三種寫法都是主流,

  • 第二種寫法是透過「index」去拿取 arr 裡面的值
  • 第三種寫法是,「我們直接去對應的記憶體位置,把值拿出來

    所以這邊我們看到 for 開頭宣告是指標的 int
    因為我們是透過這個 int
    ,作為 iterator 去遍歷我們的 array 的內容。

    而這裡還有一個重要的觀念,注意輸出結果的部分,我們發現儲存的記憶體位置,
    每一次都是移動 4 個 bytes,並且連續。

    我們唯有透過正確的一次移動 4 bytes 的記憶體位置,才能夠拿到正確的值。
    (而我們怎麼知道「記憶體位置正確的移動」是 4 bytes? 注意到我們 iterator 定義的是 int* 了嗎! )

而這個例子,經常有的延伸應用

通常這樣子的寫法會被我們拿來遍歷各種更複雜的資料結構,例如像是 vector…
這也是為什麼我們在 for 的後面,必須要宣告一個指標的原因,
實際上我們就是在不斷地移動記憶體位置,好讓我們去拿取對應的值。

第四段 for loop 的例子 (重要),其實,我們也是直接去地址拿值!

第四種寫法出現後,更是讓我跟前面的第二、三個例子,整個大爆炸!!!
這也是為什麼這次整理,一開始就在強調,
現在就是要整理 for 迴圈後面出現的東西,
為什麼有時候有 * ? 有 & ?
他們一起出現的時候,我的觀念就爆了XDDD,
開始懷疑人生,跟我是不是不適合寫程式XDDD

for (int &ele : arr)
{
    cout << ele;
}

這個寫法其實還蠻新鮮,是在 C++ 11之後才出現,
因此如果使用 C++ 98 的編譯器是沒有辦法成功執行的。

關於這個寫法的關鍵字,可以搜尋「Range-based for loop」
* Range-based for loop
* Range-based for loop in C++

他一開始出現的用意,是為了幫助我們簡化寫 for loop,
但面對像我這種觀念不穩的人,這個東西出現之後整個就讓我觀念大爆炸XDDD,

總之, 他做的事情非常簡單,就是去指定物件中去拿每一個地址的值。
像上面的表示方法,因為我知道 arr 是 Int array,我就透過 int & 去拿每一個值。

題外話,那不加 & 可以嗎? 為什麼有時候看到不加也可以?

沒錯,不加也可以!
但這也是我們另外今天要另外討論的另外一個主題!

拿參考? 拿真實地址?

為了解決這個問題,我們另外加了一點點程式碼,
這邊我們應該直接看結果就知道差別了。
(先跟人家說,沒錯,印出結果會是一樣的,但注意細節!)

for (int ele : arr)
{
    cout << &ele << ", " << ele << endl;
}
cout << endl << "---------------------" << endl;

for (int &ele : arr)
{
    cout << &ele << ", " << ele << endl;
}
cout << endl << "---------------------" << endl;

  • 與他對應的結果

有注意到差別了嗎?仔細看上面「沒有 &」的例子,雖然記憶體位置好像感覺都一樣,
但這並不好!!!
這表示實際上我們多使用了一個 int ele 的記憶體空間。

而且,再仔細觀察一下記憶體位置,
你會發現下面的寫法跟第三個例子印出來的記憶體位址,結果完全一模一樣。

因此上面的寫法實際上我們在 int ele 多跟記憶體要了一個 int 空間,
但實際上這是完全沒有必要的,我們只是單純的要做指標的移動,
不需要新的記憶體空間, 所以這邊使用「int &」的方法會更好。

Reference

⭐C++ 基礎用法 相關文章整理⭐:
1.【C++】C++ compile 程式碼 使用 c++ 11 與使用相關的 package
2.【C++】C/C++ 顯示資料的類別 (type) sample code (內含範例程式碼) print C data type, cout C++ data type, get variable type in c++
3.【C++】C++ 複製 2D array的方法 copy 2d array memcpy sample code (內含範例程式碼)
⭐Modern C++ ⭐:
⭐C++ 字串處理相關文章整理⭐:
1.【C++】字串 char string stringstream 相關用法總整理 (內含範例程式碼) 與利用 sprinf, snprinf assign 值的方法
2.【C++】字串 char string stringstream 「轉換」用法總整理 (內含範例程式碼)
3.【C】printf, fprintf, sprintf, snprintf 相關用法總整理 (內含範例程式碼)
4.【C++】C++ String 用法 連接兩個 String c++ string concat
⭐C++ 系統偵測相關文章整理⭐:
1.【C++】C++ 利用 dirent.h 計算資料夾的檔案數量 count files sample code (內含範例程式碼)
2.【C++】C++ inotify sample code 偵測指定路徑底下的文件變化 (內有範例程式碼)
⭐C++ OpenCV 相關文章整理⭐:
1.【OpenCV】c++ OpenCV – 在 ubuntu 上第一次執行 OpenCV 程式 sample code (內含範例程式碼)
2.【OpenCV】c++ OpenCV - 在圖片上寫上文字 cv::putText sample code (內含範例程式碼)
3.【OpenCV】c++ OpenCV - cv::Rect 矩形用法與相關功能函數 sample code (內含範例程式碼)
4.【OpenCV】c++ OpenCV - OpenCV 中的純量 定義顏色 cv::Scalar(255,255,255) color sample code (內含範例程式碼)
5.【OpenCV】用 C++ 計算 iou 的方法 與網路算法常見錯誤(內附範例程式碼) sample code
⭐C++ Makefile 相關文章整理⭐:
1.【C++ Makefile】- 1 / 嘗試撰寫自己的第一份 Makefile
2.【C++ Makefile】- 2 / 新增自己的變數
3.【C++ Makefile】- 3 / Makefile 常用變數 -「$@」, 「$^」
4.【C++ Makefile】- 4 / Makefile 常用 fake target -「.PHONY」
5.【C++ Makefile】- 5 / Makefile 內建變數 -「$@」, 「$^」, 「$<」, 「$* 」,「$? 」
⭐【喜歡我的文章嗎? 歡迎幫我按讚~ 讓基金會請創作者喝一杯咖啡!
如果喜歡我的文章,請幫我在下方【按五下Like】 (Google, Facebook 免註冊),會由 「LikeCoin」 贊助作者鼓勵繼續創作,讀者們「只需幫忙按讚,完全不用出錢」哦!

likecoin-steps
Howard Weng
Howard Weng

我是 Howard Weng,很多人叫我嗡嗡。這個網站放了我的各種筆記。希望這些筆記也能順便幫助到有需要的人們!如果文章有幫助到你的話,歡迎幫我點讚哦!
另外,因為定位是「個人的隨手筆記」,有些文章內容「⚠️可能我理解有誤⚠️」或「?只寫到一半?」,如果有發現這樣的情況,歡迎在該文章的最下面留言提醒我!我會儘快修正或補上!感謝大家的建議與幫忙,讓網站能變得更好?

文章: 890

★留個言吧!內容有誤或想要補充也歡迎與我討論!