1. 顺序结构程序设计概述
顺序结构是C语言中最基础的程序控制结构,代码按照从上到下的顺序逐行执行。在专升本考试中,掌握顺序结构是理解后续选择结构和循环结构的前提。本章将重点讲解printf和scanf这两个最常用的输入输出函数,它们是顺序结构程序设计的核心工具。
提示:顺序结构看似简单,但在实际编程中,很多同学容易忽略格式控制细节,导致输出结果不符合预期。建议在学习时多动手实践,观察不同格式控制符的效果。
2. printf输出函数详解
2.1 printf函数的基本用法
printf函数是C语言标准库中最常用的输出函数,其基本语法格式为:
c复制printf("格式控制字符串", 输出项列表);
格式控制字符串包含两类内容:
- 普通字符:原样输出的字符
- 格式说明符:以%开头的特殊字符,控制输出项的格式
一个简单的例子:
c复制int age = 20;
printf("我今年%d岁", age); // 输出:我今年20岁
2.2 格式字符详解
格式字符决定了数据的输出形式,常用的有以下几种:
| 格式字符 | 说明 | 示例 | 输出结果 |
|---|---|---|---|
| %d/%i | 带符号十进制整数 | printf("%d", 123); | 123 |
| %u | 无符号十进制整数 | printf("%u", 123); | 123 |
| %o | 八进制无符号整数 | printf("%o", 10); | 12 |
| %x/%X | 十六进制无符号整数 | printf("%x", 255); | ff |
| %f | 浮点数 | printf("%f", 3.14); | 3.140000 |
| %c | 单个字符 | printf("%c", 'A'); | A |
| %s | 字符串 | printf("%s", "hello"); | hello |
| %e/%E | 科学计数法 | printf("%e", 1000); | 1.000000e+03 |
| %g/%G | 自动选择%f或%e | printf("%g", 1000.0); | 1000 |
2.3 修饰符详解
修饰符可以进一步控制输出格式,它们位于%和格式字符之间:
-
标志修饰符:
+:强制显示正负号-:左对齐输出(空格):正数前加空格,负数前加负号#:对o、x/X格式,输出前导0、0x/0X
-
宽度和精度:
m:最小字段宽度.n:浮点数小数位数或字符串最大输出字符数0:用前导0填充宽度
示例:
c复制printf("%+5d", 10); // 输出: +10
printf("%-5d", 10); // 输出:10
printf("%05d", 10); // 输出:00010
printf("%.2f", 3.14159); // 输出:3.14
printf("%#x", 255); // 输出:0xff
2.4 printf使用注意事项
-
格式说明符的数量和类型必须与输出项匹配,否则会导致未定义行为:
c复制int a = 10; printf("%d %f", a); // 错误:缺少一个输出项 -
输出顺序是从右向左计算(在部分编译器中):
c复制int i = 1; printf("%d %d %d", i++, i++, i++); // 输出可能是3 2 1 -
要输出%字符,需要使用%%:
c复制printf("折扣率:20%%"); // 输出:折扣率:20% -
对于长整型和双精度浮点数,需要使用l修饰符:
c复制long num = 100000L; printf("%ld", num); double d = 3.1415926; printf("%lf", d);
3. scanf输入函数详解
3.1 scanf函数的基本用法
scanf函数用于从标准输入读取数据,其基本语法格式为:
c复制scanf("格式控制字符串", 输入项地址列表);
格式控制字符串与printf类似,但有一些重要区别:
- 不需要考虑对齐和填充
- 不需要处理普通字符(除非用于分隔输入)
示例:
c复制int age;
scanf("%d", &age); // 从键盘读取一个整数存入age变量
3.2 scanf的格式字符
scanf支持的格式字符与printf类似,但有一些特殊之处:
| 格式字符 | 说明 | 示例输入 | 存储结果 |
|---|---|---|---|
| %d | 十进制整数 | 123 | 123 |
| %i | 自动识别进制(0开头为八进制,0x开头为十六进制) | 012 | 10 |
| %u | 无符号十进制整数 | 123 | 123 |
| %o | 八进制整数 | 12 | 10 |
| %x | 十六进制整数 | ff | 255 |
| %f/%lf | 浮点数(float/double) | 3.14 | 3.14 |
| %c | 单个字符 | A | 'A' |
| %s | 字符串(遇到空白字符停止) | hello | "hello" |
| %[] | 扫描字符集合 | [0-9] | 只读取数字 |
3.3 scanf的修饰符
-
长度修饰符:
h:短整型(short)l:长整型(long)或双精度(double)ll:长长整型(long long)
-
宽度修饰符:
m:指定最大输入字符数
c复制char str[10]; scanf("%9s", str); // 最多读取9个字符,留一个给'\0' -
*修饰符:- 跳过该输入项,不赋值给任何变量
c复制int a, b; scanf("%d %*d %d", &a, &b); // 输入"1 2 3",a=1,b=3,跳过2
3.4 scanf使用注意事项
-
必须使用变量的地址:
c复制int num; scanf("%d", num); // 错误:缺少& scanf("%d", &num); // 正确 -
输入数据的分隔:
- 当格式字符串中有空白字符(空格、制表符、换行符)时,可以匹配任意数量的空白字符
- 当格式字符串中有非空白字符时,输入中必须严格匹配这些字符
c复制scanf("%d,%d", &a, &b); // 输入必须像"10,20" -
字符串输入的安全问题:
- 使用%s时容易发生缓冲区溢出
- 更安全的做法是指定最大宽度或使用fgets
c复制char name[20]; scanf("%19s", name); // 最多读取19个字符 -
处理输入缓冲区:
- 当混合使用scanf和字符输入函数时,容易遇到换行符残留问题
c复制int age; char ch; scanf("%d", &age); // 输入数字后按回车 ch = getchar(); // 会读取到换行符解决方法:
c复制scanf("%d", &age); while(getchar() != '\n'); // 清空输入缓冲区 ch = getchar();
4. 字符和字符串输入输出函数
4.1 putchar和getchar
-
putchar:输出单个字符
c复制putchar('A'); // 输出字符A putchar(65); // 同样输出A,65是'A'的ASCII码 -
getchar:从标准输入读取一个字符
c复制char c = getchar(); // 读取一个字符
4.2 puts和gets
-
puts:输出字符串并自动添加换行符
c复制puts("Hello"); // 输出Hello并换行 -
gets:读取一行输入(已废弃,不安全)
c复制char str[100]; gets(str); // 不推荐使用,容易导致缓冲区溢出推荐替代方案:
c复制fgets(str, sizeof(str), stdin); // 更安全
5. 顺序结构程序设计案例
5.1 温度转换案例
c复制#include <stdio.h>
int main() {
double C, F;
printf("请输入华氏温度:");
scanf("%lf", &F);
C = (5.0 / 9) * (F - 32);
printf("对应的摄氏温度为:%.1lf°C\n", C);
return 0;
}
注意事项:
- 使用5.0而不是5,确保进行浮点数除法
- %.1lf控制输出一位小数
5.2 大小写字母转换
c复制#include <stdio.h>
int main() {
char big, small;
printf("请输入大写字母:");
scanf("%c", &big);
small = big + 32; // ASCII码差值
printf("对应小写字母:%c\n", small);
return 0;
}
常见问题:
- 如果输入的不是大写字母,结果会不正确
- 可以添加输入验证:
c复制if(big < 'A' || big > 'Z') { printf("输入的不是大写字母!\n"); return 1; }
5.3 变量交换
c复制#include <stdio.h>
int main() {
int a, b, temp;
printf("请输入两个整数:");
scanf("%d%d", &a, &b);
printf("交换前:a=%d, b=%d\n", a, b);
temp = a;
a = b;
b = temp;
printf("交换后:a=%d, b=%d\n", a, b);
return 0;
}
替代方案(不使用临时变量):
c复制a = a + b;
b = a - b;
a = a - b;
5.4 数字逆序输出
c复制#include <stdio.h>
int main() {
int num, a, b, c;
printf("请输入一个三位数:");
scanf("%d", &num);
a = num / 100; // 百位数
b = (num / 10) % 10; // 十位数
c = num % 10; // 个位数
printf("逆序输出:%d%d%d\n", c, b, a);
return 0;
}
扩展思考:
- 如何实现任意位数的数字逆序?
- 如何处理负数的情况?
5.5 进制转换
c复制#include <stdio.h>
int main() {
int num;
printf("请输入一个十进制整数:");
scanf("%d", &num);
printf("八进制:%o\n", num);
printf("十六进制:%x\n", num);
return 0;
}
注意事项:
- 使用%#o和%#x可以输出前导0和0x
- 对于负数,输出的是补码表示
6. 常见错误与调试技巧
6.1 printf常见错误
-
格式说明符与参数类型不匹配:
c复制int a = 10; printf("%f", a); // 错误:应该用%d -
忘记转义特殊字符:
c复制printf("路径:C:\new\file.txt"); // 错误:\n和\f被解释为转义字符 printf("路径:C:\\new\\file.txt"); // 正确 -
浮点数精度问题:
c复制float f = 0.1; printf("%.20f", f); // 输出:0.10000000149011611938
6.2 scanf常见错误
-
忘记取地址运算符&:
c复制int num; scanf("%d", num); // 错误:应该是&num -
缓冲区溢出:
c复制char name[5]; scanf("%s", name); // 如果输入超过4个字符,会导致溢出 -
输入不匹配:
c复制int a, b; scanf("%d,%d", &a, &b); // 输入必须包含逗号
6.3 调试技巧
-
使用printf调试:
c复制printf("调试信息:a=%d, b=%d\n", a, b); // 查看变量值 -
检查返回值:
c复制int items = scanf("%d", &num); if(items != 1) { printf("输入错误!\n"); } -
分步测试:
- 先测试输入部分
- 再测试计算部分
- 最后测试输出部分
7. 应试技巧与备考建议
-
重点掌握:
- printf和scanf的格式控制
- 各种格式字符的含义
- 修饰符的使用方法
-
常见考点:
- 输出对齐和填充
- 浮点数精度控制
- 输入分隔符处理
- 混合数据类型的输入输出
-
备考建议:
- 多做练习题,特别是格式控制相关的题目
- 注意区分printf和scanf的格式控制差异
- 掌握常见错误的排查方法
-
考试时间分配:
- 选择题:快速判断格式控制的结果
- 填空题:注意细节,如%#x的输出
- 编程题:先写框架,再补充细节
在实际编程中,我发现很多同学容易混淆printf和scanf的格式控制,特别是在处理浮点数时。建议通过制作对比表格来强化记忆。另外,scanf的安全问题经常被忽视,这在考试中可能不会考察,但在实际开发中非常重要。
