CC语言通关
第03课 · 要写代码
教材对照
第03课配套 · 纯代码

第03课 · 要写代码

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

29 段代码每行都有注释边敲边想
教材依据第3章《最简单的C程序设计——顺序程序设计》书页 p.37–82
本课覆盖:教材第3章正文 + 书末习题(p.80–82)。标「教材 p.X」= 教材段落总结;「例题」= 教材例题;「习题」= 书末题目;「本课补充」= 非教材原文。
在全书对照表中查看 →

用法:每段都是完整可编译程序,每行后面都有 // 注释。先照着敲一遍、跑通,再盖住注释自己讲一遍。
编译环境:Visual Studio 2022(新建空项目 → 添加 .c 文件 → Ctrl+F5)。

一、知识点代码

c
// ============ 1. 变量 / 常变量 const / 符号常量 #define ============
#include <stdio.h>                  // 包含标准输入输出头文件,才能用 printf
#define PI 3.14159                  // 符号常量:编译前 PI 会被原样替换成 3.14159,行末没有分号
int main()                          // 主函数,程序入口
{                                   // 主函数开始
    float r = 2.0f;                 // 定义单精度浮点变量 r,初值 2.0(f 后缀表示 float 常量)
    const float pi = 3.14159f;      // 常变量:有类型、占内存,但值不能再改
    float area;                     // 定义变量 area,暂时没有值
    area = pi * r * r;              // 用常变量算圆面积
    printf("area=%f\n", area);      // 输出面积,%f 默认 6 位小数
    printf("PI=%f\n", PI);          // PI 已被替换成 3.14159,正常输出
    return 0;                       // 告诉系统程序正常结束
}                                   // 主函数结束
c
// ============ 2. 整型:字节数、取值范围、溢出 ============
#include <stdio.h>                          // 标准输入输出
int main()                                  // 主函数
{                                           // 开始
    short a = 32767;                        // short 占 2 字节,最大值就是 32767
    int b = 2147483647;                     // int 占 4 字节,最大值 2147483647
    printf("short=%d\n", a);                // 输出 32767
    a = a + 1;                              // 再加 1 就超出范围,发生"溢出"
    printf("short+1=%d\n", a);              // 溢出后变成 -32768
    b = b + 1;                              // int 也溢出
    printf("int+1=%d\n", b);                // 变成 -2147483648
    printf("sizeof(short)=%d\n", (int)sizeof(short));    // sizeof 求字节数,结果是 2
    printf("sizeof(int)=%d\n", (int)sizeof(int));        // 结果是 4
    printf("sizeof(long)=%d\n", (int)sizeof(long));      // VC++ 下也是 4
    printf("sizeof(double)=%d\n", (int)sizeof(double));  // 结果是 8
    return 0;                               // 结束
}                                           // 结束
c
// ============ 3. 字符型:本质是"1 字节的小整数" ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    char c1 = 'A';                  // 字符常量用单撇号,柜格里存的是 ASCII 码 65
    char c2 = 97;                   // 也可以直接存整数 97,它就是 'a'
    char c3 = 'a' - 32;             // 'a'=97,减 32 得 65,就是 'A'
    printf("%c %d\n", c1, c1);      // %c 按字符输出 A,%d 按整数输出 65
    printf("%c %d\n", c2, c2);      // 输出 a 97
    printf("%c %d\n", c3, c3);      // 输出 A 65
    printf("%d\n", 'A' + 1);        // 字符参与运算按 ASCII 码算:66
    printf("%d\n", '1' + '1');      // '1' 是 49,49+49 得 98(不是 2)
    return 0;                       // 结束
}                                   // 结束
c
// ============ 4. 浮点型:float 6 位、double 15 位有效数字 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    float f = 10000 / 3.0f;         // 3.0f 是 float 常量,结果 3333.333 存进 float
    double d = 10000 / 3.0;         // 3.0 是 double 常量,结果按 double 存
    printf("%f\n", f);              // 默认 6 位小数,float 从第 7 位起就不准
    printf("%.15f\n", d);           // 指定 15 位小数,看到 double 的真实精度
    printf("%.2f\n", 3.14159);      // 只留 2 位小数,第 3 位四舍五入
    return 0;                       // 结束
}                                   // 结束
c
// ============ 5. 算术运算符:/ 与 % 的坑 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int a = 5, b = 2;               // 两个整型变量
    double x;                       // 用来装 5/2 的结果
    printf("%d\n", a / b);          // 两个整数相除,商取整,得 2
    printf("%d\n", a % b);          // 求余,得 1
    x = 5 / 2;                      // 先算整数除法得 2,再转成 2.0 存进 x
    printf("%f\n", x);              // 输出 2.000000(不是 2.5)
    printf("%f\n", 5 / 2.0);        // 有一个是小数,按小数除,得 2.500000
    printf("%f\n", (float)a / b);   // 强制转换后按小数除,得 2.500000
    printf("%d\n", -5 / 3);         // 向零取整,得 -1
    return 0;                       // 结束
}                                   // 结束
c
// ============ 6. 自增自减:++i 与 i++ ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int i = 3, j;                   // i 是操作数,j 用来接结果
    j = ++i;                        // 先加 1(i 变 4),再把 4 赋给 j
    printf("i=%d j=%d\n", i, j);    // 输出 i=4 j=4
    i = 3;                          // 恢复初值,重新演示
    j = i++;                        // 先把 3 赋给 j,再让 i 加 1
    printf("i=%d j=%d\n", i, j);    // 输出 i=4 j=3
    i = 3;                          // 再恢复
    printf("%d\n", ++i);            // 先加后用,输出 4
    i = 3;                          // 再恢复
    printf("%d\n", i++);            // 先用后加,输出 3
    printf("%d\n", i);              // 此时 i 已经变成 4
    return 0;                       // 结束
}                                   // 结束
c
// ============ 7. 混合运算 + 强制类型转换 ============
#include <stdio.h>                      // 标准输入输出
int main()                              // 主函数
{                                       // 开始
    int i = 3;                          // 整型
    float f = 2.5f;                     // 单精度
    double d = 7.5;                     // 双精度
    double r;                           // 存最终结果
    r = 10 + 'a' + i * f - d / 3;       // 'a'=97,i*f 转 double,d/3 是 double
    printf("%f\n", r);                  // 最终结果 112.000000
    printf("%d\n", (int)3.9);           // 强制转换直接截断小数,得 3
    printf("%f\n", (double)7 / 2);      // 先转 double 再除,得 3.500000
    printf("%d\n", 7 % 3);              // 求余,得 1
    printf("%f\n", (float)(7 % 3));     // 把整数 1 转成 float,输出 1.000000
    return 0;                           // 结束
}                                       // 结束
c
// ============ 8. 赋值语句、复合赋值、赋值表达式 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int a = 3;                      // 定义时赋初值
    int b, c;                       // 只定义,不赋初值
    a += 3;                         // 等价于 a = a + 3,a 变 6
    b = c = 5;                      // 赋值右结合:先 c=5,再把 5 给 b
    printf("%d %d %d\n", a, b, c);  // 输出 6 5 5
    a = b = 3 * 4;                  // 先算 3*4 得 12,赋给 b,再赋给 a
    printf("%d %d\n", a, b);        // 输出 12 12
    printf("%d\n", a = 7);          // 赋值表达式的值就是赋进去的值:7
    a *= 2 + 3;                     // 等价于 a = a * (2+3),不是 a*2+3
    printf("%d\n", a);              // 7*5 得 35
    return 0;                       // 结束
}                                   // 结束
c
// ============ 9. printf 的格式控制 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int n = 42;                     // 待输出的整数
    double x = 3.14159;             // 待输出的小数
    printf("[%d]\n", n);            // 按实际长度输出:42
    printf("[%5d]\n", n);           // 占 5 列右对齐,左边补 3 个空格
    printf("[%-5d]\n", n);          // 占 5 列左对齐,右边补 3 个空格
    printf("[%5.2f]\n", x);         // 共占 5 列,小数 2 位
    printf("[%.3f]\n", x);          // 只指定小数位,整数部分按实际长度
    printf("[%e]\n", 123.456);      // 指数形式输出
    printf("[%g]\n", 123.456);      // 自动选较短格式
    printf("[%%]\n");               // 想输出一个 % 号,必须写两个 %
    return 0;                       // 结束
}                                   // 结束
c
// ============ 10. scanf:格式控制 + 地址表列 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int a, b;                       // 两个整型柜格
    double x;                       // 一个双精度柜格
    printf("请输入两个整数:");      // 提示语
    scanf("%d%d", &a, &b);          // %d 之间用空白分隔,& 取地址
    printf("a=%d b=%d\n", a, b);    // 原样输出
    printf("请输入一个小数:");      // 提示语
    scanf("%lf", &x);               // double 输入必须用 %lf
    printf("x=%f\n", x);            // 输出时 %f 就够了
    return 0;                       // 结束
}                                   // 结束
c
// ============ 11. putchar 与 getchar ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    char c1, c2;                    // 两个字符柜格
    printf("请输入两个字符:");      // 提示语
    c1 = getchar();                 // 从键盘读一个字符(连回车也照收)
    c2 = getchar();                 // 再读一个
    printf("你输入的是:");          // 提示语
    putchar(c1);                    // 输出一个字符
    putchar(c2);                    // 再输出一个字符
    putchar('\n');                  // 输出换行符
    return 0;                       // 结束
}                                   // 结束
c
// ============ 12. 输入缓冲区:getchar 会吃掉上一行的回车 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int n;                          // 整数柜格
    char c;                         // 字符柜格
    printf("请输入一个整数:");      // 提示语
    scanf("%d", &n);                // 读完数字后,回车还留在缓冲区里
    printf("请输入一个字符:");      // 提示语
    c = getchar();                  // 它读到的其实是刚才那个回车
    printf("n=%d c=[%c] ASCII=%d\n", n, c, c);   // c 是 '\n',ASCII 是 10
    return 0;                       // 结束
}                                   // 结束

