**ANSI C (C89) 之前**:塊作用域內的數組**必須**聲明為 static 才能進行初始化列表賦值。
**ANSI C (C89) 及之後**:**取消此限制**,允許自動存儲期(非 static)的數組在定義時初始化。
**譚浩強教材**基於現代標準編寫,故字符數組定義時直接初始化(如 char str[] = "hello";)**無需 static**,完全合法、標準。
static 局部變量)允許初始化列表。{...} 初始化,只能逐元素賦值。int a[3]; a = {1,2,3}; 非法,任何標準均不支持)。int a[10] = { [5] = 100, [2] = 50 };。| 概念 | 含義 | 與初始化的關係 |
|---|---|---|
| 靜態存儲期 | 程序啟動分配、結束釋放。全局變量、static 變量屬此類。 | 早期標準**只有**此類允許列表初始化。 |
| 自動存儲期 | 塊進入分配、退出釋放。函數內非 static 變量屬此類(含數組)。 | C89+ 允許定義時列表初始化。 |
static 修飾局部變量 | 改變存儲期為靜態,**不改變作用域**(仍局部可見)。 | 早期為了初始化不得不加 static;現代無此必要。 |
static 修飾全局變量/函數 | 限制**鏈接屬性**為內部鏈接(僅本文件可見),存儲期本就是靜態。 | 與初始化無關,屬於模塊封裝手段。 |
// 全局作用域:默認靜態存儲,允許初始化(任何標準)
int g_arr[3] = {1, 2, 3}; // OK
static int g_arr2[3] = {4, 5, 6}; // OK,內部鏈接
void func() {
// C89/C99/C11/C17/C23 均合法
int auto_arr[3] = {7, 8, 9}; // 自動存儲期,定義時初始化 ✅
static int static_arr[3] = {10,11,12}; // 靜態存儲期,定義時初始化 ✅
// 任何標準均非法:分離聲明與初始化
int illegal[3];
// illegal = {1,2,3}; // ❌ 編譯錯誤:賦值運算符左邊須為可修改左值,數組名不可賦值
// 正確的運行時賦值方式
for(int i=0;i<3;i++) illegal[i] = i+1; // ✅ 循環賦值
memcpy(illegal, (int[]){1,2,3}, sizeof(illegal)); // ✅ memcpy 複製
}
char str1[] = "hello"; // 自動存儲期,定義時初始化 ✅ 標準寫法
static char str2[] = "world"; // 靜態存儲期,定義時初始化 ✅ 但通常無必要
char *p = "literal"; // 指向字符串字面量(只讀區),非數組初始化
char str[] = "..."; 是**數組初始化**,編譯器分配數組空間並拷貝字符串內容(含 \0),可修改內容。static,C89 起完全合法。int a[3] = {1,2,3}; 和 static int a[3] = {1,2,3}; 在函數內效果相同」。"abc" 就是字符數組」。const char[],存儲在只讀區,**不可修改**;char a[] = "abc"; 會拷貝到可寫數組。int a[10] = {0};、char buf[256] = "";。清晰、重入安全、無額外開銷。static 或動態分配 malloc。static(內部鏈接),**非**為了初始化。memcpy/memmove、結構體整體賦值(結構體允許運行時整體賦值,數組不允許)。譚浩強教材字符數組直接初始化**完全符合 ANSI C 及後續標準**,無需 static。早期 K&R C 限制已成歷史。理解「存儲期、作用域、鏈接屬性、初始化時機」四大屬性區別,才能寫出正確、高效、可移植的 C 代碼。