1. C语言编程实战:山东理工大学期末测试题解析
作为一名计算机专业的过来人,我深知期末测试对大一学生的重要性。今天我将详细解析山东理工大学《程序设计基础Ⅰ》期末测试中的典型题目,帮助大家掌握C语言的核心编程技巧。这些题目涵盖了字符串处理、质因数分解、指针操作等多个重要知识点,都是实际开发中经常遇到的问题。
2. 字符串排序与查找实现
2.1 题目分析与思路
这道题目要求我们对教师姓名进行排序并查找特定老师的位置。题目给出了7位老师的姓名,存储在指针数组中。我们需要实现Sort_Tea函数来完成排序功能。
关键点在于:
- 使用指针数组存储字符串,避免直接操作字符串内容
- 采用冒泡排序算法实现字符串的升序排列
- 通过strcmp函数比较字符串大小
2.2 代码实现详解
c复制void Sort_Tea(char *p[], int n) {
char *temp;
for(int i=0; i<n-1; i++) {
for(int j=0; j<n-i-1; j++) {
if(strcmp(p[j], p[j+1]) > 0) {
temp = p[j];
p[j] = p[j+1];
p[j+1] = temp;
}
}
}
}
代码解析:
- 外层循环控制排序轮数(n-1轮)
- 内层循环比较相邻字符串
- strcmp返回值>0表示前字符串"大于"后字符串
- 通过交换指针实现排序,不改变原字符串内容
2.3 常见问题与优化
常见错误:
- 直接使用赋值运算符(=)复制字符串内容
- 忘记包含string.h头文件
- 数组越界访问
优化建议:
- 可以使用更高效的排序算法如快速排序
- 添加输入验证确保老师姓名存在
- 考虑大小写不敏感的比较方式
提示:指针数组排序只交换指针位置,比直接操作字符串内容效率更高,这是处理字符串排序的常用技巧。
3. 质因数分解算法实现
3.1 问题理解与数学原理
质因数分解是将一个合数表示为若干质数乘积的形式。例如20000=2^5×5^4。这道题要求我们实现primeFac函数完成这个功能。
数学原理:
- 从最小的质数2开始尝试除法
- 如果能整除,则该质数是因数之一
- 重复这个过程直到商为1
3.2 代码实现与解析
c复制void primeFac(int n) {
printf("%d=", n);
while(n != 1) {
int i;
for(i=2; i<=n; i++) {
if(n%i == 0) {
printf("%d", i);
n = n/i;
if(n != 1) printf("*");
break;
}
}
}
}
代码特点:
- 外层循环保证分解到n=1为止
- 内层循环寻找最小能整除n的质数
- 输出格式处理确保正确显示乘号
3.3 性能优化与边界情况
优化方向:
- 只需检查到sqrt(n)即可
- 跳过偶数因子(除2外)
- 预先生质数表
边界情况处理:
- 输入本身就是质数
- 输入为1(题目限定n≥2)
- 大数分解时的效率问题
4. 指针交换与内存操作
4.1 指针基础与交换原理
这道题考察指针的基本操作,要求实现swap函数交换两个整数的值。理解指针的关键在于明白它存储的是内存地址。
交换原理:
- 通过解引用操作(*)访问指针指向的值
- 使用临时变量保存其中一个值
- 完成三步交换操作
4.2 代码实现与分析
c复制void swap(int *p1, int *p2) {
int t = *p1;
*p1 = *p2;
*p2 = t;
}
关键点:
- 函数参数为指向int的指针
- 使用临时变量t保存*p1的值
- 通过解引用修改原内存位置的值
4.3 常见误区与扩展应用
常见错误:
- 交换指针本身而不是指针指向的值
- 忘记解引用直接操作指针
- 使用未初始化的指针
扩展应用:
- 交换任意类型数据(void指针)
- 实现泛型交换函数
- 在排序算法中的应用
5. 条件判断与基础IO操作
5.1 问题分析与解决方案
这道饺子分配问题考察基本的条件判断和输入输出操作。关键在于判断饺子数是否是班级人数的倍数。
解决方案:
- 使用取模运算符%判断整除关系
- 根据结果输出不同信息
- 注意输入输出格式要求
5.2 代码实现与验证
c复制#include <stdio.h>
int main() {
int m, n;
scanf("%d %d", &m, &n);
if(m % n == 0)
printf("HAPPY NEW YEAR");
else
printf("Who can eat the rest of the dumplings?");
return 0;
}
验证要点:
- 边界情况测试(如n=0,但题目保证n≥1)
- 大数测试(确保没有整数溢出)
- 格式验证(输出字符串完全匹配)
5.3 代码风格建议
- 添加适当的注释
- 考虑使用宏定义字符串常量
- 添加输入验证(如n≠0)
- 统一缩进风格
6. 复杂条件判断与浮点运算
6.1 问题分解与实现策略
这道加油费用计算题涉及:
- 汽油品种判断(90/93/97)
- 服务类型判断(m/e)
- 浮点数运算和格式化输出
实现策略:
- 使用嵌套if-else处理多种组合情况
- 应用折扣率计算最终价格
- 使用%.2lf保证输出格式
6.2 代码实现与解析
c复制#include <stdio.h>
int main() {
int m, n;
char ch;
scanf("%d %d %c", &m, &n, &ch);
double price = 0;
switch(n) {
case 90: price = 6.95; break;
case 93: price = 7.44; break;
case 97: price = 7.93; break;
default:
printf("The input should be 90 or 93 or 97.");
return 0;
}
double discount = (ch == 'm') ? 0.95 : 0.97;
printf("%.2lf", m * price * discount);
return 0;
}
改进点:
- 使用switch-case替代多重if-else
- 引入中间变量提高可读性
- 统一处理错误情况
6.3 浮点数精度问题
注意事项:
- 避免直接比较浮点数相等
- 了解浮点数的二进制表示限制
- 考虑使用整型分币计算避免精度问题
7. 字符串处理与元音统计
7.1 问题分析与算法设计
这道题要求统计字符串中元音字母的数量,包括大小写。需要考虑:
- 多行输入处理(使用gets或fgets)
- 大小写不敏感的元音判断
- 高效遍历字符串的方法
7.2 代码实现与优化
c复制#include <stdio.h>
#include <ctype.h>
#include <string.h>
int is_vowel(char c) {
c = tolower(c);
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}
int main() {
char str[81];
while(fgets(str, 81, stdin)) {
int count = 0;
for(int i = 0; str[i] != '\0'; i++) {
if(is_vowel(str[i])) {
count++;
}
}
printf("%d\n", count);
}
return 0;
}
优化技巧:
- 使用辅助函数提高代码可读性
- 采用tolower统一大小写处理
- 使用fgets更安全(避免缓冲区溢出)
7.3 输入处理注意事项
- gets函数已从C11标准中移除,不推荐使用
- fgets会保留换行符,需要处理
- 考虑超长行的处理策略
8. 数组操作与查找算法
8.1 顺序查找算法实现
这道题要求实现基本的顺序查找,找到目标数第一次出现的位置。顺序查找是最简单的查找算法,但效率较低(O(n))。
实现要点:
- 遍历数组元素
- 比较当前元素与目标值
- 找到立即返回下标
- 遍历完未找到返回特定值
8.2 代码实现与错误处理
c复制#include <stdio.h>
int main() {
int n, x;
scanf("%d", &n);
int arr[n];
for(int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
scanf("%d", &x);
for(int i = 0; i < n; i++) {
if(arr[i] == x) {
printf("%d", i);
return 0;
}
}
printf("NO");
return 0;
}
错误处理:
- 输入n超过数组声明大小
- 输入数据类型不匹配
- 多个匹配项时的处理(题目要求第一个)
8.3 算法优化与变种
优化方向:
- 哨兵技巧减少比较次数
- 对有序数组可采用二分查找
- 大规模数据考虑哈希表
9. 数组去重算法实现
9.1 问题分析与解决思路
这道题要求去除数组中的重复元素,保留第一次出现的元素。需要考虑:
- 高效判断元素是否已存在
- 原地修改数组或使用额外空间
- 输出格式要求
9.2 代码实现与解析
c复制#include <stdio.h>
#define MAX 20001
int main() {
int n, arr[MAX];
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
printf("%d", arr[0]);
for(int i = 1; i < n; i++) {
int is_dup = 0;
for(int j = 0; j < i; j++) {
if(arr[i] == arr[j]) {
is_dup = 1;
break;
}
}
if(!is_dup) {
printf(" %d", arr[i]);
}
}
return 0;
}
算法分析:
- 时间复杂度O(n²),适合n≤20000
- 空间复杂度O(1),原地操作
- 输出格式处理确保正确空格
9.3 高效去重方法
更优解决方案:
- 先排序后去重(时间复杂度O(nlogn))
- 使用哈希表记录出现元素(时间复杂度O(n))
- 位图法(适用于数据范围较小的情况)
10. 多条件筛选与奖学金评定
10.1 问题分析与数据结构选择
这道奖学金评定问题需要检查每个学生的三门成绩是否都≥90分。需要考虑:
- 多维数组存储学生成绩
- 多重条件判断
- 输出符合条件的学号
10.2 代码实现与验证
c复制#include <stdio.h>
int main() {
int n;
scanf("%d", &n);
int scores[40][3];
for(int i = 0; i < n; i++) {
scanf("%d %d %d", &scores[i][0], &scores[i][1], &scores[i][2]);
}
int has_winner = 0;
for(int i = 0; i < n; i++) {
if(scores[i][0] >= 90 && scores[i][1] >= 90 && scores[i][2] >= 90) {
printf("%d\n", i);
has_winner = 1;
}
}
if(!has_winner) {
printf("None.");
}
return 0;
}
验证要点:
- 边界值测试(刚好90分)
- 全不符合条件情况
- 多个符合条件情况
- 输入格式异常处理
10.3 代码优化与扩展
优化建议:
- 使用结构体组织学生数据
- 添加更多评定条件(如总分排名)
- 考虑从文件读取输入数据
- 输出结果到文件
在实际编程中,我发现理解题目要求并设计清晰的算法结构是最关键的。这些基础题目涵盖了C语言编程的核心概念,掌握它们对后续学习数据结构和算法有很大帮助。特别是指针操作和内存管理概念,这是C语言区别于其他高级语言的重要特性。