CC语言通关
第03课 · 顺序程序设计
教材对照
第3章 · 书页 37–82

第03课 · 顺序程序设计

变量与数据类型、运算符、自增自减、printf/scanf、字符输入输出

9 个小节 40 段代码 建议 2h
教材依据第3章《最简单的C程序设计——顺序程序设计》书页 p.37–82
本课覆盖:教材第3章正文 + 书末习题(p.80–82)。标「教材 p.X」= 教材段落总结;「例题」= 教材例题;「习题」= 书末题目;「本课补充」= 非教材原文。
在全书对照表中查看 →

教材《C程序设计》第五版(谭浩强)第3章,书页 37–82,共 46 页|建议 2h
上一课:第2课《算法——程序的灵魂》|本课开始,你写的程序第一次能"吃"键盘输入


课前一句话

📖 本课补充 · 非教材原文

第 2 章你学会了"把步骤想清楚",但程序还只会 printf 打一串写死的字。这一课给程序装上两样东西:能存数的柜子(变量 + 数据类型)和能进能出的门(scanf / printf / getchar / putchar)。学完你就能写"键盘输入 → 计算 → 屏幕输出"的完整程序:温度换算、方程求根、算利息、字符加密。这一章是全书的语法地基,第 4~10 章所有变量、运算、输入输出都从这里长出来。


一、先补地基:本章要解决的问题

📖 本课补充 · 非教材原文

第 2 课写 5! 时,t = t * i 里的 t 为什么能变?i <= 5 凭什么能判断?当时是照猫画虎,今天要把这只"猫"拆开。更实际的困境:算 c=(5/9)(f-32),写死 f=64.0 只能算一个温度,换个温度就得改程序重编译。程序如果不能接收外部数据,就只是一台只会唱一首歌的八音盒。

本章解决三件事:数据放哪儿(变量、常量、数据类型)、数据怎么算(运算符、表达式、优先级、类型转换)、数据怎么进出(printf/scanf/putchar/getchar)。

贯穿全课的比喻:快递驿站

把内存想成一间快递驿站,屋里有一排排柜子:

驿站C 语言说明
带名牌的柜格变量有名字、有位置、能放货、能换货
柜格规格数据类型决定能装多大、装整数还是小数
印在包裹上的数字常量没柜格、没名字,就是一个值
柜门上的便利贴符号常量 #define编译前被撕掉换成真值,撕完就不存在
装货 / 换货赋值 =新货进去旧货被顶掉,不是叠加
货太大塞爆柜子溢出超出范围,结果变成莫名其妙的负数
大件硬塞小柜,多的切掉截断高字节被丢弃,数值失真
出货单printf按单据格式把货写出来
收货单scanf按单据格式把键盘的货装进柜格
柜格门牌号& 取地址符快递员得知道送哪个格子
门口暂存货架输入缓冲区字符先排队,按回车才一起进屋

二、知识点讲解

3.1 顺序程序设计举例

📖 教材 p.37–38 · 正文总结

【一句话】 顺序结构就是"从上到下、一条接一条、不拐弯、不回头"。

教材开篇两例(例 3.1 温度转换、例 3.2 算利息)不为教新语法,只为说明:写程序 = 想算法(第2章)+ 用 C 语法表示出来(本章)。骨架都是:定义变量 → 赋值计算 → printf 输出。例 3.1 的 N-S 图只有三框(输入 f → c=5/9(f-32) → 输出 c),竖着摞起来就是顺序结构。

考点顺序结构:程序按书写顺序逐条执行,每条语句执行且只执行一次(无分支、无循环时)。


3.2 数据的表现形式及其运算

📖 教材 p.39–50 · 正文总结

3.2.1 常量和变量

📖 教材 p.39–41 · 正文总结

【一句话】 数据只有两种活法:不能变的叫常量,能变的叫变量。 【拆名字】 constant=恒定 → 常量;variable=可变的 → 变量;identifier=identify+-er → 标识符(给对象起的名字)。

常量 5 类:

1. 整型常量:1000、12345、0、-345。

2. 实型常量(两种写法):

写法例子
十进制小数123.456、0.345、-56.79、0.0
指数形式12.34e3、-346.87e-25、0.145E-25

指数形式两条铁律:e/E 前必须有数字(不能写 e4),后面必须是整数(不能写 12e2.5)。12.34e3 = 12340,不是 12.34×3。

3. 字符常量(两种):

  • 普通字符:单撇号括起来的一个字符,如 'a'、'Z'、'3'、'?'。单撇号只是界限符;'a' 与 'A' 不同;不能写 'ab'、'12'。
  • 转义字符:以 \ 开头,表示打不出、看不见的控制字符(表 3.1)。
转义作用转义作用
\n换行\\输出反斜线 \
\t水平制表(8 列)\'输出单撇号 '
\r回车到本行开头\"输出双撇号 "
\b退格\?输出问号 ?
\f换页\a警告(响铃)
\v垂直制表\0 或 \ooo / \xhh八进制 / 十六进制码对应字符

'\101' 八进制 101 = 十进制 65 = 'A';'\x41' 十六进制 41 = 65 = 'A'。

易错'\n' 是一个字符;要输出反斜线必须写 '\\'。

4. 字符串常量:双撇号括起来的若干字符,如 "boy"、"CHINA"。双撇号内可多个字符,单撇号内只能一个;不能写 'CHINA'、'boy'。

5. 符号常量:#define PI 3.1416(行末没有分号)。编译前预处理器把所有 PI 原样替换成 3.1416,替换完名字就不存在。好处:见名知义、一改全改。

易错符号常量不占内存、不能赋值(PI=3.14; 错);习惯全大写。

变量三条规矩:

  1. 先定义,后使用(定义时指明名字和类型);
  2. 变量名 ≠ 变量值(名字是柜格名牌,值是柜格里的货);
  3. 变量名实际上代表一个存储地址——编译连接时系统分配地址,取值就是"按名字找地址再读数据"。

常变量(C99):const int a = 3; 有类型、占存储单元,但值不能再改。

对比符号常量 #define PI 3.1415926常变量 const float pi = 3.1415926;
处理阶段预处理,纯字符替换编译,是真正的变量
占内存不占,替换完消失占,有类型有值
能否改值不能不能

教材原话:常变量是"有名字的不变量",常量是"没有名字的不变量"。

标识符:只能由字母、数字、下划线组成,第 1 个字符必须是字母或下划线。合法:sum、average、Class、day、Student_name、lotus_123、li_ling。非法:M.D.John(点号)、#33(#)、3D64(数字开头)、a>b(运算符)。

易错C 区分大小写:sum 与 SUM、Class 与 class 都是不同变量。


3.2.2 数据类型

📖 教材 p.42–43 · 正文总结

【一句话】 类型 = 对数据分配存储单元的安排:占多少字节 + 数据怎么存。 【拆名字】 int=integer 整数;char=character 字符;float=浮点(小数点可浮动);double=双倍精度。 【驿站比喻】 类型就是柜格规格:1 字节小抽屉、4 字节中柜、8 字节大柜,而且"码放方式"不同(整数补码平放,小数指数分层)。

