C 语言变量与常量 📦
🎯 概述
变量和常量是 C 语言程序的基本组成部分。变量用于存储可以改变的数据,而常量则表示程序运行期间值不会改变的数据。理解它们的使用方法是学习 C 语言的重要基础。
📝 什么是变量?
变量的概念
变量是内存中用于存储数据的命名空间。可以把变量想象成一个带标签的盒子,用来存放不同类型的数据。
变量的三要素
- 变量名:标识符,用于引用变量
- 数据类型:决定变量能存储什么样的数据
- 变量值:存储在变量中的实际数据
变量声明
c
// 基本语法:数据类型 变量名;
int age; // 声明一个整型变量
float price; // 声明一个浮点型变量
char grade; // 声明一个字符型变量变量初始化
c
// 声明的同时赋初值
int age = 25;
float price = 99.99;
char grade = 'A';
// 先声明后赋值
int count;
count = 10;
// 同时声明多个变量
int x = 1, y = 2, z = 3;变量命名规则
✅ 允许的命名规则:
- 由字母、数字、下划线组成
- 必须以字母或下划线开头
- 区分大小写(
age和Age是不同的变量)
c
// 合法的变量名
int age;
int student_count;
int _temp;
int value123;❌ 不允许的命名:
c
int 123abc; // 不能以数字开头
int my-var; // 不能包含连字符
int int; // 不能使用关键字
int my var; // 不能包含空格变量命名建议
c
// 使用有意义的名称
int studentAge; // 好:清晰表达含义
int sa; // 差:含义不明确
// 使用驼峰命名或下划线命名
int studentCount; // 驼峰命名
int student_count; // 下划线命名
// 常量使用大写
#define MAX_SIZE 100
const int BUFFER_SIZE = 256;🔢 变量的作用域
局部变量
在函数或代码块内部声明的变量,只在该范围内有效。
c
#include <stdio.h>
void myFunction() {
int localVar = 10; // 局部变量
printf("局部变量: %d\n", localVar);
}
int main() {
myFunction();
// printf("%d", localVar); // 错误!localVar 在这里不可见
return 0;
}全局变量
在所有函数外部声明的变量,整个程序都可以访问。
c
#include <stdio.h>
int globalVar = 100; // 全局变量
void function1() {
printf("函数1访问全局变量: %d\n", globalVar);
}
void function2() {
globalVar = 200; // 修改全局变量
printf("函数2修改全局变量: %d\n", globalVar);
}
int main() {
printf("主函数访问全局变量: %d\n", globalVar);
function1();
function2();
printf("修改后的全局变量: %d\n", globalVar);
return 0;
}静态变量
使用 static 关键字声明,保持变量值在函数调用之间不变。
c
#include <stdio.h>
void counter() {
static int count = 0; // 静态局部变量,只初始化一次
count++;
printf("调用次数: %d\n", count);
}
int main() {
counter(); // 输出: 调用次数: 1
counter(); // 输出: 调用次数: 2
counter(); // 输出: 调用次数: 3
return 0;
}💎 什么是常量?
常量是程序运行期间值不能改变的量。使用常量可以提高代码的可读性和可维护性。
1️⃣ 字面量常量
字面量是直接写在代码中的固定值。
整型字面量
c
int decimal = 100; // 十进制
int octal = 077; // 八进制(以 0 开头)
int hex = 0x2A; // 十六进制(以 0x 开头)
int binary = 0b1010; // 二进制(C23 标准,部分编译器支持)
// 长整型字面量
long bigNum = 1000000L;
long long veryBig = 9223372036854775807LL;
// 无符号整型
unsigned int positive = 100U;
unsigned long bigPositive = 1000000UL;浮点型字面量
c
float pi = 3.14f; // 单精度浮点数(f 后缀)
double e = 2.718281828; // 双精度浮点数(默认)
double scientific = 1.5e-3; // 科学计数法:1.5 × 10^-3
// 十六进制浮点数(C99)
double hexFloat = 0x1.2p3; // 1.125 × 2^3 = 9.0字符字面量
c
char letter = 'A'; // 单个字符
char newline = '\n'; // 转义字符
char tab = '\t'; // 制表符
char backslash = '\\'; // 反斜杠
char quote = '\''; // 单引号字符串字面量
c
char *greeting = "Hello, World!";
char *path = "C:\\Users\\Documents"; // 路径中的反斜杠需要转义
char *multiline = "这是第一行\n"
"这是第二行\n"
"这是第三行";常用转义字符
| 转义字符 | 含义 | 示例 |
|---|---|---|
\n | 换行 | printf("第一行\n第二行"); |
\t | 制表符 | printf("姓名\t年龄"); |
\\ | 反斜杠 | printf("路径: C:\\Windows"); |
\' | 单引号 | char c = '\''; |
\" | 双引号 | printf("他说:\"你好\""); |
\0 | 空字符 | 字符串结束标志 |
\r | 回车 | 回到行首 |
\b | 退格 | 删除前一个字符 |
2️⃣ 符号常量(宏定义)
使用 #define 预处理指令定义的常量。
基本用法
c
#include <stdio.h>
#define PI 3.1415926
#define MAX_SIZE 100
#define APP_NAME "我的应用程序"
#define VERSION "1.0.0"
int main() {
double radius = 5.0;
double area = PI * radius * radius;
printf("应用名称: %s\n", APP_NAME);
printf("版本: %s\n", VERSION);
printf("圆的面积: %.2f\n", area);
printf("最大容量: %d\n", MAX_SIZE);
return 0;
}宏的特点
✅ 优点:
- 编译前替换,不占用内存
- 可以定义任何类型的常量
- 可以用于条件编译
❌ 缺点:
- 没有类型检查
- 调试困难(预处理后被替换)
- 可能产生意外的副作用
宏函数
c
#include <stdio.h>
// 简单的宏函数
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
// 多行宏(使用反斜杠续行)
#define SWAP(a, b) do { \
typeof(a) temp = (a); \
(a) = (b); \
(b) = temp; \
} while(0)
int main() {
int x = 5;
printf("5 的平方: %d\n", SQUARE(x));
printf("5 和 10 的最大值: %d\n", MAX(5, 10));
// ⚠️ 注意宏的副作用
int y = 3;
printf("错误示例: %d\n", SQUARE(y++)); // 结果可能不是预期的
return 0;
}宏函数的陷阱
c
// ❌ 错误的宏定义(缺少括号)
#define BAD_SQUARE(x) x * x
int result1 = BAD_SQUARE(2 + 3); // 展开为: 2 + 3 * 2 + 3 = 11(错误!)
// ✅ 正确的宏定义(添加括号)
#define GOOD_SQUARE(x) ((x) * (x))
int result2 = GOOD_SQUARE(2 + 3); // 展开为: ((2 + 3) * (2 + 3)) = 25(正确!)3️⃣ const 常量
使用 const 关键字声明的常量,具有类型安全性。
基本用法
c
#include <stdio.h>
int main() {
const int MAX_STUDENTS = 50;
const double PI = 3.1415926;
const char GRADE = 'A';
printf("最大学生数: %d\n", MAX_STUDENTS);
printf("圆周率: %.7f\n", PI);
printf("等级: %c\n", GRADE);
// MAX_STUDENTS = 100; // 错误!不能修改 const 变量
return 0;
}const 指针
c
#include <stdio.h>
int main() {
int value1 = 10, value2 = 20;
// 1. 指向常量的指针(不能通过指针修改值)
const int *ptr1 = &value1;
// *ptr1 = 15; // 错误!
ptr1 = &value2; // 正确!可以改变指针指向
// 2. 常量指针(指针本身是常量)
int *const ptr2 = &value1;
*ptr2 = 15; // 正确!可以修改值
// ptr2 = &value2; // 错误!不能改变指针指向
// 3. 指向常量的常量指针(都不能改)
const int *const ptr3 = &value1;
// *ptr3 = 15; // 错误!
// ptr3 = &value2; // 错误!
return 0;
}const 与 #define 的区别
| 特性 | const | #define |
|---|---|---|
| 类型检查 | ✅ 有 | ❌ 无 |
| 作用域 | ✅ 遵循作用域规则 | ❌ 全局替换 |
| 调试 | ✅ 可以调试 | ❌ 预处理后消失 |
| 内存 | 占用内存 | 不占用内存 |
| 指针 | ✅ 可以取地址 | ❌ 不能取地址 |
c
#include <stdio.h>
#define MACRO_PI 3.14
const double CONST_PI = 3.14;
int main() {
// const 可以取地址
const double *ptr = &CONST_PI; // 正确
printf("CONST_PI 的地址: %p\n", (void*)ptr);
// #define 不能取地址
// const double *ptr2 = &MACRO_PI; // 错误!
return 0;
}4️⃣ 枚举常量
枚举(enum)用于定义一组相关的整型常量。
基本用法
c
#include <stdio.h>
// 定义枚举类型
enum Weekday {
MONDAY, // 0
TUESDAY, // 1
WEDNESDAY, // 2
THURSDAY, // 3
FRIDAY, // 4
SATURDAY, // 5
SUNDAY // 6
};
int main() {
enum Weekday today = WEDNESDAY;
printf("今天是星期: %d\n", today);
if (today == WEDNESDAY) {
printf("今天是星期三\n");
}
return 0;
}指定枚举值
c
#include <stdio.h>
// 自定义枚举值
enum Color {
RED = 1,
GREEN = 2,
BLUE = 4,
YELLOW = 8
};
// 月份枚举
enum Month {
JAN = 1, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC
};
// 状态码
enum Status {
SUCCESS = 0,
ERROR_FILE_NOT_FOUND = -1,
ERROR_PERMISSION_DENIED = -2,
ERROR_INVALID_INPUT = -3
};
int main() {
enum Color myColor = RED;
enum Month currentMonth = MAR;
enum Status result = SUCCESS;
printf("颜色值: %d\n", myColor);
printf("月份: %d\n", currentMonth);
printf("状态: %d\n", result);
return 0;
}枚举的实际应用
c
#include <stdio.h>
enum Direction {
NORTH,
SOUTH,
EAST,
WEST
};
void move(enum Direction dir) {
switch(dir) {
case NORTH:
printf("向北移动\n");
break;
case SOUTH:
printf("向南移动\n");
break;
case EAST:
printf("向东移动\n");
break;
case WEST:
printf("向西移动\n");
break;
}
}
int main() {
move(NORTH);
move(EAST);
return 0;
}🎯 实战示例
示例 1:计算圆的面积和周长
c
#include <stdio.h>
#define PI 3.1415926
int main() {
const char *title = "圆形计算器";
double radius;
printf("=== %s ===\n", title);
printf("请输入圆的半径: ");
scanf("%lf", &radius);
double area = PI * radius * radius;
double circumference = 2 * PI * radius;
printf("圆的面积: %.2f\n", area);
printf("圆的周长: %.2f\n", circumference);
return 0;
}示例 2:温度转换程序
c
#include <stdio.h>
#define FREEZING_POINT 32.0
#define CONVERSION_FACTOR 1.8
double celsiusToFahrenheit(double celsius) {
return celsius * CONVERSION_FACTOR + FREEZING_POINT;
}
double fahrenheitToCelsius(double fahrenheit) {
return (fahrenheit - FREEZING_POINT) / CONVERSION_FACTOR;
}
int main() {
const char *title = "温度转换器";
double temp;
int choice;
printf("=== %s ===\n", title);
printf("1. 摄氏度转华氏度\n");
printf("2. 华氏度转摄氏度\n");
printf("请选择 (1 或 2): ");
scanf("%d", &choice);
printf("请输入温度: ");
scanf("%lf", &temp);
if (choice == 1) {
printf("%.2f°C = %.2f°F\n", temp, celsiusToFahrenheit(temp));
} else if (choice == 2) {
printf("%.2f°F = %.2f°C\n", temp, fahrenheitToCelsius(temp));
} else {
printf("无效的选择!\n");
}
return 0;
}示例 3:学生成绩管理
c
#include <stdio.h>
#define MAX_STUDENTS 100
#define PASS_SCORE 60
enum Grade {
EXCELLENT = 90,
GOOD = 80,
AVERAGE = 70,
PASS = 60,
FAIL = 0
};
const char* getGradeLevel(int score) {
if (score >= EXCELLENT) return "优秀";
if (score >= GOOD) return "良好";
if (score >= AVERAGE) return "中等";
if (score >= PASS) return "及格";
return "不及格";
}
int main() {
int studentCount;
int scores[MAX_STUDENTS];
int passCount = 0;
double totalScore = 0;
printf("请输入学生人数 (最多 %d): ", MAX_STUDENTS);
scanf("%d", &studentCount);
if (studentCount > MAX_STUDENTS || studentCount <= 0) {
printf("学生人数无效!\n");
return 1;
}
// 输入成绩
for (int i = 0; i < studentCount; i++) {
printf("请输入第 %d 个学生的成绩: ", i + 1);
scanf("%d", &scores[i]);
totalScore += scores[i];
if (scores[i] >= PASS_SCORE) {
passCount++;
}
}
// 统计结果
double average = totalScore / studentCount;
double passRate = (double)passCount / studentCount * 100;
printf("\n=== 统计结果 ===\n");
printf("总人数: %d\n", studentCount);
printf("平均分: %.2f\n", average);
printf("及格人数: %d\n", passCount);
printf("及格率: %.2f%%\n", passRate);
// 显示每个学生的等级
printf("\n=== 成绩等级 ===\n");
for (int i = 0; i < studentCount; i++) {
printf("学生 %d: %d 分 - %s\n",
i + 1, scores[i], getGradeLevel(scores[i]));
}
return 0;
}📚 最佳实践
1. 变量命名建议
c
// ✅ 好的命名
int studentAge;
int totalScore;
double averagePrice;
// ❌ 不好的命名
int a;
int x123;
int temp;2. 常量使用建议
c
// ✅ 使用常量代替魔法数字
#define MAX_BUFFER_SIZE 1024
const int RETRY_COUNT = 3;
char buffer[MAX_BUFFER_SIZE];
for (int i = 0; i < RETRY_COUNT; i++) {
// ...
}
// ❌ 直接使用数字(魔法数字)
char buffer[1024];
for (int i = 0; i < 3; i++) {
// ...
}3. 选择合适的常量类型
c
// 简单的数值常量 → 使用 #define
#define BUFFER_SIZE 256
// 需要类型安全 → 使用 const
const double TAX_RATE = 0.08;
// 相关的整型常量 → 使用 enum
enum Status { SUCCESS, FAILURE, PENDING };4. 初始化变量
c
// ✅ 声明时初始化
int count = 0;
double price = 0.0;
char *name = NULL;
// ❌ 使用未初始化的变量
int count;
printf("%d", count); // 未定义行为!💡 常见错误
错误 1:修改常量
c
const int MAX = 100;
MAX = 200; // 编译错误!错误 2:宏定义缺少括号
c
#define DOUBLE(x) x + x
int result = DOUBLE(3) * 2; // 结果是 8,不是 12!
// 正确写法
#define DOUBLE(x) ((x) + (x))错误 3:变量作用域混淆
c
int x = 10; // 全局变量
void func() {
int x = 20; // 局部变量,隐藏全局变量
printf("%d", x); // 输出 20
}📖 小结
变量要点
- 变量用于存储可变的数据
- 必须先声明后使用
- 遵循作用域规则
- 使用有意义的命名
常量要点
- 字面量:直接写在代码中的值
- #define:预处理宏,无类型检查
- const:类型安全的常量,推荐使用
- enum:定义相关的整型常量集合
选择建议
| 场景 | 推荐方式 |
|---|---|
| 简单数值常量 | #define 或 const |
| 需要类型安全 | const |
| 相关整型常量 | enum |
| 条件编译 | #define |
| 宏函数 | #define(谨慎使用) |
下一步:学习 C 语言运算符,了解如何对变量和常量进行各种运算操作。