一、选填部分
第一题:
下面代码在64位系统下的输出为( )
void print_array(int arr[])
{
int n = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < n; i++)
printf("%d", arr[i]);
}
int main()
{
int arr[] = { 1,2,3,4,5 };
print_array(arr);
return 0;
}
A . 1
B . 1 2
C . 1 2 3 4 5
D . 0 0 0 0 0
思路提示:数组名一般情况下代表的是数组首元素地址,而当我们将数组作为参数传递到函数时,数组名代表的是什么呢?并且需要注意:为什么要强调64位系统呢?
答案:B
解析:或许很多人选择了A(因为我也选了A...),这就是强调64位系统的原因。当我们将数组作为参数传递到函数时,数组名代表的是首元素地址,在平时我们使用32位系统时,地址大小为4字节,所以之前这种情况下得到的n应该为1,但64位系统下,地址大小为8字节,所以n = (8/4) = 2,故输出的应该为1 2。
第二题:
以下函数输出的结果为( )
void func()
{
int k = 1 ^ (1 << 31 >> 31);
printf("%d\n", k);
}
int main()
{
func();
return 0;
}
思路提示:此题考查二进制及其操作符,首先我们需要知道" ^ "," << "," >> "三种操作符分别都是什么作用:
" ^ "(异或操作符):将异或操作符左右两边的数字二进制补码进行对比,相同为0,否则为1。
" << "(左移操作符):将二进制所有位向左移动相应位数,右侧补0。
" >> "(右移操作符):将二进制所有位向右移动相应位数,左侧补符号位。
答案:- 2
解析:首先我们先计算(1 << 31 >> 31),按顺序计算,先算1 << 31:
然后 1 << 31,将左移31次:
再将此时的数据 >> 31,右移31次:
最后计算此数据与 1 的异或:
则为 - 2。
第三题:
以下代码中,当 A = 2,B = 3 时,pointer分配 ( ) 个字节的空间?
#define MAX_SIZE A+B
struct _Record_Struct
{
unsigned char Env_Alarm_ID : 4;
unsigned char Para1 : 2;
unsigned char state;
unsigned char avail : 1;
}*Env_Alarm_Record;
struct _Record_Struct *pointer = (struct _Record_Struct*)malloc(sizeof(struct _Record_Struct) * MAX_SIZE);
思路提示:此题考查位段,以及使用位段时,如何计算大小的知识点,如果了解不多的话可以查看这篇文章的第四部分→C语言的结构体类型-CSDN博客。
位段是在变量后加一个 :(数字),代表此变量只占用(数字)个比特位。
结构体中使用位段时,大小的计算为:以此从低字节处开始,向高字节开始存储,当一个字节剩余空间存不下下一个变量时,则取此字节的下一个字节从头再次开始存储。
答案:9。
解析:其中四个变量,第三个变量为一个字节,第一个变量占四个比特位,第二个变量占两个比特位,第四个变量占一个比特位,计算此结构体大小,通过此图来看:
得到的结构体大小为:3,而当 A = 2,B = 3 时,计算大小的方式为:3 * 2 + 3 (大小 * A + B)。
第四题:
以下代码运行的结果为 ( )
int main()
{
unsigned char puc[4];
struct tagPIM
{
unsigned char ucPim1;
unsigned char ucData0 : 1;
unsigned char ucData1 : 2;
unsigned char ucData2 : 3;
}*pstPimData;
pstPimData = (struct tagPIM*)puc;
memset(puc,0,4);
pstPimData->ucPim1 = 2;
pstPimData->ucData0 = 3;
pstPimData->ucData1 = 4;
pstPimData->ucData2 = 5;
printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]);
return 0;
}
A.02 03 04 05
B.02 29 00 00
C.02 25 00 00
D.02 29 04 00
思路提示:此题考查的是位段在内存中的存储。首先我们需要将数据转换成二进制形式,然后按照低字节到高字节的顺序依次进行存储,需要注意的是:char型数组的访问,一次越过一个字节,需要注意访问越界问题。
答案:B。
解析:与上题类似,首先我们先计算一下此结构体的大小:第一个变量存储到第一个字节,第二,三,四变量加在一起仍小于8个比特位,于是结构体大小仅为2字节,于是puc[2],puc[3]都属于越界,打印的是00 00,于是A,D排除:
第五题:
以下代码的结果是 ( )
union Un
{
short s[7];
int n;
};
int main()
{
printf("%d\n", sizeof(union Un));
return 0;
}
思路提示:此题考查的知识点是对联合体大小的计算。
联合体大小计算规则:
① 编译器只为其最大成员分配足够内存空间。
② 联合体大小内存必须为所有成员变量内存的整数倍。
答案:16。
解析:short s[7]; 大小为14字节,int n;为4字节,按照①得到的内存大小为14,而按照②得到浪费两个空间,内存大小为16。
二、编程题部分
第一题:天梯赛座位分配
假设某赛场有 N 所学校参赛,第 i 所学校有 M[i] 支队伍,每队 10 位参赛选手。令每校选手排成一列纵队,第 i+1 队的选手排在第 i 队选手之后。从第 1 所学校开始,各校的第 1 位队员顺次入座,然后是各校的第 2 位队员……如果最后只剩下 1 所学校的队伍还没有分配座位,则需要安排他们的队员隔位就坐。
本题就要求你编写程序,自动为各校生成队员的座位号,从 1 开始编号。
输入格式:
输入在一行中给出参赛的高校数 N (不超过100的正整数);
第二行给出 N 个不超过10的正整数,其中第 i 个数对应
第 i 所高校的参赛队伍数,数字间以空格分隔。
输出格式:
从第 1 所高校的第 1 支队伍开始,顺次输出队员的座位号。
每队占一行,座位号间以 1 个空格分隔,行首尾不得有多余空格。
另外,每所高校的第一行按"#X"输出该校的编号X,从 1 开始。
输入样例:
3
3 4 2
输出样例:
#1
1 4 7 10 13 16 19 22 25 28
31 34 37 40 43 46 49 52 55 58
61 63 65 67 69 71 73 75 77 79
#2
2 5 8 11 14 17 20 23 26 29
32 35 38 41 44 47 50 53 56 59
62 64 66 68 70 72 74 76 78 80
82 84 86 88 90 92 94 96 98 100
#3
3 6 9 12 15 18 21 24 27 30
33 36 39 42 45 48 51 54 57 60
思路提示:刚开始阅读此题时我并不觉得有什么难的,只是将从1开始的数字分别依次存放不就好了嘛?但当我编写完代码后看着乱错一片的结果才知道,其实此题的坑还是蛮多的。
① 在只有一组学校时,排列的顺序应该遵循1,3,5,7...的顺序排列。(隔位就坐)
② 在多组学校时,先按照依次排列的方式存储,当最后只剩下一个学校时,如果上一个学生不是本校,则不用空一个位置。(因为不是一个学校,故不用隔位)
③ 在多组学校时,先按照依次排列的方式存储,当最后只剩下一个学校时,如果上一个学生恰好是本校学生,则需要空一个位置。
答案:
int main()
{
int n = 0, i = 0, j = 0, k = 0;
scanf("%d", &n);//高校数
int arr[n][100];//不超过100的正整数
for (i = 0; i < n; i++)
for (j = 0; j < 100; j++)
arr[i][j] = 0;
int num[n];//存储各高校
int N = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &num[i]);
N += num[i] * 10;//运算学生总数
}
int sum = 1;
for (i = 0; i < N; i++)
{
k = 0;
int s = 0;
while (k != n)
s += num[k++];//计算此时未坐满的学校的需求行数
//(用于后续判断是否只剩一个学校)
j = 0;
while (j != n)
{
if (i < num[j] * 10)//判断该学校是否坐满
{
if (s != num[j])//判断是否只剩余该学校
arr[j][i] = sum++;//(不止剩该学校)
if (s == num[j]) //(只剩该学校)
{
sum += 2;//此时就需要隔位就坐,故+2
//(以3 3 4 2测试集为例,当存入80后,sum此时为81,故需-1存入)
arr[j][i] = sum - 1;
if (arr[j][i] - 2 != arr[j][i - 1])//若上一个学生不是本校
arr[j][i] -= 1;//则再-1
}
if (i == num[j] * 10 - 1)
num[j] = 0;
}
j++;
}
}
k = 0;
while (k != n)
{
printf("#%d\n", k + 1);
for (i = 0; i < 100; i++)
{
if (arr[k][i])
printf("%d", arr[k][i]);
if ((i + 1) % 10 != 0 && arr[k][i])
printf(" ");
if ((i + 1) % 10 == 0 && arr[k][i])
printf("\n");
}
k++;
}
return 0;
}
解析:首先我们输入高校数,然后为每个高校数分配相应的行数,并计算其总学生数量(用于后续判断是否坐满),随后创建一个大循环将学生一个一个的存入对应学校并为其编号,在常规情况下只需要依次加一的一个一个一次存入学校就好,而当只剩余一个学校时,我们分别按照②情况和③情况进行分类~:
① 只剩一个学校时,上一个学生不是本校的学生。我们先将最后一个学生编码+2作为下一个学生的编码(默认隔位相坐),然后此时我们需要进行一个判断,若 arr[j][i] - 2 不等于 arr[j][i - 1] 那么上一个学生就不是本校的,则使本相隔的学生编码-1也就是不用空位。
② 只剩一个学校时,上一个学生是本校的学生。其实和上一个是一样的,只是进行判断时发现是本校的,故不用-1了(第一次判断后,从下一次开始每上一个学生都是本校的,故都不会-1)。
第二题:福到了
本题会给你一个 N * N 格式的"福"字,你需要将其改成"倒福"的形式,并且将组成福的字符改换成输入的字符。
输入格式:
输入在第一行中给出倒过来的汉字所用的字符、以及网格的规模 N
(不超过100的正整数),其间以 1 个空格分隔;随后 N 行,
每行给出 N 个字符,或者为 @ 或者为空格。
输出格式:
输出倒置的网格,如样例所示。但是,如果这个字正过来倒过去是一样的,
就先输出bu yong dao le,然后再用输入指定的字符将其输出。
输入样例:
$ 9
@ @@@@@
@@@ @@@
@ @ @
@@@ @@@
@@@ @@@@@
@@@ @ @ @
@@@ @@@@@
@ @ @ @
@ @@@@@
输出样例:
$$$$$ $
$ $ $ $
$$$$$ $$$
$ $ $ $$$
$$$$$ $$$
$$$ $$$
$ $ $
$$$ $$$
$$$$$ $
思路提示:其实此题并不难,有两种解题思路:
① 与逆序一段字符串一个道理,一段字符串逆序可以使用left和right进行首位字符互换,其实此题只是逆序字符串的复杂版,也就是二维字符串的对角互换,定义两个left和两个right分别代表行,列,每行首,每行尾,就能够解决此题(此解法较麻烦,我直接为大家讲解第二种简单方法,大家有兴趣可以自行尝试~)
② 我们先对整个"福"进行查看,依次遍历,如果"福"倒过来和没倒过来是完全一致的,那么我们就可以直接打印"bu yong dao le",如果其中有字符不一致,就打印此"福"的倒置(方法就留在后面说吧...不然全提示完了,后面解析没得说了...)
答案:
int main()
{
char str[105][105];
char c;
int n, i, j;
scanf("%c %d", &c, &n);
getchar();//去除多余的换行符
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
scanf("%c", &str[i][j]);
}
getchar();//去除多余换行符
}
int flag = 0;
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
if (str[i][j] != str[n - i - 1][n - j - 1])
flag = 1;//对每一个字符进行判断,有不同就变1
}
}
if (!flag)
printf("bu yong dao le\n");//完全相同
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
if (str[n - i - 1][n - j - 1] != ' ')
printf("%c", c);
else
printf(" ");
}
printf("\n");
}
return 0;
}
解析:此题其实上面的思路提示中已经讲解的比较清楚了,代码也并不复杂,只要搞明白如何倒置"福",此题就能够迎刃而解了~:
第三题:敲笨钟
寻压“ong”韵的古诗词,把句尾的三个字换成“敲笨钟”。现在给你一大堆古诗词句,要求你写个程序自动将压“ong”韵的句子糟改成“敲笨钟”。
输入格式:
输入首先在第一行给出一个不超过 20 的正整数 N。
随后 N 行,每行用汉语拼音给出一句古诗词,分上下两半句,
用逗号 , 分隔,句号 . 结尾。相邻两字的拼音之间用一个空格分隔。
题目保证每个字的拼音不超过 6 个字符,每行字符的总长度不超过 100,并且下半句诗至少有 3 个字。
输出格式:
对每一行诗句,判断其是否压“ong”韵。即上下两句末尾的字都是“ong”结尾。
如果是压此韵的,就按题面方法糟改之后输出,输出格式同输入;否则输出 Skipped,即跳过此句。
输入样例:
5
xun zhang zhai ju lao diao chong, xiao yue dang lian gua yu gong.
tian sheng wo cai bi you yong, qian jin san jin huan fu lai.
xue zhui rou zhi leng wei rong, an xiao chen jing shu wei long.
zuo ye xing chen zuo ye feng, hua lou xi pan gui tang dong.
ren xian gui hua luo, ye jing chun shan kong.
输出样例:
xun zhang zhai ju lao diao chong, xiao yue dang lian qiao ben zhong.
Skipped
xue zhui rou zhi leng wei rong, an xiao chen jing qiao ben zhong.
Skipped
Skipped
思路提示:此题看似复杂,其实并不算什么难题。只需要认真细致的阅读题目,创建出一个能够对每一段诗句末尾都进行判断的程序,并且需要注意的是,只有第一句或第二句存在"ong"是不足以"改换大笨钟"的,必须两句都存在"ong"结尾,才能够"改换大笨钟"。
(注意:记得在最后输出时,改换大笨钟的诗句不输出最后三个字~)
答案:
int main()
{
int n, N = 0, i = 0, j = 0, m = 0, l = 0;
int num1 = 0;
scanf("%d", &n);
getchar();
char str[n + 1][105];
for (i = 0; i < n; i++)
gets_s(str[i]);//输入诗句
for (i = 0; i < n; i++)
{
while (str[i][j] != '\0')
{
if (str[i][j] == ' ')//统计其中的空格数,用于后续输出空格
N++;
if (str[i][j] == ',' || str[i][j] == '.')//用于分别判断第一句与第二句
if (str[i][j - 3] == 'o' && str[i][j - 2] == 'n' && str[i][j - 1] == 'g')
num1++;//如果句尾为"ong"则num1++
j++;
}
if (num1 == 2)//说明两句尾都是"ong"
{
while (m != N - 2)//-2代表不输出后三个字
{
printf("%c", str[i][l]);
if (str[i][l] == ' ')
m++;
l++;
}
printf("qiao ben zhong.\n");//后三个字改换为"敲笨钟"
}
else
printf("Skipped\n");
N = 0; num1 = 0; j = 0; m = 0; l = 0;
}
return 0;
}
解析:我们先创建出一个二维字符串数组,用来存储相应个数的诗句。然后创建循环分别对每一个诗句进行判断,需要注意的是:诗句中的" , "和" . "是非常重要的解题关键,我们可以利用他们来判断此时为第一句还是第二句,并且能够知道此句子是否结束!当我们访问到" , "或" . "时,就是证明来到了句尾,此时开始判断" , "和" . "前的三个字符是否为' o ',' n ',' g '。若是,则计数器++,到后续再判断如果计数器为2(即两句都押韵了"ong")就改换大笨钟~
同时我们还需要统计空格的个数,如果诗句符合改换大笨钟的条件,则需要将后三个字该换为"qiao ben zhong.",那么我们就同时需要舍弃三个字,也就是输出时,当空格数达到"总空格数 - 2"时,就不用在输出了,直接输出"qiao ben zhong."就好了~
那么今天我们的刷题日记就分享到这里啦~如果有哪里讲的不够清楚,或者解题不够简便,不够严谨的地方,还请大家多多在评论区指出,我也会多多吸取教训,多多改正的~你们的指点就是使我进步的能量~那么我们下一期再见啦~