为什么分类型? 数学里 1/3 是精确的,但存储单元是有限字节,装不下无穷小数。printf("%f", 1.0/3.0) 只能给 0.333333。计算机算的是工程近似值,不是数学真理。

text
数据类型
├─ 基本类型:整型(int/short/long/long long/char)、
│            浮点型(float/double/long double)、bool(C99)、枚举 enum
├─ 空类型 void
└─ 派生类型:指针 *、数组 [ ]、结构体 struct、共用体 union、函数类型

教材补充名词:基本类型和枚举类型统称算术类型;算术类型 + 指针类型统称纯量类型;数组和结构体统称组合类型;共用体不属于组合类型。本章只管整型、字符型、浮点型。


3.2.3 整型数据

📖 教材 p.44–46 · 正文总结

【一句话】 整型就是"不带小数点的数",按能装的范围分 int、short、long、long long 四档。

类型写法VC++ 字节说明
基本整型int4最常用
短整型short2省空间
长整型long4VC++ 下与 int 同大
双长整型long long8C99 新增

考点C 标准不规定具体字节数,只规定 sizeof(short)≤sizeof(int)≤sizeof(long)≤sizeof(long long)。Turbo C 2.0 的 int 是 2 字节,VC++ 是 4 字节。

补码:正数补码 = 二进制本身(5 → 00000000 00000101);负数补码 = 绝对值取二进制 → 按位取反 → 加 1(-5 → 11111111 11111011)。存储单元最左一位是符号位:0 正 1 负。

表 3.2 整型数据的存储空间和取值范围(VC++):

类型字节取值范围
int4−2 147 483 648 ~ 2 147 483 647,即 −2³¹~(2³¹−1)
unsigned int40 ~ 4 294 967 295,即 0~(2³²−1)
short2−32 768 ~ 32 767,即 −2¹⁵~(2¹⁵−1)
unsigned short20 ~ 65 535,即 0~(2¹⁶−1)
long / unsigned long4同 int / unsigned int
long long8−2⁶³~(2⁶³−1),约 ±9.22×10¹⁸
unsigned long long80~(2⁶⁴−1),约 1.84×10¹⁹

记忆窍门:n 字节有符号 −2^(8n−1)~(2^(8n−1)−1),无符号 0~2^(8n)−1,正数范围翻一倍。

unsigned short price = -1; 为什么输出 65535? −1 的补码是 16 位全 1;price 无符号,最高位不代表符号,整个数按无符号读就是 65535。

易错只有整型(含字符型)能加 signed/unsigned,实型不能加。
易错无符号变量不要赋负值。
考点超出范围叫溢出,结果显然不正确(例:2 字节 int 存 32768)。


3.2.4 字符型数据

📖 教材 p.47–48 · 正文总结

【一句话】 字符在内存里存的是 ASCII 码(一个整数),所以 char 本质是1 字节的整型。

必背 6 个 ASCII 码:'A'=65,'a'=97,'0'=48,'1'=49,' '=32,'\n'=10。 核心规律:同一字母,小写比大写大 32。

C 规定用一个字节(8 位)存一个字符,字节最高位固定为 0。

char c='?'; 存的是 63。输出可选两种读法:printf("%d %c\n", c, c); → 63 ?。

易错字符 '1' 和整数 1 不是一回事:'1' 存 ASCII 码 49、占 1 字节;整数 1 按补码存、占 4 字节。1+1=2,但 '1'+'1'=49+49=98(不是 2,也不是 '2')。

表 3.3 字符型数据的存储空间和取值范围:

类型字节范围
signed char1−128 ~ 127,即 −2⁷~(2⁷−1)
unsigned char10 ~ 255,即 0~(2⁸−1)

易错存字符实际只用 0~127,最高位是 0。


3.2.5 浮点型数据

📖 教材 p.49 · 正文总结

【一句话】 浮点型是带小数点的实数,存时拆成小数部分 + 指数部分,小数点位置可以"浮动"。

为什么叫"浮点"? 3.14159 可写成 3.14159×10⁰、0.314159×10¹、31.4159×10⁻¹……值一样,小数点位置在浮动,只要同时调整指数。这就是名字的来历。

表 3.4 实型数据(VC++):

类型字节有效数字数值范围(绝对值)
float460 及 1.2×10⁻³⁸ ~ 3.4×10³⁸
double8150 及 2.3×10⁻³⁰⁸ ~ 1.7×10³⁰⁸
long double8(VC++)/16(Turbo C)15 / 19同 double / 更大

三条结论:① float 只有 6 位有效数字,double 有 15 位;② 浮点运算时 float 自动转 double 再算;③ 有限存储单元不可能精确存实数(float 最小正数 1.2×10⁻³⁸,10⁻⁴⁰ 存不了)。

考点float 的数值分三段:−3.4×10³⁸~−1.2×10⁻³⁸、0、1.2×10⁻³⁸~3.4×10³⁸,中间贴近 0 的空白叫下溢区。


3.2.6 怎样确定常量的类型

📖 教材 p.50 · 正文总结

【一句话】 常量的类型看长相:有没有小数点、有没有后缀。

长相类型
不带小数点且在 int 范围内int
不带小数点但超出 int(在 long long 内)long long
末尾加 L/llong
带小数点或指数形式double
末尾加 F/ffloat
实型末尾加 Llong double
单撇号括一个字符char

10 是整型常量,10.0 是浮点型常量——类型不同。

易错float a=3.14159; 右边是 double(8 字节),塞进 4 字节 float 会损失精度,编译器报 truncation from 'const double' to 'float' 警告;想消除就写 3.14159f。

类型 vs 变量(教材类比):"大学生"是抽象类型,代表共有属性,不占空间,没法"输出大学生的成绩";张方章、李四元是具体变量,有姓名有成绩,占空间。所以 int a; a=3; 正确,int = 3; 错误。


3.3 运算符和表达式

📖 教材 p.51–55 · 正文总结

3.3.1 C 运算符

📖 教材 p.52 · 正文总结

【一句话】 运算符是 C 里的"动作符号",C 把几乎所有基本操作都做成了运算符。

类别符号类别符号
算术+ − * / %关系> < == >= <= !=
逻辑! && ||位<< >> ~ | ^ &
赋值= 及扩展赋值条件? :
逗号,指针* 和 &
求字节数sizeof强制类型转换(类型)
成员. ->下标[ ]
其他函数调用 () 等

本章只讲算术运算符和赋值运算符,其余后面各章登场。


3.3.2 基本的算术运算符

📖 教材 p.52 · 正文总结

【一句话】 加减乘除加求余,但 / 和 % 有坑。

表 3.5:+ 正号(单目);− 负号(单目);* 乘;/ 除(求商);% 求余;+ 加;− 减。

三条铁律:

  1. 键盘没有 × ÷,用 * / 代替;
  2. 两个整数相除结果还是整数,小数直接舍去:5/3 得 1;要小数至少一个操作数是小数(5.0/3=1.666667);
  3. % 的操作数必须是整数,结果也是整数:8%3 得 2。

负数除法取整方向:-5/3 有的系统得 −1,有的得 −2。多数系统(如 VC++)向零取整,所以是 −1。