二、课后题 · 代码题

c
// ============ 习题 1:国民生产总值增长 ============
#include <stdio.h>                  // 标准输入输出
#include <math.h>                   // 用 pow 求幂,必须包含数学头文件
int main()                          // 主函数
{                                   // 开始
    double r = 0.07, p;             // r 是年增长率,p 是倍数
    int n = 10;                     // 年数
    p = pow(1 + r, n);              // 求 (1+r) 的 n 次方
    printf("p=%f\n", p);            // 输出倍数,约 1.967151
    printf("增长 %.2f%%\n", (p - 1) * 100);   // 增长百分比,%% 输出一个 % 号
    return 0;                       // 结束
}                                   // 结束
c
// ============ 习题 2:存款利息(5 年 5 种存法) ============
#include <stdio.h>                  // 标准输入输出
#include <math.h>                   // 用 pow
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;   // 5 种存法的本息和
    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);      // 活期:每季度结息,5 年 20 次
    printf("5年期:     %.2f\n", p_5);          // 1150.00
    printf("先2年再3年: %.2f\n", p_2_3);        // 1127.96(浮点舍入,末位可能与下面差 0.01)
    printf("先3年再2年: %.2f\n", p_3_2);        // 1127.97
    printf("5次1年期:   %.2f\n", p_1x5);        // 1077.28
    printf("活期:       %.2f\n", p_huo);        // 1017.65
    return 0;                       // 结束
}                                   // 结束
c
// ============ 习题 3:购房贷款还清月数 ============
#include <stdio.h>                  // 标准输入输出
#include <math.h>                   // 用 log10
int main()                          // 主函数
{                                   // 开始
    double d = 300000, p = 6000, r = 0.01, m;   // 贷款额、月还款、月利率、月数
    m = log10(p / (p - d * r)) / log10(1 + r);  // 套公式求月数
    printf("m=%.1f\n", m);                      // 保留 1 位小数,输出 69.7
    return 0;                       // 结束
}                                   // 结束
c
// ============ 习题 6:"China" 译成密码(每个字母后移 4 位) ============
#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);                            // 输出 G
    putchar(c2);                            // 输出 l
    putchar(c3);                            // 输出 m
    putchar(c4);                            // 输出 r
    putchar(c5);                            // 输出 e
    putchar('\n');                          // 换行
    printf("%c%c%c%c%c\n", c1, c2, c3, c4, c5);   // 再用 printf 输出一遍
    return 0;                               // 结束
}                                           // 结束
c
// ============ 习题 7:圆与圆柱的 5 个量 ============
#include <stdio.h>                  // 标准输入输出
#define PI 3.1415926                // 符号常量,行末没有分号
int main()                          // 主函数
{                                   // 开始
    double r, h;                    // 半径和高度
    printf("请输入半径和高度:");    // 提示语
    scanf("%lf%lf", &r, &h);        // 输入两个 double
    printf("圆周长     = %.2f\n", 2 * PI * r);              // 2πr
    printf("圆面积     = %.2f\n", PI * r * r);              // πr²
    printf("圆球表面积 = %.2f\n", 4 * PI * r * r);          // 4πr²
    printf("圆球体积   = %.2f\n", 4.0 / 3.0 * PI * r * r * r);   // (4/3)πr³
    printf("圆柱体积   = %.2f\n", PI * r * r * h);          // πr²h
    return 0;                       // 结束
}                                   // 结束
c
// ============ 习题 8:getchar 读两个字符 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    char c1, c2;                    // 两个字符柜格
    c1 = getchar();                 // 读第一个字符
    c2 = getchar();                 // 读第二个字符
    putchar(c1);                    // 用 putchar 输出第一个
    putchar(c2);                    // 用 putchar 输出第二个
    putchar('\n');                  // 换行
    printf("%c %c\n", c1, c2);      // 用 printf 再输出一遍
    printf("%d %d\n", c1, c2);      // 输出两个字符的 ASCII 码
    return 0;                       // 结束
}                                   // 结束

