C++ array使用方法詳細介紹

更多關於STL的文章:STL專欄


爲了防止學習的過程中出現學後忘的情況,我將接觸到的知識進行整理,作該筆記,由於本人水平有限,如果出現錯誤,還望賜正。

介紹

數組是固定大小的序列容器:它們包含按嚴格的線性順序排列的特定數量的元素。一個array——也就是容器類array<>的一份實體——模塑出一個static array。它包覆一個尋常的static C-style array 並提供一個STL容器接口。

通用格式:array<類型名, 元素個數> 數組名;

注意,因爲長度固定,這裏的元素個數不能是變量。

在內部,數組除了它所包含的元素之外不保留任何數據(甚至不保留它的大小,這是一個模板參數,在編譯時固定)。就存儲大小而言,它與使用該語言的括號語法([])聲明的普通數組一樣有效。這個類只是向它添加了一層成員和全局函數,它比尋常的數組安全,而且效率並沒有因此變差,因此數組可以用作標準容器。

與其他標準容器不同,數組具有固定的大小,並且不通過分配器管理其元素的分配:它們是封裝固定大小的元素數組的聚合類型。因此,它們不能動態地展開或收縮。

大小爲零的數組是有效的,但是不應該取消對它們的引用(成員 front, back, 和 data)。

數組容器的另一個獨特的特性是它們可以被視爲元組對象:array頭文件重載get函數來訪問數組的元素,就好像它是一個元組一樣,還有專門的tuple_size和tuple_element類型。

array並不支持(也就是不允許你指定)分配器(allocator)

array成員函數

函數 功能
begin(),end() ,cbegin(),cend() 提供正向迭代器支持
rbegin(),rend(),crbegin(),crend() 提供反向迭代器支持
size() 返回數組大小
max_size() 返回數組最大大小(由於array爲固定序列,該函數返回值與size()相同)
empty() 判斷數組是否爲空 (幾乎沒用)
at(),operator[] 獲取數組元素
front() 返回數組第一個元素的引用
back() 返回數組最後一個元素的引用
data() 返回指向數組對象包含的數據的指針
fill() 用值填充數組
swap() 交換兩個數組元素
get(array) 返回某一個數組元素的引用

array會把元素複製到其內部的 static C-style array 中。這些元素總是擁有一個明確次序。因此 array 是一種有序集合。array 允許隨機訪問,也就是你可以在常量時間內直接訪問任何元素, 前提是你得知道元素位置。 array 的迭代器屬於隨機訪問迭代器,所以你可以對它運用任何STL算法。

成員函數用法示例

array用法及初始化

template < class T, size_t N > class array;
//T爲所包含元素的類型,別名爲成員類型value_type 。N爲數組的大小,以元素數表示。

在使用array前,首先要添加array這個頭文件,即#include <array>

注意:array<>是唯一一個無任何東西被指定爲初值時,會被預初始化的容器。這意味着對於基礎類型,初值可能不明確,而不是0,例如:下面定義一個有妖妖靈個int元素的數組arr:

     std::array<int,110> arr;

上面定義的arr並未進行初始化。未初始化將會分配隨機值,如圖:

在這裏插入圖片描述
所以儘量不要定義未初始化的數組,否則訪問數組元素,而該元素恰好未初始化時,可能出現意想不到的錯誤。

array數組對象初始化與標準數組初始化一模一樣,如:

    std::array<int,110> arr  { };//將數組所有元素初始化爲0
    std::array<int,110> arr{1,2,3,4};//將數組前4個元素分別初始化爲1,2,3,4,其餘全部爲0

在這裏插入圖片描述
另外由於沒有提供針對初值而寫的構造函數或assignment 操作符,因此“ 在array聲明期間完成初始化”是使用初值列的唯一途徑。基於這個原因,你無法使用小括號指明初值(此不同於其他容器類型)

std::array<int,5> a({1,2,3,4,5})  //錯誤
  • fill()
    fiil() 函數可以用指定值給數組中所有元素賦值。

fill()函數原型如下:

void fill(const value_type & u); //value_type爲數組元素類型;

【例】

#include<iostream>
#include<array>
using namespace std;

int main()
{   
    std::array<int,110> arr{1,2,4,5,6,7,8,9};
    arr.fill(3); //用3對數組所有元素賦值
    for(auto i:arr)
        cout<<i<<" ";
    cout<<endl;
    
    return 0;
}

輸出結果爲:

3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3

array元素的獲取

特別注意!array,string,vector等容器的第一個元素下標爲0!!!

  • array元素的獲取可以使用下標[](與標準數組用法相同),以及STL容器特有的at()
    [] 與 at() 的區別在於,[]不會進行檢查數字是否越界,而 at() 會進行檢查(時間開銷很少),如果越界則拋出 std::out_of_rang 異常。
    因此,除非確定訪問沒有越界,否則應該儘量使用更安全的 at() 。