易错5/2 得 2 不是 2.5;要 2.5 得写 5.0/2 或 5/2.0。
易错5.0 % 2 是语法错误(% 只能用于整数)。
考点除 % 外,其他算术运算符的操作数可以是任何算术类型。


3.3.3 自增、自减运算符

📖 教材 p.53 · 正文总结

【一句话】 ++ 让变量加 1,−− 让变量减 1;写前面先加后用,写后面先用后加。 【驿站比喻】 ++i 是"先装新货再拿出来用";i++ 是"先把旧货拿出来用,再偷偷换新货"。

写法含义i 原值 3
++i先 i=i+1,再使用 ij=++i; → i=4,j=4
i++先使用 i,再 i=i+1j=i++; → j=3,i=4
−−i先减 1 再用i 变 2 后使用
i−−先用再减 1使用 3 后 i 变 2

printf("%d", ++i); 若 i 原为 3,先加变 4,输出 4;printf("%d", i++); 先输出 3,之后 i 变 4。

自增自减常用于循环变量加 1,也用于指针变量指向下一地址。

易错i+++j 按"最长匹配"是 (i++)+j,但这种写法要坚决避免。教材建议:只用最简单形式 i++、i--,作为单独表达式,不塞进复杂表达式。


3.3.4 算术表达式和运算符的优先级与结合性

📖 教材 p.53 · 正文总结

【一句话】 用运算符和括号把操作数连起来的合法式子叫表达式;先看优先级,同级看结合性。

  • 操作数:常量、变量、函数等。合法例子:a*b/c-1.5+'a'。
  • 优先级:先乘除后加减,括号最优先。a-b*c 等价于 a-(b*c)。
  • 结合性:算术运算符自左至右(左结合性),a-b+c 先算 a-b;赋值运算符自右至左(右结合性),a=b=c 先把 c 给 b,再把 b 给 a。

本章够用的优先级(高→低):

text
( )  →  单目(! ++ -- + - (类型) sizeof)  →  * / %  →  + -  →  赋值 =

考点教材原话:"不必死记,只要知道算术运算符是左结合性、赋值运算符是右结合性,其他的遇到时查一下即可。"


3.3.5 不同类型数据间的混合运算

📖 教材 p.54 · 正文总结

【一句话】 类型不同时系统自动转成同一类型再算,方向是"往精度高、范围大的那边靠"。 【驿站比喻】 大柜小柜一起搬货,先统一换成大柜规格再干活。

三条规则:① + − * / 中有一个是 float/double,结果是 double;② int 与 float/double 运算,先都转 double;③ 字符与整型运算,拿 ASCII 码去算(12+'A'=12+65=77),字符与实型运算则转 double。

自动转换方向(低→高):

text
char, short  →  int  →  unsigned  →  long  →  double  ←  float

教材经典例题:i=3(int)、f=2.5(float)、d=7.5(double),求 10 + 'a' + i * f - d / 3:

  1. 10+'a' → 10+97 = 107(int);
  2. i*f → 都转 double,3×2.5 = 7.5;
  3. 107+7.5 → 107 转 double = 114.5;
  4. d/3 → 3 转 double,7.5/3 = 2.5;
  5. 114.5−2.5 = 112.0(double)。

考点整个式子最终类型是 double,结果 112.0。


3.3.6 强制类型转换运算符

📖 教材 p.55 · 正文总结

【一句话】 用 (类型名)(表达式) 把表达式的值临时转成你要的类型。 【驿站比喻】 借一个别的规格的箱子临时装货,原来的柜子和货一点没动。

写法含义
(double)a把 a 转成 double
(int)(x+y)把 x+y 的值转成 int
(float)(5%3)把 5%3 转成 float

两个必须注意:① 表达式要用括号括起来((int)x+y 是"只把 x 转 int 再和 y 相加");② 得到的是中间临时值,原变量类型和值都不变(a=(int)x; 若 x 是 float 3.56,a 得 3,x 仍是 3.56)。

必须用强制转换的场合:% 要求两边整型,若 x 是 float,x%3 不合法,必须 (int)x%3——强制转换优先级高于 %,先转换再求余。


3.4 C 语句

📖 教材 p.56–63 · 正文总结

3.4.1 C 语句的作用和分类

📖 教材 p.56–57 · 正文总结

【一句话】 语句是向计算机发出的操作指令,一个 C 语句编译后产生若干条机器指令。

关键区分:函数包含声明部分(不产生机器指令,不是语句)和执行部分(由语句组成)。

C 语句分 5 类:

(1)控制语句(C 只有 9 种):if()...else... 条件;for()...、while()...、do...while() 循环;continue 结束本次循环;break 中止 switch 或循环;switch 多分支;return 从函数返回;goto 转向(结构化程序基本不用)。

(2)函数调用语句:函数调用 + 分号,如 printf("This is a C statement.");。

(3)表达式语句:表达式 + 分号,最典型的是赋值语句。

考点分号是语句的组成部分,不是语句之间的分隔符。a=3 是表达式,a=3; 才是语句。x+y; 也合法,但算完不存,没有实际意义。

(4)空语句:只有一个 ;,什么也不做。可作流程转向点或循环体。

(5)复合语句:用 { } 把若干语句和声明括起来,又称语句块。例如:

c
{
    float pi = 3.14159, r = 2.5, area;   // 声明部分
    area = pi * r * r;
    printf("area=%f\n", area);
}

易错复合语句中最后一个语句末尾的分号不能漏。


3.4.2 最基本的语句——赋值语句

📖 教材 p.58–63 · 正文总结

【一句话】 赋值语句 = 赋值表达式 + 分号,作用是把一个值装进一个变量。 【驿站比喻】 赋值是"往柜格里装货":新货一进去,旧货立刻被顶掉,不是叠加。

1. 赋值运算符 =:= 不是"等于",而是"赋给"。a=3 表示把 3 赋给 a;右边也可以是表达式,如 a=3+5。

2.选学复合的赋值运算符:

写法等价于写法等价于
a += 3a = a + 3a -= ba = a - b
x *= y+8x = x * (y+8)a /= ba = a / b
x %= 3x = x % 3

窍门:把 += 的 + 挪到右边,左边补变量名。

易错x *= y+8 等价于 x = x*(y+8),不是 x = x*y+8。复合赋值一是简化程序、二是提高编译效率;初学者不必多用,本小节了解即可。

3. 赋值表达式:变量 赋值运算符 表达式。

  • 具有计算和赋值双重功能;赋值表达式的值 = 赋值后左侧变量的值(a=3*5,a 和整个表达式的值都是 15);
  • 左值(lvalue):能出现在赋值号左边、值可改的量。变量可以;常量不行,a+b 不行;
  • 右值(rvalue):能出现在赋值号右边的表达式。凡是左值都能作右值;
  • 右结合:a=b=5 等价于 a=(b=5);a = (b=4)+(c=6); 值 10,a=10,b=4,c=6。

赋值表达式还能塞进别的语句:printf("%d", a=b); 在输出时同时完成赋值。

易错赋值表达式没有分号,赋值语句必须有分号。if 条件里可含赋值表达式,不能含赋值语句:if ((a=b)>0) ✅,if ((a=b;)>0) ❌。

