今天用 6 个小任务 学会变量与基本类型:
变量、类型、变量名 (5 分钟扫一遍)
任务 1: 打印年龄 —— int、声明、printf
任务 2: 输入出生年份算年龄 —— scanf
任务 3: 温度转换 —— double、小数格式
任务 4: 找零计算 —— / 与 %
任务 5: 字符与编码 —— char
任务 6: 交换两个数 —— 临时变量与赋值
语法补全 + 输入输出一览 + 课堂编码
先想一个问题: 求平均分——总分算出来之后, 在除以人数之前, 放在哪里?
程序需要一种临时存储数据的地方, 否则中间结果算完就丢
变量: 程序执行过程中, 用来临时存储数据的有名字的单元
height 的"盒子", 里面装着 175类型: 每个变量都有类型, 用来说明盒子里装什么种类的数据——本课常用 int、float、double、char, 接下来随用随讲
变量名: 命名规则见后面「语法补全: 标识符与关键字」
概念扫完, 动手写第一个任务:
任务: 把自己的年龄存进一个变量, 打印出来
样例:
我今年 19 岁
提示:
整数用什么类型? 打印整数用哪个占位符?
声明时就把值放进去——试试 int age = 19;
参考实现: 声明、初始化、打印三步:
#include <stdio.h>
int main(void)
{
int age = 19; /* 声明 + 初始化 */
printf("我今年 %d 岁\n", age);
return 0;
}
声明: int age; 告诉编译器"留一个装整数的盒子"
初始化: 声明的同时放值 = 19; 不初始化就读取, 可能得到垃圾值
printf 里用 %d 对应 int——占位符要和变量类型一致
= 是赋值 (把右边存进左边), 不是数学的"相等"
会打印了, 下一步让程序读入数据:
任务: 输入出生年份, 计算并输出今年的年龄
样例:
请输入出生年份: 2007
今年 19 岁
提示: 用 scanf 读入, 别漏了 &; 年龄 = 2026 - birth_year
参考实现: 读入、计算、输出三步:
/* age.c: 计算年龄 */
#include <stdio.h>
int main(void) {
int birth_year;
printf("请输入出生年份: ");
scanf("%d", &birth_year);
int age = 2026 - birth_year;
printf("今年 %d 岁\n", age);
return 0;
}
scanf("%d", &birth_year): %d 读整数, & 取地址——漏掉 & 程序会出错
2026 - birth_year 先算出值, 再存进 age——赋值右边可以是表达式
2026 是常量, 不占变量盒子
C99 起变量可以随用随声明 (int age 写在中间也可以)
整数会了, 换成带小数的温度:
任务: 输入摄氏温度, 输出对应的华氏温度: \(F = \frac{9}{5} C + 32\)
样例:
请输入摄氏温度: 37.0
37.0 C = 98.6 F
提示: 温度会带小数——用什么类型? 输出保留一位小数: %.1f
小心 9 / 5: 两个整数相除会截断
参考实现: 用 double 存温度, 用 9.0/5 做浮点除法:
/* temp.c: 摄氏转华氏 */
#include <stdio.h>
int main(void) {
double c, f;
printf("请输入摄氏温度: ");
scanf("%lf", &c);
f = 9.0 / 5 * c + 32;
printf("%.1f C = %.1f F\n", c, f);
return 0;
}
double 存小数; 声明两个可以写在一起 double c, f;
scanf 读 double 用 %lf; printf 打印 double 用 %f (写 %.1f 保留一位小数)
9.0 / 5 而不是 9 / 5: 整数除法得 1, 浮点除法才是 1.8
浮点数是近似存储: 0.1 可能是 0.099999…——比较两个浮点数要格外小心
小数会了, 再看整数除法与取余:
任务: 输入金额 (整数元), 输出需要各种面额多少张: 100、50、20、10、5、1
样例:
请输入金额 (元): 386
100元: 3 张
50元: 1 张
20元: 1 张
10元: 1 张
5元: 1 张
1元: 1 张
提示: / 求"有几个", % 求"剩多少"——两个运算符配合, 把金额一层层拆开
参考实现: 用 / 和 % 逐层拆金额:
/* change.c: 找零计算 */
#include <stdio.h>
int main(void) {
int amount;
printf("请输入金额 (元): ");
scanf("%d", &amount);
printf("100元: %d 张\n", amount / 100);
amount = amount % 100;
printf(" 50元: %d 张\n", amount / 50);
amount = amount % 50;
printf(" 20元: %d 张\n", amount / 20);
amount = amount % 20;
printf(" 10元: %d 张\n", amount / 10);
amount = amount % 10;
printf(" 5元: %d 张\n", amount / 5);
amount = amount % 5;
printf(" 1元: %d 张\n", amount);
return 0;
}
amount / 100: 整数除法, 得到"有几个 100"
amount % 100: 取余, 得到"剩下的钱"——再拿剩下的继续拆
amount = amount % 100;: 新值覆盖旧值, 同一个变量反复赋值
/ 与 % 只对整数有意义; 浮点数不能取余
整数运算会了, 最后看字符:
任务: 存一个大写字母, 输出它的 ASCII 编码; 再把编码存成整数, 输出对应的字符
样例:
M 的编码是 77
编码 77 对应 M
提示:
字符用 char, 值写在单引号里: 'M'
同一个值, 用 %c 打印是字符, 用 %d 打印是编码——两种都试试
参考实现: 同一个值, 两种占位符两种视角:
#include <stdio.h>
int main(void)
{
char ch = 'M';
int code = 77;
printf("%c 的编码是 %d\n", ch, ch);
printf("编码 %d 对应 %c\n", code, code);
return 0;
}
char 存的其实是字符的编码 (0~127 的整数): 'a'=97, 'A'=65, '0'=48
单引号是字符 ('M'), 双引号是字符串 ("M")——字符串后面再讲
%c 按字符打印, %d 按整数打印; 同一个 ch 两种视角
字符本质是整数, 可以参与运算 (如 'a' - 'A' 等于 32)——常用编码见下一页 ASCII 表
任务: 读入两个整数 a、b, 交换它们的值后输出
样例:
输入: 3 5
输出: a=5 b=3
提示: 直接写 a = b; b = a; 会怎样? 试试看, 再用临时变量修正
#include <stdio.h>
int main(void)
{
int a, b, t;
scanf("%d %d", &a, &b);
t = a; /* 先把 a 存起来 */
a = b;
b = t;
printf("a=%d b=%d\n", a, b);
return 0;
}
直接 a=b; b=a;: 第一步就把 a 原值覆盖, 两次都变成 b 的值
用临时变量 t 保存一个值, 再交换——这就是赋值"覆盖"特性的应用
顺序: 先存 a → 把 b 给 a → 把 t (原 a) 给 b
三行交换是后面排序、链表操作的基本动作
ASCII: 常用字符的编码表 (0~127)。记住三组就够用:
| 字符 | 编码 | 字符 | 编码 | 字符 | 编码 |
|---|---|---|---|---|---|
空格 ' ' |
32 | '0' |
48 | 'A' |
65 |
'!' |
33 | '1' |
49 | 'B' |
66 |
',' |
44 | '9' |
57 | 'Z' |
90 |
'.' |
46 | 'a' |
97 | ||
'?' |
63 | 'z' |
122 |
数字字符: '0'~'9' 连续 → 48~57; 想得到数值要 ch - '0'
大写字母: 'A'~'Z' 连续 → 65~90; 小写: 'a'~'z' 连续 → 97~122
小写比大写大 32: 'a' - 'A' == 32——后面做大小写转换会用到
换行 \n 的编码是 10; 控制字符不可打印, 用 %c 打印会看到怪符号
编码表备查; 回到语法, 先看名字怎么起:
标识符: 变量、函数等对象的名字
由字母、数字、下划线组成; 不能以数字开头 (10times 非法)
C 是大小写敏感的: job、Job、jOb 是三个不同的名字
不能用关键字 (int、return、if、while …); 建议避免以下划线开头
起名要见名知义: birth_year 比 a 好; 风格统一
名字会起了, 再看变量怎么声明、初始化、赋值:
int height; /* 声明: 留一个装整数的盒子, 但还没放值 */
int height = 8; /* 初始化: 声明的同时放入 8 */
height = 10; /* 赋值: 用新值覆盖旧值 */
= 是赋值不是"相等"; 赋值前必须先声明
变量会用了, 还要会读写——四种常用类型的占位符:
| 类型 | printf 占位符 | scanf 占位符 | 例子 |
|---|---|---|---|
int |
%d |
%d |
printf("%d", n); / scanf("%d", &n); |
float |
%f |
%f |
printf("%.1f", f); / scanf("%f", &f); |
double |
%f |
%lf |
printf("%.2f", d); / scanf("%lf", &d); |
char |
%c |
%c |
printf("%c", ch); / scanf(" %c", &ch); |
scanf 的参数要加 & (取地址); printf 不用
double: printf 用 %f, scanf 用 %lf——最容易混的一处
%.1f / %.2f: 保留 1 位/2 位小数
%c 前加空格 ( %c) 可跳过遗留的空白/换行
轮到你了: 把课程演示变成自己的程序——现场完成 (10 分钟):
提示:
变量: 需要什么类型? (double? int?)
输入: scanf("%lf", &c); —— 不要遗漏 &
输出: printf("%.1f\n", f);
卡住了? 温度转换看任务 3; 交换两个数先自己想, 再问助教——今天每个人的程序都要能跑起来
程序跑通后, 用四道题检验概念:
int x; 与初始化 int x = 5; 有什么区别? 只声明不初始化就用, 可能发生什么?
int a = 7, b = 2; printf("%d %f\n", a / b, a / 2.0); 输出什么? 为什么?
int 2age = 19; ② scanf("%d", age); ③ char c = "M";