三、我出的题 · 随课练习

🔮 猜输出

c
// ============ 猜输出 1:整数除法与取余 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int a = 5, b = 2;               // 两个整数
    printf("%d %d\n", a / b, a % b);    // 输出 a/b 和 a%b
    printf("%f\n", (double)a / b);      // 把 a 转成 double 再除
    return 0;                       // 结束
}                                   // 结束
c
// ============ 猜输出 2:++ 的前后之别 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int i = 3;                      // 初值 3
    printf("%d ", i++);             // 后缀自增
    printf("%d ", i);               // 输出 i 的当前值
    printf("%d ", ++i);             // 前缀自增
    printf("%d\n", i);              // 再输出 i 的当前值
    return 0;                       // 结束
}                                   // 结束
c
// ============ 猜输出 3:字符与整数 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    char c = 'A';                   // 字符 A,存的是 65
    printf("%c %d %c\n", c, c + 2, c + 2);    // 三种写法输出 c、c+2
    printf("%d\n", '0' + 1);                  // 字符 '0' 参与整数运算
    return 0;                       // 结束
}                                   // 结束
c
// ============ 猜输出 4:格式控制的宽度 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    printf("[%5d][%-5d]\n", 42, 42);          // 右对齐与左对齐
    printf("[%7.2f][%.3f]\n", 3.14159, 3.14159);   // 两种小数位控制
    return 0;                       // 结束
}                                   // 结束