4. 赋值过程中的类型转换(5 条规则):

情况规则例子
浮点 → 整型舍弃小数部分取整i=3.56; → i=3
整型 → 浮点数值不变,改浮点形式存f=23; → 23.0
double → float只取 6~7 位有效数字,别超 float 范围超范围会出错
字符 → 整型把 ASCII 码赋给整型i='A'; → 65
长 → 短/字符型只送低字节,发生"截断"int i=289; char c=i; → c=33('!')

截断经典例:int a=32767; short b; b=a+1; 理论 32768,实际输出 −32768。因为 short 只有 2 字节、最大 32767,32768 的低 16 位是 1000000000000000,最高位为 1,按有符号读就是 −32768。

考点教材原话:"要避免把占字节多的整型数据向占字节少的整型变量赋值,因为赋值后数值可能失真。"这种失真不属于语法错误,编译器不报错,全靠程序员经验排查。

5. 变量赋初值:

c
int a = 3;                 // 定义时赋初值
float f = 3.56;
char c = 'a';
int a, b, c = 5;           // 只对 c 初始化
int a = 3, b = 3, c = 3;   // 三个都是 3

易错不能写 int a = b = c = 3;,要写 int a=3, b=3, c=3;。
一般变量的初始化是在程序运行时执行本函数时赋初值,相当于执行一个赋值语句(静态存储变量和外部变量除外)。


3.5 数据的输入输出

📖 教材 p.64–79 · 正文总结

3.5.1 输入输出举例

📖 教材 p.64 · 正文总结

教材用例 3.5:求 ax²+bx+c=0 的根(设 b²−4ac>0)把 scanf 和 printf 一起用上:x₁,₂=(−b±√(b²−4ac))/2a,拆成 p=−b/(2a)、q=√(b²−4ac)/(2a),则 x1=p+q,x2=p−q。代码见「三、现场写代码」。

先记住:输入用 scanf 要加 &,输出用 printf 不加。


3.5.2 有关数据输入输出的概念

📖 教材 p.65–66 · 正文总结

【三句话】

  1. 输入输出以"计算机主机"为主体:主机往显示器、打印机送数据叫输出;键盘、扫描仪往主机送数据叫输入。
  2. C 语言本身不提供输入输出语句,输入输出由标准函数库实现。printf、scanf 不是关键字,只是库函数名。
  3. 用它们必须在开头写 #include <stdio.h>。

【拆名字】 stdio.h = standard(标准)+ input(输入)+ output(输出)+ .h(header 头文件)。

为什么不把 I/O 做成语句? 让编译系统简单精练:语句翻成二进制指令是编译阶段的事,没有 I/O 语句就不必在编译阶段处理硬件问题,通用性强、可移植性好。

#include 两种写法:

写法查找顺序用于
#include <stdio.h>到存放 C 编译系统的子目录找(标准方式)系统头文件
#include "stdio.h"先在用户当前目录找,找不到再按标准方式自己写的头文件

考点只要用标准输入输出库函数,一律加 #include <stdio.h>。


3.5.3 用 printf 函数输出数据

📖 教材 p.67–73 · 正文总结

【一句话】 printf 按给定"格式"把数据输出到屏幕。 【拆名字】 print(打印)+ f(formatted,格式化的)。

一般格式:printf(格式控制, 输出表列)

  • 格式控制:双撇号字符串,含格式声明(% + 格式字符,如 %d)和普通字符(原样输出,如 =、\n);
  • 输出表列:要输出的数据,可以是常量、变量或表达式。

printf("a=%d b=%d\n", a, b); 若 a=3、b=4,输出 a=3 b=4。

格式字符(表 3.6):

格式字符说明
d、i带符号十进制整数(正数不输出符号)
o八进制无符号整数(不输出前导 0)
x、X十六进制无符号(不输出 0x);x 小写 a~f,X 大写
u无符号十进制整数
c输出一个字符
s输出字符串
f以小数形式输出实型,隐含 6 位小数
e、E以指数形式输出(1.2e+02 / 1.2E+02)
g、G自动选 %f 或 %e 中较短的一种,不输出无意义 0

【拆名字】格式符的英文来源:%d=decimal 十进制,%o=octal 八进制,%x=hexadecimal 十六进制,%u=unsigned 无符号,%c=character 字符,%s=string 字符串,%f=float 浮点,%e=exponent 指数。

附加字符(表 3.7):l 长整型(%ld);m 数据最小宽度;n 对实数表示小数位数、对字符串表示截取字符个数;- 在域内向左靠。

写法含义例(值 → 输出)
%d按实际长度12 → 12
%5d占 5 列右对齐,左补空格12 → 12
%-5d占 5 列左对齐,右补空格12 → 12
%f整数部分全出,小数 6 位1.0/3 → 0.333333
%7.2f共 7 列,小数 2 位3.14159 → 3.14
%.2f只限小数 2 位3.14159 → 3.14
%20.15f20 列宽,15 位小数输出 double 的 15 位
%e指数形式,小数 6 位123.456 → 1.234560e+002
%%输出一个 %→ %

易错%7.0f 会连小数点一起省掉,只剩整数;不要轻易把小数位数指定为 0。
易错除 X、E、G 外,格式符必须小写,%D 是错的。
易错输出对象类型必须与格式说明匹配,否则结果错误。


3.5.4 用 scanf 函数输入数据

📖 教材 p.74–75 · 正文总结

【一句话】 scanf 按给定"格式"从键盘读数,装进你指定的地址。 【拆名字】 scan(扫描)+ f(formatted,格式化的)。

一般格式:scanf(格式控制, 地址表列)。地址表列由若干地址组成,可以是变量地址(&a)或字符串首地址。& 是取地址运算符,&a 表示"变量 a 在内存中的地址"——scanf 拿到地址才能把数据送进正确柜格。

c
scanf("%d%d", &a, &b);

格式字符(表 3.8):d 有符号十进制;u 无符号十进制;o 无符号八进制;x 无符号十六进制;c 单个字符;s 字符串;f、e、E、g、G 实数(小数或指数形式,可互换)。

附加字符(*表 3.9,选学备查):l 长整型(%ld、%lo、%lx、%lu)以及 double(%lf 或 %le);h 短整型(%hd 等);域宽 指定输入宽度;* 读入后不赋给变量。

使用 scanf 的 4 个注意:

(1)格式控制后必须是变量地址,不是变量名。

c
scanf("%f%f%f", a, b, c);        // ❌ 少了 &
scanf("%f%f%f", &a, &b, &c);     // ✅

易错这是初学者最常犯的错误,没有之一;漏了 & 程序运行时可能直接崩溃。

(2)格式串里有普通字符时,输入必须在对应位置敲同样的字符。 scanf("a=%f,b=%f,c=%f", &a,&b,&c); 必须输入 a=1,b=3,c=2;输入 1 3 2 就错了——系统会把输入和格式串逐字符对照。

(3)%c 输入字符时,空格和转义字符都算有效字符。 scanf("%c%c%c", &c1,&c2,&c3); 输入 abc → c1='a',c2='b',c3='c' ✅;输入 a b c → c1='a',c2=' '(空格),c3='b' ❌。