reference at(size_type n);
const_reference at(size_type __n) const;

#include<iostream>
#include<array>
using namespace std;

int main()
{   
    std::array<int,11> arr{1,2,3,4,5,6,7,8,9};
    arr.at(9) = arr.at(3) + arr.at(5);
    arr[10] = arr[1] + arr[8];
    cout<<arr.at(9)<<endl;
    cout<<arr[10]<<endl;

    //arr[11] = 6;越界訪問,程序異常,但Qt Creator並未報錯
    arr.at(11) = 6; //異常
    return 0;
}

程序運行結果爲:

10
11

terminate called after throwing an instance of ‘std::out_of_range’
what(): array::at: __n (which is 11) >= _Nm (which is 11)

  • front() 和 back()
    front() 返回數組第一個元素的引用。
    back() 返回數組最後一個元素的引用。
#include<iostream>
#include<array>
using namespace std;

int main()
{   
    std::array<int,11> arr{1,2,3,4,5,6,7,8,9};
    arr.front() = 666;
    arr.back() = 666;
    for(auto i:arr)
        cout<<i<<" ";
    cout<<endl;
    return 0;
}

程序運行結果爲:

666 2 3 4 5 6 7 8 9 0 666

(注:這兩個函數極少使用)

  • data()
    返回指向數組對象中第一個元素的指針。
    該函數無參數。
#include<iostream>
#include<array>
#include<cstring>
using namespace std;

int main()
{   
    std::array<int,10> arr{1,2,3,4,5,6,7,8,9,10};

    cout<< *arr.data()<<endl;
    cout<< *(arr.data()+6)<<endl;//獲取元素

    const char* cstr = "Test string";
    std::array<char,12> charray;
    std::memcpy (charray.data(),cstr,charray.size());

    cout << charray.data() << endl;


    return 0;
}

程序運行結果爲:

1
7
Test string

  • size() 和 max_size()
    由於array在創建的時候必須明確指定大小,而且array爲固定容器,因此max_size()與size()的返回值相同。
    通常使用 size() 函數。
    返回值類型爲size_t 即無符號整數

使用size()可以有效避免使用for遍歷數組時,發生越界的情況。同時它也使得你在寫程序的時候,不必去花心思記憶數組的大小。

    std::array<int,10> arr{1,2,3,4,5,6,7,8,9,10};

    for(unsigned int i(0);i< arr.size();++i)
        cout<< arr[i] <<" ";
    cout<<endl;
//程序運行結果爲1 2 3 4 5 6 7 8 9 10
  • empty()
    該函數在array中爲雞肋函數。這是因爲array在定義的時候已經指明瞭大小,不可能爲空。除非你寫出如此代碼std::array<int,0> var;但這毫無意義。
    然而,對於其他元素可變或者元素可刪除的容器來說,它們使用 empty() 時的機制是一樣的,因此爲它們提供了一個一致性的操作。

Tuple接口

array 提供 tuple 接口。因此可以使用表達式 tuple_size<>::value 取得元素個數,用 tuple_element<>::type 取得某特定元素的類型,用 get<>() 取得某特定元素。

  • get()
    get() 函數爲非成員函數重載
    該函數返回array中指定元素的引用

函數原型如下:

template <size_t I, class T, size_t N> T& get (array<T,N>& arr) noexcept;
template <size_t I, class T, size_t N> T&& get (array<T,N>&& arr) noexcept;
template <size_t I, class T, size_t N> const T& get (const array<T,N>& arr) noexcept;
//參數l爲:元素在數組中的位置,第一個元素的位置爲0 。
//參數 T爲:數組中包含的元素類型(通常從arr隱式獲得)。
//參數 N爲:數組的大小,以元素數爲單位(通常從arr隱式獲得)。

由於參數T,N可以從arr中隱式獲得。因此在使用時一般不顯式指定二者。
【例】

#include<iostream>
#include<array>
using namespace std;

int main()
{   
    std::array<int,10> arr{1,2,3,4,5,6,7,8,9,10};

    //int a = std::get<6,int,10>(arr); 一般不這麼寫

    int a = std::get<6>(arr);
    cout<<a<<endl;

    std::get<5>(arr) = 666;
    for(auto i:arr)
        cout<<i<<" ";
    cout<<endl;

    return 0;
}

程序運行結果爲:

7
1 2 3 4 5 666 7 8 9 10

另外參數l必須是明確的數字,不能使用變量。如:

    int n = 3;
    std::get<n>(arr);//錯誤寫法
  • tuple_size<>::value 和 tuple_element<>::type
    在array中用途不大,示例如下:
#include <iostream>
#include <array>
#include <string>
using namespace std;

int main()
{   

    std::array<string,5> arr = {"one","two","three","four","five"};;
    //返回元素個數
    cout<< std::tuple_size<decltype(arr)>::value <<endl;
    
    //獲取第3個元素類型
    std::tuple_element<1,decltype(arr)>::type type = get<3>(arr);
    cout<< type <<endl;

    return 0;
}