🛠 变式题

c
// ============ 变式题 1:输入华氏温度,输出摄氏温度(保留 2 位) ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    float f, c;                     // 华氏和摄氏
    printf("请输入华氏温度:");      // 提示语
    scanf("%f", &f);                // 读入华氏温度
    // ______ 在这里写:用 c = (5.0/9)*(f-32) 算出摄氏温度
    // ______ 在这里写:用 printf 输出 c,保留 2 位小数
    return 0;                       // 结束
}                                   // 结束
c
// ============ 变式题 2:两整数的和差积商余(商保留 2 位) ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int a, b;                       // 两个整数
    printf("请输入两个整数:");      // 提示语
    scanf("%d%d", &a, &b);          // 读入
    // ______ 在这里写:输出 a+b、a-b、a*b
    // ______ 在这里写:输出商,注意先转 double 再除,保留 2 位
    // ______ 在这里写:输出 a%b
    return 0;                       // 结束
}                                   // 结束
c
// ============ 变式题 3:小写字母转大写,并输出 ASCII 码 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    char c1, c2;                    // 小写和大写
    printf("请输入一个小写字母:");  // 提示语
    c1 = getchar();                 // 读一个字符
    // ______ 在这里写:把 c1 转成大写,放进 c2
    // ______ 在这里写:用 putchar 输出 c2
    // ______ 在这里写:用 printf 输出 c1 和 c2 的 ASCII 码
    return 0;                       // 结束
}                                   // 结束
c
// ============ 变式题 4:scanf 后 getchar 读到回车,补一行修好 ============
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int n;                          // 整数
    char c;                         // 字符
    printf("请输入一个整数:");      // 提示语
    scanf("%d", &n);                // 读完数字,回车留在缓冲区
    // ______ 在这里补一行:把缓冲区里那个回车吃掉
    c = getchar();                  // 现在才能读到真正的字符
    printf("n=%d c=%c\n", n, c);    // 输出
    return 0;                       // 结束
}                                   // 结束

🐛 改错题

c
// ============ 改错题 1:scanf 少了取地址符 ============
// ❌ 错误示例(故意)
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int a, b;                       // 两个整数
    scanf("%d%d", a, b);            // 错:这里传的是变量值,不是地址
    printf("%d\n", a + b);          // 想输出和
    return 0;                       // 结束
}                                   // 结束
// 错在哪:scanf 的地址表列必须是地址,变量名前面漏了 &
// 怎么改:改成 scanf("%d%d", &a, &b);
c
// ============ 改错题 2:格式符与数据类型不匹配 ============
// ❌ 错误示例(故意)
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int a = 5, b = 2;               // 两个整数
    printf("%f\n", a / b);          // 错:a/b 是 int,却用 %f 输出
    return 0;                       // 结束
}                                   // 结束
// 错在哪:① a/b 做的是整数除法,得 2,不是 2.5;② int 用 %f 输出,类型不匹配
// 怎么改:先转 double 再除——printf("%f\n", (double)a / b);
c
// ============ 改错题 3:语句末尾漏了分号 ============
// ❌ 错误示例(故意)
#include <stdio.h>                  // 标准输入输出
int main()                          // 主函数
{                                   // 开始
    int a = 3                       // 错:这一行末尾漏了分号
    printf("%d\n", a);              // 输出 a
    return 0;                       // 结束
}                                   // 结束
// 错在哪:int a = 3 后面必须有分号,否则编译报错
// 怎么改:写成 int a = 3;

四、加练题

(暂无。你随时喊"再出几道 XX 题",我出的题会标日期追加到这里。)