C 语言中的变量
C 语言中的变量是一块“有名内存”,用来保存数据,并在需要时通过名字随时访问。它让我们不必记住确切的内存地址就能使用内存。
创建变量时,必须同时给出“数据类型”和“名字”,语法如下:
数据类型 名字;
C 提供了多种数据类型,几乎可以存储所有常见数据,例如:int、char、float、double 等。
示例:
int num; // 整数
char letter; // 字符
float decimal; // 单精度浮点数
在 C 中,所有变量必须“先声明、后使用”。同一类型的多个变量可在一条语句中声明,用逗号分隔:
数据类型 名字1, 名字2, 名字3, ...;
C 变量命名规则
只要满足以下条件,可任意取名:
- 只能由字母、数字和下划线组成。
- 必须以字母或下划线开头,不能以数字开头。
- 不能出现空白字符。
- 不得使用保留字(关键字)。
- 同一作用域内名字必须唯一。
C 语言变量的初始化
变量声明后,需要把第一个有用的值存进去,这个值叫“初值”,这个过程叫“初始化”。用赋值运算符 = 完成。
int num; // 先声明
num = 3; // 再初始化
注意:变量刚声明时里面只是“垃圾值”(随机数据),所以初始化很重要。也可以“声明 + 初始化”一步完成:
int num = 3;
提示:赋给变量的值必须与声明时的类型一致,否则出错。
访问变量
想使用变量里保存的数据,直接写变量名即可。
示例:
#include <stdio.h>
int main() {
int num = 3; // 创建并初始化
printf("%d", num); // 通过名字访问,输出 3
return 0;
}
修改变量中的值
在程序运行过程中,可以随时用赋值运算符 = 把一个新值重新放进变量。
示例:
#include <stdio.h>
int main() {
int n = 3; // 创建并初始化为 3
n = 22; // 把新值 22 存进去,旧值 3 被覆盖
printf("%d", n); // 输出 22
return 0;
}
如何在 C 中使用变量
变量就是内存地址的“名字”,里面装着某个值。只要语法上允许使用“值”的地方,就可以用变量名代替——变量名就是它所存值的替身。
示例:整数变量可以直接写在数学表达式里,代替具体的数字。
#include <stdio.h>
int main() {
// 直接用字面值计算
int sum1 = 20 + 40;
// 先定义变量
int a = 20, b = 40;
// 用变量代替字面值计算
int sum2 = a + b;
printf("%d\n%d", sum1, sum2); // 两行结果都是 60
return 0;
}
C 变量的内存分配
在“声明”阶段,编译器只知道某个名字和类型存在,此时并未真正分配内存;只有当变量被“定义”时,编译器才会为它划出一块具体内存。
在 C 语言里,通常把“声明 + 定义”合并成一条语句完成(例如前面所有例子)。
分配给变量的字节数由它的类型决定,可用 sizeof 运算符查看。
示例:
#include <stdio.h>
int main() {
int num = 22;
// 查看 num 占多少字节
printf("%zu bytes", sizeof(num)); // 常见输出:4 bytes
return 0;
}
变量根据存储类别的不同,也会被放到内存的不同区域。
C 语言中的存储类别
存储类别用于规定变量的生命周期、作用域和可见性。它决定了变量存放在哪里、值会保留多久、以及能被谁访问,从而帮助我们在程序运行期间追踪某一变量的“存在轨迹”。C 语言共有 4 种主要存储类别:
- auto
- register
- static
- extern
auto(自动)
函数或代码块内部声明的变量,默认就是 auto 类型。这类变量只能在所属代码块/函数内使用,离开该范围就不可见。
auto 变量特性
- 作用域:局部
- 默认值:垃圾值(随机)
- 内存位置:RAM
- 生命周期:到所属作用域结束为止
解释: auto关键字用于显式声明一个“自动存储期”的局部变量。- 但在 C 语言里,局部变量默认就是
auto,写不写都一样,因此通常省略。 - 函数前不能加
auto,因为函数本身并不受块作用域限制。 示例:
#include <stdio.h>
int main() {
auto int x = 10; // auto 可省略,这是默认行为
printf("%d", x);
return 0;
}
static(静态)
该存储类别用来声明“静态变量”,其特点是:即使离开作用域,变量值仍然被保留。因此,下次再进入作用域时,能继续使用上一次留下的值。
static 存储类特性
- 作用域:局部(只能在本代码块/函数内按名访问)
- 默认值:0(未显式初始化时自动清零)
- 内存位置:RAM
- 生命周期:贯穿整个程序运行期间
示例:
#include <stdio.h>
void counter() {
static int count = 0; // 静态变量,只初始化一次
count++;
printf("Count = %d\n", count);
}
int main() {
counter(); // 输出 Count = 1
counter(); // 输出 Count = 2
return 0;
}
解释: 变量 count 在第一次调用时创建并初始化为 0,函数结束后值仍被保留;第二次调用时不再重新初始化,而是继续在上一次的基础上累加,因此输出 2。
register(寄存器)
该存储类别用于声明“寄存器变量”。它的功能与 auto 变量完全一样,唯一的区别是:编译器会尽量把这类变量放进 CPU 的寄存器里(如果有空闲寄存器),从而让访问速度远高于普通内存变量。
register 存储类特性
- 作用域:局部
- 默认值:垃圾值(随机)
- 内存位置:优先 CPU 寄存器,否则退回到 RAM
- 生命周期:到所属作用域结束为止
注意:编译器可能因寄存器不足而忽略你的“建议”。
示例:
#include <stdio.h>
int main() {
register int i; // 建议把 i 放进寄存器
for (i = 0; i < 5; i++) {
printf("%d ", i);
}
return 0;
}
解释: register 只是一个“提示”。如果编译器觉得可行,就会把 i 放入寄存器以加快循环速度;若寄存器不够用,它会像普通 auto 变量一样处理。
extern(外部)
extern 存储类用来告诉编译器:“这个变量是在别的代码块(或别的源文件)里真正定义的,此处只是声明,并不分配内存”。 因此,它的值可以在别的块里赋值或修改。
extern 存储类特性
- 作用域:全局(整个程序都能按名访问)
- 默认值:0(未显式初始化时自动清零)
- 内存位置:RAM
- 生命周期:程序结束才释放
示例:
文件 printVar.c
/* 仅声明,不定义 */
extern int globalVar; // 告诉编译器:真正的定义在别处
文件 main.c
#include <stdio.h>
int globalVar = 100; // 真正的定义 + 初始化
void printGlobalVar(); // 函数原型
int main() {
printGlobalVar(); // 输出:Global variable is: 100
return 0;
}
编译方法(GCC 需要把两个文件一起编译):
gcc main.c printVar.c -o main
总结:在 C 语言中,存储类别定义了变量的生存期、作用域和可见性。它们规定了变量在运行内存中的存储位置、值的保留时间以及访问方式,这些特性帮助我们在程序运行期间追踪特定变量的存在。
| 存储说明符 | 存储位置 | 初始值 | 作用域 | 生命周期 |
|---|---|---|---|---|
| auto | 栈 | 垃圾值 | 代码块内部 | 代码块结束 |
| extern | 数据段 | 零 | 全局,多文件 | 程序结束为止 |
| static | 数据段 | 零 | 代码块内部 | 程序结束为止 |
| register | CPU 寄存器 | 垃圾值 | 代码块内部 | 代码块结束 |
你会发现上面的示例都是搞得在方法内部声明的局部变量, 普通全局变量放在“数据段”(Data Segment),程序一加载就存在,直到进程结束才释放。记住全局变量不能用auto,register来修饰噢!!!
C 语言中变量的作用域
前面说“变量一旦声明就能在任何地方使用”,其实只讲对了一半。变量只能在它的作用域——即名字有效的程序区域——中被访问。作用域通常就是一对花括号 {} 所包围的区域。
示例:
// 这里不能访问 num
int main() {
// 这里也不能访问 num
{
int num; // 变量声明
} // 作用域结束
// 这里依旧不能访问 num
return 0;
}
C 语言中的常量
如果希望变量的值不允许被修改,可以用 const 关键字把它定义成常量。
语法:
const 数据类型 名字 = 值;
常量必须在声明时就初始化,否则编译报错。