C++ array獲取(存取)元素

2020-07-16 10:04:28

可以通過在方括號中使用索引表示式汸問和使用陣列容器的元素,這和標準陣列的存取方式相同,例如:

values[4] = values[3] + 2.O*values[1];
第 5 個元素的值被賦值為右邊表示式的值。像這樣使用索引時,因為沒有做任何邊界檢査,所以,如果使用越界的索引值去存取或儲存元素,就不會被檢測到。為了能夠檢查越界索引值,應該使用成員函數 at():
values.at (4) = values.at(3) + 2.O*values.at(1);
這和前一條語句的功能相同,除了當傳給 at() 的索引是一個越界值時,這時會丟擲 std::out_of_rang 異常。應該總是使用 at(),除非確定索引沒有越界。這也產生了一個疑問,為什麼 operator[]() 的實現沒有進行邊界檢查?答案是因為效能。如果每次存取元素,都去檢查索引值,無疑會產生很多開銷。當不存在越界存取的可能時,就能避免這種開銷。

陣列物件的 size() 函數能夠返回 size_t 型別的元素個數值,所以能夠像下面這樣去計算陣列所有元素的和:
double total {};
for(size_t i {} ; i < values.size() ; ++i)
{
    total += values[i];
}
size() 函數的存在,為陣列容器提供了標準陣列所沒有的優勢,陣列元素能夠知道它包含多少元素。接受陣列容器作為引數的函數,只需要通過呼叫容器的成員函數 size(),就能得到元素的個數。不需要去呼叫 size() 函數來判斷一個陣列容器是否為空。如果容器中沒有元素的話,成員函數 empty() 會返回 true:
if(values.empty())
    std::cout << "The container has no elements.n";
else
    std::cout << "The container has "<< values.size()<<"elements.n";
然而,我們很難想象陣列容器沒有元素的情形,因為當生成一個陣列容器時,它的元素個數就固定了,而且無法改變。生成空陣列容器的唯一方法是,將模板的第二個引數指定為 0,這種情況基本不可能發生。然而,對於其他元素可變或者元素可刪除的容器來說,它們使用 empty() 時的機制是一樣的,因此為它們提供了一個一致性的操作。

對於任何可以使用疊代器的容器,都可以使用基於範圍的迴圈,因此能夠更加簡便地計算容器中所有元素的和:
double total {};
for(auto&& value : values)
    total += value;
當然,通過把容器作為引數傳給函數,也能達到同樣的效果。陣列容器的成員函數 front() 和 back() 分別返回第一個元素和最後一個元素的參照。成員函數 data() 同樣能夠返回 &from(),它是容器底層用來儲存元素的標準陣列的地址,一般不會用到。

模板函數 get<n>() 是一個輔助函數,它能夠獲取到容器的第 n 個元素。模板引數的實參必須是一個在編譯時可以確定的常數表示式,所以它不能是一個迴圈變數。它只能存取模板引數指定的元素,編譯時會對它進行檢查。get<n>() 模板提供了一種不需要在執行時檢查,但能用安全的索引值存取元素的方式。下面展示如何使用它:
std::array<std::string, 5> words {"one","two","three”,"four","five" };
std::cout << std::get<3>(words) << std::endl; // Output words[3]
std::cout << std::get<6>(words) << std::endl; // Compiler error message!
下面是一個範例,展示了關於陣列容器你到目前為止所學到的知識:
/**範例 1**/
#include <iostream> // For standard streams
#include <iomanip>  // For stream manipulators
#include <array>    // For array<T,N>
int main()
{
    const unsigned int min_wt {100U};
    const unsigned int max_wt {250U};
    const unsigned int wt_step {10U};
    const size_t wt_count {1 + (max_wt - min_wt) / wt_step};

    const unsigned int min_ht {48U};
    const unsigned int max_ht {84U};
    const unsigned int ht_step {2U};
    const size_t ht_count { 1 + (max_ht - min_ht) / ht_step };

    const double lbs_per_kg {2.20462};
    const double ins_per_m {39.3701};

    std::array<unsigned int, wt_count> weight_lbs;
    std::array<unsigned int, ht_count> height_ins;

    // Create weights from lOOlbs in steps of lOlbs
    for (size_t i{}, w{min_wt} ; i < wt_count ; w += wt_step, ++i)
    {
        weight_lbs.at(i) = w;
    }

    //Create heights from 48 inches in steps of 2 inches
    unsigned int h{min_ht};
    for(auto& height : height_ins)
    {
        height = h;
        h += ht_step;
    }
    //Output table headings
    std::cout << std:: setw (7) <<" |";
    for (const auto& w : weight_lbs)
        std::cout << std:: setw (5) << w<<"11";
    std::cout << std::endl;
    // Output line below headings
    for (size_t i{1} ; i < wt_count ; ++i)
        std::cout<<"---------";
    std::cout << std::endl;
    double bmi {};
    unsigned int feet {};
    unsigned int inches {};
    const unsigned int inches_per_foot {12U};
    for (const auto& h : height_ins)
    {
        feet = h / inches_per_foot;
        inches = h % inches_per_foot;
        std::cout << std::setw (2) <<feet <<"'"<<std::setw (2) << inches <<"""<<"|";
        std::cout << std::fixed <<std::setprecision(1);
        for (const auto& w : weight_lbs)
        {
            bmi = h / ins_per_m;
            bmi = (w / lbs_per_kg) / (bmi*bmi);
            std::cout << std:: setw (2) <<""<<bmi <<" |";
        }
        std::cout << std::endl;
    }
    for (size_t i {1} ; i < wt_count ; ++i)
        std::cout << "---------";
    std::cout << "nBMI from 18.5 to 24.9 is normal" << std::endl;
}
本節中,不再展示這個範例的輸出結果,因為可能會佔據很多篇幅。這裡有兩套引數,每套定義了 4 個有關身高、體重範圍的常數,它們被包含在 BMI 表中。因為身高、體重都是整數、非負數,所以存放在陣列容器中的身高和體重都是 unsigned int 型別的元素。

在迴圈中,可以用適當的值初始化容器。第一個迴圈展示了 at() 函數的使用,這裡也可以放心地使用 weight_lbs[i]。接下來的兩個迴圈分別輸出了表的列頭,以及一條用來分隔表頭和表的橫線。資料表是以迴圈巢狀的方式生成的。外迴圈遍歷身高並輸出英尺和英寸的最左一列的身高。內迴圈遍歷體重,輸出當前身高每行的 BMI 值。