链接我放出来 是计算机能力挑战赛官方公众号发的题
选择题
1
以下描述不正确的是( )。
C程序经过编译、连接步骤之后才能形成一个真正可执行的二进制机器指令文件
C语言中的每条可执行语句和非执行语句最终都将被转换成二进制的机器指令
C语言源程序经编译后生成后缀为.obj的目标程序
用C语言编写的程序称为源程序,它以ASCII代码形式存放在一个文本文件中
选B
2
以下叙述中正确的是( )。
由三种基本结构构成的程序只能解决小规模的问题
一个结构化程序必须同时由顺序、分支、循环三种结构组成
结构化程序使用goto语句会很便捷
在C语言中,程序的模块化是利用函数实现的
选D
3
设a、b和c都是int型变量, 且a=3、b=4、c=5, 则下面的表达式中,值为0的表达式是( )
!((a<b)&&!c||1)
\'a\'&&\'b\'
a<=b
a||++c&&b-c
解析: 选项A: !((a<b)&&!c||1)为 先执行(a<b) 为真,再执行!c||1, 为0, 与远算后为0,取非为非0
4
以下描述正确的是( )。
do-while语句构成的循环,必须用break语句才能退出
do-while语句构成的循环,当while语句中的表达式值为零时结束循环
do-while语句构成的循环,当while语句中的表达式值为非零时结束循环
不能使用do-while语句构成的循环
解析: 对于A,dowhile是先做再判断, 不是必须使用break
对于C 非0为真 继续循环而非结束循环
对于D 可以
选B
6
以下描述正确的是( )。
C语言的函数可以嵌套调用
C语言的函数可以嵌套定义
C语言编译时不检查语法
C语言的子程序有过程和函数两种
直接选A
对于D C语言的子程序由函数组成,过程不是C语言的组成部分,显然过程和函数并不是C语言的子程序的两种不同形式,故选项B错误
7
以下说法中不正确的是( )。
在程序结束时,应当用fclose函数关闭已打开的文件
二进制文件打开后可以先读文件的末尾,而顺序文件不可以
不可以用FILE定义指向二进制文件的文件指针
利用fread函数从二进制文件中读数据,可以用数组名给数组中所有元素读入数据
选项 A 正确,应当在程序结束时使用 fclose
函数关闭已打开的文件。选项 B 正确,二进制文件可以先移动文件指针到文件的末尾,而顺序文件不可以(通常只能顺序读取)。选项 D 正确,fread
函数可以从二进制文件中读取数据,并且可以使用数组名给数组中所有元素读入数据。选项C错误
FILE *binaryFile = fopen("example.bin", "rb"); // ... fclose(binaryFile);
8
若已定义:int x[9],*y=x;并在以后的语句中未改变y的值,不能表示x[1]地址的表达式是( )。
&x[0]+4
y+1
y++
x++
解析: int*类型的指针p,存储地址为数组首元素的地址,指向x[0],
选项A &x[0]+4 对数组首元素取地址,跳过4*sizeof(int)字节的地址, 也就是等价于&x[4]
选项B y+1 ,y存储的是&x[0],往前一个int元素大小字节, 于是存储的是&x[1]
选项C y++ , ++后表示y+1,是&x[1],为x[1]的地址
选项D x++ ,++后表示跳过9*sizeof(int)字节,也就是&x[8]+1,在数组后面了
参考答案选D
不懂A哪里不对, 评论区有懂的uu说一下
9
以下定义不正确的是( )。
#define X struct xx X{ int a; float b; }stu;
struct{ int a; float b; }xx; struct xx stu;
typedef struct xx { int a; float b; }X; X stu;
struct { int a; float b; }stu;
B不对,它意思是表达XX为自定义类名,实则不是
正确的应该是
typedef struct{ int a; float b; }xx;xx stu;
对于选项A
使用了宏 #define
将 X
定义为 struct xx
。然后通过 X { ... } stu;
的方式定义了一个结构体变量 stu
。
对于选项C
就是B的改正版本
对于选项D
是一个直接定义结构体变量的方式 但是定义的是匿名结构体
就是B的改正版本
10
以下程序的输出结果是( )。
#include <stdio.h>
#define f(x) x*x
void main()
{
int a=6,b=2,c;
c=f(a)/f(b);
printf("%d",c);
}
#define f(x) x*xint main(){ int a=6, b=2, c; c=f(a)/f(b); printf("%d",c); return 0;}
解析: c = 6*6 / 2*2 = 36/2*2 = 18*2 = 36
如果加上括号就是9了 c = (6x6)/(2x2)= 9
11
以下描述正确的是( )。
位运算的对象只能是整型或字符型数据
右移运算时,高位总是补0
左移运算的结果总是原操作数据2倍
位运算符都需要两个操作数
解析:位运算的对象 移位操作符的操作数只能是整数,字符型数据也是整数(存储的是ASCLL码值)
char a = 'a'; printf("%d\n", a); a = a>>1; printf("%d\n", a);
9748
右移运算时, 对于原码,往往补0,对于补码反码,补1
举个例子,假设有一个8位的二进制数,表示的是一个负数 -5 的补码。该数的补码是:11111011。如果对这个补码进行右移一位,补充的位数都是在左边补零,得到的结果是:11111101。
对于正数来说,无论是原码、补码还是反码,在右移时都是在左边补零。对于负数,原码和反码在右移时同样在左边补零,而补码在右移时在左边补符号位(即补1)。
左移运算的结果总是原操作数据2倍
左移一位是扩大2倍,左移n为扩大为2^n倍
位运算符都需要两个操作数 按位取反只需要一个操作数,
int x = 1; int ret = ~x;
12
以下选项不正确的是( )。
a^=b 与 a=a^b 等价
a&=b 与 a=a&b 等价
a|=b 与 a=a|b 等价
a!=b 与 a=a!b 等价
解析:观察这几个运算符的区别,只有最后一个是单目运算符, 单目运算符只能对一个元素进行运算,因此此题选D
13
若函数调用时的实参为变量时,以下叙述中正确的是( )。
同名的实参和形参占同一存储单元
函数的形参和实参分别占用不同的存储单元
函数的实参和其对应的形参共占同一存储单元
形参只是形式上的存在,不占用具体存储单元
解析:实参形参占用不同的存储单元
举个例子你就能懂了
经典的交换数值的函数
首先是正确写法,传入需要交换的两个变量的地址
void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;}int main() {int a = 1;int b = 2;printf("%d %d\n", a, b);swap(&a, &b);printf("%d %d\n", a, b);}
其次是错误写法,
void swap(int a, int b) {int temp = a;a = b;b = temp;}
可以看到函数执行完成后a, b的值并没有发生交换
因为,swap中的形参a和b,是在另一个空间上执行的,传参传入的是主函数a,b中的值1,2;
调试分析
这两句执行后 a,b地址如下
进入到函数中后,找到a,b地址,
发现函数申请了新的地址存放形参 因此这道选择题答案为B
14
有以下程序
#include<stdio.h>
int x=1;
int f(int a)
{ static int x=2;
int n=0;
if(a%2)
{ static int x=3;n+=x++; }
else
{ static int x=5;n+=x++; }
return n+x++;
}
void main()
{ int sum=x,i;
for(i=0;i<4;i++)
sum+=f(i);
printf("%d",sum);
}
程序运行后的输出结果是( )。
#include <stdio.h>int x = 1;int f(int a) {static int x = 2;int n = 0;if (a % 2) {static int x = 3;n += x++;}else{static int x = 5;n += x++;}return n + x++;}int main() {int sum = x, i;for ( i = 0; i < 4; i++){sum += f(i);}printf("%d", sum);}
在解决这道题之前,需要知道几个方面的知识,对于使用的变量,有局部优先,全局最后的原则
其次是,static修饰局部变量,出了作用域,不会销毁该变量的值
那么有了以上知识后,我们就可以理解到这些x分别生效的范围
为了方便观察调试,我们将函数改为等价的x1,x2,x3,
int f(int a) {static int x1 = 2;int n = 0;if (a % 2) {static int x2 = 3;n += x2++;}else{static int x3 = 5;n += x3++;}return n + x1++;}
接下来是详细解析
从主函数第一行开始int sum = x, i; 这段相当于
int sum = x;int i;
那么,此处sum使用全局变量x=1,于是sum = 1;
下一段是执行此函数sum += f(i);
相当于四句
sum += f(0);sum += f(1);sum += f(2);sum += f(3);
先看第一次执行
sum += f(0);
int f(0) {static int x1 = 2;int n = 0;if (0 % 2) {static int x2 = 3;n += x2++;}else{static int x3 = 5;n += x3++;}return n + x1++;}
直接进入if判断语句中的(0%2),进入else
执行
static int x3 = 5;n += x3++;
n = n +x++; 此时n = 0, 加上先使用x3再++,那么n = 0+3;
接下来return n + x1++, 使用x1, 那么return 0+3+2;
这次执行完后,函数中有两个变量进行了修改, x1和x3,x1++和x3++以后,这两个变量值分别是3,6,
函数返回5,sum = 1 + 5;
第二次执行函数,传入参数为1
if (a % 2) {static int x2 = 3;n += x2++;}
那么执行该段语句, n = 0 + x2,并且x2自增
return n+x1,也就是3+3, 返回6,并且此次函数执行完成后变量x1,x2,x3的值分别为4,4, 6
sum = 8 + 6 = 14
再下一步,传入参数为2
else{static int x3 = 5;n += x3++;}return n + x1++;
n = 0 + 6, return n+4,返回10,x1,x3自增,x2不变 值分别为5,4,7
sum = 14 +10 = 24
下一步传参3
if (a % 2) {static int x2 = 3;n += x2++;}return n + x1++;
n = 0 + 4; return 4+5,返回9,x1,x2自增,x1,x2,x3的值分别为6,5, 6
sum = 24+9 = 33
最后输出sum为33
15
有以下程序
#include <stdio.h>
int f(int x)
{ int n;
if(x==1) return 1;
n = x+f(x-1);
return (n);
}
void main()
{
printf("%d",f(5));
}
程序的输出结果是( )。
执行的是f5
int f(x = 5){ int n; if (x == 1) return 1; n = x + f(x - 1); return (n);}
此处递归调用到函数参数为1, 以下是return值
f(5) : return 5+f(4)
f(4) : return 4+f(3)
f(3) : return 3+f(2)
f(2) : return 2+f(1)
f(1) : return 1
最后结果是1+2+3+4+5 = 15
编程题
16
题目
近日,华园星球的网络系统遭受到了黑客的攻击,他们盗取了很多热门网站的基本信息,其中包括:用户名,登录密码,以及注册时所使用手机号码。这些信息的泄露给华园星球居民的生活带来了很大的麻烦,小华也是其中的一位,小华在这些网站上也注册了很多的账号,注册时对不同网站使用的用户名和密码都是不一样的,但绑定的手机号都是相同的,为了让生活尽快回归正常,小华来到了华园星球的警察局拿到了这份泄露的信息列表,列表中信息很多,小华需要在这些信息当中找到自己的账号,然后把自己的密码改掉。注册时使用的用户名虽然不同,但绑定的手机号是一样的,所以小华可以根据自己的手机号来确定哪些是自己的账号了,找到账号之后可以对密码进行修改,修改密码的规则也很简单:将大小写字母互换即可,即如果是大写字母就转化为小写字母,若为小写字母就转化为大写字母。你可以帮助小华完成查找账号和修改密码的任务吗?
输入格式:
第一行:输入一个仅包含数字的字符串,表示小华在注册这些账号时所使用的手机号;
第二行:输入一个整数n,表示泄露的数据一共有n条。
接下来的n行:每一行包含三条信息,分别表示在不同网站上注册的用户名,密码以及手机号。它们之间用单个空格分开。用户名、密码、手机号均不含空格,且长度不超过50个字符。
输出格式:
有若干行,每行为一个账号,包括:账号,修改后的密码(之间用单个空格分隔)。
如果没有小华的账号,则输出empty。
输入样例1:
13612348765
5
helloKitty iLoveCats 13612348765
2012 maya2012 13256566565
KittyCat 5iKitty 13612348765
program password 16898765432
whoAmi Feb.29$ 13612348765
输入样例2:
13612348765
1
2012 maya2012 13612348788
输出样例1:
helloKitty IlOVEcATS
KittyCat 5IkITTY
whoAmi fEB.29$
输出样例2:
empty
解析:
本题有2个要求,第一个是查找账号, 其次是修改密码
修改密码是将小写转换为大写,大写转换为小写, 这需要判断函数islower()和isupper, 以及修改函数, tolower和toupper
第一步, 定义结构体,包括账号密码手机号, 定义为account的自定义类型,
typedef struct { char name[50]; char password[50]; char phonenumber[12];} Account;
第二步, 设置泄露账号和小华密码
处理输入
//处理输入 char xiaohua_phone[12]; scanf("%s", xiaohua_phone); int n; scanf("%d", &n); Account leakage[n]; input_account(leakage, n);
输入的函数input
void input_account(Account* leakage, int n){ for (int i=0; i<n; i++) { scanf("%s %s %s", leakage[i].name, leakage[i].password, leakage[i].phonenumber); }}
设置查找小华账号的函数,如果没有输出empty
void find(Account* leakage, int n, char phone){ int flag = 0; for (int i=0; i<n; i++) { if(符合){ 更改密码 flag++; } } if(flag == 0){ printf("empty\n"); }}
判断字符串是否匹配需要用到strcmp函数,如果相同会返回0
该函数需要引入函数库string.h,注意声明
if(strcmp(leakage[i].phonenumber, phone)){
接下来是改密码函数
需要引入头文件ctype.h,
void change(char* password){ for (int i=0; i<11; i++) { if(islower(password[i])){ password[i] = toupper(password[i]); } else if (isupper(password[i])){ password[i] = tolower(password[i]); } }}
最后调用并输出
change(leakage[i].password); printf("%s %s\n", leakage[i].name, leakage[i].password);
总代码
#include <stdio.h>#include <string.h>#include <ctype.h>typedef struct { char name[50]; char password[50]; char phonenumber[12];} Account;void change(char* password){ for (int i=0; password[i]; i++) { if(islower(password[i])){ password[i] = toupper(password[i]); } else if (isupper(password[i])){ password[i] = tolower(password[i]); } }}void find(Account* leakage, int n, char* phone){ int flag = 0; for (int i=0; i<n; i++) { if(strcmp(leakage[i].phonenumber, phone) == 0){ //更改密码 change(leakage[i].password); printf("%s %s\n", leakage[i].name, leakage[i].password); flag++; } } if(flag == 0){ printf("empty\n"); }}void input_account(Account* leakage, int n){ for (int i=0; i<n; i++) { scanf("%s %s %s", leakage[i].name, leakage[i].password, leakage[i].phonenumber); }}int main(int argc, const char * argv[]) { //处理输入 char xiaohua_phone[12]; scanf("%s", xiaohua_phone); int n; scanf("%d", &n); Account leakage[n]; input_account(leakage, n); find(leakage, n, xiaohua_phone); return 0;}
测试样例:
1361234876512012 maya2012 13612348788emptyProgram ended with exit code: 0
136123487655helloKitty iLoveCats 136123487652012 maya2012 13256566565KittyCat 5iKitty 13612348765program password 16898765432whoAmi Feb.29$ 13612348765helloKitty IlOVEcATSKittyCat 5IkITTYwhoAmi fEB.29$Program ended with exit code: 0
17
花坛中有一排n朵花,每朵花的漂亮度为
。不同漂亮度的花排在一起会产生一个凌乱度,定义这n朵花的凌乱度为所有相邻花朵漂亮度的差的绝对值的最大值。比如对于花朵漂亮度{5,2,2,6,7},其凌乱度max{|5-2|, |2-2|, |2-6|, |6-7|}=4。
现在园丁小明最多可以进行k次操作,每次操作可以选择一朵花将其替换成一朵任意漂亮度的花,求操作完成后能够达到的最小凌乱度。
输入格式:
第一行两个整数n,k分别表示花朵的数量和最多能操作的次数。(1<=k<=n<=1000)
第二行n个整数表示这n朵花的漂亮度。(-10^9<=<=10^9)
输出格式:
输出一个整数表示达到的最小凌乱度。
输入样例1:
5 2
5 2 2 6 7
输入样例2:
10 3
56 43 12 10 34 24 25 11 -90 -88
输出样例1:
1
输出样例2:
31
这道题不会 有没有会的给我讲讲?
18
现有一个n*m的地图,地图上每个格子有一个正整数表示该格子的幸运值。
小明初始时站在地图左上角((1,1)的位置),同时面朝右方,他每次去往一个相邻(上下左右)且没有被经过的格子,若是他前往的格子方向是自己面朝的方向,则不需要转向,否则需要消耗一张转向卡,且小明最开始拥有k张转向卡。
小明经过的所有格子中的数字按照顺序拼接起来就是他得到的总的幸运值,比如他经过了(1,45,37,21)四个格子,幸运值就为1453721。
请问若是小明需要幸运值为7的倍数,请问他有多少种不同的路径可以走?(不需要走到底,符合条件可以随时停下)
输入格式:
第一行依次输入三个数字n,m,k分别表示地图大小和转向卡的数量(1<=n, m<=10, 1<=k<=8)
接下来n行输入m个正整数,空格间隔开,表示每个格子上的幸运值(1<=幸运值<=99)
输出格式:
能够实现总幸运值为7的倍数时的不同路径数量
输入样例1:
2 3 2
79 8 12
31 10 5
输入样例2:
2 3 1
79 8 12
31 10 5
输出样例1:
4
输出样例2:
2