(4)输入数值时遇到空格、回车、Tab 或非法字符,就认为该数据结束。 如输入 1234a1230.26,%d 读到 a 就停,把 1234 赋给第一个变量,a 被后面的 %c 读走。

考点scanf 里 double 必须用 %lf,printf 里用 %f 就行——每年都有人栽。


3.5.5 字符输入输出函数

📖 教材 p.76–79 · 正文总结

【一句话】 putchar 输出一个字符,getchar 输入一个字符;名字就是说明书。 【拆名字】 put(放)+ char(acter) = 放一个字符出去;get(取得)+ char = 取一个字符进来。

1. putchar:putchar(c) 把一个字符输出到屏幕。c 可以是字符常量、整型常量、字符变量或整型变量(值在 ASCII 范围内)。

c
putchar('B');     // 输出 B
putchar(66);      // 66 是 'B' 的 ASCII 码,也输出 B
putchar('\n');    // 输出换行符

易错putchar 只能输出一个字符,不能输出多位数(putchar(1234) 只输出低字节对应的字符)。

2. getchar:getchar() 无参数,从键盘读一个字符,函数的值就是那个字符。想读多个就用多个 getchar。

c
c = getchar();               // 读一个字符
putchar(getchar());          // 读一个并立刻输出
printf("%c", getchar());     // 用 printf 输出刚读到的字符

3. 输入缓冲区(本章最易忽略、考试最爱考)

关键事实:敲键盘时不是敲一个字符就立刻送进计算机。 字符先暂存在键盘缓冲区,只有按了 Enter,才一起送入计算机,再按顺序赋给各变量。

经典翻车现场:例 3.9 要读 3 个字符,若每输一个就按一次回车,实际送入 'B'、'\n'、'O'、'\n' 四个字符,于是 a='B'、b=换行符、c='O',输出变成两行。

考点getchar 会把回车符也当成有效字符读走——这正是后面写菜单、连续读字符时"莫名其妙跳过输入"的根源。
易错scanf("%d",&n) 之后再 getchar(),读到的往往是刚才那个回车。


书末习题一览(书页 80–82)

📖 教材 p.80–82 · 习题

本章习题共 8 题:第 1 题算 10 年增长(pow);第 2 题 5 年 5 种存法;第 3 题房贷还清月数(log10);第 4 题分析 char 程序三问;第 5 题 scanf 键盘怎么敲;第 6 题 "China"→"Glmre";第 7 题圆与圆柱 5 个量;第 8 题 getchar 读两个字符。逐题精讲见「四、书上习题精讲」。


三、现场写代码

📖 教材例题 · 本课范围 p.37–79

教材例题 3.1~3.10 全部列出,每段都是完整可编译程序。

例 3.1 华氏温度转摄氏温度

📖 教材 p.37 · 例题 3.1

题目:华氏 64°F 转摄氏温度。思路:c = (5/9)(f−32),三步:输入 f → 套公式 → 输出 c。

c
#include <stdio.h>
int main()
{
    float f, c;                    // 定义 f 和 c 为单精度浮点型变量
    f = 64.0;                      // 指定 f 的值
    c = (5.0 / 9) * (f - 32);      // 利用公式计算 c 的值
    printf("f=%f\nc=%f\n", f, c);  // 输出 f 和 c 的值
    return 0;
}

逐行解释: ① stdio.h 让后面能用 printf;② 申请两个单精度柜格;③ 把 64.0 装进 f;④ 5.0/9 是小数除法(写 5/9 会得 0),再乘 (64−32);⑤ %f 按小数输出,\n 换行;⑥ return 0 正常结束。

运行结果:

text
f=64.000000
c=17.777778

【说明】不同编译器浮点舍入略有差别,VS2022 下第二行可能显示 c=17.777779,末位差 1 属正常。
易错写成 (5/9) 会得 0.000000,因为 5/9 是整数除法,结果是 0。


例 3.2 计算存款利息

📖 教材 p.38 · 例题 3.2

题目:1000 元存 1 年,三种存法:①活期 r1;②一年定期 r2;③两次半年定期 r3。 思路:p1=p0(1+r1);p2=p0(1+r2);p3=p0(1+r3/2)(1+r3/2)。

c
#include <stdio.h>
int main()
{
    float p0 = 1000, r1 = 0.0036, r2 = 0.0225, r3 = 0.0198, p1, p2, p3;
    p1 = p0 * (1 + r1);                       // 计算活期本息和
    p2 = p0 * (1 + r2);                       // 计算一年定期本息和
    p3 = p0 * (1 + r3 / 2) * (1 + r3 / 2);    // 计算存两次半年定期的本息和
    printf("p1=%f\np2=%f\np3=%f\n", p1, p2, p3);   // 输出结果
    return 0;
}

逐行解释: ① 一次定义 7 个 float,同时给 p0、r1、r2、r3 赋初值;② 三行公式,r3/2 先算(除法优先于加法);③ 三个 %f 对应三个变量,每个后面 \n 换行。

运行结果:

text
p1=1003.599976
p2=1022.500000
p3=1019.898010

【注意】尾数不是 1003.600000 而是 1003.599976——float 只有 6 位有效数字,不是程序错了,是浮点存不准。
【说明】教材是旧版 VC++ 的结果。在 VS2022 上实测会输出 p2=1022.500061、p3=1019.897949——中间计算精度不同导致末位差异,属正常现象,不是你的程序写错了。


例 3.3 大写字母转小写

📖 教材 p.54 · 例题 3.3

思路:同字母小写 ASCII 比大写大 32:'A'=65,加 32 得 97='a'。

c
#include <stdio.h>
int main()
{
    char c1, c2;
    c1 = 'A';                 // 将字符 'A' 的 ASCII 代码放到 c1 变量中
    c2 = c1 + 32;             // 得到字符 'a' 的 ASCII 代码,放在 c2 变量中
    printf("%c\n", c2);       // 输出 c2 的值,是一个字符
    printf("%d\n", c2);       // 输出 c2 的值,是字符 'a' 的 ASCII 代码
    return 0;
}

逐行解释: ① 两个 1 字节字符柜格;② c1 里实际存 65;③ 字符按 ASCII 运算,65+32=97 存入 c2;④ %c 把 97 翻译成 a;⑤ %d 直接输出 97。

运行结果: 第一行 a,第二行 97。


例 3.4 求三角形面积

📖 教材 p.58 · 例题 3.4

思路:海伦公式 area=√(s(s−a)(s−b)(s−c)),s=(a+b+c)/2;开方要用数学库 sqrt。

c
#include <stdio.h>
#include <math.h>
int main()
{
    double a, b, c, s, area;                        // 定义各变量,均为 double 型
    a = 3.67;                                       // 对边长 a 赋值
    b = 5.43;
    c = 6.21;
    s = (a + b + c) / 2;                            // 计算 s
    area = sqrt(s * (s - a) * (s - b) * (s - c));   // 计算 area
    printf("a=%f\tb=%f\tc=%f\n", a, b, c);          // 输出三边 a,b,c 的值
    printf("area=%f\n", area);                      // 输出面积 area 的值
    return 0;
}

