變量聲明語法規範
類型 <變量表>;
// 例:
int i, j, k;
unsigned char c, str[5], *p;
- 類型:C 合法類型 (基本/構造/指針/void*)
- 變量表:一個或多個標識符,逗號分隔
- 聲明 vs 定義:聲明引入標識符屬性,定義分配存儲。
extern int a; 聲明,int a; 定義 (兼聲明)
三大變量類別:由聲明位置決定
| 類別 | 聲明位置 | 別名 | 生命周期 | 作用域 | 默認初始值 | 典型用途 |
| 局部變量 | 函數內部 / 複合語句塊 | 自動變量 (auto) | 函數調用期間 | 塊/函數內部 | 不定 (垃圾值) | 臨時計算、循環計數、函數內部狀態 |
| 形式參數 | 函數參數列表 | 參數變量 | 函數調用期間 | 函數內部 | 由實參決定 | 接收調用者傳遞的值/地址 |
| 全局變量 | 所有函數之外 (文件頂層) | 外部變量 (extern) | 程序整個運行期間 | 全文件 (可跨文件) | 0 / NULL | 模塊間共享數據、狀態保持、配置參數 |
深度剖析:局部變量
- 自動分配/釋放:調用時棧上分配,返回時棧幀彈出自動銷毀
- 無隱式初始化:**必須顯式賦值後使用**,否則讀取垃圾值 → 未定義行為
- 遞歸/並發隔離:每次調用獨立棧幀,天然線程安全 (無共享)
- 遮蔽規則:內層塊同名變量遮蔽外層,
{ int x; { int x; } }
形式參數:值傳遞的本質
// 形式參數聲明在函數首部,無需重複聲明
void puthz(int x, int y, int color, char *p) {
int i, j, k; // 局部變量
// x, y, color, p 直接可用
}
- 值傳遞:實參值拷貝給形參,函數內修改形參**不影響**實參
- 模擬引用:傳遞地址 (
&var),形參為指針,通過解引用修改實參
- 數組參數退化:
void f(int arr[]) 等價 void f(int *arr),傳遞首元素地址,**可修改原數組內容**
全局變量:雙刃劍
正確使用模式
#include
int test = 0; // 定義全局變量 (習慣放在 main 前)
void f1(int x, float y);
void f2(void);
int main() {
test = 5; // 賦值
f1(20, 5.5); // test 變 115
f2(); // test 變 1150
printf("%d\n", test);
}
void f1(int x, float y) {
float z = x * y; // 局部變量
test = test + z; // 修改全局
}
void f2(void) {
int count = 10; // 局部變量
test = test * count;
}
優缺點權衡
| 優點 | 缺點 |
| 跨函數共享數據,無需層層傳參 | 破壞模塊獨立性,增加耦合 |
| 生命周期長,適合狀態保持 | 命名空間污染,易發生衝突 |
| 中斷/信號處理程序通信必需 | 併發訪問需同步 (鎖/原子操作) |
| 嵌入式寄存器映射、內存池指針 | 測試困難 (隱式依賴)、難以重入 |
最佳實踐
- 能不用盡量不用:優先傳參、返回值、結構體上下文
- 必用則
static 限制作用域:文件私有全局變量
- 命名加前綴:
g_、modulename_ 區分
- 頭文件
extern 聲明:// globals.h extern int g_counter;
- 初始化歸零不依賴默認:
int g_flag = 0; 明確語義
綜合示例:三類變量協作
// 全局配置 (文件級私有)
static int g_max_retries = 3;
// 函數聲明
void send_packet(const char *data, int len, int *bytes_sent);
int main() {
char buffer[1024]; // 局部:數據緩衝區
int sent = 0; // 局部:輸出參數
int retry = 0; // 局部:循環計數
// 填充 buffer...
while (retry < g_max_retries) { // 訪問全局配置
send_packet(buffer, 1024, &sent); // 傳地址模擬引用
if (sent > 0) break;
retry++;
}
return 0;
}
void send_packet(const char *data, int len, int *bytes_sent) {
// 形式參數:data, len, bytes_sent
// 模擬發送...
*bytes_sent = len; // 通過指針修改實參
}
總結
變量聲明位置決定其「身份」:函數內=局部、參數列=形式參數、函數外=全局。掌握三者的生命周期、作用域、初始化、傳遞語義,是編寫正確、可維護、高性能 C 代碼的基礎。**原則:局部優先,全局極慎,參數傳值/傳址明確語義。**