简介:吉林大学程序设计C语言上机题目汇总,面向吉大在校生及准备C语言机考的自学者,覆盖期中上机与期末上机典型题型,帮助快速熟悉考试范围与常考代码写法。资源共25个文件,其中23个为cpp源文件,1个为c源文件,另有1张吉大C语言笔试标识符参考图片,压缩包仅2.26MB,轻便易用。目前已有362人浏览学习,可作为备考吉大机考的高频复习资料。内容涉及链表创建与删除、递归分解与排序、素数判断、字符串处理、二维数组排序、文件操作等核心考点,代码完整且按题目类型整理,便于逐题编译调试、对照练习和举一反三;同时含有实验报告相关的链表与二维数组排序等代码,可帮助提升上机应试能力与C语言动手水平。
1. C语言上机题:考前最该刷的一份题库资源
第一次接触某高校的程序设计上机题库时,我并不太服气:题目看起来都挺基础,无非是字符统计、排序、链表反转,怎么一提交就白屏。后来连续练了两周才意识到,上机考核的从来不是“会不会写这个语法”,而是“在限时和不能翻资料的前提下,能不能把输入输出边界处理干净”。这份资源解决的正是这件事——它不是知识讲解,而是把程序设计课程里反复出现的题型和细节考点集合在一起,适合想要考前集中刷题、或者希望摸清常见踩坑点的在校学生和自学者。能把这里面的题刷透,上机考试基本就稳了一半。
2. 题目分类拆解:基础、控制流、指针三挡难度怎么练
拿到这种题目资源,第一件事不是急着从第一题做到最后一题,而是先按考点把题目归类。某高校这份上机题目的难度分布大概可以分成三档:基础语法题、控制结构题、数组指针与结构体题。前两类占了大头,但真正拉开分数差距的,往往是第三类里那两三道“压轴题”。
2.1 基础语法题:输入输出、字符处理与表达式求值
基础语法题在题库里约占三分之一,表面看只是热手题,实际上最容易丢分。因为这类题不考算法,考的是对细节的敏感度。最常见的就是 scanf 和 printf 的格式问题:读整数时忘记写取地址符&,输出时精度和宽度写错,都会直接判错。
| 考点 | 常见变形 | 最容易扣分的地方 |
|---|---|---|
| scanf / printf 格式 | 保留两位小数、左对齐、按宽度输出 | 漏写&、格式串与变量类型不匹配 |
| 字符处理 | 统计字母数字、大小写转换、ASCII 转换 | 混淆字符'0'与数字0 |
| 表达式 | 自增自减、复合赋值、优先级 | 把赋值=写在条件判断里 |
字符处理类的题目最容易翻车。比如“读入一行字符,统计其中英文字母、数字和其他字符的个数”,很多人会用scanf("%s", str)去读,结果一遇到空格就断了,因为%s遇到空白字符会停止。上机输入里经常带空格,这个坑几乎每周都有人踩。正确做法是getchar()循环读,或者用fgets整行读进来再逐字符判断。
表达式求值类的题,考点往往不是计算本身,而是运算符优先级。比如a + b << 2到底先算哪个,很多人凭感觉写,结果答案是反的。这类题建议做题时先把优先级表放在手边,写完代码再读一遍表达式,别依赖编译器帮你看,因为编译能过不代表语义对。
2.2 控制结构题:循环边界、分支遗漏与递归出口
第二档题目开始从“语法会不会”转向“逻辑对不对”。常见题型是素数判断、最大公约数、数位拆分、斐波那契数列。这类题目的坑集中在三个地方:
一是循环边界。判断 n 是否为素数,循环条件写成for (i = 2; i <= n; i++),功能上没错,但 n 稍大就会超时。很多上机题目会卡时间,常见做法是循环到sqrt(n)就停,因为大于 sqrt(n) 的因子必然成对出现。这一条不仅节省时间,也避免了大数场景下的不必要计算。
二是分支遗漏。比如数位拆分时,有人只处理了正整数,没考虑 0 和负数。输入是 0 的时候,循环直接不进去,输出就空着,判题结果就是格式错误。再比如求最大公约数,用辗转相除法时while (b != 0)的终止条件写错,程序会直接卡死。
三是递归出口。有的题目会考递归实现,比如斐波那契数列。递归本身不难,难在递归边界和终止条件。很多人写完递归函数,不检查 n=0 和 n=1 的情况,一跑直接栈溢出。遇到这类题,我一般会在主函数里先把最小两个输入用例跑一遍,确认递归出口有效,再提交。
2.3 数组、指针与结构体:拉分题大多从这里出
这一类题在资源里通常排在最后,也是整卷最值钱的部分。题目表面是“数组排序”“链表反转”“学生成绩管理”,实际考的是三个能力:数组下标的偏移计算、指针与数组名的区别、结构体与动态内存的使用。
数组题的经典场景是二维数组行列操作,比如矩阵转置。很多人写着写着就把下标写反了:a[i][j]和a[j][i]混用。这一点在纸上推演很简单,但上机时紧张起来很容易写错。我一般会先把行列数用变量名区分开,比如row和col,不要在代码里直接用裸数字。
指针与结构体结合的题目更难一点。比如结构体数组排序,用qsort需要写比较函数,比较函数里经常会忘记类型转换,或者返回值写反导致排序结果倒序。链表题则集中在头插、尾插、反转、删除这几个操作,核心就是指针之间的顺序:先保存下一个节点,再改当前节点的指针,否则链就断了。
建议练习顺序:一维数组统计 -> 二维数组操作 -> 结构体数组排序 -> 单链表反转。每一步都对应一类独立考点,跳着练容易卡在半路。
3. 真题实战:三道代表性上机题的手写解法与参数说明
题目资源里的数量很多,但把这些题拆开看,核心题型就那么几种。这一章我用三道具有代表性的题目,把完整代码、逻辑说明和常见参数坑一次讲清楚。
3.1 题目一:读入一行字符,统计英文字母、数字和其他字符个数
这道题是基础语法题的典型代表,既考字符输入方式,也考 ASCII 判断逻辑。
#include <stdio.h> #include <ctype.h> int main(void) { char ch; int letters = 0, digits = 0, others = 0; // 用 getchar 逐个读入,遇到换行符结束 while ((ch = getchar()) != '\n') { if (isalpha(ch)) { letters++; } else if (isdigit(ch)) { digits++; } else { others++; } } printf("%d %d %d\n", letters, digits, others); return 0; }逻辑说明:getchar()每次从标准输入读一个字符,包括空格和标点,直到读到换行符\n为止。isalpha和isdigit是标准库<ctype.h>提供的判断函数,比手写(ch >= 'a' && ch <= 'z')更安全也更易读。
参数说明:这里容易踩的坑有两个。第一,如果用scanf(" %c", &ch)配合while,会自动跳过空白字符,导致读不到空格,统计结果错误。第二,有些平台输入不是以换行结束,而是以文件结束符 EOF 结束。这种情况下判断条件应写成while ((ch = getchar()) != EOF),否则最后一个字符读不出来,输出会比预期少。遇到这种题目,先看输入描述里写的是“一行”还是“多行”,再决定循环边界。
3.2 题目二:按成绩从高到低输出学生信息,成绩相同按姓名升序
这道题是结构体数组和排序的经典组合,几乎每个版本的上机题库里都会出现。
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char name[32]; int score; } Student; // qsort 比较函数:先按成绩降序,成绩相同按姓名升序 int cmp(const void *a, const void *b) { Student *pa = (Student *)a; Student *pb = (Student *)b; if (pa->score != pb->score) { return pb->score - pa->score; } return strcmp(pa->name, pb->name); } int main(void) { int n, i; Student stu[128]; scanf("%d", &n); for (i = 0; i < n; i++) { scanf("%s %d", stu[i].name, &stu[i].score); } qsort(stu, n, sizeof(Student), cmp); for (i = 0; i < n; i++) { printf("%s %d\n", stu[i].name, stu[i].score); } return 0; }逻辑说明:qsort需要传入四个参数:待排序数组、元素个数、单个元素字节数、比较函数指针。比较函数返回负值表示 a 排在 b 前面,返回正值表示 a 排在 b 后面。这里成绩降序用pb->score - pa->score,姓名升序直接借助strcmp的返回值。
参数说明:Student stu[128]表示最多支持 128 个学生,如果题目没有明确说上限,建议声明成Student stu[1024]或直接定义为全局数组,避免局部变量栈空间不足。姓名数组name[32]够用,但有的题目名字会带空格,此时%s读不进去,需要改用%[^\n]或fgets。排序结果验证时,先看成绩是否降序,再看同分段的姓名是否按字典序,两个都满足再提交。
3.3 题目三:单链表反转
链表题是很多人的心理阴影,但它考的就是一个核心动作:在修改当前节点指向之前,先保存它的下一个节点。
#include <stdio.h> #include <stdlib.h> typedef struct Node { int data; struct Node *next; } Node; // 反转单链表,返回新头节点 Node* reverse(Node *head) { Node *prev = NULL; Node *curr = head; while (curr != NULL) { Node *next = curr->next; // 先保存下一个节点 curr->next = prev; // 反转当前节点的指针 prev = curr; // prev 前移 curr = next; // curr 前移 } return prev; // 遍历结束后 prev 就是新头 }逻辑说明:遍历链表时,如果先执行curr->next = prev,那么原来的下一个节点就找不到了,链表会在中途断开。所以标准做法是先把curr->next存进临时变量next,再修改指针,最后把prev和curr同时前移。
参数说明:这个函数需要处理两个边界。链表为空时,while不进入,直接返回NULL,逻辑上没问题。链表只有一个节点时,next为NULL,循环执行一次后prev指向原头节点,也能正确返回。调用的地方记得用返回值接住新头,不要直接打印旧head,否则输出会少一半节点。如果要求释放内存,反转后需要重新遍历一趟逐个free,但大多数上机题只要求输出,不强制释放。
4. 上机环境与调试:把编译报错变成得分点
代码写出来只是第一步,上机考试真正花时间的环节是调试。很多人在本地编译器里跑得好好的,一提交就报运行错误或答案错误,最后只能归咎于“玄学”。实际上这种问题基本都出在输入输出边界和环境差异上。
4.1 提交前必做的环境自检
上机判题系统通常使用 Linux 环境的 GCC 编译器,和本地 Windows 上用的编译器有些细节差异。我每次写完代码,先花两分钟做几个固定检查:
| 检查项 | 常见做法 | 典型错误 |
|---|---|---|
| 文件编码 | 保存为 UTF-8 无 BOM | 输出中文时出现乱码 |
| main 函数返回值 | 写return 0; | 省略返回值,部分平台警告甚至扣分 |
| scanf 调用 | 确认每个非字符变量都加& | 漏掉取地址符,程序直接崩溃 |
| 数组大小 | 按题目上限再加 10 的余量 | 临界数据访问越界,本地可能正常但线上报越界 |
还有一个容易被忽略的是输入中的“空行”。有些题目用scanf读数据,但输入文件末尾有多余换行,scanf会跳过空白字符,所以问题不大。但如果你用gets或fgets读固定行,空行会被当成字符串读进去,处理不好就会格式错。遇到这种情况,最稳妥的做法是先去掉字符串末尾的换行符。
4.2 调试三板斧:printf、注释法、样例对照
上机环境通常没有图形化断点调试工具,最实用的调试方式还是printf三板斧。第一个技巧是在关键循环里打印中间变量。比如排序后不确定比较函数是否生效,就在cmp里临时加一行printf("%d %d\n", pa->score, pb->score);,看调用顺序是否符合预期。确认逻辑正确后再删掉这行。
第二个技巧是注释法。如果程序输出完全不对,先把主流程里看似不影响结果的部分注释掉,只保留最小输入输出框架,看框架本身是否正确。比如先写死一个固定数据,不用输入,直接输出,确认输出函数没问题后,再逐步放开输入逻辑。这样能快速定位到底是读入问题还是计算问题。
第三个技巧是样例对照。大多数题目会给出 1 到 2 个标准样例,先把样例跑通,再自己构造边界用例。上机考试常见边界包括:最小输入、最大输入、单个元素、空输入、输入中带空格、输入序列中有重复值。每套题我都建议构造至少五个用例,跑完再提交。
4.3 从报错到通过:三个高频编译信息处理
编译报错不是扣分,而是给你送分。我第一次刷题库时最怕看到红字,后来发现报错信息里往往直接指向了问题行。
第一种是warning: control reaches end of non-void function。这个警告说明函数有返回值,但某个分支没有写return。常见于cmp比较函数或递归函数。解决方法是检查所有出口,确保每个分支都有返回语句。上机判题通常不会把编译警告直接判错,但存在不确定风险,能消掉就消掉。
第二种是segmentation fault,也就是段错误。出现这个大概率是数组越界或指针访问非法内存。排查顺序是:先看数组下标是否可能等于数组长度,再看指针是否可能为 NULL,最后看字符串末尾是否有\0。如果代码里用了scanf("%s", str)读超长字符串,缓冲区溢出也是段错误的主要来源。
第三种是time limit exceeded,运行超时。这种报错说明算法复杂度不够好,常见于素数判断没开根号、排序用了手写冒泡而题目数据量偏大、或者循环里不小心让计数器不更新导致死循环。遇到超时先别急着优化算法,先确认循环是否真的会退出,经常只是少写了一条更新语句。
4.4 时间与空间边界:为什么卡循环次数和数组大小
上机题资源里有些题目看起来简单,但运行效率要求很高。比如输入 n 万条记录并排序,写冒泡排序本地能过,提交后大概率超时,因为 O(n²) 的复杂度在数据量增大后会急剧放大。遇到这情况,换qsort或直接手写快速排序是最常见的处理方式。
数组空间也一样。int a[1000000]写在函数内部,可能直接栈溢出,改用全局数组或malloc动态分配就能通过。很多题目故意把数据量设定在动态分配才能通过的级别,就是为了考察这一点。我一般会养成一个习惯:如果读到的 n 可能很大,就不开固定局部大数组,直接malloc,用完后free,既省空间也省心。
5. 常见问题排查:五个最容易丢分的坑
根据这份题库的常见翻车点,我整理了五个反复出现的坑。每个坑都是先看到现象,再查原因,最后给解决方式,按这个顺序做能省下大量瞎猜的时间。
5.1 五个高频坑:现象、原因、解决
坑一:用scanf("%s", str)读带空格的字符串,结果只读到空格前的内容。
现象:输入hello world,输出只有hello,或者统计字符数时结果偏少。原因:%s会自动跳过和终止于空白字符,空格后的内容根本没有读进数组。解决:改用fgets(str, sizeof(str), stdin)整行读入,然后手动去掉结尾的\n;或者用scanf("%[^\n]", str)读入到换行为止。
坑二:判断数字字符时写成ch == 0而不是ch == '0'。
现象:输入0时程序不认为它是数字。原因:'0'是字符,ASCII 码是 48;0是空字符,ASCII 码是 0。两者完全不同。解决:所有字符常量都要加单引号,同时养成用isdigit(ch)的习惯,避免手写判断出错。
坑三:本地编译器跑样例完全正常,提交后报运行错误。
现象:样例能过,但隐藏测试点崩溃。原因:数组越界在本地会被系统宽容处理,在判题环境里直接触发段错误。最常见的是数组长度开了n但下标从1开始,最后访问到a[n]越界。解决:数组长度按题目上限再加 10,并且检查所有循环边界,确认最大下标不会超过数组大小减一。
坑四:条件判断写成if (n = 1),程序进了不该进的分支。
现象:输出结果完全不符合预期,甚至某些分支永远执行。原因:=是赋值运算符,表达式n = 1的返回值是 1,恒为真;==才是比较运算符。解决:把常量写在左边,写成if (1 == n),这样写错时编译器会报错,不会默默执行。
坑五:计算 20 的阶乘或 2 的 30 次方,结果变成负数。
现象:输出与手算答案差很多,甚至出现负数。原因:int类型最大值大约 21 亿,超过这个范围会发生有符号整数溢出,行为不可预期。解决:根据题目数据范围选择long long,配合%lld输出;如果数值更大,则需要用浮点或高精度方案。
5.2 排查工具与自测流程
每次刷题时,我都会把验证流程固定下来。第一步,先用题目给的样例跑通;第二步,自己构造一组边界数据,比如最小 n、最大 n、全同值、逆序;第三步,把输入数据写入一个文本文件,用输入重定向运行程序,再把输出重定向到另一个文件,用文件对比工具和预期结果逐项比对。
这种文件化的测试方式比手工输入高效很多,尤其是链表和排序这类输出较长的题型。手动输入容易看花眼,文件对比可以精确到每个字符的差异。格式化输出题有一类问题专坑人:结果完全正确,但多了一个空格或者少了一个换行。用文件对比一眼就能看出来,不用反复提交浪费时间。
6. 进阶用法:把题库刷成一套自己的训练闭环
题目资源刷一遍只是熟悉题型,真正让它值回票价的做法,是把整份题库变成一套可重复执行的训练闭环。我后来重新刷某高校这份题目时,用的已经不是“从第一题做到最后一题”的方式,而是按考点分组、限时训练。
具体做法分三步。第一步,把题库里的题目按我前面拆的分类打上标签:基础语法、控制结构、数组指针、结构体链表。第二步,每个分类每天抽 3 到 5 题,限定 30 分钟内完成,重点不是做对,而是记录哪一题卡住、哪一题报错次数多。第三步,每周回头重做一次上周的错题,不看答案直接重写。重复到第三周时,很多原先需要很久才能调通的题,基本一次就能过。
我还会把每次踩坑记录成一条简短的笔记,格式是:题目编号、考点、错因、修复方法。这个错题记录不用写得很长,关键是指出自己为什么错。比如“又忘了加&”“链表反转时没保存 next”“scanf 读空格断掉”。这些记录比任何教材都管用,因为它们来自自己真实的失误。
从那以后,我每次做完一道上机题,都会强制自己再做一遍“边界自测”:最小输入、最大输入、空输入、重复值输入,四个用例挨个跑完再提交。这个习惯帮我省掉了不少提交判错的次数。希望帮到你。
本文还有配套的精品资源,点击获取