ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

专升本C语言编程题刷题框架:从题型逻辑到高频考点精讲

专升本C语言编程题刷题框架:从题型逻辑到高频考点精讲 你刚打印了那份传说中“专升本必做”的《C语言100道经典编程题》第一篇是水仙花数。照着书敲完编译运行看到153、370、371、407依次输出心里踏实了。但等考场上的题目换成“输出所有五位数中各位数字的五次方之和等于本身的数”你还能在五分钟内写出来吗我见过太多同学刷完这100道题分数反而没比只认真刷20道的室友高。差别不在刷题数量而在有没有把每道题背后的题型逻辑吃透。这篇文章就围绕这100道经典编程题给你一套真正能用在专升本、专接本考场上的拆解方法包含高频考点、10道必刷题的精讲以及我这些年从学生代码里总结出来的高频失分点。1. 先把专升本C语言编程题的“游戏规则”摸清楚刷题前需要搞明白的三件事1.1 专升本C语言和计算机二级C语言刷题思路不能照搬很多人手里同时攥着计算机二级的题库和专升本真题觉得都是C语言混着刷就行。这个想法得改。计算机二级C语言更偏重语法细节和“补全代码”选择题里大量考运算符优先级、类型转换、指针加减上机题也经常只是让你填一个函数。专升本的编程题则完全不一样它要求你从main函数开始完整地写出一个能处理输入、能运行出结果、能应对边界情况的程序。我辅导过的一个学弟计算机二级考了“优秀”结果做专升本模拟卷时在文件读取那道题上整整卡了二十分钟。原因很真实二级里文件操作只考概念专升本直接让你从data.txt里读一串整数求和还要考虑文件打不开的情况。两种考试的“肌肉记忆”完全不同所以刷题前先定位清楚别拿二级的存量去硬套专升本的题型。1.2 高频考点和大致分值分布先有全局再动手根据近几年部分省份的专升本C语言真题编程题的分值分布虽然不完全相同但大类非常稳定。我把它们整理成一张表你可以对照着安排复习时间。考点模块典型题目大致占比顺序与循环结构水仙花数、素数、累加累乘、穷举20%数组排序、逆置、删除重复元素、二维数组20%字符串字符统计、逆序、回文判断、子串查找15%函数与递归传参、返回值、递归边界15%指针交换变量、指针遍历数组、指针与字符串15%结构体与文件学生成绩管理、地址簿、文件读写15%从这张表能看出两个信息第一循环和数组合起来占了40%左右是绝对的“基本盘”100道题里至少有50道在反复考这两件事第二指针很少单独出一道题它更喜欢藏在数组和字符串里一起考。所以刷题的时候不要孤立地刷“指针题”而是要在数组、字符串的题目里顺手把指针用法练熟。1.3 100道题不是让你刷完而是让你“筛一遍”我在文章开头那句话不是在吓唬人。真正的100道经典题作用是一张筛网把你可能遇到的题型面全部覆盖一遍。每做完一道题你应该问自己三个问题这道题的考点属于哪个模块这题有没有一个可以套用的解题模板如果题目条件改一下三位数变五位数、升序变降序、数组变链表我还能不能很快改出来能做到这三点一道题顶别人十道。做不到刷一百道也只是反复在最基础的for循环里打转越刷越空虚。下面我按照题型框架把这100道题里最值得深挖的内容拆给你看。2. 从100道经典题里提炼出的6大核心题型按这个框架刷思路不会乱2.1 输入输出与顺序结构scanf和printf是地基但地基里藏着雷很多同学觉得输入输出有什么好刷的printf谁不会。但专升本机试和笔试的读题要求是“从键盘输入”“输出格式见样例”这里面的坑可不少。比如scanf里如果加了多余的换行符或者用gets去接收含空格的字符串都会让你的程序在评测系统上表现异常。这类题的正确刷法是把scanf、getchar、gets、fgets的区别搞清楚。我的建议是字符串输入统一用fgets整数输入用scanf但要注意把上一行残留的换行符吃掉。100道题里前三道往往就是这种看似简单的输入输出题很多人的代码功能对却因为输出多了个空格被扣分特别冤。2.2 分支和循环穷举水仙花、素数、完数、数字累加全是这一类循环穷举是专升本编程题的题眼。水仙花数、输出100到200之间的素数、求1000以内的完数、判断闰年全是for循环里套if条件的经典结构。这类题拿分的关键不是会不会写for而是能不能把穷举范围、取位拆分、标志变量这三件事写对。取位拆分是其中的核心技能。比如一个三位数n百位是n/100十位是n/10%10个位是n%10。这个套路背下来不算本事你要能理解为什么这样拆然后迁移到“五位水仙花数”这种变体题上。我那篇标题里提到的“5位水仙花数”就是把三位拆位变成了五位拆位本质完全一样。2.3 数组、排序与查找手写算法不是背代码要背“过程”数组题最容易出现的情况是看着答案能懂合上书自己写就断片。原因在于大多数人只背了代码没有背排序过程中的状态变化。比如冒泡排序你一定要能自己说出每一轮比较会把当前未排序部分的最大值“冒”到最后所以内层循环的比较次数会越来越少。专升本的数组题很少让你直接写库函数qsort更多是要求你手写冒泡、选择、插入排序。高频题目包括数组逆序、删除重复元素、找出最大值及其下标、二维数组转置。这些题写一遍不够我建议你在草稿纸上画一个长度为5的数组手动模拟一遍排序过程再对照代码这样才算真正掌握。2.4 字符串处理忘掉“字符串对象”用字符数组和下标去思考不少从Python转过来学C语言的同学总想着“字符串能不能像Python那样直接反转”现实很残酷C语言里根本没有字符串类型只有字符数组和字符指针。所以字符串题目的核心是理解字符串末尾的\0以及用下标去遍历每一个字符。经典题包括统计大写字母、小写字母、数字、空格个数字符串逆序判断回文删除指定字符。刷这些题时建议把strlen、strcpy、strcmp等常用字符串函数的源码逻辑自己实现一遍。专升本不太会直接考“请写出strcpy的实现”但你把底层逻辑想清楚之后所有字符串操作题都会变得简单很多。2.5 函数与递归递归的难点不在代码而在调用栈函数题在专升本里往往不会单独考得太深更多是要求你写一个函数完成特定功能然后在main里调用。这里最容易失分的不是函数本身而是参数传递到底是传值还是传地址。比如写一个交换两个变量的函数如果参数写成int a, int b那就是白写交换的是副本main里的变量根本不变。所以指针的知识在这里就必需了。递归是另一个让很多人头疼的点。我的建议是遇到递归题先画调用栈从递归边界往上推。比如斐波那契数列先想清楚n等于1和2时返回什么再想n2时如何递归下去。不要死记代码要能自己推导。2.6 结构体与文件读写最后一道综合大题的标准配置很多省份的专升本最后一题会考察结构体和文件操作因为它能把前面的知识全部串起来。比如定义一个学生结构体从文件读入成绩按分数排序再把排序结果写入另一个文件。这道题如果你前面数组、排序、函数都练扎实了其实就是换个容器重新组装。文件操作的第一个难点是文件指针的用法fopen的打开模式“r”“w”“a”分别代表什么fscanf和fprintf如何格式化读写fclose忘记写会怎样。第二个难点是判断文件是否打开成功很多同学忽略这个判断文件不存在时程序直接崩溃在机试环境下是很严重的失误。3. 从100道题里选出的10道必刷经典题每一道都拆开讲透3.1 水仙花数与“变体题”循环拆位的通用套路题目输出所有三位水仙花数即各位数字的立方和等于该数本身。#include stdio.h int main() { for (int n 100; n 999; n) { int a n / 100; // 百位 int b n / 10 % 10; // 十位 int c n % 10; // 个位 if (a * a * a b * b * b c * c * c n) { printf(%d\n, n); } } return 0; }这道题考了一个很重要的思维把“数的各个位”拆出来。你一旦会拆三位拆五位就照葫芦画瓢用数组循环除以10取余也能做。我建议你顺便想一想如果题目不告诉你这个数是几位数只要求你判断它是不是“水仙花数”该怎么办这时就需要用一个临时变量不断n/10统计位数再求每一位的k次方。这种变体在100道题里经常出现防的就是你只会背三位数的模板。3.2 区间素数输出标志变量该放哪里放错位置全盘皆输题目输出1990到2000之间所有的素数每个数之间用tab分隔。#include stdio.h int main() { for (int n 1990; n 2000; n) { if (n 2) continue; int is_prime 1; for (int i 2; i * i n; i) { if (n % i 0) { is_prime 0; break; } } if (is_prime) { printf(%d\t, n); } } return 0; }这道题最经典的一个坑是is_prime这个标志变量定义在哪个位置。如果你把它定义在n的循环外面那么第二次数n时它已经不是1了后面的判断全乱套。正确做法是每次循环重新初始化为1。另外判断素数只需要让i从2到根号n不要傻乎乎地循环到n-1这个优化能在稍微大一点的区间题里省下大量时间。3.3 手写冒泡排序内外层循环边界是最大失分点题目输入n个整数用冒泡排序法从小到大排序并输出。#include stdio.h void bubble_sort(int arr[], int n) { for (int i 0; i n - 1; i) { for (int j 0; j n - 1 - i; j) { if (arr[j] arr[j 1]) { int tmp arr[j]; arr[j] arr[j 1]; arr[j 1] tmp; } } } } int main() { int n; scanf(%d, n); int arr[100]; for (int i 0; i n; i) { scanf(%d, arr[i]); } bubble_sort(arr, n); for (int i 0; i n; i) { printf(%d , arr[i]); } return 0; }我发现很多学生背熟了“in-1、jn-1-i”但不知道为什么。你只要记住一个原则每轮冒泡结束后最后一个元素已经是当前的最大值所以下一轮少比较一次。如果考场上紧张忘了公式就在纸上模拟一个长度为4的数组很快就能推出边界。还有一个小细节如果某轮循环没有任何交换说明数组已经有序可以提前break。这个优化在“判断数组是否已经有序”的变体题里很有用建议你顺手写进去。3.4 字符串逆序双下标法比指针法更不容易错题目输入一个字符串将其逆序输出。#include stdio.h #include string.h void reverse(char s[]) { int left 0; int right strlen(s) - 1; while (left right) { char tmp s[left]; s[left] s[right]; s[right] tmp; left; right--; } } int main() { char s[100]; fgets(s, sizeof(s), stdin); // fgets会读入换行符去掉它 size_t len strlen(s); if (len 0 s[len - 1] \n) { s[len - 1] \0; } reverse(s); printf(%s\n, s); return 0; }这道题看起来简单但字符串操作里全是细节。首先不要用getsgets无法限制长度评测系统里很容易因为输入过长导致数组越界。用fgets时又会多读一个换行符需要在逆序前把它去掉。逆序本身用双下标一左一右向中间移动比定义第三个数组更节省空间也不容易出错。如果你想练指针版本可以用char *left schar *right s strlen(s) - 1然后交换指针指向的内容。思路是一样的但指针虽然帅反而更容易把right指针指错位置所以考试时选自己最有把握的写法就好。3.5 递归求斐波那契数列递归边界才是考察重点题目用递归函数求斐波那契数列的第n项。#include stdio.h int fib(int n) { if (n 2) { return 1; } return fib(n - 1) fib(n - 2); } int main() { int n; scanf(%d, n); printf(%d\n, fib(n)); return 0; }递归题在专升本里不算高频但几乎每套模拟卷都会出一道。很多人背下来fib表达式却在边界条件上翻车比如n等于1或2时应该返回1如果写成if (n 1) return 1;那n等于2时就会调用fib(1)和fib(0)而fib(0)又无限递归下去。所以写递归第一件事是确定边界条件第二件事是确认递归调用方向一定会向边界靠近。如果n比较大比如n50这个递归会卡到怀疑人生。你可以在草稿纸上画一下调用树会发现大量重复计算。能主动想到用数组存中间结果来优化这种思路在面试和竞赛里都是加分项。3.6 统计字符串中各类字符个数别自己造轮子判断字母题目输入一行字符统计其中英文字母、数字、空格和其他字符的个数。#include stdio.h #include ctype.h int main() { char s[200]; fgets(s, sizeof(s), stdin); int letters 0, digits 0, spaces 0, others 0; for (int i 0; s[i] ! \0; i) { if (isalpha(s[i])) { letters; } else if (isdigit(s[i])) { digits; } else if (s[i] ) { spaces; } else { others; } } printf(letters:%d digits:%d spaces:%d others:%d\n, letters, digits, spaces, others); return 0; }这道题的核心不是统计本身而是很多学生会在判断是否字母时写一堆手动区间判断(s[i] a s[i] z) || (s[i] A s[i] Z)。这样写没错但容易漏掉大写或小写还容易在“字母”和“字符”上犯迷糊。直接用ctype.h里的isalpha、isdigit代码既简洁又不会错。还有一个小坑空格和其他字符的判断顺序。先判断字母和数字再用else if判断空格最后的else兜底。如果你先把空格判断放在字母前面那空格会被正确识别但字母会被误判成其他字符。3.7 结构体数组按成绩排序交换结构体时别只交换分数题目定义学生结构体姓名、学号、成绩输入n个学生信息按成绩从高到低排序并输出。#include stdio.h #include string.h typedef struct { char name[20]; char id[10]; int score; } Student; int main() { int n; scanf(%d, n); Student stu[100]; for (int i 0; i n; i) { scanf(%s %s %d, stu[i].name, stu[i].id, stu[i].score); } // 选择排序按成绩降序 for (int i 0; i n - 1; i) { int max_idx i; for (int j i 1; j n; j) { if (stu[j].score stu[max_idx].score) { max_idx j; } } if (max_idx ! i) { Student tmp stu[i]; stu[i] stu[max_idx]; stu[max_idx] tmp; } } for (int i 0; i n; i) { printf(%s %s %d\n, stu[i].name, stu[i].id, stu[i].score); } return 0; }这道题在专升本试卷里几乎是以“压轴题”的身份出现的难度其实不大但综合性很强结构体定义、数组、排序、字符串复制全考到了。最容易犯的错是排序时只交换了score没交换name和id最后输出时成绩顺序变了名字却没跟着变整个结果全错。所以在交换结构体变量时直接整体交换Student结构体或者用strcpy逐个字段交换千万不要只交换分数。如果你想练得更细一点可以再加一个“成绩相同的按姓名排序”这就是比较常见的变体题。3.8 文件读入整数并求和文件操作题最怕忘记判断打开失败题目文件data.txt中每行有一个整数读入这些整数并输出它们的和。#include stdio.h int main() { FILE *fp fopen(data.txt, r); if (fp NULL) { printf(file open failed\n); return 1; } int sum 0; int x; while (fscanf(fp, %d, x) 1) { sum x; } fclose(fp); printf(%d\n, sum); return 0; }文件题是很多人的“心理阴影”其实考点就那么几个。第一fopen的第一个参数是文件路径第二个参数“r”表示只读。“w”表示写“a”表示追加这个不能混。第二fopen返回的是FILE*指针如果文件不存在会返回NULL一定要判断否则下一步fscanf会直接崩溃。第三fscanf的返回值是成功读取的参数个数所以用while (fscanf(fp, %d, x) 1)来循环读读到文件末尾就自动退出。第四fclose别忘写虽然程序结束会自动关闭但养成习惯能避免文件写入不完整。3.9 二维数组转置只遍历一半元素别转完又转回去题目将一个n*n的二维数组转置即行列互换。#include stdio.h void transpose(int a[][100], int n) { for (int i 0; i n; i) { for (int j i 1; j n; j) { int tmp a[i][j]; a[i][j] a[j][i]; a[j][i] tmp; } } } int main() { int n; scanf(%d, n); int a[100][100]; for (int i 0; i n; i) { for (int j 0; j n; j) { scanf(%d, a[i][j]); } } transpose(a, n); for (int i 0; i n; i) { for (int j 0; j n; j) { printf(%d , a[i][j]); } printf(\n); } return 0; }二维数组题在100道经典题里一般会占5到8道转置是里面最典型的。我看到不少学生写转置时内层循环从j0开始这样每个元素会被交换两次转完又转回原样输出根本没变化。正确做法是从j i 1开始也就是只操作对角线右上方的元素让每个元素只被交换一次。这道题还可以延伸成“顺时针旋转90度”它需要四要素循环交换难度更高但如果你能把转置彻底想明白旋转也不会太吃力。3.10 数组去重先排序再双指针能覆盖90%的题目题目输入一个有序数组删除其中重复的元素输出删除后的长度和数组。#include stdio.h int remove_duplicates(int a[], int n) { if (n 0) return 0; int k 0; for (int i 1; i n; i) { if (a[i] ! a[k]) { k; a[k] a[i]; } } return k 1; } int main() { int n; scanf(%d, n); int a[100]; for (int i 0; i n; i) { scanf(%d, a[i]); } int len remove_duplicates(a, n); for (int i 0; i len; i) { printf(%d , a[i]); } return 0; }如果题目没有说数组有序你要先自己写排序。有序之后双指针的思路就很清晰k指针保存“当前不重复序列的最后一位”i指针往后遍历只要发现新元素和a[k]不同就说明遇到了新的不重复元素把它放到k1的位置。这个思路在C语言里很常用比起“开一个新数组判断是否存在”要省内存也写得更快。很多人会忘记处理n等于0的特殊情况直接返回0没问题但如果你在函数里先访问a[0]就崩了。边界判断永远是数组题里最容易被扣分的地方。4. 阅卷老师最反感的5类“送命代码”这些坑值得单独拿出来说4.1 scanf后面紧跟gets或fgets缓冲区残留的换行符这个坑出现的频率实在太高了。当你用scanf输入一个整数后再调用fgets读字符串fgets会立刻读到上一次留在缓冲区里的换行符然后直接返回一个空串。解决办法是在scanf后加一句getchar();把换行符吃掉或者统一用fgets读入每一行再用sscanf解析。我建议冲刺阶段尽量养成第二种习惯它在处理混合输入时更稳定。4.2 数组越界编译不报错运行也不报错但结果就是不对C语言对数组越界没有安全检查你在arr[5]里写了个值大概率不会立刻崩溃而是悄悄写到了相邻内存里。这种bug非常难排查而且评测系统里可能因为越界导致输出错乱。越界最常见的原因有两个一是循环边界写成i n二是字符串忘了留出\0的位置。凡是定义字符数组长度至少要能装下字符串长度加1这已经是老生常谈了。4.3 用直接判断浮点数相等100道题里有一些涉及浮点运算的题目比如判断一个数是否为完全平方数有人写出sqrt(n) * sqrt(n) n这几乎必然失败。因为浮点数在计算机里是近似存储1.9999999和2.0不会相等。正确做法是计算两个数的差当差的绝对值小于1e-6时认为相等。记住这个经验能帮你避开一大类“玄学错误”。4.4 局部变量不初始化就当0用在main函数里定义int sum;然后直接sum x程序会输出一个随机数。局部变量的初值是不确定的不是0。所有累加、统计的变量定义时都要先赋0或1。有些同学在VC6.0里跑没发现问题因为编译器恰好把内存清零但换到考场环境就翻车。这个习惯一定要从刷题第一天就养成。4.5 函数声明了返回值却有分支没有return写一个判断素数的函数int is_prime(int n)如果循环里没有找到约数但你在循环外忘记写return 1;函数就会返回一个不确定的值。这时候主程序可能把素数判成非素数。任何一个有返回值的函数必须保证所有路径都有return。写完后从头到尾检查一遍每一条分支都看一眼这个动作花不了十秒钟但能救回好几分。5. 把100道题刷出“真题感”三轮复刷法亲测有效5.1 第一轮按知识点分块每道题独立完成并写注释第一轮刷题不要按100道题的顺序从头刷到尾而是按我前面说的6大题型分块。比如这三天只刷循环穷举题下三天只刷数组题。每道题都不要直接看答案先自己写卡住时再看答案看明白后把答案关掉自己重新写一遍。写完还要在关键代码旁边加注释解释“为什么这里要这样写”这个强迫自己输出的过程比单纯抄一遍有用得多。5.2 第二轮乱序刷题限时模拟考场第二轮时你对每类题已经有基本手感这时候要开始打乱顺序。把100道题的列表随机排列每天抽10道限时90分钟做完就像在考场上一样。这个做法的目的是打碎你的思维惯性。很多同学平时按题型刷看到题目就知道该用排序还是递归但考场上不会有人告诉你这题属于哪类。乱序训练能帮你培养“读题→判断题型→套方法”的反射速度。5.3 第三轮不动手只动脑快速默写思路第三轮复习时时间通常比较紧张了。你不需要每道题都完完整整敲一遍代码而是只盯着题目在脑子里或草稿纸上快速写出定义什么变量、用什么循环、边界条件在哪、有没有需要单独处理的特殊情况。每道题控制在5分钟以内。如果某道题你连思路都说不出来就把它标记为重点题回到第二轮重新完整写一遍。这个“思维默写”的速度直接决定你考场上的答题效率。5.4 考前一周用历年真题做“脱敏训练”最后一周我建议你把100道经典题先放一放专心做报考省份的历年真题。因为经典题是通用训练而真题才代表当地出题老师的偏爱。比如有的省份特别喜欢考结构体排序有的省份则每年都有一道文件读写题。做真题时严格计时用A4纸当答题卡编程题直接在纸上手写代码写完之后再上机验证。手写代码这个环节特别重要因为专升本笔试时不会给你编译器你必须在没有提示的情况下写出没有语法错误的代码。这个能力只能靠平时刻意训练。“100道经典编程题”这个名字听起来像是一个数量指标但实际上它是一套能力体检清单。我见过太多人刷完这100道题最后只得了一个“我好像都见过”的印象却写不出一个完整的冒泡排序。说到底真正让你上岸的不是那100道题而是你核对参考答案时反复追问“为什么”的习惯。你可以在刷题群里看到别人用各种花哨解法但你自己的那份代码应该是你能在考场上最快写完、最不容易出错、最经得起边界条件考验的版本。按照上面这套框架去刷哪怕只完成了50道效果也会比你盲目刷完100道来得好。
返回列表