期中复习习题 2¶
本页最后更新于 ,内容可能过时
本页是课件《期中复习习题-2.pdf》的文字版
一、选择题¶
第1题¶
下列选项中,合法的 C 语言关键字是
- A.
VAR - B.
integer - C.
default - D.
public
答案
C
第2题¶
以下选项中不属于 C 语言的数据类型是
- A. 整型
- B. 实型
- C. 双精度型
- D. 复数型
答案
D
第3题¶
在 C 语言中,不正确的 short 类型(假设存储单元数为 2 个 bytes)的常数是
- A.
123 - B.
32768 - C.
037 - D.
0xAF
答案
B
第4题¶
以下选项中合法的实型常数是
- A.
.58 - B.
E-3 - C.
.E2 - D.
1.3E
答案
A
第5题¶
下面哪种运算的优先级最高
- A.
! - B.
!= - C.
|| - D.
&&
答案
A
第6题¶
7/9*9 在 C 语言中的计算结果是
- A.
1 - B.
0.08642 - C.
0 - D. 以上都不是
答案
C
第7题¶
C 语言程序的基本单位是
- A. 语句
- B. 程序行
- C. 函数
- D. 字符
答案
C
第8题¶
以下哪一个是 main() 的正确声明
- A.
int main() - B.
int main(int argc, char *argv[]) - C. A 和 B 都是不正确的
- D. A 和 B 都是正确的
答案
D
第9题¶
以下叙述中正确的是
- A. 可以在一个函数中定义另一个函数
- B. main() 函数必须放在其它函数之前
- C. 所有被调用的函数一定要在调用之前进行定义
- D. 以上皆不正确
答案
D
第10题¶
表达式 !(1&&1||1&&0) 的值是
- A. 错误的表达式
- B.
True/1 - C.
False/0 - D. 不确定
答案
C
第11题¶
有数组定义 int a[2][2]={{1},{2,3}};,则 a[0][1] 的值为
- A.
0 - B.
1 - C.
2 - D.
3
答案
A
第12题¶
下列描述中不正确的是
- A. 字符型数组中可以存放字符串
- B. 可以对字符型数组进行整体输入、输出
- C. 可以对整型数组进行整体输入、输出
- D. 不能在赋值语句中通过赋值运算符“=”对字符型数组进行整体赋值
答案
C
第13题¶
这个循环语句 for (int x=0; x=3; x++) 会执行多少次
- A. 1 次都不
- B. 3 次
- C. 4 次
- D. 死循环
答案
D
第14题¶
设有如下定义 int x=1, y=-1,则语句 printf("%d\n", (x--&++y)); 的输出结果是
- A.
1 - B.
0 - C.
-1 - D.
2
答案
B
第15题¶
十进制数 1384 转换成十六进制数为
- A.
567 - B.
568 - C.
D84 - D.
D54
答案
B
第16题¶
以下程序的输出结果是
#include<stdio.h>
int main( )
{
int i;
for (i = 1; i < 6; i++) {
if (i % 2) {
printf("#");
continue;
}
printf("*");
}
printf("\n");
}
- A.
#*#*# - B.
##### - C.
***** - D.
*#*#*
答案
A
第17题¶
以下程序的输出结果是
- A. 编译不通过,无输出
- B.
aceg - C.
acegi - D.
abcdefghi
答案
A
解析
材料上 i++ 后面和 printf 的参数之间用的是全角逗号,所以编译不通过。
第18题¶
以下程序的运行结果是
#include<stdio.h>
int main( )
{
char a[10] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', 0}, *p;
int i;
i = 8;
p = a + i;
printf("%s\n", p-3);
}
- A.
6 - B.
6789 - C.
'6' - D.
789
答案
B
第19题¶
以下程序的输出结果是
int main( )
{
char s[] = "12134211";
int v[4] = {0, 0, 0, 0}, k, i;
for (k = 0; s[k]; k++) {
switch (s[k]) {
case '1': i = 0;
case '2': i = 1;
case '3': i = 2;
case '4': i = 3;
}
v[i]++;
}
for (k = 0; k < 4; k++)
printf("%d ", v[k]);
}
- A.
4 2 1 1 - B.
0 0 0 8 - C.
4 6 7 8 - D.
8 8 8 8
答案
B
第20题¶
运行以下程序将会出现
- A. 输出 0123..99
- B. 输出 0123...100
- C. 输出 0123...101
- D. 不确定
答案
D
二、填空题¶
第1题¶
#include <filename.h> 和 #include "filename.h" 有什么区别?
答案
前者编译器只会到系统指定目录下搜索头文件;后者编译器会先在工作目录下查找头文件,如果找不到,则到系统指定目录下搜索
第2题¶
下列程序的输出结果是什么?
#include <stdio.h>
#include <string.h>
int main()
{
char ch[] = "abc", x[3][4];
int i;
for (i = 0; i < 3; i++)
strcpy(x[i], ch);
for (i = 0; i < 3; i++)
printf("%s", &x[i][i]);
printf("\n");
}
答案
abcbcc
第3题¶
下列程序的输出结果是什么?
#include<stdio.h>
int main()
{
int a = 1, b;
for (b = 1; b <= 10; b++) { /* b=1, a=6; b=2, a=3; b=3, a=8; b=4 */
if (a >= 8)
break;
if (a % 2 == 1) {
a += 5;
continue;
}
a -= 3;
}
printf("%d\n", b);
}
答案
4
三、程序改错题¶
int binsearch(int x, int v[], int n)
{
int low, high, mid;
low = 1;
high = n;
mid = (high - low) / 2;
while (low < high && x = v[mid]) {
if (x < v[mid])
high = mid - 1;
else
low = mid + 1;
}
if (x == v[mid])
return mid; /* found match */
else
return -1; /* no match */
}
答案
三、综合题(略)¶
第1题 · 质因子分解¶
输入一个自然数 N(N>1),输出它的质因子分解式。如 n=8,程序输出 8=222。
思路
从 2 开始依次试除:
- n 能被 d 整除:输出 d,并令
n = n / d,d 保持不变 - n 不能被 d 整除:d 加 1
- n 变成 1 时结束
整除后不增大 d,是为了把同一个因子连续取干净,例如 n = 8 会连续输出三个 2。轮到 d 时,比 d 小的因子已经除尽,所以能整除剩余部分的最小因子一定是质数,不用单独判断 d 是不是质数。
因子之间补 *。输出最后一个因子后 n 已经变成 1,不再补星号。
以 n = 30 为例:
| d | n | 动作 |
|---|---|---|
| 2 | 30 | 整除,输出 2,n 变成 15 |
| 2 | 15 | 不整除,d 加 1 |
| 3 | 15 | 整除,输出 3,n 变成 5 |
| 3 | 5 | 不整除,d 加 1 |
| 4 | 5 | 不整除,d 加 1 |
| 5 | 5 | 整除,输出 5,n 变成 1,结束 |
结果为 30=2*3*5。
答案
#include <stdio.h>
int main(void)
{
int n, d;
scanf("%d", &n);
printf("%d=", n);
d = 2;
while (n > 1) {
if (n % d == 0) {
printf("%d", d);
n /= d;
if (n > 1)
printf("*");
} else {
d++;
}
}
printf("\n");
return 0;
}
运行示例:
第2题 · 取棋子¶
有 n 个棋子,甲、乙两方轮流取棋子,每方至少取一个,最多取 m 个。谁最后取剩下的一个棋子谁就输。甲方先取,给出甲方必赢的算法(即无论乙怎么下,甲都能赢)。
思路
按剩余棋子数分类,从只剩 1 个的局面开始倒推:
| 剩余棋子数 | 结论 | 依据 |
|---|---|---|
| 1 | 必败× | 只能取走最后一个,直接输 |
| 2 | 必胜 | 取 1 个,给对方留 1 个 |
| 3 | 必胜 | 取 2 个,给对方留 1 个 |
| 4 | 必胜 | 取 3 个,给对方留 1 个 |
| …… | 必胜 | 剩 n 个就取 n−1 个,只要不超过 m |
m+1 |
必胜 | 取 m 个,给对方留 1 个 |
m+2 |
必败× | 无论取 k 个(1 ≤ k ≤ m),留给对方的都是 m+2−k 个,落在 2 到 m+1,是对方的必胜局面 |
照此递推,必败局面依次是 1、m+2、2(m+1)+1,即 n ≡ 1(mod m+1)。
必胜一方的走法:
- 先取
(n−1) mod (m+1)个,把局面留成n ≡ 1(mod m+1) - 此后对方取
k个,自己就取m+1−k个,每轮两方合计固定取走m+1个 - 重复第 2 步,最终就可以给对方只剩下 1 个
若一开始就面对 n ≡ 1(mod m+1),则没有必胜策略。
以 n = 8、m = 3 为例,(8−1) mod 4 = 3,甲先取 3 个:
| 轮次 | 取前棋子数 | 行动 | 取后剩余数 | 剩余数满足 |
|---|---|---|---|---|
| 甲 | 8 | 取 3 个 | 5 | 5 ≡ 1(mod 4) |
| 乙 | 5 | 取 1 个 | 4 | |
| 甲 | 4 | 取 3 个 | 1 | 1 ≡ 1(mod 4) |
| 乙 | 1 | 只能取最后 1 个 | 0,乙输 |
以 n = 15、m = 3 为例,(15−1) mod 4 = 2,甲先取 2 个:
| 轮次 | 取前棋子数 | 行动 | 取后剩余数 | 剩余数满足 |
|---|---|---|---|---|
| 甲 | 15 | 取 2 个 | 13 | 13 ≡ 1(mod 4) |
| 乙 | 13 | 取 3 个 | 10 | |
| 甲 | 10 | 取 1 个 | 9 | 9 ≡ 1(mod 4) |
| 乙 | 9 | 取 2 个 | 7 | |
| 甲 | 7 | 取 2 个 | 5 | 5 ≡ 1(mod 4) |
| 乙 | 5 | 取 1 个 | 4 | |
| 甲 | 4 | 取 3 个 | 1 | 1 ≡ 1(mod 4) |
| 乙 | 1 | 只能取最后 1 个 | 0,乙输 |
以 n = 10、m = 4 为例,(10−1) mod 5 = 4,甲先取 4 个:
| 轮次 | 取前棋子数 | 行动 | 取后剩余数 | 剩余数满足 |
|---|---|---|---|---|
| 甲 | 10 | 取 4 个 | 6 | 6 ≡ 1(mod 5) |
| 乙 | 6 | 取 2 个 | 4 | |
| 甲 | 4 | 取 3 个 | 1 | 1 ≡ 1(mod 5) |
| 乙 | 1 | 只能取最后 1 个 | 0,乙输 |
以 n = 6、m = 2 为例,(6−1) mod 3 = 2,甲先取 2 个:
| 轮次 | 取前棋子数 | 行动 | 取后剩余数 | 剩余数满足 |
|---|---|---|---|---|
| 甲 | 6 | 取 2 个 | 4 | 4 ≡ 1(mod 3) |
| 乙 | 4 | 取 2 个 | 2 | |
| 甲 | 2 | 取 1 个 | 1 | 1 ≡ 1(mod 3) |
| 乙 | 1 | 只能取最后 1 个 | 0,乙输 |
答案
#include <stdio.h>
int main(void)
{
int n, m, stones, take, k;
scanf("%d%d", &n, &m);
if (n % (m + 1) == 1) {
printf("甲没有必胜策略:先手面对 %d 个棋子必输\n", n);
return 0;
}
stones = n;
take = (stones - 1) % (m + 1);
printf("甲取 %d 个,剩 %d 个\n", take, stones - take);
stones -= take;
while (stones > 1) {
k = 1; /* 演示中乙每次只取 1 个 */
if (k > m)
k = m;
printf("乙取 %d 个,剩 %d 个\n", k, stones - k);
stones -= k;
if (stones == 0) {
printf("乙取走最后一个,乙输\n");
return 0;
}
take = m + 1 - k;
if (take > stones - 1)
take = stones - 1; /* 留 1 个给乙 */
printf("甲取 %d 个,剩 %d 个\n", take, stones - take);
stones -= take;
}
printf("乙只能取最后 1 个,乙输\n");
return 0;
}
输入 8 3,输出:
输入 9 3,9 ≡ 1(mod 4),输出:
第3题 · 白黑石子移动¶
设有 N 个白石子和 N 个黑石子,开始时排成一行,中间有一个空位置。N=3 时,三个白子和三个黑子排成 WWW.BBB,其中 W 为白、B 为黑,. 是空位。
目标是把这一行变成 N 个黑子在前、N 个白子在后,中间仍是一个空位置,即 BBB.WWW。
移动规则:
- 每次只能移动一个石子
- 石子朝自己的目标方向移动:走进相邻的空位置,或者跳过一颗不同颜色的石子,进入空位置
设计移动策略,并编写程序,输出每次移动后的状态。
思路
把局面写成一串字符,W 是白子,B 是黑子,. 是空位,初始 WWW.BBB,目标 BBB.WWW。
白子只向右走,黑子只向左走。设空位在某一格,能走的棋子只有空位左右两侧的两格:
| 棋子位置 | 合法移动 |
|---|---|
| 空位左边第 1 格 | 白子向右走进空位 |
| 空位左边第 2 格 | 白子向右跳过一颗黑子,进入空位 |
| 空位右边第 1 格 | 黑子向左走进空位 |
| 空位右边第 2 格 | 黑子向左跳过一颗白子,进入空位 |
表外的位置都不能走。跳跃时被越过的棋子必须与移动的棋子颜色不同,同色之间不能跳。
于是问题变成在状态图上找一条从初始局面到目标局面的路径。每个局面是一个结点,一步移动是一条边。广度优先搜索按步数逐层扩展,第一次到达目标局面时经过的步数就是最少步数。哈希表记录已经出现过的局面,同一个局面只入队一次。
N = 1 到 5 实测的最少步数:
| N | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| 步数 | 3 | 8 | 15 | 24 | 35 |
步数符合 N² + 2N,每增加一对棋子,步数增加 2N + 1。
答案
#include <stdio.h>
#include <string.h>
#define MAXN 10
#define LEN (2 * MAXN + 1)
#define MAXS 600000
#define HSIZE (1 << 20)
static char state[MAXS][LEN + 1];
static int parent[MAXS];
static int from[MAXS]; /* 这步移动的石子原来所在的格子 */
static int table[HSIZE];
static int head, tail, L;
static unsigned long long hashStr(const char *s)
{
unsigned long long h = 1469598103934665603ULL;
while (*s) {
h ^= (unsigned char)*s++;
h *= 1099511628211ULL;
}
return h;
}
static int lookup(const char *s)
{
unsigned i = (unsigned)(hashStr(s) % HSIZE);
while (table[i]) {
if (strcmp(state[table[i] - 1], s) == 0)
return table[i] - 1;
i = (i + 1) % HSIZE;
}
return -1;
}
static void put(const char *s, int id)
{
unsigned i = (unsigned)(hashStr(s) % HSIZE);
while (table[i])
i = (i + 1) % HSIZE;
table[i] = id + 1;
}
static void expand(int id)
{
char s[LEN + 1], t[LEN + 1];
int e = 0, i, d, mid;
strcpy(s, state[id]);
while (s[e] != '.')
e++;
for (i = 0; i < L; i++) {
if (i == e)
continue;
d = e - i;
if (s[i] == 'W' && d < 0) /* 白子只向右走 */
continue;
if (s[i] == 'B' && d > 0) /* 黑子只向左走 */
continue;
if (d == 1 || d == -1) {
/* 邻格为空,直接移动 */
} else if (d == 2 || d == -2) {
mid = (i + e) / 2;
if (s[mid] == '.' || s[mid] == s[i])
continue; /* 只能跳过另一种颜色的石子 */
} else {
continue;
}
strcpy(t, s);
t[e] = t[i];
t[i] = '.';
if (lookup(t) < 0) {
strcpy(state[tail], t);
parent[tail] = id;
from[tail] = i;
put(t, tail);
tail++;
}
}
}
int main(void)
{
int n, i, id, goal = -1, path[MAXS], len = 0;
char s[LEN + 1], g[LEN + 1];
scanf("%d", &n);
L = 2 * n + 1;
for (i = 0; i < n; i++)
s[i] = 'W';
s[n] = '.';
for (i = n + 1; i < L; i++)
s[i] = 'B';
s[L] = '\0';
for (i = 0; i < n; i++)
g[i] = 'B';
g[n] = '.';
for (i = n + 1; i < L; i++)
g[i] = 'W';
g[L] = '\0';
strcpy(state[0], s);
parent[0] = -1;
put(s, 0);
tail = 1;
while (head < tail) {
if (strcmp(state[head], g) == 0) {
goal = head;
break;
}
expand(head);
head++;
}
if (goal < 0) {
printf("无解\n");
return 0;
}
for (id = goal; id != -1; id = parent[id])
path[len++] = id;
printf("%d 步\n", len - 1);
for (i = len - 1; i >= 0; i--) {
id = path[i];
if (parent[id] < 0)
printf(" %s\n", state[id]);
else
printf("%2d步 %s 移动第 %d 格的 %c\n",
len - 1 - i, state[id], from[id] + 1,
state[parent[id]][from[id]]);
}
return 0;
}
输入 3,输出:
15 步
WWW.BBB
1步 WW.WBBB 移动第 3 格的 W
2步 WWBW.BB 移动第 5 格的 B
3步 WWBWB.B 移动第 6 格的 B
4步 WWB.BWB 移动第 4 格的 W
5步 W.BWBWB 移动第 2 格的 W
6步 .WBWBWB 移动第 1 格的 W
7步 BW.WBWB 移动第 3 格的 B
8步 BWBW.WB 移动第 5 格的 B
9步 BWBWBW. 移动第 7 格的 B
10步 BWBWB.W 移动第 6 格的 W
11步 BWB.BWW 移动第 4 格的 W
12步 B.BWBWW 移动第 2 格的 W
13步 BB.WBWW 移动第 3 格的 B
14步 BBBW.WW 移动第 5 格的 B
15步 BBB.WWW 移动第 4 格的 W