1. 题目背景与需求解析
PTA(Programming Teaching Assistant)是高校程序设计课程常用的在线评测平台,"习题9-4 查找书籍"是一道典型的C语言结构体练习题。题目要求编写程序,从输入的若干本书籍信息中查找价格最高和最低的书籍,并输出其信息。
这道题的核心训练目标包括:
- 结构体类型的定义与使用
- 结构体数组的输入输出处理
- 最值查找算法的实现
- 字符串处理技巧
在实际教学中,这类题目常作为结构体应用的入门练习,帮助学生掌握复杂数据类型的组织方式。从网络热词可以看出,与之相关的"字符串逆序"、"二分查找"等也是PTA平台的常见题型。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据结构设计与输入处理
2.1 书籍结构体定义
首先需要设计合适的数据结构来存储书籍信息。根据常规题目要求,每本书通常包含:
- 书名(字符串)
- 作者(字符串)
- 价格(浮点数)
对应的C语言结构体定义如下:
c复制#define MAX_LEN 100 // 书名和作者名的最大长度
typedef struct {
char name[MAX_LEN];
char author[MAX_LEN];
double price;
} Book;
2.2 输入处理要点
书籍信息的输入需要注意几个关键点:
- 输入格式:通常题目会指定输入格式,如"第一行给出正整数n,随后n行每行给出书名、作者和价格"
- 字符串读取:书名和作者名可能包含空格,不能直接用scanf的%s
- 输入缓冲:混合使用scanf和gets/fgets时要注意清除缓冲区
推荐的安全输入方案:
c复制int n;
scanf("%d", &n);
getchar(); // 清除换行符
Book books[n];
for (int i = 0; i < n; i++) {
fgets(books[i].name, MAX_LEN, stdin);
books[i].name[strcspn(books[i].name, "\n")] = '\0'; // 去除换行
fgets(books[i].author, MAX_LEN, stdin);
books[i].author[strcspn(books[i].author, "\n")] = '\0';
scanf("%lf", &books[i].price);
getchar(); // 清除换行
}
3. 最值查找算法实现
3.1 基础遍历法
最简单的实现方式是遍历结构体数组,记录当前找到的最高价和最低价书籍:
c复制void findMinMaxBooks(Book books[], int n, Book *minBook, Book *maxBook) {
if (n <= 0) return;
*minBook = *maxBook = books[0];
for (int i = 1; i < n; i++) {
if (books[i].price < minBook->price) {
*minBook = books[i];
}
if (books[i].price > maxBook->price) {
*maxBook = books[i];
}
}
}
3.2 优化技巧
虽然题目数据量通常不大,但可以做一些优化:
- 在一次遍历中同时查找最小和最大值,减少遍历次数
- 使用指针而非结构体拷贝,节省内存和时间
- 添加边界检查(如n=0的情况)
4. 完整代码实现与测试
4.1 完整解决方案
c复制#include <stdio.h>
#include <string.h>
#define MAX_LEN 100
typedef struct {
char name[MAX_LEN];
char author[MAX_LEN];
double price;
} Book;
void findMinMaxBooks(Book books[], int n, Book *minBook, Book *maxBook) {
if (n <= 0) return;
*minBook = *maxBook = books[0];
for (int i = 1; i < n; i++) {
if (books[i].price < minBook->price) {
*minBook = books[i];
}
if (books[i].price > maxBook->price) {
*maxBook = books[i];
}
}
}
int main() {
int n;
scanf("%d", &n);
getchar();
Book books[n];
for (int i = 0; i < n; i++) {
fgets(books[i].name, MAX_LEN, stdin);
books[i].name[strcspn(books[i].name, "\n")] = '\0';
fgets(books[i].author, MAX_LEN, stdin);
books[i].author[strcspn(books[i].author, "\n")] = '\0';
scanf("%lf", &books[i].price);
getchar();
}
Book minBook, maxBook;
findMinMaxBooks(books, n, &minBook, &maxBook);
printf("%.2lf, %s\n", maxBook.price, maxBook.name);
printf("%.2lf, %s\n", minBook.price, minBook.name);
return 0;
}
4.2 测试用例设计
针对PTA平台的测试,建议准备以下测试用例:
- 正常情况:3-5本书,价格有明显差异
- 边界情况:只有1本书
- 特殊情况:多本书价格相同
- 极端值:价格非常大或非常小
- 书名/作者名包含空格
示例测试输入1:
code复制3
Programming in C
K. N. King
59.99
C Primer Plus
Stephen Prata
89.99
The C Programming Language
Brian W. Kernighan
79.99
预期输出1:
code复制89.99, C Primer Plus
59.99, Programming in C
5. 常见错误与调试技巧
5.1 典型错误分析
-
字符串读取不完整:使用scanf("%s")读取书名会导致遇到空格就停止
- 解决方案:改用fgets并处理末尾换行符
-
缓冲区问题:混合使用scanf和fgets时容易出错
- 解决方案:在scanf后使用getchar()清除缓冲区
-
浮点数精度问题:价格比较时直接使用==可能导致误差
- 解决方案:比较时考虑允许的误差范围
-
数组越界:没有检查输入的n值是否合理
- 解决方案:添加n>0的检查
5.2 PTA提交注意事项
- 输出格式必须严格匹配题目要求,包括空格、标点等
- 变量命名要有意义,避免使用过于简单的名字
- 添加适当的注释,特别是关键步骤
- 在本地测试通过后再提交,避免多次失败影响成绩
6. 扩展思考与进阶练习
掌握了基础解法后,可以尝试以下扩展:
- 将查找函数改为递归实现
- 使用函数指针实现不同的比较策略(如按书名排序)
- 将书籍信息存储在文件中,从文件读取
- 实现更复杂的查询功能(如价格区间查询)
类似题目推荐:
- PTA习题9-5 通讯录排序
- PTA习题10-1 计算两个复数之积
- PTA习题10-3 递归求阶乘和
在实际编程中,这类结构体操作是数据库和对象操作的基础。理解了这个练习,对后续学习C++类和更复杂的数据结构有很大帮助。
