全国大学生计算机应用能力与数字素养大赛 C语言程序设计赛项——本科组练习
1.
错误分析
1.函数 fun 的参数类型错误:
函数 fun 的目的是对整数进行反转操作,参数应该是 long int 类型,而不是 double 类型。因为输入的是整数,用 double 可能会带来不必要的精度问题。
2.while 循环的条件变量错误:
在 fun 函数中,while 循环的条件使用的是 n,但是 n 并没有在函数 fun 中定义,这里应该使用参数 m(在修正参数类型后 )或者重新梳理变量逻辑,实际应该是基于传入的整数进行操作,原代码中在 fun 函数内又定义了一个局部变量 m ,并且循环条件使用未定义的 n ,逻辑混乱。
3.if 条件判断错误:
在 main 函数中,if(fun(n)) 这样的判断是错误的。fun 函数的作用应该是返回反转后的整数,然后需要将返回的反转数和原数 n 进行比较,来判断是否是回文数,而不是直接判断 fun(n) 的返回值是否为真。
修改代码如下:
#include<stdio.h> /**********found**********/ long int fun(long int n){int m=0;/**********found**********/while(n>0){m=m*10+n%10;n=n/10;}return m; } int main(){long int n;scanf("%ld",&n);/**********found**********/if(fun(n)==n)printf("%ld是回文数",n);elseprintf("%ld不是回文数",n);return 0; }
2.
错误分析与修正
- 第一个
found
处:
- 错误原因:选择排序中,每一轮应该先假设当前
p
指向的元素是这一轮的最小值,所以min
初始值应设为p
,而不是a
(a
是数组起始地址,这里逻辑不对 )。- 修正:将
min = a;
改为min = p;
。- 第二个
found
处:
- 错误原因:要找最小值,应该比较指针指向的元素值,即
*q
和*min
,而不是比较指针q
和p
(比较指针是比较地址,不是值 )。- 修正:将
if ( q < min )
改为if ( *q < *min )
。- 第三个
found
处:
- 错误原因:交换元素时,
t
是用来暂存值的,原代码中t = p;
是将指针p
的地址赋给t
,逻辑错误。应该交换p
和min
指向的元素值,所以要先暂存*p
的值,即t = *p;
。- 修正:将
t = p; *p = *min; *min = t;
改为t = *p; *p = *min; *min = t;
。#include<stdio.h> #define N 20 int main() {int a[N], *p, t, *q, *min;int n;scanf("%d", &n);for (p = a; p < a + n; p++) {scanf("%d", p);}// 用选择法排序for (p = a; p < a + n - 1; p++) {/********** found **********/min = p; for (q = p + 1; q < a + n; q++) {/********** found **********/if (*q < *min) min = q;}/********** found **********/t = *p; *p = *min; *min = t; }for (p = a; p < a + n; p++) {printf("%d ", *p);}printf("\n");return 0; }
3.
1. main 函数中结构体变量定义
错误行:Box_type box;
修正:结构体类型使用需要带 struct (或已 typedef 情况,这里原代码未 typedef ),改为 struct Box_type box;
2. input 函数中 scanf 参数
错误行:scanf("%f%f%f%f", box_p->length, box_p->width, box_p->high, box_p->per_price);
修正:scanf 传入指针,这里应取结构体成员地址,改为 scanf("%f%f%f%f", &box_p->length, &box_p->width, &box_p->high, &box_p->per_price);
3. value 函数中计算总价
错误行:box_p->total_price=area*per_price;
修正:per_price 是结构体成员,需通过 box_p 访问,改为 box_p->total_price = area * box_p->per_price;
4. output 函数定义
错误行:void output(struct *box_p)//输出箱子信息
修正:结构体指针作为参数需带类型名,改为 void output(struct Box_type *box_p)//输出箱子信息
修改前代码:
#include <stdio.h>struct Box_type {float length,width,high;//箱子的长、宽、高float per_price; //材料单位价格float total_price; //箱子总价格 }; void input(struct Box_type *box_p); void value(struct Box_type *box_p); void output(struct Box_type *box_p);int main() {/**********FOUND**********/Box_type box;input(&box);value(&box);output(&box);return 0; }void input(struct Box_type *box_p)//输入箱子信息 {/**********FOUND**********/scanf("%f%f%f%f",box_p->length,box_p->width,box_p->high,box_p->per_price); }void value(struct Box_type *box_p)//计算箱子造价 {float area; //箱子表面积area=(box_p->length*box_p->width+box_p->length*box_p->high+box_p->width*box_p->high)*2;/**********FOUND**********/box_p->total_price=area*per_price; }/**********FOUND**********/ void output(struct *box_p)//输出箱子信息 {printf("箱子的长、宽、高、单价、总造价为:\n");printf("长\t宽\t高\t单价\t造价\n");printf("%.1f\t%.1f\t%.1f\t%.1f\t%.1f\n",box_p->length,box_p->width,box_p->high,box_p->per_price,box_p->total_price); }
修改后代码如下:
#include <stdio.h>struct Box_type {float length,width,high;//箱子的长、宽、高float per_price; //材料单位价格float total_price; //箱子总价格 }; void input(struct Box_type *box_p); void value(struct Box_type *box_p); void output(struct Box_type *box_p);int main() {/**********FOUND**********/struct Box_type box;input(&box);value(&box);output(&box);return 0; }void input(struct Box_type *box_p)//输入箱子信息 {/**********FOUND**********/scanf("%f%f%f%f",&box_p->length,&box_p->width,&box_p->high,&box_p->per_price); }void value(struct Box_type *box_p)//计算箱子造价 {float area; //箱子表面积area=(box_p->length*box_p->width+box_p->length*box_p->high+box_p->width*box_p->high)*2;/**********FOUND**********/box_p->total_price=area*box_p->per_price; }/**********FOUND**********/ void output(struct Box_type *box_p)//输出箱子信息 {printf("箱子的长、宽、高、单价、总造价为:\n");printf("长\t宽\t高\t单价\t造价\n");printf("%.1f\t%.1f\t%.1f\t%.1f\t%.1f\n",box_p->length,box_p->width,box_p->high,box_p->per_price,box_p->total_price); }
4.
正确代码:
#include<stdio.h>int main() {int jin,yin,tong,n,i;int sum_jin,sum_yin,sum_tong,sum;/************SPACE************/sum_jin=sum_yin=sum_tong= 0;scanf("%d",&n);/************SPACE************/for(i=1;i<=n;i++){scanf("%d%d%d",&jin,&yin,&tong);sum_jin+=jin;sum_yin+=yin;/************SPACE************/sum_tong+=tong;}sum=sum_jin+sum_yin+sum_tong;printf("%d %d %d %d",sum_jin,sum_yin,sum_tong,sum);return 0; }
5.
正确代码如下:
- 第一个
SPACE
处:fun
函数需要返回STU
类型,所以补充STU
作为返回值类型。- 第二个
SPACE
处:要比较结构体数组中每个元素的num
成员,所以补充std[i].num
。- 第三个
SPACE
处:找到对应编号的结构体元素后,返回该元素std[i]
。- 另外,
fgets
会读取换行符,通过n[strcspn(n, "\n")] = '\0';
去掉换行符,保证和结构体中存储的编号格式一致以便正确比较 。#include <stdio.h> #include <string.h> #define N 8 typedef struct {char num[10];int year, month, day; } STU; /**********SPACE**********/ STU fun(STU *std, char *num) {int i;STU a = {"", 9999, 99, 99};for (i = 0; i < N; i++)/**********SPACE**********/if (strcmp(std[i].num, num) == 0)/**********SPACE**********/return std[i];return a; }int main() {STU std[N] = {{"111111", 1984, 2, 15}, {"222222", 1983, 9, 21}, {"333333", 1984, 9, 1}, {"444444", 1983, 7, 15}, {"555555", 1984, 9, 28}, {"666666", 1983, 11, 15}, {"777777", 1983, 6, 22}, {"888888", 1984, 8, 19}};STU p;char n[10];fgets(n, 10, stdin);p = fun(std, n);if (p.num[0] == '\0')printf("未找到该编号!");else{printf("找到该编号!\n");printf("出生年月:%d-%d-%d\n", p.year, p.month, p.day);}return 0; }
6.
填补说明
1.while
循环条件:要持续对value
进行除 16 取余操作直到value
小于 16,所以条件为value >= 16
。2.数组赋值:每次取
value
除以 16 的余数作为索引,从data
数组中取对应十六进制字符存入num
,即data[value % 16]
。
3.fun
函数返回值:需要返回十六进制数的有效位数n
,用于
4.main
函数调用:调用fun
函数,将返回的有效位数赋值给n
,传给这样代码就能正确将输入的十进制非负整数转换为十六进制并输出。
正确代码如下:
#include <stdio.h> #include <stdlib.h>char data[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};void Print(char *num,int n) {int i;for(i=n-1;i>=0;i--) printf("%c",num[i]);printf("\0");printf("\n"); }int fun(char *num,int value) {int n=0;/**********SPACE**********/while(value>=16){/**********SPACE**********/num[n++]=data[value%16];value/=16;}num[n++]=data[value%16];/**********SPACE**********/return n; }int main() {int value;char num[10];int n;scanf("%d",&value);/**********SPACE**********/n=fun(num,value);Print(num,n);return 0; }
7.
1.fun 函数:
1.遍历数字 n 的每一位,跳过值为 x 的间谍数字。
2.将剩余数字反转,得到原始数字。
2.main 函数:
1.读取输入的两个加密数字 a、b 和间谍字符 x。
2.如果 x 是 'N',表示没有间谍数字,将 spy 赋值为 -1(不可能是数字,避免干扰)。
3.否则,将 x 转换为数字(x - '0')。
4.调用 fun 函数处理 a 和 b,输出原始算式的结果。
正确代码如下:
#include<stdio.h>int fun(int n,int x){ /**********Program**********/ int res = 0; while(n>0){int digit = n%10;if(digit!=x){res = res*10+digit;}n/=10; } return res;/********** End **********/ }int main(){int a,b;char x;scanf("%d%d %c",&a,&b,&x);int spy = (x=='N')?-1:(x-'0');printf("%d",fun(a,spy)*fun(b,spy));return 0; }
7.
代码说明
1.保存列尾元素:定义 temp 数组,遍历矩阵每一行,把每一列的最后一个元素(即 t[i][N - 1])保存到 temp 中对应行的位置。
2.列元素后移:通过两层循环,外层遍历行,内层从每列的倒数第二个元素开始往前遍历,将当前元素赋值为前一个元素的值,实现每列前 N - 1 个元素整体右移 1 位。
3.恢复列尾元素到列首:再次遍历每一行,把 temp 中保存的原列尾元素赋值给对应列的第一个位置(即 t[i][0]),完成 “绕回左边” 的操作。
4.输出矩阵:按照要求的格式输出处理后的矩阵内容。
#include <stdio.h> #define M 3 #define N 4int t[M][N], i, j, k; int x;int main() {// 输入矩阵元素for (i = 0; i < M; i++) {for (j = 0; j < N; j++) {scanf("%d", &t[i][j]);}}/*********Program*********/// 先保存每列最后一个元素int temp[M];for (i = 0; i < M; i++) {temp[i] = t[i][N - 1];}// 从后往前,将每列前 N - 1 个元素依次后移for (i = 0; i < M; i++) {for (j = N - 1; j > 0; j--) {t[i][j] = t[i][j - 1];}}// 将每列保存的最后一个元素放到该列第一个位置for (i = 0; i < M; i++) {t[i][0] = temp[i];}/********* End *********/for (i = 0; i < M; i++) {for (j = 0; j < N; j++) {printf("%d ", t[i][j]);}printf("\n");}return 0; }
8.
关键逻辑说明
1.核心思路:通过 for 循环枚举 “购买的瓶数 m”,从 m=1 开始尝试,模拟买饮料 → 喝饮料 → 空瓶换饮料的过程,直到找到 “能喝到的饮料总数 s 满足需求 n” 的最小 m。
2.空瓶兑换:每次用空瓶换饮料时,ex = b/3 是 “能换几瓶新的”,b = b%3 + ex 是 “换完后剩余的空瓶(没参与兑换的 + 新喝出来的空瓶)”。
3.终止条件:当 s >= n 时,说明当前 m 已经能让所有人喝到饮料,此时的 m 就是 “最少购买量”,跳出循环输出结果。
#include<stdio.h> // 头文件,提供标准输入输出函数(如 scanf、printf 等)的声明// 注释:假设题目背景是“12 个空瓶,三个空瓶换一瓶”,实际代码逻辑是通用的“空瓶换饮料”问题 int main() {int m; // 最少购买 m 瓶饮料(变量声明)int s; // 实际能喝到 s 瓶饮料(变量声明)// 程序逻辑开始区域(题目要求补充代码的范围)/**********Program**********/int n; // 声明变量 n,用于存储输入的运动员人数(或需要满足的饮料总数)scanf("%d",&n); // 从控制台读取用户输入的整数,存入变量 n// for 循环:从 m=1 开始尝试,每次 m 自增 1,直到找到满足条件的最少购买量// 注意:原代码 for(m=1;;m++) 写法是“死循环”,靠内部 break 跳出,也可写成 for(m=1; ; m++)for(m=1;;m++){ s = m; // 初始能喝到的饮料数 = 购买的瓶数(先喝掉买的)int b = m; // 空瓶数初始为购买的瓶数(喝完产生的空瓶)// while 循环:只要空瓶数 b ≥ 3,就可以继续换饮料while(b>=3){ int ex = b/3; // 计算当前空瓶能换几瓶新饮料(商)s += ex; // 能喝到的总数增加“兑换的瓶数”b = b%3 + ex; // 兑换后剩余空瓶 = 兑换前空瓶 % 3(换完剩下的空瓶) + 新喝出来的空瓶(兑换的瓶数)}// 如果实际能喝到的饮料数 s ≥ 需要满足的人数 n,说明当前 m 是可行解,跳出循环if(s>=n){ break;}}/********** End **********/// 输出最少购买瓶数 mprintf("最少应购买%d瓶饮料\n",m); // 输出实际能喝到的瓶数 sprintf("实际能喝到%d瓶饮料\n",s); return 0; // 程序正常结束,返回 0 }
9.
代码说明
1.拆分数字:通过 %10 和 /10 操作,将输入的四位整数拆分到数组 aa 中,数组下标 0 存储个位,1 存储十位,以此类推。
2.加密处理:遍历数组,每位数字加 5 后对 10 取余。
3.交换位置:按照规则交换第一位和第四位、第二位和第三位。
4.输出结果:逆序遍历数组(因为拆分时低位存在数组前半部分 ),输出加密后的四位数字。
#include <stdio.h> int main() {int a ,i,aa[4],t;scanf("%d",&a);/**********Program**********/// 拆分四位整数到数组for (i = 0; i < 4; i++) {aa[i] = a % 10;a /= 10;}// 每位数字加 5 并取余for (i = 0; i < 4; i++) {aa[i] = (aa[i] + 5) % 10;}// 交换第一位和第四位,第二位和第三位t = aa[0]; aa[0] = aa[3]; aa[3] = t;t = aa[1]; aa[1] = aa[2]; aa[2] = t;// 输出加密后的结果for (i = 3; i >= 0; i--) {printf("%d", aa[i]);}/********** End **********/return 0; }
11.
正确代码如下:
#include<stdio.h> int main() {char a[14];int i,k=1,sum=0,j,f=0; //k为数字1、2.....,j为识别码,f为x标识/**********Program**********/scanf("%s", a);// 计算前9位数字的加权和for (i = 0; k <= 9; i++) {if (a[i] != '-') { // 跳过分隔符sum += (a[i] - '0') * k;k++;}}int correct = sum % 11; // 计算正确识别码// 提取输入的识别码if (a[12] == 'X') j = 10;else j = a[12] - '0';// 验证并输出结果if (correct == j) {printf("Right\n");} else {if (correct == 10) a[12] = 'X';else a[12] = correct + '0';printf("%s\n", a);}/********** End **********/return 0; }
12.
在
sum
函数里,利用for
循环从1
遍历到n
,根据项数的奇偶性(通过i % 2 == 1
判断)来决定是做加法还是减法操作,逐步累加得到表达式的和并返回,主函数中调用sum
函数并输出结果 。#include <stdio.h>float sum(int n) {/**********Program**********/float num=0.0;for(int i=1;i<=n;i++){if(i%2==0){num=num-1.0/i;//注意1.0,如果使用1那么1/i会自动取整}else{num=num+1.0/i;//同上}}return num;/********** End **********/ }int main() {int n;scanf("%d",&n);printf("sum=%f\n",sum(n)); }
#include <stdio.h>float sum(int n) {// 用于存储累加的结果float s = 0; int i;for (i = 1; i <= n; i++) {if (i % 2 == 1) {// 奇数项做加法s += 1.0 / i; } else {// 偶数项做减法s -= 1.0 / i; }}return s; }int main() {int n;scanf("%d", &n);printf("sum=%f\n", sum(n)); }
13.
修正点说明
- 函数定义:原代码
fun(int m)
缺少返回值类型,需补充为double fun(int m)
(因计算结果是浮点数,用double
类型更合适 )。- 循环逻辑:原循环条件和语法正确,无需修改,但要注意理解从
100
开始、每次加100
直到不超过m
的逻辑。- 除法运算符:
\
是转义字符,除法需用/
,所以y += 1.0 \ d ;
改为y += 1.0 / d;
。- 输出格式:原
printf
中%lf
虽也可输出double
,但示例输出是0.000160
(保留 6 位小数 ),调整为%.5f
保证输出格式与示例一致(实际计算结果保留五位小数后符合示例 ),也可根据需求调整小数位数 。运行修改后的代码,输入
m = 2000
时,就能得到正确结果0.00016
。#include <stdio.h>// 修正:添加函数返回值类型为 double double fun(int m) {double y = 0, d;int i;// 修正:初始化 i 为 100,步长 100,条件 i <= mfor (i = 100; i <= m; i += 100) {d = (double)i * (double)i;// 修正:除法运算符为 /,不是 \y += 1.0 / d;}return y; }int main() {int n = 2000;// 修正:格式字符串中保留 5 位小数,与示例输出匹配printf("\nThe result is %.5f\n", fun(n));return 0; }
14.
#define N 30 #include "stdlib.h" #include <stdio.h> int max_min(int a[], int n) {/**********Program**********/int max = a[0], min = a[0];int i;for(i = 1; i < n; i++) {if(a[i] > max) {max = a[i];}if(a[i] < min) {min = a[i];}}return max * min;/********** End **********/ }int main() {int a[N], i, k;for(i = 0; i < N; i++)a[i] = 10;for(i = 0; i < N; i++){printf("%5d", a[i]);if(((i + 1) % 5) == 0) printf("\n");}k = max_min(a, N);printf("the result is:%d\n", k); }
15.
补充说明
1.第一处 int 【?】[14] ,应填 fib ,用于定义存储斐波那契数列的数组。
2.第二处 fib[i] = 【?】 ,根据斐波那契数列的递推规律,填 fib[i - 1] + fib[i - 2] ,即当前项是前两项之和。
3.第三处 if (【?】) ,填 (i + 1) % 5 == 0 ,用于判断是否已经输出了 5 项,达到换行条件。 这样程序就能正确输出斐波那契数列的前 15 项,且每行输出 5 项。
#include <stdio.h>int main() {// 定义存储斐波那契数列的数组int fib[15], i; fib[0] = 1; fib[1] = 1;for (i = 2; i < 15; i++)// 斐波那契数列规律:当前项 = 前两项之和fib[i] = fib[i - 1] + fib[i - 2]; for (i = 0; i < 15; i++){printf("%d\t", fib[i]);// 每 5 项输出后换行if ((i + 1) % 5 == 0) printf("\n"); } }
16.
#include <stdio.h> #define N 5void fun(int arr[],int n) {/**********Program**********/int l = 0, r = n - 1;while (l < r){int tmp = arr[l];arr[l++] = arr[r];arr[r--] = tmp;}/********** End **********/ }int main() {int a[N]={8,6,5,4,1},i;for(i=0;i<N;i++)printf("%4d",a[i]);printf("\n");fun(a,N);for(i=0;i<N;i++)printf("%4d",a[i]); }
#include <stdio.h> #define N 5void fun(int arr[], int n) {// 用于临时存储交换的元素int temp; int i;for (i = 0; i < n / 2; i++) {// 对称位置元素交换temp = arr[i]; arr[i] = arr[n - 1 - i];arr[n - 1 - i] = temp;} }int main() {int a[N]={8,6,5,4,1},i;for(i=0;i<N;i++)printf("%4d",a[i]);printf("\n");fun(a,N);for(i=0;i<N;i++)printf("%4d",a[i]); }
17.
double fun(int n) {double s = 0.0;int i;/**********Program**********/for (i = 1; i < n; i++) {// 判断是否能同时被 5 和 11 整除if (i % 5 == 0 && i % 11 == 0) { s += i;}}// 计算平方根s = sqrt(s); /********** End **********/return s; }
18.
#include <stdio.h> int main() {int i;// 修正:存储 10 个成绩,数组大小应为 10float a[10], min, max, avg; printf("input 10 score:\n");// 修正:循环条件,i 从 0 到 9(共 10 次)for (i = 0; i < 10; i++) { // 修正:scanf 需取地址,应为 &a[i]scanf("%f", &a[i]); }max = min = avg = a[0];// 修正:循环条件,i 从 1 到 9(遍历剩余 9 个元素)for (i = 1; i < 10; i++) { // 修正:找最小值,条件应为 min > a[i]if (min > a[i]) min = a[i];// 修正:找最大值,条件应为 max < a[i]if (max < a[i]) max = a[i];avg += a[i];}avg = avg / 10;printf("max:%f\nmin:%f\navg:%f\n", max, min, avg); }
19.
#include <stdio.h> int main() {int i, n, sum;sum = 0;/**********SPACE**********/n = 0; /**********SPACE**********/for (i = 1; i <= 300; i++) /**********SPACE**********/if (i % 7 == 0 || i % 17 == 0) if (i % 2 == 0){sum = sum + i;n++;printf("%6d", i);/**********SPACE**********/if (n % 5 == 0) printf("\n");}printf("\n\ntotal=%d", sum); }
20.
21.
#include <stdio.h> // 修正:函数需要返回 int 类型,改为 int fun(int m) int fun(int m) {int i, k = 1;if (m <= 1) k = 0;// 修正:循环条件,从 2 开始到 m-1,避免冗余判断for (i = 2; i < m; i++) // 修正:判断是否能被整除,若能则不是素数,k 置 0if (m % i == 0) k = 0; // 修正:返回判断结果 k(1 表示素数,0 表示非素数)return k; }int main() {int m, k = 0;for (m = 1; m < 100; m++)// 修正:调用函数判断是否为素数,素数返回 1if (fun(m) == 1) {printf("%4d", m); k++;if (k % 5 == 0) printf("\n");} }
22.
选择排序法:第一次从待排序的数据元素中选出最小的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
#include <stdlib.h> #include <stdio.h>void sort(int a[], int n) {/**********Program**********/int i, j, min_idx, temp;for (i = 0; i < n - 1; i++) {min_idx = i;for (j = i + 1; j < n; j++) {if (a[j] < a[min_idx]) {min_idx = j;}}temp = a[i];a[i] = a[min_idx];a[min_idx] = temp;}/********** End **********/ }int main() {int a[13], i;for (i = 0; i < 13; i++)a[i] = random(20) - 5;for (i = 0; i < 13; i++)printf("%3d", a[i]);printf("\n----------------------\n");sort(a, 13);for (i = 0; i < 13; i++)printf("%3d", a[i]); }