变量与数据类型 — 存储你的数据
C语言学习教程
变量与数据类型 — 存储你的数据
🌟 课前故事:你的储物柜
假设你走进学校体育馆,教练递给你一把更衣柜的钥匙,说:“这是你的柜子,你可以把运动服、球鞋、水壶放进去。需要的时候随时来取。”
这个”储物柜”就是C语言中的变量。
- 每个柜子有一个编号(变量名),你靠编号找到它
- 柜子有固定大小(数据类型),球鞋柜和水壶柜大小不同
- 柜子里放着你的东西(变量的值),随时可以换
没有变量,程序就像一个人没有记忆——上一秒算出来的结果,下一秒就忘了。有了变量,程序才能”记住”信息、处理数据、做出判断。
今天,我们就来学习如何给程序”装上记忆”。
📖 概念讲解:变量三要素
什么是变量?
变量(Variable)是内存中的一块命名存储空间,用来存放程序运行中需要用到的数据。
每个变量有三个核心属性:
┌──────────────────────────────────────────────┐
│ 变量 │
│ │
│ ① 变量名 ② 数据类型 ③ 变量的值 │
│ (name) (type) (value) │
│ │
│ 例子: │
│ int age = 18; │
│ ↑ ↑ ↑ │
│ 类型 名 值 │
└──────────────────────────────────────────────┘
为什么需要变量?
- 存储数据:程序需要记住用户的输入、计算结果、中间状态
- 重复使用:一次存储,多次读取,不用每次重新计算
- 可修改性:变量的值可以动态改变,适应不同场景
- 代码可读:
int studentCount = 30;比直接写30更容易理解
什么时候用变量?
任何需要”记住”数据的地方:
- 用户输入的名字、年龄、成绩
- 计算过程的中间结果
- 循环计数
- 程序状态(开/关、真/假)
📊 变量在内存中长什么样?(可视化)
计算机内存(简化视图)
┌──────────────────────────────────────────────┐
│ 地址: 0x1000 │
│ ┌────────────┬────────────┬────────────┐ │
│ │ age │ score │ grade │ │
│ │ (int) │ (float) │ (char) │ │
│ │ 4字节 │ 4字节 │ 1字节 │ │
│ │ ┌──────┐ │ ┌──────┐ │ ┌──┐ │ │
│ │ │ 18 │ │ │ 95.5 │ │ │A │ │ │
│ │ └──────┘ │ └──────┘ │ └──┘ │ │
│ └────────────┴────────────┴────────────┘ │
│ │
│ 声明:int age = 18; │
│ 意思:在内存中找块地方(4字节), │
│ 命名为 "age",把 18 放进去 │
└──────────────────────────────────────────────┘
当你写 int age = 18; 时,计算机做了三件事:
- 分配空间:在内存中预留4个字节(因为int占4字节)
- 贴标签:给这块空间起名叫
age - 写数据:把数字
18的二进制形式存入这片空间
以后每当你使用 age 这个名字,计算机就知道去那个位置读取或修改数据。
📊 基本数据类型详解
| 类型 | 关键字 | 占内存 | 大致范围 | 用途 | 示例 |
|---|---|---|---|---|---|
| 整数 | int | 4 字节 | -2,147,483,648 ~ 2,147,483,647 | 年龄、人数、计数 | int age = 18; |
| 小数(单精度) | float | 4 字节 | ~7位有效数字 | 身高、成绩、价格 | float pi = 3.14f; |
| 小数(双精度) | double | 8 字节 | ~15位有效数字 | 科学计算、高精度金额 | double e = 2.71828; |
| 字符 | char | 1 字节 | -128 ~ 127(ASCII) | 单个字母、符号 | char grade = 'A'; |
为什么有这么多类型?
问题:为什么不用一种类型装所有东西?
答案:内存是有限的,按需分配最省空间
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 年龄 18 │ │ 圆周率 │ │ 等级 A │
│ │ │ 3.14159 │ │ │
│ 用 int │ │ 用 float │ │ 用 char │
│ (4字节) │ │ (4字节) │ │ (1字节) │
└──────────┘ └──────────┘ └──────────┘
如果全用 double (8字节):
年龄占8字节(太浪费!)
等级占8字节(太浪费!)
int — 整数类型
int age = 18; // 正整数
int temperature = -5; // 负整数
int zero = 0; // 零
int big = 2147483647; // int 能装的最大值
// int overflow = 2147483648; // 超出范围,结果不可预料!
int 的小秘密——溢出:
int max_value = 2147483647; // int 的最大值
printf("最大值: %d\n", max_value);
max_value = max_value + 1; // 加1
printf("溢出后: %d\n", max_value); // 变成 -2147483648!(回环)
就像汽车的里程表——达到最大值后,又从头开始。
float 和 double — 浮点数类型
float pi = 3.14159f; // f 后缀表示这是 float
float score = 95.5f; // 考试分数
double e = 2.718281828; // double 不需要后缀
double g = 9.80665; // 重力加速度
// 科学计数法
float tiny = 1.5e-3; // 0.0015
double huge = 3.0e8; // 300000000(光速)
float vs double 怎么选?
float f = 1.0f / 3.0f;
double d = 1.0 / 3.0;
printf("float: %.10f\n", f); // 0.3333333433 ← 有误差
printf("double: %.10f\n", d); // 0.3333333333 ← 更精确
- 普通场景用
float(省内存) - 需要高精度用
double(比如金融计算) - 初学阶段:不确定就用
double,更安全
char — 字符类型
char letter = 'A'; // 大写字母
char digit = '7'; // 数字字符(注意:这是字符'7',不是数字7)
char symbol = '@'; // 符号
char newline = '\n'; // 特殊字符(转义字符也可以用char存储)
字符 vs 数字:
char ch = 'A';
printf("字符: %c\n", ch); // 输出:A
printf("ASCII: %d\n", ch); // 输出:65(A对应的ASCII码)
// 每个字符在计算机中存的是一个数字(ASCII码)
// 'A'=65, 'B'=66, '0'=48, 'a'=97
| 字符 | ASCII码 | 字符 | ASCII码 |
|---|---|---|---|
| ’0’ | 48 | ’A’ | 65 |
| ’1’ | 49 | ’B’ | 66 |
| ’9’ | 57 | ’Z’ | 90 |
| ’ ‘ | 32 | ’a’ | 97 |
💻 声明与初始化
方式1:先声明,后赋值
#include <stdio.h>
int main() {
int age; // 声明:告诉编译器"我需要一个叫age的int变量"
age = 18; // 赋值:把18放进去
float score; // 声明
score = 95.5f; // 赋值
printf("Age: %d, Score: %.1f\n", age, score);
return 0;
}
注意: 声明但未赋值的变量,里面是随机值(垃圾值)!
int x; // x 的值是随机的!
printf("%d\n", x); // 可能输出任何数字,比如 -858993460
方式2:声明的同时初始化(推荐)
#include <stdio.h>
int main() {
int age = 18; // 声明并初始化
float score = 95.5f; // 声明并初始化
char grade = 'A'; // 声明并初始化
printf("年龄:%d,成绩:%.1f,等级:%c\n", age, score, grade);
return 0;
}
推荐理由: 一步到位,避免忘记赋值导致的”垃圾值”问题。
方式3:一次声明多个变量
#include <stdio.h>
int main() {
// 同类型变量可以一次声明多个
int x = 1, y = 2, z = 3;
// 也可以声明时不初始化(不推荐)
int a, b, c;
a = 10;
b = 20;
c = 30;
printf("x=%d, y=%d, z=%d\n", x, y, z);
printf("a=%d, b=%d, c=%d\n", a, b, c);
return 0;
}
💻 printf 格式占位符大全
printf 用占位符(也叫格式说明符)来表示”这里要插入一个变量的值”。
| 占位符 | 对应类型 | 含义 | 示例 |
|---|---|---|---|
%d | int | 十进制整数 | printf("%d", 42) |
%f | float / double | 浮点数(默认6位小数) | printf("%f", 3.14) |
%.2f | float / double | 保留2位小数 | printf("%.2f", 3.14) |
%c | char | 单个字符 | printf("%c", 'A') |
%s | char[] (字符串) | 字符串 | printf("%s", "Hello") |
%x | int | 十六进制整数 | printf("%x", 255) — 输出 ff |
%% | (无) | 百分号本身 | printf("100%%") — 输出 100% |
综合示例
#include <stdio.h>
int main() {
int age = 20;
float height = 1.75f;
double pi = 3.14159265358979;
char grade = 'A';
char name[] = "小明";
printf("我叫%s,今年%d岁\n", name, age);
printf("身高%.2f米,成绩等级%c\n", height, grade);
printf("圆周率:%.2f(保留2位)\n", pi);
printf("圆周率:%.10f(保留10位)\n", pi);
printf("年龄的十六进制表示:%x\n", age);
printf("正确率:100%%\n"); // 输出百分号
return 0;
}
输出:
我叫小明,今年20岁
身高1.75米,成绩等级A
圆周率:3.14(保留2位)
圆周率:3.1415926536(保留10位)
年龄的十六进制表示:14
正确率:100%
格式控制的进阶用法
#include <stdio.h>
int main() {
int n = 42;
float f = 3.14159f;
// 宽度控制
printf("|%d|\n", n); // |42|
printf("|%5d|\n", n); // | 42| (宽度5,右对齐)
printf("|%-5d|\n", n); // |42 | (宽度5,左对齐)
printf("|%05d|\n", n); // |00042| (宽度5,前导零填充)
// 浮点数控制
printf("|%f|\n", f); // |3.141590| (默认6位)
printf("|%.2f|\n", f); // |3.14| (保留2位)
printf("|%8.2f|\n", f); // | 3.14| (总宽8,2位小数)
printf("|%-8.2f|\n", f); // |3.14 | (左对齐)
return 0;
}
记忆口诀:
%d→ decimal(十进制整数)%f→ float(浮点数)%c→ char(字符)%s→ string(字符串)
💻 变量命名规则
合法命名规则
- 只能包含:字母(A-Z, a-z)、数字(0-9)、下划线(_)
- 必须以字母或下划线开头(不能数字开头)
- 不能使用C语言的关键字(保留字)
- 区分大小写:
age、Age、AGE是三个不同的变量
命名示例
// ✅ 合法的变量名
int score; // 小写字母
int player1; // 字母+数字
int max_value; // 下划线分隔(蛇形命名法,C语言主流)
int _count; // 下划线开头(可行但不推荐)
int numberOfStudents; // 驼峰命名法(也可行)
// ❌ 不合法的变量名
int 2player; // 不能以数字开头!
int if; // if 是C语言关键字,不能用!
int my score; // 不能有空格!
int my-score; // 不能有连字符(-会被当成减号)!
C语言关键字(不能用作变量名)
auto break case char const continue
default do double else enum extern
float for goto if int long
register return short signed sizeof static
struct switch typedef union unsigned void
volatile while
命名习惯建议
// 🏆 推荐:有意义的英文名
int studentAge = 18;
float examScore = 95.5f;
int itemCount = 10;
// 😕 不推荐:无意义的单个字母(除了循环变量i、j、k)
int a = 18; // a 代表什么?
float b = 95.5f; // b 又代表什么?
// 😅 可行但最好避免:拼音
int nianLing = 18; // 能理解,但不专业
💻 变量的值可以改变
变量之所以叫”变”量,就是因为它的值可以改变。
#include <stdio.h>
int main() {
int x = 10; // x 初始值为 10
printf("初始值: x = %d\n", x); // 10
x = 20; // 直接赋值新值
printf("修改后: x = %d\n", x); // 20
x = x + 5; // 在自身基础上加 5
printf("加5后: x = %d\n", x); // 25
x = x * 2; // 翻倍
printf("翻倍后: x = %d\n", x); // 50
x = x - 30; // 减 30
printf("减30后: x = %d\n", x); // 20
// 总结:每次赋值,"旧值"被覆盖,"新值"取而代之
return 0;
}
关键理解: 赋值操作 = 是”覆盖”而不是”累加”。x = 20 的意思是”把20放进去,原来有什么不管了”。
💻 综合示例:一个完整的个人信息程序
#include <stdio.h>
int main() {
// ---- 个人信息变量 ----
char name[20] = "张三"; // 姓名(字符数组,即字符串)
int age = 20; // 年龄
float height = 1.78f; // 身高(米)
double weight = 70.5; // 体重(公斤)
char bloodType = 'O'; // 血型
int studentId = 20240001; // 学号
// ---- 输出个人信息 ----
printf("========================================\n");
printf(" 个人信息卡片 \n");
printf("========================================\n");
printf(" 姓名:%s\n", name);
printf(" 学号:%d\n", studentId);
printf(" 年龄:%d 岁\n", age);
printf(" 身高:%.2f 米\n", height);
printf(" 体重:%.1f 公斤\n", weight);
printf(" 血型:%c 型\n", bloodType);
printf("========================================\n");
// ---- 修改变量的值(模拟"过了一年") ----
age = age + 1; // 年龄加1岁
height = 1.79f; // 身高长了一厘米
weight = 71.0; // 体重变了一点点
printf("\n --- 一年后的信息 ---\n\n");
printf(" 年龄:%d 岁\n", age);
printf(" 身高:%.2f 米\n", height);
printf(" 体重:%.1f 公斤\n", weight);
printf("========================================\n");
return 0;
}
从这个例子你学到:
- 不同类型的数据用不同类型的变量存储
- 一个程序可以有多个变量
- 变量的值可以随时修改
- 格式化输出使信息排列整齐
⚠️ 常见错误(5个经典”坑”)
错误1:类型和占位符不匹配
// ❌ 错误代码
int age = 18;
float score = 95.5f;
printf("年龄:%f\n", age); // 用 %f 输出 int!输出乱码
printf("成绩:%d\n", score); // 用 %d 输出 float!输出乱码
// 编译器可能不报错,但输出是错的——这叫"未定义行为"
// ✅ 正确代码
int age = 18;
float score = 95.5f;
printf("年龄:%d\n", age); // %d 配 int
printf("成绩:%.1f\n", score); // %f 配 float
规则: %d → int, %f → float/double, %c → char。谁配谁,不能乱!
错误2:整数赋值小数
// ❌ 错误代码
int price = 9.99; // 小数赋值给int,被截断为9!
printf("价格:%d\n", price); // 输出:9,丢失了 .99
// ✅ 正确代码
float price = 9.99f; // 用 float 存小数
printf("价格:%.2f\n", price); // 输出:9.99
规则: 要存小数,就用 float 或 double,别用 int。
错误3:未初始化就使用变量
// ❌ 错误代码
int x; // 声明但未初始化
printf("%d\n", x); // x 的值是随机的垃圾值!结果不可预料
// ✅ 正确代码
int x = 0; // 初始化!
printf("%d\n", x); // 输出确定的值:0
规则: 声明变量的同时,给它一个初始值。不确定是什么就写 = 0。
错误4:char 用双引号
// ❌ 错误代码
char grade = "A"; // 双引号表示字符串(多个字符),不是单个字符!
// 编译器报错:incompatible types when assigning to type 'char'
// ✅ 正确代码
char grade = 'A'; // 单引号表示单个字符
char name[] = "A"; // 双引号表示字符串(char数组)
规则: 单个字符用单引号 'A',字符串用双引号 "Hello"。
错误5:float 字面量忘写 f
// ❌ 不是错误,但是一个"疏忽"
float pi = 3.14; // 3.14 默认是 double 类型
// 编译器会做一个隐式转换,可能有警告
// ✅ 正确写法
float pi = 3.14f; // 明确告诉编译器:这是 float
double e = 2.71828; // double 不需要后缀
规则: float 类型的字面量加 f 或 F 后缀,double 不用。
💡 练习建议
初级练习
- 个人信息:声明变量存储你的姓名、年龄、身高,然后打印出来
- 四则运算:声明两个
int变量,输出它们的和、差、积、商 - 购物小票:声明变量存储商品名、单价、数量,计算总价并输出
中级练习
- 变量交换:有两个变量
a=10, b=20,不用直接赋值,交换它们的值 - 格式化对齐:用宽度控制
%5d、%-5d打印一个整齐的表格 - 刻意实验:给 int 赋一个超大的值,看看溢出后变成什么
进阶思考
- ASCII码探索:打印所有大写字母和它们的ASCII码(提示:字符可以用
%d输出) - 精度实验:用 float 和 double 分别计算
1.0/3.0,输出到第10位小数,观察差异 - sizeof探索:用
sizeof(int)、sizeof(float)查看每种类型在你这台电脑上占多少字节
📝 要点速查清单
- 变量 = 名字(变量名)+ 类型(数据类型)+ 值(存储的数据)
- C语言基本数据类型:
int(整数)、float(单精度小数)、double(双精度小数)、char(字符) -
int占4字节,float占4字节,double占8字节,char占1字节 - 声明变量的同时初始化:
int age = 18;(推荐做法) -
printf输出的占位符:%d→int,%f→float,%c→char,%s→字符串 - 变量命名:字母/下划线开头,只用字母数字下划线,不用关键字,区分大小写
- 变量的值可以随时改变:
x = 20;覆盖原来的值 - 赋值给不兼容的类型会截断或出错(如
int x = 3.14;→ 结果是3) - 未初始化的变量包含随机”垃圾值”——必须初始化!
-
float字面量要加f后缀:3.14f;char用单引号'A'
🔗 相关主题
- 上一课:第一个C程序 — Hello World 详解
- 继续学习:运算符 — 加减乘除与比较 — 用运算符操作变量
- 继续学习:输入输出 — 用 scanf 读取用户输入到变量
- 继续学习:常量与const — 有些”变量”不应该变
- 参考:C语言基本数据类型详解