用法:每段都是完整可编译程序,每行后面都有
//注释。先照着敲一遍、跑通,再盖住注释自己讲一遍。
编译环境: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 题",我出的题会标日期追加到这里。)