跳转至

數組

數組是存放相同類型對象的容器,數組中存放的對象沒有名字,而是要通過其所在的位置訪問。數組的大小是固定的,不能隨意改變數組的長度。

定義數組

數組的聲明形如 a[d],其中,a 是數組的名字,d 是數組中元素的個數。在編譯時,d 應該是已知的,也就是説,d 應該是一個整型的常量表達式。

1
2
3
4
unsigned int d1 = 42;
const int d2 = 42;
int arr1[d1];  // 錯誤:d1 不是常量表達式
int arr2[d2];  // 正確:arr2 是一個長度為 42 的數組

不能將一個數組直接賦值給另一個數組:

1
2
3
int arr1[3];
int arr2 = arr1;  // 錯誤
arr2 = arr1;      // 錯誤

應該儘量將較大的數組定義為全局變量。因為局部變量會被創建在棧區中,過大(大於棧的大小)的數組會爆棧,進而導致 RE。如果將數組聲明在全局作用域中,就會在靜態區中創建數組。

訪問數組元素

可以通過下標運算符 [] 來訪問數組內元素,數組的索引(即方括號中的值)從 0 開始。以一個包含 10 個元素的數組為例,它的索引為 0 到 9,而非 1 到 10。但在 OI 中,為了使用方便,我們通常會將數組開大一點,不使用數組的第一個元素,從下標 1 開始訪問數組元素。

例 1:從標準輸入中讀取一個整數 \(n\),再讀取 \(n\) 個數,存入數組中。其中,\(n\leq 1000\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <iostream>
using namespace std;

int arr[1001];  // 數組 arr 的下標範圍是 [0, 1001)

int main() {
  int n;
  cin >> n;
  for (int i = 1; i <= n; ++i) {
    cin >> arr[i];
  }
}

例 2:(接例 1)求和數組 arr 中的元素,並輸出和。滿足數組中所有元素的和小於等於 \(2^{31} - 1\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;

int arr[1001];

int main() {
  int n;
  cin >> n;
  for (int i = 1; i <= n; ++i) {
    cin >> arr[i];
  }

  int sum = 0;
  for (int i = 1; i <= n; ++i) {
    sum += arr[i];
  }

  printf("%d\n", sum);
  return 0;
}

越界訪問下標

數組的下標 \(\mathit{idx}\) 應當滿足 \(0\leq \mathit{idx}< \mathit{size}\),如果下標越界,則會產生不可預料的後果,如段錯誤(Segmentation Fault),或者修改預期以外的變量。

多維數組

多維數組的實質是「數組的數組」,即外層數組的元素是數組。一個二維數組需要兩個維度來定義:數組的長度和數組內元素的長度。訪問二維數組時需要寫出兩個索引:

1
2
3
int arr[3][4];  // 一個長度為 3 的數組,它的元素是「元素為 int 的長度為的 4
                // 的數組」
arr[2][1] = 1;  // 訪問二維數組

我們經常使用嵌套的 for 循環來處理二維數組。

例:從標準輸入中讀取兩個數 \(n\)\(m\),分別表示黑白圖片的高與寬,滿足 \(n,m\leq 1000\)。對於接下來的 \(n\) 行數據,每行有用空格分隔開的 \(m\) 個數,代表這一位置的亮度值。現在我們讀取這張圖片,並將其存入二維數組中。

1
2
3
4
5
6
7
const int maxn = 1001;
int pic[maxn][maxn];
int n, m;

cin >> n >> m;
for (int i = 1; i <= n; ++i)
  for (int j = 1; j <= m; ++j) cin >> pic[i][j];

同樣地,你可以定義三維、四維,以及更高維的數組。