Skip to content

C 语言变量与常量 📦

🎯 概述

变量和常量是 C 语言程序的基本组成部分。变量用于存储可以改变的数据,而常量则表示程序运行期间值不会改变的数据。理解它们的使用方法是学习 C 语言的重要基础。

📝 什么是变量?

变量的概念

变量是内存中用于存储数据的命名空间。可以把变量想象成一个带标签的盒子,用来存放不同类型的数据。

变量的三要素

  1. 变量名:标识符,用于引用变量
  2. 数据类型:决定变量能存储什么样的数据
  3. 变量值:存储在变量中的实际数据

变量声明

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;

变量命名规则

允许的命名规则:

  • 由字母、数字、下划线组成
  • 必须以字母或下划线开头
  • 区分大小写(ageAge 是不同的变量)
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:定义相关的整型常量集合

选择建议

场景推荐方式
简单数值常量#defineconst
需要类型安全const
相关整型常量enum
条件编译#define
宏函数#define(谨慎使用)

下一步:学习 C 语言运算符,了解如何对变量和常量进行各种运算操作。