c++基礎(陣列)

Cplusplus-tutorial-in-hindi.jpg
陣列就是一些列具有相同型別變數集合,便於維護。可以將陣列理解為一個變數的集合的變數。
陣列宣告
陣列在宣告的時候需要指定出陣列中元素的 型別 和陣列的 大小 。
int arr[5];
陣列即指標
int main(int argc, char const *argv[]) { int arr[5]; std::cout << arr << std::endl; std::cin.get(); }
執行程式碼,我們發現 arr 是一個記憶體地址,定義一個數組 arr 實際是一個指標型別,是一個數組的指標。
0x7ffeeafaa7f0
visual studio IDE 提供根據記憶體地址檢視記憶體的功能,可以檢視到陣列是連續的記憶體的根據記憶體元素型別(也就是佔用記憶體大小)以及陣列的長度乘積所定。這裡每個 int 佔 4 位元組。
陣列還是一個有序的元素集合,這表示我們通過下標可以訪問到陣列的元素,在 c++ 下標是從 0 開始計算的,也有的語言是從 1 開始計算。
arr[0] = 1;
陣列越界
當我們訪問到那些不受我們控制的記憶體( arr[-1], arr[5]
),編譯時候就會丟擲警告,不過編譯還是成功。不過既然我們做出規定還是應該按規定辦事,要不可能在以後存在隱患和問題,難於除錯。
arr[-1] = 1; arr[5] = 1;
warning: array index 5 is past the end of the array (which contains 5 elements) [-Warray-bounds]
陣列的遍歷
for (int i = 0; i < 5; i++) { std::cout << arr[i] << std::endl; }
進一步證明陣列就是指標
int main(int argc, char const *argv[]) { int arr[5]; int *prt = arr; for (int i = 0; i < 5; i++) { std::cout << prt[i] << std::endl; } std::cout << arr << std::endl; std::cin.get(); }
定義一個指標變數然後將陣列 arr 賦值給這個變數。然後遍歷 prt 可以得到同上面相同結果。
int main(int argc, char const *argv[]) { int arr[5]; int *prt = arr; for (int i = 0; i < 5; i++) { prt[i] = 2; } *(prt + 2) = 5; for (int i = 0; i < 5; i++) { std::cout << prt[i] << std::endl; } std::cin.get(); }
在上面程式碼中我們可以通過移動指標位置來修改指定位置陣列的值, prt + 2
為指標為 2 的元素然後,通過 *(prt+2)
進行對其賦值,輸入結果如下。
這裡是 int 型別指標所以記憶體儲存單元為 4 位元組,所以指標移動 2 表示移動了 8 位元組,已經知道字元是佔一個位元組,所以將指標修改用於儲存字元 (char*)
,現在是按字元的位元組數來移動指標所以移動 8 位元組。然後將其轉換為指向資料型別為 int 的指標。
*(int *)((char *)prt + 8) = 5;
棧與堆
之前我們所定義陣列都是位於棧記憶體而非堆記憶體,如果我們用 new 所建立的陣列都是位於堆記憶體而非棧記憶體。
int main(int argc, char const *argv[]) { int arr[5]; int *another_arr = new int[5]; std::cin.get(); }
棧:是一種連續儲存的資料結構,具有先進後出的性質。通常的操作有入棧(圧棧)、出棧和棧頂元素。想要讀取棧中的某個元素,就要將其之前的所有元素出棧才能完成。類比現實中的箱子一樣。
堆:是一種非連續的樹形儲存資料結構,每個節點有一個值,整棵樹是經過排序的。特點是根結點的值最小(或最大),且根結點的兩個子樹也是一個堆。常用來實現優先佇列,存取隨意。
陣列位於堆還是位於棧記憶體區別在於其生命週期。
int *another_arr = new int[5]; delete[] another_arr;
因為位於堆記憶體,所需需要手動釋放記憶體,這裡因為是陣列所以通過 delete[]
來代替 delete
釋放陣列 another_arr
。
class Tut { int arr[5]; Tut() { for (int i = 0; i < 5; i++) { arr[i] = 2; } } };
上面 Tut 類中定義了一個數組,並且在建構函式對其進行賦值。然後我們開啟記憶體檢視器,就會發現這個陣列記憶體地址位於該類中。
class Tut { int *arr = new int[5]; Tut() { for (int i = 0; i < 5; i++) { arr[i] = 2; } } };
如果修改通過 new 在 Tut 類中建立陣列就會發現,在類中僅有陣列的指標地址,我們需要通過該地址可以訪問到陣列記憶體。
在 c++ 中我們無法通過 size 來像其他語言那樣獲取到陣列的大小。
arr->size();
我們可以通過下面方法來間接獲取陣列的大小,通過陣列所佔位元組數/陣列元素型別所佔的位元組數,不過並不推薦這樣使用我們需要自己來維護陣列的大小。
int arr[5]; int count = sizeof(arr) / sizeof(int); std::cout << count << std::endl;
推薦自己控制陣列的大小
class Tut { static const int size = 5; int arr[size]; Tut() { for (int i = 0; i < size; i++) { arr[i] = 2; } } };
c++11
在 c++11版本支援標準庫中的陣列,而且也提供了便於操作的一些方法。
#include <iostream> #include <array> class Tut { static const int size = 5; int arr[size]; std::array<int, 5> another; Tut() { for (int i = 0; i < another.size(); i++) { another[i] = 2; } } };
不過更多便利就是意味著更多效能的代價,個人推薦使用原生陣列而不是c++ 提供陣列。