逐行解释: ① math.h 管 sqrt;② 全部 double 为了提高精度;③ s=(a+b+c)/2 括号不能少;④ sqrt=square root;⑤ \t 让三列按 Tab 区对齐(每 8 列);⑥ 输出面积。

运行结果:

text
a=3.670000      b=5.430000      c=6.210000
area=9.903431

考点用数学库函数,必须 #include <math.h>。


例 3.5 求 ax²+bx+c=0 的根

📖 教材 p.64 · 例题 3.5

思路:设 b²−4ac>0,p=−b/(2a),q=√(b²−4ac)/(2a),则 x1=p+q,x2=p−q。

c
#include <stdio.h>
#include <math.h>                            // 程序中要调用求平方根函数 sqrt
int main()
{
    double a, b, c, disc, x1, x2, p, q;      // disc 用来存放判别式(b*b-4ac)的值
    scanf("%lf%lf%lf", &a, &b, &c);          // 输入双精度型变量的值要用格式声明"%lf"
    disc = b * b - 4 * a * c;
    p = -b / (2.0 * a);
    q = sqrt(disc) / (2.0 * a);
    x1 = p + q; x2 = p - q;                  // 求出方程的两个根
    printf("x1=%7.2f\nx2=%7.2f\n", x1, x2);  // 输出方程的两个根
    return 0;
}

逐行解释: ① stdio 管输入输出,math 管 sqrt;② 全部 double;③ scanf 三个 %lf 对应三个 double,每个都有 &;④ 判别式;⑤ 2.0 保证小数除法;⑥ %7.2f 占 7 列、小数 2 位,两根小数点对齐。

运行结果(输入 1 3 2,数与数之间用空格,最后回车):

text
1 3 2
x1=  -1.00
x2=  -2.00

易错格式串里没有逗号,输入里就不能有逗号;1,3,2 会出错。


例 3.6 %f 只能输出 6 位小数

📖 教材 p.70 · 例题 3.6
c
#include <stdio.h>
int main()
{
    double a = 1.0;
    printf("%f\n", a / 3);
    return 0;
}

逐行解释: ① double 变量初值 1.0;② a/3 是 double 除法,但 %f 默认只输出 6 位小数。

运行结果: 0.333333。改成 printf("%20.15f\n", a/3); 输出 0.333333333333333(0 前 3 个空格,共占 20 列)。

考点%f 的"6 位"是输出位数,不是数据精度;double 的真实精度是 15 位有效数字。


例 3.7 float 的有效位数

📖 教材 p.70 · 例题 3.7
c
#include <stdio.h>
int main()
{
    float a;
    a = 10000 / 3.0;
    printf("%f\n", a);
    return 0;
}

逐行解释: ① float 只有 6~7 位有效数字;② 3.0 是 double,除法按 double 算得 3333.333…,装进 float 时被砍到 6~7 位;③ 输出 6 位小数。

运行结果: 3333.333252。理论值 3333.333333…,但 float 从第 7 位起就不保证。不是 bug,是精度的物理极限。


例 3.8 用 putchar 输出 BOY

📖 教材 p.76 · 例题 3.8
c
#include <stdio.h>
int main()
{
    char a = 'B', b = 'O', c = 'Y';   // 定义 3 个字符变量并初始化
    putchar(a);                        // 向显示器输出字符 B
    putchar(b);                        // 向显示器输出字符 O
    putchar(c);                        // 向显示器输出字符 Y
    putchar('\n');                     // 向显示器输出一个换行符
    return 0;
}

逐行解释: ① 一行定义三个 char 并赋初值;② 三个 putchar 依次输出 B、O、Y,不会自动换行;③ 补一个换行。

运行结果: BOY。若改成 int a=66, b=79, c=89;,输出仍是 BOY——putchar 认的是 ASCII 码,66 就是 'B'。


例 3.9 用 getchar 输入 BOY

📖 教材 p.78 · 例题 3.9
c
#include <stdio.h>
int main()
{
    char a, b, c;              // 定义字符变量 a,b,c
    a = getchar();             // 从键盘输入一个字符,送给字符变量 a
    b = getchar();
    c = getchar();
    putchar(a);                // 将变量 a 的值输出
    putchar(b);
    putchar(c);
    putchar('\n');             // 换行
    return 0;
}

逐行解释: ① 三个 getchar() 依次从缓冲区取字符;② 连续输入 BOY 后按 Enter,三个字符才一起送到计算机,再按顺序分给 a、b、c;③ 三个 putchar 输出,最后换行。

运行结果: BOY。

易错每敲一个字符就按回车,b 会拿到换行符,输出变两行。缓冲区不认"你想输入什么",只认排队顺序。


例 3.10 任意大写字母转小写

📖 教材 p.79 · 例题 3.10

思路:getchar 读入 → 加 32 → putchar 输出。

c
#include <stdio.h>
int main()
{
    char c1, c2;
    c1 = getchar();        // 从键盘读入一个大写字母,赋给字符变量 c1
    c2 = c1 + 32;          // 求对应小写字母的 ASCII 代码,放在字符变量 c2 中
    putchar(c2);           // 输出 c2 的值,是一个字符
    putchar('\n');
    return 0;
}

逐行解释: ① 两个字符柜格;② 读一个字符(如 'N'=78);③ 78+32=110='n';④ 输出 n。

运行结果(输入 N):n。也可把最后两行换成 printf("大写字母:%c\n小写字母:%c\n", c1, c2);。


四、书上习题精讲

📖 教材 p.80–82 · 习题

第 1 题 国民生产总值增长

📖 教材 p.80 · 习题 1

题目:年增长率 7%,求 10 年后与现在相比增长多少百分比。公式 p=(1+r)ⁿ。 思路:pow 求幂(在 math.h 中);p 是倍数,增长率 = (p−1)×100%。

c
#include <stdio.h>
#include <math.h>
int main()
{
    double r = 0.07, p;
    int n = 10;
    p = pow(1 + r, n);                      // 求 (1+r) 的 n 次方
    printf("p=%f\n", p);                    // 10 年后是现在的多少倍
    printf("增长 %.2f%%\n", (p - 1) * 100);  // 增长百分比,%% 输出一个 % 号
    return 0;
}

结果:p=1.967151,约为现在的 1.97 倍,增长 96.72%。 要点:pow(x,y) 两个参数都是 double;%% 才能输出百分号。


第 2 题 存款利息(5 年 5 种存法)

📖 教材 p.80 · 习题 2

题目:1000 元存 5 年。①一次 5 年期;②先 2 年再 3 年;③先 3 年再 2 年;④连续 5 次 1 年期;⑤活期(每季结息)。利率:1 年 1.5%、2 年 2.1%、3 年 2.75%、5 年 3%、活期 0.35%。 教材公式:1 年期 P=1000(1+r);n 年期 P=1000(1+n×r)(单利);存 n 次 1 年期 P=1000(1+r)ⁿ(复利);活期 P=1000(1+r/4)^(4n)。

