变量与常量(Variables & Constants)
变量是程序中存储和操作数据的基本单元。常量则保证某些值在程序运行期间不可修改,提升安全性。
1. 变量——命名的存储空间
1.1 声明与定义
声明(Declaration):告诉编译器"这个名字是什么类型"。 定义(Definition):声明的同时分配内存空间。
int age; // 定义了一个 int 变量 age,未初始化(值是随机的)
float score = 95.5; // 定义并初始化
extern int count; // 声明(不含定义),count 在其他文件中定义
在 C 语言中,局部变量如果不初始化,其值是不确定的(即内存中残留的垃圾值)。使用未初始化的变量是常见的 bug 来源:
int x; // x 的值是未知的
printf("%d", x); // 输出不可预测——危险!
1.2 命名规则
| 规则 | 示例 |
|---|---|
| 只能包含字母、数字、下划线 | speed、max_value、data2 |
| 不能以数字开头 | 2value ❌ → value2 ✓ |
| 不能是 C 关键字 | int ❌、return ❌ |
| 大小写敏感 | count 和 Count 是两个不同变量 |
命名风格建议:
| 场景 | 风格 | 示例 |
|---|---|---|
| 普通变量 | snake_case |
motor_speed、max_index |
| 常量 | UPPER_SNAKE_CASE |
MAX_SIZE、PI |
| 单字符 | 循环计数器 | i、j、k |
2. 变量的作用域与生命周期
┌─────────────────────────────────────────────┐
│ #include <stdio.h> │
│ │
│ int global = 100; ← 全局变量 │
│ 文件作用域 │
│ void func() │
│ { ┌──────────────────┐ │
│ int local = 10; │ 局部变量 │ │
│ // ... │ 函数作用域 │ │
│ } └──────────────────┘ │
│ │
│ int main() │
│ { ┌──────────────────┐ │
│ for (int i = 0; │ i 仅在循环体内 │ │
│ i < 5; i++) │ 有效(C99起) │ │
│ { │ │ │
│ int j = i * 2; │ j 仅在此代码块内 │ │
│ } │ 有效 │ │
│ // i 和 j 在此处不可见 │ │
│ } └──────────────────┘ │
└─────────────────────────────────────────────┘
作用域规则表
| 变量类型 | 定义位置 | 可见范围 | 生命周期 |
|---|---|---|---|
| 全局变量 | 所有函数外部 | 整个文件(extern 可跨文件) |
程序启动到结束 |
| 局部变量 | 函数内部 | 定义处到 } 结束 |
进入函数到退出函数 |
| 块变量 | {} 内部 |
定义处到所属 } 结束 |
同可见范围 |
3. 常量——不可修改的值
3.1 const 常量
const 关键字声明一个"只读"变量,编译器会阻止对其的修改:
const int MAX_STUDENTS = 50; // 只能读,不能写
const double TAX_RATE = 0.13;
MAX_STUDENTS = 60; // 编译错误!
const 与指针的组合有四种形式,需区分清楚:
int x = 10, y = 20;
const int* p1 = &x; // 指向的内容不可改,指针本身可改
p1 = &y; // OK
*p1 = 30; // 编译错误!
int* const p2 = &x; // 指针本身不可改,指向的内容可改
*p2 = 30; // OK
p2 = &y; // 编译错误!
const int* const p3 = &x; // 指针和内容都不可改
速记法则:const 修饰它右边最近的类型。
3.2 #define 宏常量
#define PI 3.14159
#define MAX_SIZE 100
#define NAME "GMaster"
| 对比项 | const |
#define |
|---|---|---|
| 处理时机 | 编译时 | 预处理时(纯文本替换) |
| 是否有类型 | 有 | 无(只是文本) |
| 是否占用内存 | 是 | 否(直接替换为字面量) |
| 是否有作用域 | 有 | 无(从定义处到文件末尾) |
| 可调试 | 是 | 否(预处理后宏名消失) |
建议:优先使用 const(有类型检查、可调试)。#define 适合定义编译期数组大小或条件编译标志。
3.3 枚举常量(enum)
当一组相关常量取离散值时,用 enum 比逐个定义 const 更清晰:
enum Direction {
NORTH = 0,
EAST = 1,
SOUTH = 2,
WEST = 3
};
enum Direction dir = NORTH; // 语义清晰
// 默认从 0 开始递增,所以也可简写:
enum Status { IDLE, RUNNING, STOPPED, ERROR };
// IDLE=0, RUNNING=1, STOPPED=2, ERROR=3
4. 初始化 vs 赋值
这是初学者容易混淆的两个概念:
int x = 10; // 初始化(initialization)——创建变量时赋予初始值
x = 20; // 赋值(assignment)——修改已有变量的值
| 操作 | 时机 | 实质 |
|---|---|---|
| 初始化 | 变量创建时 | 向刚分配的内存写入初始值 |
| 赋值 | 变量已存在后 | 用新值覆盖旧值 |
多种初始化方式
int a = 10; // 传统初始化
int b(20); // 构造函数风格(C++ 中更常见,C 也支持)
int c = {30}; // C99 统一初始化(推荐,可检测窄化转换)
int d; // 未初始化——值未定义
5. 常见错误
| 错误代码 | 问题 | 正确写法 |
|---|---|---|
const int n; n = 5; |
const 变量必须在定义时初始化 |
const int n = 5; |
int 2val; |
标识符不能以数字开头 | int val2; |
int x; printf("%d", x); |
使用了未初始化的变量 | int x = 0; printf("%d", x); |
#define SIZE = 100 |
#define 不需要等号 |
#define SIZE 100 |
| 局部变量与全局变量同名 | 局部变量会"遮蔽"全局变量(不易察觉) | 使用不同名称或显式访问 |
6. 总结
| 要点 | 说明 |
|---|---|
| 变量必须初始化 | 未初始化的局部变量值是垃圾值 |
const 优于 #define |
有类型检查、可调试 |
| 命名规范 | 小写下划线(snake_case)是 C 语言主流风格 |
| 作用域 | 从定义处到所在 {} 结束 |
| 局部遮蔽全局 | 同名时局部变量优先,应避免这种写法 |
enum 管理相关常量 |
比散落的 const 更清晰 |
作者: Qing | 修改日期: 2026-07-18