程序運行結果爲:

5
four

array元素的修改

array元素的修改與標準數組用法幾乎相同。
如:

    std::array<int,10> arr{1,2,3,4,5,6,7,8,9,10};
    arr[3] = 6;
    arr[2] = arr[0] + arr[1];

同樣也可以使用指針、引用對其進行修改。

不同與標準數組的是:只要兩個array類型的數組的數據類型和大小相同,就可以用 = 賦值。
如:

#include<iostream>
#include<array>
using namespace std;

int main()
{   
    std::array<int,3> arr_1 {1,2,3};
    std::array<int,3> arr_2 {4,5,6};

    arr_1 = arr_2; //用arr_2的元素覆蓋arr_1的元素

    for(auto i:arr_1)
        cout<<i<<" ";
    cout<<endl;

    for(auto i:arr_2)
        cout<<i<<" ";
    cout<<endl;

    return 0;
}

輸出結果爲:

4 5 6
4 5 6

  • swap()
    交換兩個array的值。注:這兩個數組的大小,數據類型必須相同!
    無返回值,無參數。

與標準庫中的其他容器不同,交換兩個數組容器是一種線性操作,涉及單獨交換範圍內的所有元素,這通常效率較低

#include<iostream>
#include<array>
using namespace std;

int main()
{   
    std::array<int,10> arr{1,2,3,4,5,6,7,8,9,10};
    std::array<int,10> var{0,0,0,0,0,0,0,0,0,1};

    arr.swap(var);

    for(auto i:arr)
        cout<<i<<" ";
    cout<<endl;

    for(auto i:var)
        cout<<i<<" ";
    cout<<endl;

    return 0;
}

運行結果爲:

0 0 0 0 0 0 0 0 0 1
1 2 3 4 5 6 7 8 9 10

array迭代器

名稱 功能
begin( ) 返回指向數組第一個元素的迭代器。
end() 返回指向數組最後一個元素後緊跟的的理論元素的迭代器。
cbegin() 返回指向數組第一個元素的const類型迭代器。
cend() 返回指向數組最後一個元素後緊跟的的理論元素的const類型迭代器。
rbegin() 返回一個反向迭代器,該迭代器指向數組的最後一個元素(即它的反向開始)。
rend() 返回一個反向迭代器,該迭代器指向數組第一個元素之前的理論元素(該元素被視爲反向元素)。
crbegin() 返回一個const類型反向迭代器,該迭代器指向數組的最後一個元素(即它的反向開始)。
crend() 返回一個const類型反向迭代器,該迭代器指向數組第一個元素之前的理論元素(該元素被視爲反向元素)。

下面爲數組迭代器的簡單用法:

#include<iostream>
#include<array>
using namespace std;

int main()
{   
    std::array<int,10> arr{1,2,3,4,5,6,7,8,9,10};

    array<int,10>::iterator it_beg = arr.begin();  //或者 auto it_beg = arr.begin();
    array<int,10>::reverse_iterator rit_beg = arr.rbegin(); //或者 auto rit_brg = arr.rbegin();

    for(;it_beg!=arr.end();it_beg++)
        cout<< *it_beg * 2<<" "; //二倍輸出數組所有元素
    cout<<endl;

    for(;rit_beg != arr.rend();rit_beg++)
        cout<< *rit_beg << " "; //倒序輸出數組元素
    cout<<endl;

    return 0;
}

輸出結果爲:

2 4 6 8 10 12 14 16 18 20
10 9 8 7 6 5 4 3 2 1

在使用時最好用全局的 begin() 和 end() 函數從容器中獲取迭代器,因爲它們是通用的。
如上述array<int,10>::iterator it_beg = arr.begin(); 可以寫爲array<int,10>::iterator it_beg = std::begin(arr);

array元素的比較

可以用任何比較運算符比較兩個數組容器,只要它們有相同的大小,保存的是相同類型的元素,而且這種類型的元素還要支持比較運算符。示例如下:

#include<iostream>
#include<array>
using namespace std;

int main()
{   
    std::array<int,3> arr_1 {1,2,3};
    std::array<int,3> arr_2 {1,2,3};
    std::array<int,3> arr_3 {1,3,2};

    if (arr_1 == arr_2)
        cout << "arr_1 = arr_2" << endl;
    if (arr_1 != arr_3)
        cout << "arr_1 != arr_3"<< endl;
    if (arr_1 < arr_3)
        cout << "arr_1 < arr_3"<< endl;

    return 0;
}

輸出結果爲:

arr_1 = arr_2
arr_1 != arr_3
arr_1 < arr_3

容器被逐元素地比較。對 ==,如果兩個數組對應的元素都相等,會返回 true。對於 !=,兩個數組中只要有一個元素不相等,就會返回 true。這也是字典中單詞排序的根本方式,兩個單詞中相關聯字母的不同決定了單詞的順序。

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