c
#include <stdio.h>
#include <math.h>
int main()
{
    double p0 = 1000.0;
    double r1 = 0.015, r2 = 0.021, r3 = 0.0275, r5 = 0.03, r0 = 0.0035;
    double p_5, p_2_3, p_3_2, p_1x5, p_huo;

    p_5   = p0 * (1 + 5 * r5);                   // 一次存 5 年期(单利)
    p_2_3 = p0 * (1 + 2 * r2) * (1 + 3 * r3);    // 先 2 年再 3 年
    p_3_2 = p0 * (1 + 3 * r3) * (1 + 2 * r2);    // 先 3 年再 2 年
    p_1x5 = p0 * pow(1 + r1, 5);                 // 连续 5 次 1 年期(复利)
    p_huo = p0 * pow(1 + r0 / 4, 4 * 5);         // 活期,每季度结息

    printf("5年期:     %.2f\n", p_5);
    printf("先2年再3年: %.2f\n", p_2_3);
    printf("先3年再2年: %.2f\n", p_3_2);
    printf("5次1年期:   %.2f\n", p_1x5);
    printf("活期:       %.2f\n", p_huo);
    return 0;
}

结果:①1150.00 ②1127.96 ③1127.97 ④1077.28 ⑤1017.65(元)。 要点:②③数学上完全相同(乘法交换律),实际输出最后一位却可能差 0.01——因为两式的乘法先后顺序不同,浮点舍入误差也不同;5 年期单利最高;活期一年复利 4 次,5 年共 20 次,指数是 4*5。


第 3 题 购房贷款还清月数

📖 教材 p.81 · 习题 3

题目:d=300000,每月还 p=6000,月利率 r=1%,求还清月数(取小数后 1 位,第 2 位四舍五入)。 公式:m = [log p − log(p−d×r)] / log(1+r) = log(p/(p−d×r)) / log(1+r)。

c
#include <stdio.h>
#include <math.h>
int main()
{
    double d = 300000, p = 6000, r = 0.01, m;
    m = log10(p / (p - d * r)) / log10(1 + r);   // log10 是以 10 为底的对数
    printf("m=%.1f\n", m);                      // 保留 1 位小数
    return 0;
}

结果:m = 69.7 个月。 要点:p−d*r = 6000−3000 = 3000,p/3000 = 2,m = log10(2)/log10(1.01) ≈ 0.30103/0.0043214 ≈ 69.66,保留一位得 69.7;%.1f 自动完成四舍五入。


第 4 题 分析 char 程序

📖 教材 p.81 · 习题 4
c
#include <stdio.h>
int main()
{
    char c1, c2;
    c1 = 97;
    c2 = 98;
    printf("c1=%c,c2=%c\n", c1, c2);
    printf("c1=%d,c2=%d\n", c1, c2);
    return 0;
}

(1)输出什么?为什么? 输出 c1=a,c2=b 和 c1=97,c2=98。char 里存的是 ASCII 码:97 是 'a',98 是 'b'。%c 按字符解释,%d 按整数解释。同一份数据,两种读法。

(2)改成 c1=197; c2=198; 呢? VC++ 中 char 默认是 signed char,范围 −128~127,197、198 都超范围;197 的低 8 位 11000101 按有符号读是 −59,198 读作 −58。%c 输出 ASCII 码 197、198 对应的扩展字符(中文 Windows 下通常是乱码),%d 输出 −59、−58。结论:超范围会溢出,结果不可预期。

(3)把第 3 行改成 int c1, c2; 呢? int 是 4 字节,197、198 能完整存下;%c 只取最低字节,字符输出与(2)相同;%d 输出 197、198,不再溢出。结论:char 与 int 在"存字符"上可互换,但范围不同,超范围后果不同。


第 5 题 scanf 的键盘输入

📖 教材 p.82 · 习题 5
c
#include <stdio.h>
int main()
{
    int a, b;
    float x, y;
    char c1, c2;
    scanf("a=%db=%d", &a, &b);
    scanf("%f%e", &x, &y);
    scanf("%c%c", &c1, &c2);
    return 0;
}

要求 a=3、b=7、x=8.5、y=71.82、c1='A'、c2='a'。标准答案:

text
a=3b=7↙
8.5 71.82Aa↙

为什么这样敲? ① "a=%db=%d" 里的 a=、b= 是普通字符,输入必须原样出现;② 回车后第一行的 \n 留在缓冲区,但 %f 会自动跳过前导空白(含回车),第二行正常读;③ 8.5 给 x,空格跳过,71.82 给 y;④ 关键:%c 不跳过空白,若 71.82 后直接回车,回车会被 c1 读走,所以必须紧挨着 71.82 输入 Aa,再回车。

考点这就是"%c 吃回车"的经典考法:读字符前,缓冲区里有什么,%c 就拿什么。


第 6 题 "China" 译成密码

📖 教材 p.82 · 习题 6

题目:用字母后面第 4 个字母代替原字母("China"→"Glmre")。用赋初值让 c1~c5 为 'C','h','i','n','a',运算后变 'G','l','m','r','e',分别用 putchar 和 printf 输出。

c
#include <stdio.h>
int main()
{
    char c1 = 'C', c2 = 'h', c3 = 'i', c4 = 'n', c5 = 'a';
    c1 = c1 + 4;        // 'C'(67) + 4 = 71 = 'G'
    c2 = c2 + 4;        // 'h'(104) + 4 = 108 = 'l'
    c3 = c3 + 4;        // 'i'(105) + 4 = 109 = 'm'
    c4 = c4 + 4;        // 'n'(110) + 4 = 114 = 'r'
    c5 = c5 + 4;        // 'a'(97)  + 4 = 101 = 'e'

    putchar(c1); putchar(c2); putchar(c3); putchar(c4); putchar(c5);
    putchar('\n');

    printf("%c%c%c%c%c\n", c1, c2, c3, c4, c5);
    return 0;
}

结果: 两行 Glmre。 要点:字符本质是整数,+4 就是"往后数 4 个字母";c1=c1+4; 也可写 c1+=4;;putchar 一次只输出一个字符。


第 7 题 圆与圆柱的 5 个量

📖 教材 p.82 · 习题 7

题目:r=1.5、h=3,求圆周长、圆面积、圆球表面积、圆球体积、圆柱体积。scanf 输入,输出有文字说明,取小数点后 2 位。 公式:2πr;πr²;4πr²;(4/3)πr³;πr²h。

c
#include <stdio.h>
#define PI 3.1415926
int main()
{
    double r, h;
    scanf("%lf%lf", &r, &h);                      // 输入半径和高度
    printf("圆周长     = %.2f\n", 2 * PI * r);
    printf("圆面积     = %.2f\n", PI * r * r);
    printf("圆球表面积 = %.2f\n", 4 * PI * r * r);
    printf("圆球体积   = %.2f\n", 4.0 / 3.0 * PI * r * r * r);
    printf("圆柱体积   = %.2f\n", PI * r * r * h);
    return 0;
}

结果(输入 1.5 3):圆周长 9.42、圆面积 7.07、圆球表面积 28.27、圆球体积 14.14、圆柱体积 21.21。 要点:4.0/3.0 不能写 4/3(整数除法得 1,体积就错);%.2f 自动四舍五入;用 #define PI 比到处写 3.1415926 清楚。


第 8 题 getchar 读两个字符

