6.5 陣列的初始化
宣告陣列時可以同時指定初值,避免後來訪問到未初始化的垃圾值。不同的初始化方式有不同的優缺點。
方式 1:使用大括號指定初值
int a[5] = {1, 2, 3, 4, 5}; // 完整初始化
int b[5] = {10, 20}; // 前兩個設 10、20,其餘自動設 0
int c[5] = {}; // 所有元素設 0
方式 2:省略陣列大小
int a[] = {1, 2, 3}; // 編譯器自動推斷大小為 3
方式 3:全域陣列自動初始化為 0
int a[1000]; // 全域宣告,所有元素自動為 0
int main() {
int b[1000]; // 局域宣告,所有元素為未知(垃圾值)
}
方式 4:使用迴圈初始化
int a[20];
for (int i = 0; i < 20; i++) {
a[i] = i + 1; // 先宣告,後初始化
}
排版小提醒:大括號初始化比照 1.5 的逗號慣例——逗號後加一個空格:{1, 2, 3} ✓、{1,2,3} ✗。
¶範例程式碼
#include<iostream>
using namespace std;
int main() {
// 方式 1:宣告時初始化部分元素
int a[5] = {10, 20, 30};
// a[0]=10, a[1]=20, a[2]=30, a[3]=0, a[4]=0
for (int i = 0; i < 5; i++) {
cout << "a[" << i << "]=" << a[i] << '\n';
}
cout << "---\n";
// 方式 2:宣告時全部初始化為 0
int b[5] = {};
// b[0]~b[4] 都是 0
for (int i = 0; i < 5; i++) {
cout << "b[" << i << "]=" << b[i] << '\n';
}
return 0;
}
執行結果:
a[0]=10
a[1]=20
a[2]=30
a[3]=0
a[4]=0
---
b[0]=0
b[1]=0
b[2]=0
b[3]=0
b[4]=0
¶查表資料:把固定不變的資料寫進初始化
初始化還有一個漂亮的用法:把題目裡固定不變的「查表資料」直接寫進大括號。例如每個月的天數:
int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// days[m] 就是 m 月的天數;days[0] 塞 0 佔位,讓「1 月」剛好住在 days[1]
有了這張表,「m 月有幾天」變成取一格 days[m]——原本要寫的 12 層 if 全部消失。days[0] 佔位正是 6.3 的 1-base 對齊技巧。站上的還剩幾天呢?用的就是這招(注意:該題是 2024 閏年,2 月要填 29)。
¶初始化不是免費的
int a[1000000] = {}; 不是魔法——電腦要老老實實把一百萬格逐格清成 0。單獨做一次沒感覺,但放進多組測資的迴圈裡就出事了:
while (t--) { // 最多 10^5 組測資
int a[1000000] = {}; // ✗ 每組都清一百萬格 → 總共 10^11 步,TLE
// ...處理這組測資...
}
修法:把陣列搬到全域(程式開始時自動清 0,只做一次),每組結束後只清自己用過的格子:
int a[1000000]; // 全域:自動全 0(只做一次)
int main() {
int t;
cin >> t;
while (t--) {
int n;
// ...讀入並處理這組測資,只會動到 a[0] ~ a[n-1]...
for (int i = 0; i < n; i++) a[i] = 0; // 只清用過的前 n 格
}
return 0;
}
若題目保證「所有 n 的總和 \le 10^6」,整個程式的清理工作加起來也才 10^6 步——這種總和保證,就是在暗示你這樣做。本站曾用一道這類題目實測:整包重清的版本要跑 6.9 秒(時限 1 秒),改成只清用過的前 n 格之後 0.1 秒。
動手試試看:在上面「四種樣子」的程式碼中,把 int b[5] = {}; 改成 int b[5];(不初始化),執行看看。你會看到 b 陣列輸出垃圾值。想想看為什麼 a 陣列反而有明確的初值?