📖 教材 p.82 · 习题 8
c
#include <stdio.h>
int main()
{
    char c1, c2;
    c1 = getchar();              // 读第一个字符
    c2 = getchar();              // 读第二个字符
    putchar(c1); putchar(c2); putchar('\n');
    printf("%c %c\n", c1, c2);   // 用 printf 再输出一遍
    printf("%d %d\n", c1, c2);   // 顺便输出 ASCII 码
    return 0;
}

结果(输入 AB):AB、A B、65 66 三行。

(1)c1、c2 应定义为字符型、整型还是二者皆可? 二者皆可。char 本质是 1 字节整型,int 也能存 ASCII 码;区别是 char 占 1 字节(0~127 够用),int 占 4 字节。

(2)要求输出 ASCII 码,怎么处理?用 putchar 还是 printf? 必须用 printf + %d。putchar 只能把整数当 ASCII 码翻译成字符输出,不能输出数字本身。

(3)char c1,c2; 与 int c1,c2; 是否无条件等价? 不是。 ① 范围不同:signed char −128~127,int −2147483648~2147483647,存 197 时 char 溢出、int 不溢出;② 空间不同:1 字节 vs 4 字节;③ 输出不同:%c 只取最低字节。结论:存 0~127 的字符时可互换,超出范围或要保存完整数值时不能。


🛠 随课练习(只给题不给答案)

📖 本课补充 · 非教材原文

🔮 猜输出

题 1 先自己算,再上机验证。

c
#include <stdio.h>
int main()
{
    int a = 5, b = 2;
    printf("%d %d\n", a / b, a % b);
    printf("%f\n", (double)a / b);
    return 0;
}

题 2 ++ 的前后之别。

c
#include <stdio.h>
int main()
{
    int i = 3;
    printf("%d ", i++);
    printf("%d ", i);
    printf("%d ", ++i);
    printf("%d\n", i);
    return 0;
}

题 3 字符与整数。

c
#include <stdio.h>
int main()
{
    char c = 'A';
    printf("%c %d %c\n", c, c + 2, c + 2);
    printf("%d\n", '0' + 1);
    return 0;
}

题 4 格式控制的宽度。

c
#include <stdio.h>
int main()
{
    printf("[%5d][%-5d]\n", 42, 42);
    printf("[%7.2f][%.3f]\n", 3.14159, 3.14159);
    return 0;
}

🛠 变式题

题 1(照猫画虎) 把例 3.1 改成"从键盘输入华氏温度",输出摄氏温度,保留 2 位小数。

题 2(改需求) 输入两个整数,输出和、差、积、商、余数;商保留 2 位小数(注意整数除法)。

题 3(翻译) 输入一个小写字母,输出它的大写字母和对应 ASCII 码。

题 4(补全) 下面程序想读一个整数和一个字符,但字符总读不到。补一行修好它:

c
scanf("%d", &n);
c = getchar();      // 这里读到的是回车,怎么修?

🐛 改错题

题 1

c
#include <stdio.h>
int main()
{
    int a, b;
    scanf("%d%d", a, b);
    printf("%d\n", a + b);
    return 0;
}

题 2

c
#include <stdio.h>
int main()
{
    int a = 5, b = 2;
    printf("%f\n", a / b);
    return 0;
}

题 3

c
#include <stdio.h>
int main()
{
    int a = 3
    printf("%d\n", a);
    return 0;
}

📈 加练题(你随时喊,我随时追加到这里)

📖 本课补充 · 非教材原文

(暂无。想加练就说"再出几道 XX 题",我出的题会标上日期追加在这块。)


💬 问答区(你问过的问题 + 我的解答)

📖 本课补充 · 非教材原文

(暂无。你问的问题和我的解答会按 Q/A 整理进这里。)


该带走的 6 句话

📖 本课补充 · 非教材原文
  1. 变量是先定义后使用的"带名牌的柜格",类型决定柜格多大、怎么码放。
  2. 5/2 得 2,5.0/2 才得 2.5;% 两边只能是整数。
  3. ++i 先加后用,i++ 先用后加。
  4. printf 里 float 和 double 都用 %f;scanf 里 double 必须用 %lf,且每个变量前必须加 &。
  5. %c 连空格和回车都吃,getchar 会把上一行留下的回车读走——这是输入缓冲区在作怪。
  6. 混合运算自动往"精度高、范围大"的方向转;强制转换只产生临时值,原变量类型和值都不变。

📚 教材覆盖清单(第3章,最简单的C程序设计——顺序程序设计)

这张表把本课和教材逐节对上:从网页可以回查书页,从书页也能找到网页位置。标「未展开」的,就是教材里有、本课没讲的部分,已明确列出。

教材节号标题书页网站对应状态
3.1顺序程序设计举例p.37–383.1 顺序程序设计举例精讲
3.2数据的表现形式及其运算p.39–503.2 数据的表现形式及其运算精讲
3.2.1常量和变量p.39–413.2.1 常量和变量精讲
3.2.2数据类型p.42–433.2.2 数据类型精讲
3.2.3整型数据p.44–463.2.3 整型数据精讲
3.2.4字符型数据p.47–483.2.4 字符型数据精讲
3.2.5浮点型数据p.493.2.5 浮点型数据精讲
3.2.6怎样确定常量的类型p.503.2.6 怎样确定常量的类型精讲
3.3运算符和表达式p.51–553.3 运算符和表达式精讲
3.3.1C运算符p.523.3.1 C 运算符精讲
3.3.2基本的算术运算符p.523.3.2 基本的算术运算符精讲
3.3.3自增(++)、自减(--)运算符p.533.3.3 自增、自减运算符精讲
3.3.4算术表达式和运算符的优先级与结合性p.533.3.4 算术表达式和运算符的优先级与结合性精讲
3.3.5不同类型数据间的混合运算p.543.3.5 不同类型数据间的混合运算精讲
3.3.6强制类型转换运算符p.553.3.6 强制类型转换运算符精讲
3.4C语句p.56–633.4 C 语句精讲
3.4.1C语句的作用和分类p.56–573.4.1 C 语句的作用和分类精讲
3.4.2最基本的语句——赋值语句p.58–633.4.2 最基本的语句——赋值语句精讲
3.5数据的输入输出p.64–793.5 数据的输入输出精讲
3.5.1输入输出举例p.643.5.1 输入输出举例精讲
3.5.2有关数据输入输出的概念p.65–663.5.2 有关数据输入输出的概念精讲
3.5.3用printf函数输出数据p.67–733.5.3 用 printf 函数输出数据精讲
3.5.4用scanf函数输入数据p.74–753.5.4 用 scanf 函数输入数据精讲
3.5.5字符输入输出函数p.76–793.5.5 字符输入输出函数精讲
习题第3章书末习题p.80–82本课「书上习题精讲」逐题精讲(第1–8题)
插图本课范围内教材插图p.37–79用文字/ASCII 重画未逐张复刻
附录附录 A–Ep.357–370全书对照页未单独成课
  • 教材插图(流程图、内存示意图等)本课用文字/ASCII 重画,未逐张复刻,页码见上表。
  • 附录 A–E(p.357–370)是速查表,未单独成课;全站对照页列出。
  • 标「本课补充」的小节(先补地基、比喻、随课练习等)不是教材原文,是为理解而加的。