Day04_刷题niuke20251005
试卷01
试卷02
试卷题目
试卷01题目
单选题
C++
C语言
1.
break是结束本次循环,而continue是结束所有的循环。请问这句话的说法是正确的吗?
A
正确
B
错误
正确答案:B
官方解析:
这句话的说法是错误的。需要对break和continue的概念进行明确区分:
break和continue在循环控制中的作用是不同的:
1. break的作用是:
- 立即跳出当前所在的整个循环
- 继续执行循环后面的代码
- 适用于for、while、do-while循环以及switch语句
2. continue的作用是:
- 立即结束本次循环,跳过剩余代码
- 继续进入下一次循环的判断
- 只适用于for、while、do-while循环
所以原题说法存在两个错误:
1. break不是"结束本次循环",而是结束整个当前循环
2. continue不是"结束所有循环",而是结束本次循环,继续下一次
举例说明:
在嵌套循环中使用break只能跳出当前所在的循环层级,而不是所有循环。
使用continue会跳过本次循环中剩余的代码,但会继续执行下一次循环的内容。
因此B选项"错误"是正确答案。知识点:C++、C语言
题友讨论(12)
单选题
C语言
2.
十进制变量i的值为100,那么八进制的变量i的值为()
A
146
B
148
C
144
D
142
正确答案:C
官方解析:
这道题目考察了进制转换的知识点,具体是将十进制数100转换为八进制数。
要将十进制转换为八进制,我们可以通过除8取余的方法,从下往上读取余数:
100 ÷ 8 = 12 余 4
12 ÷ 8 = 1 余 4
1 ÷ 8 = 0 余 1
从下往上读取余数,得到八进制数:144
因此,十进制的100等于八进制的144,C选项正确。
分析其他选项:
A选项146:计算错误,146(八进制)=(1×8²)+(4×8¹)+(6×8⁰)=64+32+6=102(十进制)
B选项148:计算错误,148(八进制)=(1×8²)+(4×8¹)+(8×8⁰)=64+32+8=104(十进制)
D选项142:计算错误,142(八进制)=(1×8²)+(4×8¹)+(2×8⁰)=64+32+2=98(十进制)
这道题目主要考察了对八进制的理解和十进制转八进制的计算能力。八进制是以8为基数的数制,每一位上的数字范围是0-7。知识点:C语言
题友讨论(5)
单选题
C语言
3.
下面程序段的输出结果是()
1
2
3
4
5
6
7
#include <stdio.h>
int
main() {
int
a[] = {1, 2, 3, 4, 5, 6}, *p;
p = a;
*(p+3) += 2;
printf(
" %d,%d"
, *p, *(p+3));
}
A
0, 4
B
1, 4
C
0,6
D
1,6
正确答案:D
官方解析:
这道题目考察了指针的基本操作和数组访问。让我们逐步分析代码的执行过程:
1. 首先定义了一个整型数组 a[] = {1,2,3,4,5,6} 和一个指针 p
2. 将数组 a 的首地址赋值给指针 p,此时 p 指向数组第一个元素 1
3. 执行 *(p+3) += 2,这里:
- p+3 表示指针向后移动3个位置,指向数组的第4个元素(值为4)
- *(p+3) += 2 表示将该位置的值加2,即 4+2=6
4. printf语句中:
- *p 输出指针 p 当前指向的第一个元素,仍然是1
- *(p+3) 输出修改后的第4个元素的值,为6
所以输出结果为 1,6,D选项正确。
分析其他选项的错误原因:
A选项(0,4):错误。*p指向数组首元素1,而不是0,且第4个元素已被修改为6而不是4
B选项(1,4):错误。虽然第一个值1正确,但第4个元素已被修改为6而不是4
C选项(0,6):错误。虽然第4个元素6正确,但首元素是1而不是0
这个题目的关键是要理解指针运算和数组元素访问的关系,以及赋值操作不会改变指针的指向位置。知识点:C语言
题友讨论(8)
单选题
C语言
4.
下列程序的运行结果是()
A
8,11
B
6,13
C
13,6
D
11,8
正确答案:D
官方解析:
这道题目主要考察Java的多态特性和方法调用机制。让我们逐行分析代码执行过程:
1. 首先创建了Base类的对象b,实际类型是Sub类(多态)
2. 调用b.method(1, 2)时:
- 因为Base类中有method(int, long)和method(long, int)两个重载方法
- 参数(1, 2)都是int类型
- 调用method(int, long)需要将第二个参数2从int转为long
- 调用method(long, int)需要将第一个参数1从int转为long
- 这两种转换代价相同,根据JVM规则,编译器会选择第一个方法method(int, long)
- 由于是运行时多态,实际调用Sub类的method(int, long),输出11
3. 调用b.method(2):
- Base类中的method(int)被Sub类重写
- 根据多态特性,调用子类Sub的method(int)方法
- 输出8
所以最终输出结果是11,8,因此D选项正确。
分析其他选项:
A错误:输出顺序与实际相反
B错误:完全不符合代码执行结果
C错误:输出顺序与实际相反,且数值也不正确
这个题目很好地考察了Java的方法重载、方法重写、多态以及参数类型自动转换等概念的综合应用。知识点:C语言
题友讨论(13)
单选题
C++
C语言
5.
对于int *pa[5];的描述,正确的是()
A
pa是一个具有5个元素的指针数组,每个元素是一个int类型的指针;
B
pa[5]表示某个数组的第5个元素的值;
C
pa是一个指向数组的指针,所指向的数组是5个int类型的元素;
D
pa是一个指向某个数组中第5个元素的指针,该元素是int类型的变量;
正确答案:A
官方解析:
int *pa[5] 这个声明从右往左分析:首先[]的优先级高于*,所以pa是一个数组,数组大小为5;其次数组的元素类型是int*,即整型指针。因此pa是一个包含5个整型指针的数组,即指针数组,A选项的描述完全正确。
分析其他选项:
B错误:pa[5]实际上是一个非法访问,因为数组下标从0开始,大小为5的数组其下标范围是0-4。另外这里的pa[5]声明的是数组的大小,而不是在访问数组元素。
C错误:把pa理解成了数组指针。数组指针的正确写法应该是int (*pa)[5],这表示pa是一个指针,指向一个包含5个int元素的数组。而题目中int *pa[5]是指针数组,两者完全不同。
D错误:同样理解错误。pa既不是指向单个元素的指针,也不是指向第5个元素的指针,而是一个包含5个指针的数组。
补充说明:这种声明的理解需要掌握C语言中数组和指针相关的声明规则,尤其是[]和*的优先级关系。声明的阅读方向是从变量名开始,向右再向左解读。知识点:C++、C++工程师、2016、C语言
题友讨论(13)
单选题
C++
C语言
6.
假定a为一个字符数组名,则元素 a[i] 的指针访问方式为( )?
A
a+i
B
*(a+i)
C
&a+i
D
*a+i
正确答案:B
官方解析:
在字符数组中访问元素 a[i] 的指针表示方式是 *(a+i),这是因为:
1. 数组名 a 本身就是一个指向数组首元素的指针
2. a+i 表示从数组首地址向后偏移 i 个元素的地址
3. 在地址前加 * 号才能获取该地址中存储的值,即数组元素
分析其他选项:
A选项 a+i:
这表示数组第 i 个元素的地址,而不是元素值本身
C选项 &a+i:
&a 是整个数组的首地址,+i 后偏移的是整个数组的长度,结果错误
D选项 *a+i:
这表示将首元素的值加上 i,而不是访问第 i 个元素
因此 B 选项 *(a+i) 是正确的指针访问方式,它通过指针运算和解引用得到数组中第 i 个元素的值,这与 a[i] 的功能完全等价。事实上,编译器内部就是将 a[i] 转换为 *(a+i) 来处理的。知识点:C++、C语言
题友讨论(12)
单选题
C++
C语言
7.
若有说明:int a[3][4];则对a数组元素的非法引用是( )
A
a[0][2*1]
B
a[1][3]
C
a[4-2][0]
D
a[0][4]
正确答案:D
官方解析:
这道题目考察了数组的基本概念和数组元素的合法访问范围。对于二维数组a[3][4]来说,第一维下标范围是0-2,第二维下标范围是0-3。
选项D:a[0][4]是非法的。因为第二维下标4超出了合法范围0-3,会导致数组越界访问。这就是为什么D是正确答案。
分析其他选项:
A:a[0][2*1] = a[0][2]是合法的。第一维下标0在0-2范围内,第二维下标2*1=2在0-3范围内。
B:a[1][3]是合法的。第一维下标1在0-2范围内,第二维下标3在0-3范围内。
C:a[4-2][0] = a[2][0]是合法的。第一维下标4-2=2在0-2范围内,第二维下标0在0-3范围内。
这里的关键是要理解:数组下标必须在声明的范围内,否则就会发生数组越界。下标可以是常量也可以是表达式,只要最终计算结果在合法范围内即可。对于a[3][4]这样的二维数组,两个维度的下标都必须分别在其合法范围内。知识点:C++、C语言
题友讨论(9)
单选题
C语言
8.
假设变量a,b均为整型,表达式
1
(a = 5, b = 2, a > b ? a++ : b++, a + b)
的值是( )A
7
B
8
C
9
D
2
正确答案:B
官方解析:
这道题目考察了逗号运算符和条件运算符的运算规则。让我们逐步分析表达式 (a = 5, b = 2, a > b ? a++ : b++, a + b) 的计算过程:
1. a = 5 执行完后,a的值为5
2. b = 2 执行完后,b的值为2
3. a > b ? a++ : b++
- 由于5 > 2为true,执行a++
- a++是后自增,先使用a的值(5),再将a加1变成6
4. 最后计算 a + b
- 此时a = 6, b = 2
- 所以 a + b = 6 + 2 = 8
因此最终表达式的值为8,B选项正确。
分析其他选项:
A选项7:错误,没有正确理解后自增运算
C选项9:错误,可能是误认为a和b都进行了自增
D选项2:错误,完全没有理解表达式的运算过程
关键点:
1. 逗号运算符会按顺序执行每个表达式,并返回最后一个表达式的值
2. 条件运算符中,后自增运算符(++)会在使用变量值之后才进行自增操作
3. 整个表达式的值由最后的a + b决定知识点:C语言
题友讨论(20)
单选题
C++
C语言
9.
若已有定义:int a = 2, b = 3, c = 4; 则表达式!(a + b) - c + 1 || c + b / 2的值是( )
A
-2
B
-1
C
0
D
1
正确答案:D
官方解析:
这道题目考察了运算符优先级和逻辑运算的计算过程。让我们按照运算符优先级逐步计算:
1. 首先计算括号内和除法运算:
- b / 2 = 3 / 2 = 1(整数除法)
- (a + b) = (2 + 3) = 5
2. 然后计算非运算:
- !(a + b) = !5 = 0 (非0为假即0,0为真即1)
3. 接着按照从左到右顺序计算减法和加法:
- 0 - 4 + 1 = -3
4. 最后计算逻辑或运算:
- -3 || (4 + 1) 即 -3 || 5
- 在逻辑运算中,任何非0值都当作真(1)
- 所以这等价于 1 || 1 = 1
因此最终结果为1,所以D选项正确。
分析其他选项:
A(-2)错误:没有完整考虑逻辑或运算的结果
B(-1)错误:忽略了逻辑运算将非零值视为1的规则
C(0)错误:逻辑或运算只要有一个操作数为真,结果就为真(1)知识点:C++、C语言
题友讨论(29)
单选题
C语言
10.
设a为int型变量,执行下列赋值语句后,a的取值分别是( )
a=125.534; a=(int)125.521%4; a=5<<2;
A
125,31,1
B
125,1,20
C
125,31,20
D
125.534,2,20
正确答案:B
官方解析:
这道题目考察了变量赋值和运算的基础知识,让我们逐个分析每个赋值语句:
1. a=125.534
由于a是int类型,小数赋值给整数时会自动进行类型转换,去掉小数部分,所以a=125
2. a=(int)125.521%4
先将125.521强制转换为int得到125,然后125对4取模,得到125÷4=31余1,所以a=1
3. a=5<<2
这是左移运算,5的二进制是101,左移2位变成10100,即十进制的20,所以a=20
因此三次赋值后a的值依次为:125、1、20,对应选项B。
分析其他选项:
A错误:第二次赋值得到1而不是31
C错误:第二次赋值得到1而不是31
D错误:第一次赋值是125而不是125.534(因为发生了类型转换)
关键考点:
- 小数赋值给整型变量时的自动类型转换
- 取模运算符%的运算规则
- 左移运算符<<的计算方法知识点:C语言
题友讨论(16)
单选题
C++
C语言
11.
当n=5时,下列函数的返回值是()
1
2
3
4
int
foo(
int
n) {
if
(n<2)
return
n;
return
foo(n-1)+foo(n-2);
}
A
5
B
7
C
8
D
1
正确答案:A
官方解析:
这道题目是考察递归函数的执行过程。给定的函数foo(n)实际上是在计算斐波那契数列的第n项。
让我们来分析当n=5时的计算过程:
foo(5) = foo(4) + foo(3)
foo(4) = foo(3) + foo(2)
foo(3) = foo(2) + foo(1)
foo(2) = foo(1) + foo(0)
foo(1) = 1
foo(0) = 0
从底向上计算:
foo(2) = 1 + 0 = 1
foo(3) = 1 + 1 = 2
foo(4) = 2 + 1 = 3
foo(5) = 3 + 2 = 5
所以当n=5时,foo(5)的返回值是5,A选项正确。
分析其他选项:
B选项7错误:这个数值在斐波那契数列中是n=6时的结果
C选项8错误:这个数值在斐波那契数列中是n=7时的结果
D选项1错误:这个数值在斐波那契数列中是n=1或n=2时的结果
这个递归函数的特点是:
1. 基本情况是n<2时返回n本身
2. 递归情况是返回前两项的和
3. 产生的数列正好是斐波那契数列:0,1,1,2,3,5,8,13...知识点:C++、iOS工程师、2017、C语言
题友讨论(12)
单选题
C语言
12.
32位系统下,对于下面的结构体A和B,sizeof(A), sizeof(B)的结果分别是()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#pragma pack(2)
struct
A {
int
a;
char
b;
short
c;
};
#pragma pack()
#pragma pack(4)
struct
B {
char
b;
int
a;
short
c;
};
#pragma pack()
int
main() {
printf
(“
sizeof
(A)=%d,
sizeof
(B)=%d\n”,
sizeof
(A),
sizeof
(B));
return
0;
}
A
8,8
B
8,10
C
8,12
D
7,8
正确答案:C
官方解析:
这道题目考察的是C语言结构体的内存对齐知识。关键在于理解pragma pack指令对内存对齐的影响。
对于结构体A:
- pragma pack(2)设置对齐值为2
- int a占4字节,从偏移量0开始存储
- char b占1字节,从偏移量4开始存储
- short c占2字节,因对齐值为2,从偏移量6开始存储
- 总大小为8字节
对于结构体B:
- pragma pack(4)设置对齐值为4
- char b占1字节,从偏移量0开始存储
- int a占4字节,因对齐值为4,需要在偏移量4处存储,所以偏移量1-3需要填充
- short c占2字节,从偏移量8开始存储,最后需要填充2字节以满足整体对齐要求
- 总大小为12字节
因此sizeof(A)=8,sizeof(B)=12,选C是正确的。
分析其他选项:
A错误:虽然sizeof(A)=8正确,但sizeof(B)=8错误,忽略了B中的对齐要求
B错误:sizeof(B)=10的计算没有考虑整体对齐的要求
D错误:sizeof(A)=7的计算完全忽略了内存对齐规则
这个题目的关键是要理解:
1. pragma pack指令影响对齐值
2. 结构体成员的存储位置要满足对齐要求
3. 结构体总大小必须是最大对齐值的整数倍知识点:C语言
题友讨论(23)
单选题
C++
C语言
13.
以数组名作函数参数时,实参数组与形参数组都不必定义长度,因此实参与形参的结合方式是地址结合,与数组长度无关。请问这句话的说法是正确的吗?
A
正确
B
错误
正确答案:B
官方解析:
这句话的说法是错误的。让我来详细解释原因:
在C语言中,当数组作为函数参数传递时,形参数组必须指明除第一维以外所有维的长度。这是因为:
1. 数组作为函数参数时,实际上传递的是数组的首地址,这确实是地址结合
2. 但编译器需要知道除第一维以外的其他维度大小,才能正确计算数组元素的偏移量
具体来说:
- 一维数组:形参可以不指定长度,如 int arr[] 或 int *arr
- 二维数组:必须指定第二维的长度,如 int arr[][3]
- 多维数组:必须指定除第一维外的所有维度大小
例如:
void func(int arr[][3]) // 正确,指定了第二维长度
void func(int arr[][]) // 错误,没有指定第二维长度
void func(int arr[5][3]) // 正确,但第一维的5实际上会被忽略
因此,题目中说"形参数组都不必定义长度"是错误的,这也是选B的原因。虽然确实是地址结合方式,但对数组维度的要求仍然存在。知识点:C++、C语言
题友讨论(30)
单选题
C语言
14.
在C语言中,下列哪用于在其它函数中安全地终止main函数的函数为()
A
return(expr);
B
exit(expr);
C
abort();
D
atexit(expr);
正确答案:B
官方解析:
exit(expr)函数是C语言中用于在其他函数中安全终止main函数的标准库函数。它可以在程序的任何位置调用,会清理所有已打开的文件缓冲区,调用所有已登记的终止处理程序,然后终止程序的执行。expr参数用于向操作系统返回退出状态码。
分析其他选项:
A. return(expr)只能在当前函数中返回值,如果不是在main函数中调用,并不能终止整个程序的执行。
C. abort()函数会突然终止程序,但这是一种非正常的终止方式,不会进行任何清理工作,属于强制终止,不够安全。
D. atexit(expr)函数用于注册程序正常终止时要调用的函数,它本身不能终止程序。它的作用是设置在程序终止时需要自动执行的函数。
所以exit(expr)是最安全和标准的程序终止方式,它会保证程序进行必要的清理工作,并能够向操作系统返回状态码,这也是为什么它是正确答案的原因。知识点:C++工程师、2019、C语言
题友讨论(7)
单选题
C语言
15.
若有以下语句:
1
2
int
a[4][5], (*p)[5];
p = a;
下面表示a数组中元素的是()
A
p+1
B
* (p+3)
C
* (p+1)+3
D
* ( * p+2)
正确答案:D
官方解析:
a是一个二维数组,p是一个指向有5个元素的数组指针。
A:表达式是一个指针,不是对数组元素的引用。*(p+1)等于&a[1],即*(p+1)指向a的第二行的首元素。
B:*(p+3)是一个指针,指向第4行的首元素。
C:*(p+1)指向a的第二行的首元素;*(p+1)+3则指向第二行的第3个元素。
D:* ( *p+2)是对数组元素的正确引用,它等价于a[0][2]。
所以对a数组元素的正确引用的选项是D。
知识点:C语言
题友讨论(32)
单选题
C语言
16.
下面是C语言的操作符的是()
A
.
B
$
C
@
D
都不是
正确答案:A
官方解析:
. (点)是C语言中的操作符,它是成员访问运算符,用于访问结构体或联合体中的成员。比如在结构体struct student s中,可以用s.name来访问name成员。
分析其他选项:
B错误:$ 不是C语言的操作符,它在某些其他编程语言(如PHP)中可能有特殊含义,但在C语言中没有定义。
C错误:@ 不是C语言的操作符,它在某些编程语言(如JavaScript)中可能作为装饰器使用,但不是C语言的标准操作符。
D错误:既然选项A中的点号(.)是C语言的合法操作符,那么"都不是"的说法显然不成立。
C语言的操作符主要包括:
- 算术运算符(+, -, *, /, %, 等)
- 关系运算符(>, <, ==, !=, 等)
- 逻辑运算符(&&, ||, !, 等)
- 位运算符(&, |, ^, ~, 等)
- 赋值运算符(=, +=, -=, 等)
- 成员访问运算符(., ->)
- 其他(sizeof, &, *, [], 等)知识点:C++工程师、C语言
题友讨论(6)
单选题
C++
C语言
17.
已有定义:char a[]="xyz",b[]={'x','y','z'};,以下叙述中正确的是 ()(长度使用sizeof比较)
A
数组a和b的长度相同
B
a数组长度小于b数组长度
C
a数组长度大于b数组长度
D
上述说法都不对
正确答案:C
官方解析:
这道题目考察的是C语言中字符数组的内存分配和字符串的存储方式。
char a[]="xyz" 和 char b[]={'x','y','z'} 虽然看起来内容相同,但实际长度是不同的。
a数组是以字符串形式初始化的,编译器会自动在末尾添加''作为字符串结束符,所以a数组的实际长度是4(包含了'x','y','z'和'')。
而b数组是以字符数组形式初始化的,只包含指定的三个字符'x','y','z',没有结束符'',所以b数组的长度是3。
因此,当使用sizeof比较时:
sizeof(a) = 4字节
sizeof(b) = 3字节
所以a数组长度大于b数组长度,C选项正确。
分析其他选项:
A错误:两个数组长度并不相同,一个是4字节,一个是3字节
B错误:a数组长度不是小于b数组长度,而是大于
D错误:既然我们已经分析出a数组长度确实大于b数组长度,那么说"上述说法都不对"显然是错误的知识点:C++、C语言
题友讨论(30)
单选题
C++
C语言
18.
i最后等于多少?
1
2
3
int
i =
1
;
int
j = i++;
if
((i > j++) && (i++ == j)) i += j;
A
3
B
5
C
6
D
7
正确答案:B
官方解析:
让我们逐步分析代码的执行过程:
1) int i = 1; // i=1
2) int j = i++; // j=1, i=2 (i++是后缀自增,先赋值再加1)
3) if((i>j++) && (i++ == j))
// 第一个条件:i>j++ 判断时 i=2,j=1
// j++执行后 j=2
// 第二个条件:i++ == j 判断时 i=2,j=2
// 条件为true,i再次自增 i=3
4) i+=j; // 条件为true,执行i+=j,此时i=3,j=2
// 所以 i = i + j = 3 + 2 = 5
因此最终 i = 5,答案选B。
分析其他选项:
A(3)错误:这个结果忽略了最后的i+=j操作
C(6)错误:可能是错误地多算了一次自增
D(7)错误:计算结果明显偏大,可能是在某步骤重复计算了
这道题的关键点在于:
1. 理解后缀自增运算符i++的执行时机
2. 理解短路与&&运算符的执行特点
3. 准确追踪每一步i和j的值的变化
4. 注意到条件判断为true后会执行i+=j操作知识点:C++、C语言
题友讨论(23)
单选题
C语言
19.
执行下面程序,正确的输出是()。
1
2
3
4
5
6
7
8
9
10
11
12
int
x=5,y=7;
void
swap () {
int
z;
z=x;
x=y;
y=z
}
int
main (
void
) {
int
x=3,y=8;
swap();
printf
(
"%d,%d\n"
,x, y) ;
}
A
3,8
B
8,3
C
5,7
D
7,5
正确答案:A
官方解析:
这道题目主要考察局部变量与全局变量的作用域以及变量屏蔽的概念。
A选项(3,8)是正确的,原因如下:
1. main函数中定义了局部变量 x=3, y=8
2. 虽然swap函数中交换了全局变量x和y的值,但这不影响main函数中的局部变量
3. printf语句位于main函数中,打印的是main函数的局部变量x和y的值
4. 由于局部变量会屏蔽全局变量,所以最终输出是局部变量的值:3,8
其他选项错误原因:
B选项(8,3):错误理解为交换了main函数中的局部变量
C选项(5,7):这是全局变量的初始值,但printf输出的是局部变量
D选项(7,5):这是全局变量交换后的值,但printf输出的是局部变量
关键知识点:
1. 局部变量的作用域仅限于声明它的函数内部
2. 当局部变量和全局变量同名时,在函数内部局部变量会屏蔽全局变量
3. swap函数操作的是全局变量,而printf打印的是main函数中的局部变量,这是两组互不影响的变量知识点:C语言
题友讨论(24)
单选题
C语言
20.
若已定义:int a[4][3]={1,2,3,4,5,6,7,8,9,10,11,12},(*prt)[3]=a,*p=a[0];则能够正确表示数组元素a[1][2]的表达式是( )
A
*((*prt+1)[2])
B
*(*p+5))
C
(*prt+1)+2
D
*(*(a+1)+2)
正确答案:D
官方解析:
这道题目考察的是对数组指针的理解和多维数组元素访问方式。D 选项 *(*(a+1)+2) 是正确的,因为它准确表达了访问数组元素 a[1][2] 的指针运算。
让我们分析数组 a[4][3] 的内存布局:
- a[4][3] 是一个4行3列的二维数组
- a[1][2] 表示第2行第3列的元素(下标从0开始)
- *(*(a+1)+2) 的计算过程:
1. a+1 定位到第2行的起始位置
2. *(a+1) 获取该行的基地址
3. *(a+1)+2 在该行向后偏移2个位置
4. 最外层的 * 取出该位置的值
分析其他选项:
A. *((*prt+1)[2]) 语法错误,应该是 *(*(prt+1)+2)
B. *(*p+5) 虽然也能访问到正确的数值,但这是把二维数组当作一维数组来访问,不符合题目本意
C. (*prt+1)+2 只计算了地址,没有取出该地址对应的值
实际应用中,推荐使用 D 这种标准的指针运算方式来访问二维数组元素,这样代码更清晰易懂。知识点:C语言
题友讨论(31)
单选题
C++
C语言
21.
要使a的低四位翻转,需要进行操作是()
A
a|0xF
B
a&0xF
C
a^0xF
D
~a
正确答案:C
官方解析:
要使变量a的低四位翻转,需要使用异或运算符^与0xF进行操作,因此C选项(a^0xF)是正确答案。
异或运算符^的特点是:对应位相同时结果为0,不同时结果为1。0xF的二进制表示为0000 1111,与a进行异或运算时,会使a的低4位发生翻转(0变1,1变0),而高位保持不变(与0异或保持原值)。
分析其他选项:
A. a|0xF(按位或):会将低4位全部置为1,不是翻转
B. a&0xF(按位与):会将高4位全部置为0,保留低4位原值,不是翻转
D. ~a(按位取反):会将所有位都取反,不仅仅是低4位
举例说明:
假设a = 1010 0101
则a^0xF = 1010 0101 ^ 0000 1111 = 1010 1010
可以看到,只有低4位发生了翻转(0101变为1010),高4位保持不变(1010),这正是题目要求的效果。
因此,使用异或运算符^是实现低4位翻转的正确方法。知识点:C++、C++工程师、2019、C语言
题友讨论(10)
单选题
C语言
22.
以下程序
1
2
3
4
5
main() {
int
m, n, p;
scanf
(
"m=%dn=%dp=%d"
, &m, &n, &p);
printf
(
"%d%d%d\n"
, m, n, p);
}
若想从键盘上输入数据,使变量m中的值为123,n中的值为456,p中的值为789,则正确的输入是()
A
m=123n=456p=789
B
m=123 n=456 p=789
C
m=123,n=456,p=789
D
123 456 789
正确答案:A
官方解析:
这道题目考察了scanf函数格式化输入的使用。选项A是正确的,因为程序中scanf函数的格式控制字符串是"m=%dn=%dp=%d",要按照这个完全相同的格式输入数据才能被正确读取。
具体分析:
1. 代码中的scanf("m=%dn=%dp=%d", &m, &n, &p)要求输入格式必须严格匹配"m=数字n=数字p=数字"这种模式。
2. 分析各选项:
- A选项 "m=123n=456p=789" 完全符合scanf要求的输入格式,可以正确读取三个值
- B选项 "m=123 n=456 p=789" 中间多了空格,与格式不匹配
- C选项 "m=123,n=456,p=789" 多了逗号,与格式不匹配
- D选项 "123 456 789" 缺少了"m="、"n="、"p="这些必要的字符串
3. scanf函数的格式字符串中没有空格,所以输入时也不能有额外的空格。格式必须完全一致才能正确读取数据。
4. 程序最终会通过printf输出读取到的三个整数值。只有按A选项的格式输入,才能让程序正确读取到m=123、n=456、p=789这三个值。知识点:C语言
题友讨论(13)
单选题
C++
C语言
23.
下列代码,循环了多少次()
int k = 2000; while (k > 1) {k = k >> 1; }A
10
B
11
C
12
D
20
正确答案:A
官方解析:暂无官方题目解析,去讨论区看看吧!
知识点:C++、2017、系统工程师、C语言
题友讨论(14)
单选题
C语言
24.
在c语言中,一个函数不写返回值类型,默认的返回类型是()
A
int
B
char
C
void
D
都不是
正确答案:A
官方解析:
在C语言中,当一个函数不写返回值类型时,默认返回值类型为int。这是C语言的一个历史遗留特性,在早期的C语言标准(C89/90)中就是如此规定的。
虽然现代编程实践建议明确声明函数的返回类型,但编译器仍然保持这个默认行为以保证向后兼容性。例如:
main() { return 0; }
等价于
int main() { return 0; }
分析其他选项:
B选项char错误:char不是默认返回类型,必须显式声明
C选项void错误:void表示函数无返回值,也需要显式声明
D选项"都不是"错误:因为int确实是默认返回类型
需要注意的是,虽然有这个默认特性,但在实际编程中应该养成显式声明函数返回类型的好习惯,这样可以提高代码的可读性和可维护性,也符合现代C语言编程规范。在C++等更现代的语言中,已经不再支持省略返回类型的写法。知识点:C语言
题友讨论(72)
单选题
C语言
25.
以下程序的运行结果是()
1
2
3
4
5
6
#define MIN(x,y) (x)<(y) ? (x):(y)
int
main() {
int
i = 10, j = 15, k;
k = 10*MIN(i, j);
printf
(
"%d\n"
, k);
}
A
10
B
15
C
100
D
150
正确答案:B
官方解析:
【解释】语句k=10*MIN(i,j);在预编译时将进行宏替换为k=10*(i)<(j) ? (i) : (j);。
因i=10,j=15,所以语句等价于k=10*10<15 ? 10:15;,10*10比15大,因此k的值
将是15。故正确答案是B。
知识点:C语言
题友讨论(21)
单选题
C语言
26.
printf("%2$d%5$d",123,345,135,4294967295,666,888); 以上代码执行完成后会输出什么内容(环境Linux 64位)?
A
123-1
B
123345
C
345666
D
2$1235$345
正确答案:C
官方解析:
这道题目考察了printf格式化输出中的参数索引知识。在printf中可以使用%n$d的形式来指定使用第n个参数,其中n从1开始计数。
在给出的printf语句中:
printf("%2$d%5$d",123,345,135,4294967295,666,888)
- %2$d 表示使用第2个参数,即345
- %5$d 表示使用第5个参数,即666
所以最终输出为"345666",因此C选项正确。
分析其他选项:
A错误:输出"123-1"与格式化字符串的语法完全不符
B错误:输出"123345"是把第一个和第二个参数拼接,但实际上格式控制符要求使用第2和第5个参数
D错误:输出"2$1235$345"是直接把格式控制符字面值输出,没有进行参数替换
这种参数索引的语法在需要重复使用某个参数,或调整参数输出顺序时特别有用。不过为了代码可读性,建议谨慎使用这种特性。知识点:C语言
题友讨论(0)
单选题
C++
C语言
27.
下列关于类中的静态成员的说法错误的是()
A
虽然静态成员不属于类的某个对象,但是我们仍然可以使用类的对象、引用或者指针来访问静态成员
B
成员函数不用通过作用域运算符就能直接使用静态成员
C
静态数据成员不是由类的构造函数初始化的
D
静态成员不可以作为默认实参
正确答案:D
官方解析:
这道题目考察了C++中静态成员的特性。D选项是错误的说法,因为静态成员是可以作为默认实参的。静态成员在程序启动时就已经存在,生命周期贯穿整个程序运行期间,因此完全可以作为函数的默认参数。
分析其他选项:
A正确:静态成员虽然不属于类的某个具体对象,而是属于整个类,但可以通过类的对象、引用或指针来访问。这种访问方式是合法的,尽管通过类名和作用域运算符访问更规范。
B正确:在类的成员函数内部可以直接使用静态成员,不需要通过作用域运算符,因为成员函数可以直接访问类中的所有成员(包括静态成员)。
C正确:静态数据成员的初始化是在类外进行的,不是在构造函数中进行。静态数据成员必须在类外显式定义和初始化,因为它们在程序开始运行时就要分配空间。
总的来说,这道题目主要考察了对C++静态成员特性的理解,包括其访问方式、初始化方式以及在类中的使用规则。知识点:C++、2018、C语言
题友讨论(7)
单选题
C语言
28.
1
2
3
4
5
6
7
8
char
* getmemory(
void
){
char
p[]=
" hello world"
;
return
p;
}
void
test(
void
){
char
*str=NULL;
str=getmemory();
printf
(str);
}
请问运行Test 函数会有什么样的结果?
A
出错
B
输出"hello world"
C
输出空""
D
输出乱码
正确答案:D
官方解析:
这道题目考察了 C 语言中函数返回局部变量的指针的问题。D 选项"输出乱码"是正确答案,因为这涉及到内存访问的重要概念。
在 getmemory() 函数中,char p[] = "hello world" 定义了一个局部数组,它在栈空间中分配。当函数返回时,这个局部变量的内存空间会被释放。因此,返回的指针 p 指向的是一块已经失效的内存地址。
当在 test() 函数中使用这个返回的指针去打印内容时,会访问这块已经失效的内存空间,导致输出乱码。这种情况下的程序行为是未定义的。
分析其他选项:
A错误:虽然这段代码存在明显的问题,但不一定会导致程序崩溃。程序可能会继续运行,只是输出乱码。
B错误:不会输出"hello world",因为原来存储字符串的内存空间已经失效。
C错误:不会输出空字符串,因为指针指向的是一块已经失效的内存空间。
要修正这个问题,可以使用动态内存分配(malloc)或者将字符串定义为静态变量(static)。这样可以确保返回的指针指向有效的内存空间。这是一个典型的内存管理陷阱,在实际编程中需要特别注意避免返回局部变量的地址。知识点:C语言
题友讨论(87)
单选题
C++
C语言
29.
以下哪个函数可以在源地址和目的地址的位置任意的情况下,在源地址和目的地址的空间大小任意的情况下实现二进制代码块的复制?
A
memcpy()
B
memmove()
C
memset()
D
strcpy()
正确答案:B
官方解析:
这道题目考察了不同内存拷贝函数的特性和适用场景。memmove()函数是正确选项,因为它能够安全地处理源地址和目标地址重叠的情况,并且对内存空间大小没有特殊限制。memmove()会先将源数据复制到临时缓冲区,再将数据从临时缓冲区复制到目标位置,从而避免了数据覆盖的问题。
分析其他选项:
A. memcpy()虽然也是内存复制函数,但它要求源地址和目标地址不能重叠。如果发生重叠,可能会导致数据被覆盖,造成复制结果不正确。
C. memset()是内存设置函数,用于将一段内存空间设置为指定的值,不具备内存复制的功能。它只能用来初始化内存,不能完成数据的复制操作。
D. strcpy()是字符串复制函数,只能用于以空字符('')结尾的字符串复制,而且不能处理内存重叠的情况。它不适合用于一般二进制数据的复制,且没有长度参数限制,可能会造成缓冲区溢出。知识点:C++、C语言
题友讨论(25)
多选题
C++
C语言
30.
在声明类时,下面的说法正确的是()
A
可以在类的声明中给数据成员赋初值(c++11新标准)
B
数据成员的数据类型可以是register
C
private、public、protected可以按任意顺序出现
D
没有用private、public、protected定义的数据成员是公有成员
正确答案:AC
官方解析:
这道题目考察了C++类声明的相关知识。
选项A正确:C++11新标准允许在类的声明中直接给数据成员赋初值,这是一个很实用的特性,可以简化代码并提高可读性。
选项C正确:在类的声明中,访问修饰符private、public、protected的出现顺序是没有限制的,可以根据需要任意排列。这些修饰符的作用范围是从其出现位置开始直到下一个访问修饰符出现或类声明结束。
分析错误选项:
选项B错误:register关键字只能用于局部自动变量的声明,不能用于类的数据成员。register关键字建议编译器将变量存储在CPU寄存器中,但这种存储方式不适用于类成员。
选项D错误:在C++中,如果类成员没有显式使用访问修饰符声明,默认情况下是私有(private)成员,而不是公有成员。这是C++相对于C语言的一个重要区别,体现了C++对数据封装的支持。
这个设计有助于保证类的封装性,防止数据成员被外部直接访问,符合面向对象编程的封装原则。知识点:C++、C语言
题友讨论(22)
试卷02题目
单选题
C++
1.
有以下程序
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using
namespace
std;
int
fun (
int
x,
int
y){
if
(x == y)
return
(x);
else
return
((x + y) / 2);
}
int
main(){
int
a = 4, b = 5, c = 6;
printf
(
"%d\n"
, fun(2 * a, fun(b, c)));
}
下面程序的输出是?
A
8
B
6
C
12
D
3
正确答案:B
官方解析:
让我们逐步分析程序的执行过程:
1. 程序从main函数开始执行,定义了变量a=4, b=5, c=6
2. 在printf语句中调用了嵌套的fun函数:fun(2*a, fun(b,c))
3. 首先计算内层的fun(b,c),即fun(5,6)
- 由于5≠6,根据fun函数定义返回(5+6)/2=5
4. 然后计算外层fun(2*a, 5),即fun(8,5)
- 由于8≠5,根据fun函数定义返回(8+5)/2=6
所以最终输出结果为6,B选项正确。
分析其他选项:
A选项(8):这可能是误认为程序直接返回2*a的值
C选项(12):这可能是误认为程序返回2*a+b的结果
D选项(3):这可能是误解了除法运算的结果
关键点:
1. fun函数的逻辑是:如果两个参数相等则返回其中一个值,否则返回两数的平均值
2. 需要注意嵌套函数调用的执行顺序,先执行内层,再执行外层
3. 整数除法会舍去小数部分,但在本题中不影响最终结果
所以通过仔细分析程序的执行流程,我们可以得出最终输出确实是6。知识点:C++
题友讨论(6)
单选题
C++
C语言
2.
下列程序的功能是求出3×4的矩阵a中最大元素的值,请为横线处选择合适的程序( )
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int
main()
{
int
i, j, max;
int
a[3][4] = {{1, 2, 3, 4}, {9, 8, 7, 6}, {-10, 10, -5, 2}};
max = a[0][0];
for
(i = 0; i <= 2; i++)
for
(j = 0; j <= 3; j++)
if
(______________)
max = a[i][j];
printf
(
"max=%d\n"
, max);
}
A
a[i][j] < max
B
a[j][i] > max
C
a[i][j] > max
D
a[j][i] < max
正确答案:C
官方解析:
这道题目考察了二维数组中求最大值的算法实现。C选项 a[i][j] > max 是正确的,因为题目要求找出矩阵中的最大元素,需要将当前遍历到的元素与已知最大值进行比较,当当前元素大于已知最大值时更新最大值。
具体分析每个选项:
A选项 a[i][j] < max 错误:
这个条件是在寻找最小值而不是最大值。如果当前元素小于max时更新max,最终得到的将是最小值。
B选项 a[j][i] > max 错误:
这里颠倒了数组的下标顺序。原数组是3×4的矩阵,如果使用a[j][i],当j=3时会发生数组越界错误,因为数组第一维的大小只有3。
C选项 a[i][j] > max 正确:
初始化max为a[0][0]后,遍历数组的每个元素,当发现比当前max更大的元素时,更新max的值。这样遍历结束后,max中存储的就是数组中的最大值。
D选项 a[j][i] < max 错误:
既颠倒了数组下标顺序(会导致越界),又使用了错误的比较符号(会得到最小值而不是最大值)。
这是一个典型的数组最大值查找算法,正确的实现需要:
1. 正确的数组下标顺序
2. 正确的比较运算符
3. 合适的初始值知识点:C++、C语言
题友讨论(6)
单选题
C++
C语言
3.
表达式4 > 5 ? 1 : 0的值是1。说法是否正确?
A
正确
B
错误
正确答案:B
官方解析:
这道题考察了条件运算符(三目运算符)的运算规则。题目中表达式 4 > 5 ? 1 : 0 的值实际上是0而不是1。
因为条件运算符的语法格式是: 条件表达式 ? 表达式1 : 表达式2
- 当条件表达式结果为true时,整个表达式的值为表达式1的值
- 当条件表达式结果为false时,整个表达式的值为表达式2的值
在这个例子中:
1. 条件表达式是 4 > 5,显然4小于5,所以结果是false
2. 当条件为false时,会返回冒号后面的值,也就是0
3. 所以整个表达式 4 > 5 ? 1 : 0 的最终结果是0,而不是1
因此说该表达式的值是1的说法是错误的,选B是正确的。
这个知识点在实际编程中经常使用,它是if-else的简化写法,可以让代码更简洁。理解条件运算符的执行规则对写出正确的程序很重要。知识点:C++、C语言
题友讨论(6)
单选题
C++
C语言
4.
有以下变量说明,下面不正确的赋值语句是()
1
2
3
int
a=5, b=10, c;
int
* p1 = &a;
int
* p2 = &b;
A
p2 = &a;
B
p1 = a;
C
p2 = p1;
D
p1 = &b;
正确答案:B
官方解析:
这道题目考察了 C++ 中指针变量的赋值规则。B 选项是错误的,因为试图将整型变量 a 直接赋值给指针变量 p1,这违反了类型匹配规则。指针变量只能存储地址,不能直接存储普通整型值。
分析所有选项:
A选项(p2 = &a)正确:
可以将变量 a 的地址赋值给指针变量 p2,这种赋值方式符合语法规则。
B选项(p1 = a)错误:
试图将整型值直接赋给指针变量,这是类型不匹配的。正确的赋值方式应该是使用取地址符 & 获取变量的地址。
C选项(p2 = p1)正确:
两个同类型的指针变量之间可以直接赋值,这样 p2 会指向 p1 当前指向的地址。
D选项(p1 = &b)正确:
可以将变量 b 的地址赋值给指针变量 p1,这是合法的指针赋值操作。
总的来说,除了B选项,其他选项都是合法的指针赋值操作。在C++中,指针变量必须存储地址值,而不能直接存储普通变量的值。知识点:C++、C语言
题友讨论(11)
单选题
C++
5.
当需要用一个形参直接改变对应实参的值时,该形参应说明为()。
A
基本类型
B
引用型
C
指针型
D
常值引用型
正确答案:B
官方解析:
当需要在函数中直接修改实参的值时,应该使用引用类型的形参,所以B选项"引用型"是正确答案。
引用型参数的特点是:
1. 引用是变量的别名,它和原变量指向同一个内存地址
2. 通过引用对形参的修改会直接反映到实参上
3. 引用必须在定义时初始化,初始化后不能再引用其他变量
分析其他选项:
A. 基本类型作为形参时采用值传递,函数内对形参的修改不会影响实参的值
C. 指针虽然也能修改实参,但C++中推荐使用引用而不是指针,因为引用更安全且使用更简单
D. 常值引用型(const引用)不允许修改引用的值,与题目要求直接修改值的目的相反
使用引用作为形参的优点:
1. 避免了值传递时的数据拷贝,提高效率
2. 语法简单,使用起来像普通变量
3. 比指针更安全,不会出现空指针
4. 能够实现对实参的直接修改
因此在需要通过形参修改实参值的场景下,使用引用型参数是最佳选择。知识点:C++
题友讨论(8)
单选题
C++
6.
设j和k都是int类型,则for循环语句
for(j=0,k=0;j<=9&&k!=876;j++)
cin>>k;
最多执行10次,
该说法是否正确?
A
正确
B
错误
正确答案:A
官方解析:
这道题考察了for循环的执行逻辑和循环终止条件的判断。A选项"最多执行10次"的说法是正确的。
让我们分析循环条件:
1. 循环的初始化部分: j=0,k=0
2. 循环的判断条件: j<=9 && k!=876
3. 每次循环j增加1: j++
该循环会在以下任一条件成立时终止:
- j > 9
- k == 876
由于j从0开始,每次循环j增加1,直到j>9时循环结束,所以最多执行10次(j分别为0,1,2,...,9)。即使用户输入的k一直不等于876,循环也会在j>9时终止。
另外,如果在执行过程中用户输入了k=876,循环也会提前终止,此时执行次数会小于10次。
所以该循环的执行次数范围是:1-10次,最多执行10次这个说法是完全正确的。因此A选项正确,B选项错误。
这个例子也说明了在for循环中使用多个条件控制循环终止是完全可行的,只要任一条件不满足,循环就会终止。知识点:C++
题友讨论(16)
单选题
C++
7.
关于类与对象,下面哪一种说法是错误的?
A
一个对象是某个类的一个实例
B
一个实例是某个类型经实例化所产生的一个实体
C
创建一个对象必须指定被实例化的一个类
D
一个类的多个对象之间不仅持有独立的数据成员,而且成员函数也是独立的
正确答案:D
官方解析:
选项D错误。在类的所有对象(实例)中,数据成员是独立的,但成员函数(方法)是共享的。当我们创建一个类的多个对象时,每个对象都会有自己独立的数据成员空间,但成员函数代码只存在一份,被所有对象共享使用。这样可以节省内存空间,提高程序效率。
分析其他选项:
A正确:对象是类的具体实例,表示类的一个具体实体。
B正确:实例就是类被实例化后产生的实体,与对象是同一个概念。
C正确:创建对象时必须指定具体的类,因为对象是类的实例化,需要根据类的定义来分配内存空间和初始化。这个类定义了对象的属性和行为。
这个题目主要考察了类与对象的基本概念,特别是成员函数在对象中的存储特点。理解成员函数是共享的这一点对于理解面向对象编程的内存管理很重要。知识点:C++
题友讨论(11)
单选题
C++
C语言
8.
若给定条件表达式(M)?(a++):(a--),则其中表达式 M( )
A
和(M==0)等价
B
和(M==1)等价
C
和(M!=0)等价
D
和(M!=1)等价
正确答案:C
官方解析:
在条件运算符"?:"中,(M)?(a++):(a--)是一个典型的三目运算表达式。C选项是正确的,因为条件表达式M等价于(M!=0)。
具体分析:
1. 在C/C++等语言中,条件判断时会将表达式M转换为布尔值
2. 当M不等于0时(M!=0),表达式值为true,执行问号后的表达式a++
3. 当M等于0时,表达式值为false,执行冒号后的表达式a--
4. 这个转换过程就是将M隐式转换为布尔值,判断是否为非0
其他选项分析:
A错误:M==0与原条件正好相反,会导致执行分支颠倒
B错误:M==1的判断条件过于严格,只判断是否等于1,而实际上M任何非0值都应该执行第一个分支
D错误:M!=1的判断范围不准确,因为当M=2时也应该执行第一个分支
因此,(M)在条件表达式中的判断逻辑就是判断M是否为非0值,所以和(M!=0)是等价的。知识点:C++、C语言
题友讨论(21)
单选题
C++
9.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>
#include<string>
using
namespace
std;
class
A
{
friend
long
fun(A s)
{
if
(s.x<3) {
return
1;
}
return
s.x+fun(A(s.x - 1));
}
public
:
A(
long
a)
{
x = a--;
}
private
:
long
x;
};
int
main()
{
int
sum=0;
for
(
int
i=0; i<5; i++) {
sum += fun(A(i));
}
cout<<sum;
}
代码运行结果是?
A
21
B
15
C
9
D
36
正确答案:B
官方解析:
这道题目考察了C++中友元函数和递归的运用。让我们逐步分析程序的执行过程:
1. 首先分析fun函数的递归逻辑:
- 当输入A对象的x小于3时返回1
- 否则返回 x + fun(A(x-1))
2. for循环从i=0到4,每次调用fun(A(i)),让我们计算每次的结果:
当i=0时:fun(A(0))
- x=0, 小于3,返回1
当i=1时:fun(A(1))
- x=1, 小于3,返回1
当i=2时:fun(A(2))
- x=2, 小于3,返回1
当i=3时:fun(A(3))
- x=3, 返回3 + fun(A(2))
- = 3 + 1 = 4
当i=4时:fun(A(4))
- x=4, 返回4 + fun(A(3))
- = 4 + 4 = 8
3. 最终sum的值为: 1 + 1 + 1 + 4 + 8 = 15
所以B选项15是正确答案。
分析其他选项:
A(21)错误:可能是误算了递归过程
C(9)错误:明显偏小,没有考虑完整的递归累加过程
D(36)错误:计算结果偏大,可能重复计算了某些值
注意点:
1. A类的构造函数中x = a--是后减,不影响x的赋值
2. friend关键字使fun函数能够访问A类的私有成员x
3. 递归终止条件是x < 3时返回1知识点:C++、Java工程师、C++工程师、2016
题友讨论(24)
单选题
C++
10.
以下哪种STL容器中的对象是连续存储的:()
A
list
B
vector
C
map
D
set
正确答案:B
官方解析:
vector是STL中唯一默认采用连续存储的容器,它使用连续的内存空间来存储元素,这意味着vector中的元素在内存中是相邻的。这种存储方式让vector能够实现快速的随机访问,支持通过下标直接访问任意位置的元素。
分析其他选项:
A. list使用双向链表实现,每个节点包含数据和指向前后节点的指针,节点之间通过指针链接,在内存中并不连续。
C. map是关联容器,内部采用红黑树实现,节点之间通过指针连接形成树状结构,数据在内存中不是连续存储的。
D. set也是关联容器,同样采用红黑树实现,节点分散存储在内存中,通过指针相连,不是连续存储。
vector的连续存储特性带来的优势:
1. 支持随机访问,访问效率O(1)
2. 对CPU缓存友好,可以提高访问速度
3. 空间效率高,不需要存储额外的指针信息
但这也意味着在vector中间插入或删除元素时,需要移动后续元素,效率较低。当空间不足需要扩容时,要重新分配更大的连续空间。知识点:C++
题友讨论(14)
单选题
C++
11.
下面 C++ 程序的输出结果为()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <stack>
using namespace std;
struct TreeNode {
int
val;
TreeNode* left;
TreeNode* right;
TreeNode(
int
x) : val(x), left(nullptr), right(nullptr) {}
};
void
inorder(TreeNode* root) {
stack<TreeNode*> stk;
while
(root != nullptr || !stk.empty()) {
while
(root != nullptr) {
stk.push(root);
root = root->left;
}
root = stk.top();
stk.pop();
cout << root->val <<
" "
;
root = root->right;
}
}
int
main() {
TreeNode* root =
new
TreeNode(
1
);
root->right =
new
TreeNode(
2
);
root->right->left =
new
TreeNode(
3
);
inorder(root);
return
0
;
}
A
1 2 3
B
1 3 2
C
2 1 3
D
3 2 1
正确答案:B
官方解析:
这道题目考察了二叉树的中序遍历算法的非递归实现。根据代码构造的二叉树结构和遍历顺序,B选项"1 3 2"是正确答案。
分析如下:
1. 代码构造的二叉树结构为:
- 根节点值为1
- 根节点的右子节点值为2
- 值为2的节点的左子节点值为3
2. 中序遍历的顺序是:左子树 -> 根节点 -> 右子树
在这个例子中遍历过程:
- 从根节点1开始,1没有左子节点,直接输出1
- 访问右子节点2,2有左子节点3
- 先访问2的左子节点3,输出3
- 最后访问节点2,输出2
因此输出顺序是:1 3 2
分析其他选项:
A选项(1 2 3)错误:没有考虑到节点2的左子节点3应该在2之前访问
C选项(2 1 3)错误:违反了中序遍历的基本规则,根节点1应该最先输出
D选项(3 2 1)错误:这是后序遍历的结果,而不是中序遍历
代码中使用栈实现非递归的中序遍历,通过while循环不断将左子节点入栈,当左子树遍历完成后,依次弹出栈顶元素并访问其右子树,这样保证了中序遍历的正确顺序。知识点:C++
题友讨论(0)
单选题
C++
12.
以下程序的运行结果是()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using
namespace
std;
int
a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
void
fun(
int
* pa,
int
n);
int
main() {
int
m = 10;
fun(a, m);
cout << a[6] << endl;
}
void
fun(
int
* pa,
int
n) {
for
(
int
i = n - 1; i > 0; i--)
*(pa + 6) += pa[i];
}
A
34
B
7
C
6
D
68
正确答案:D
你的答案:A
官方解析:
程序的运行结果是68。以下是详细解析:
关键步骤分析:
- 数组初始化:a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0},其中a[6]初始值为 7。
- 函数fun的逻辑:
- 循环从i = 9到i = 1(共9次迭代),每次将a[i]累加到a[6]。
- 具体累加过程:
- i=9→a[6] += 0→7
- i=8→a[6] += 9→16
- i=7→a[6] += 8→24
- i=6→a[6] += 24→48(此时a[6]已被更新为24)
- i=5→a[6] += 6→54
- i=4→a[6] += 5→59
- i=3→a[6] += 4→63
- i=2→a[6] += 3→66
- i=1→a[6] += 2→68
- 最终输出:cout << a[6]输出 68。
结论:程序运行结果为 68。
知识点:C++、C++工程师
题友讨论(18)
单选题
C++
13.
下面程序输出结果为?
1
2
3
4
5
6
7
#include<iostream.h>
#define SUB(X,Y) (X)*Y
int
main(){
int
a=3,b=4;
cout<<SUB(a++,++b);
return
0;
}
A
15
B
16
C
20
D
12
正确答案:A
官方解析:
这道题目主要考察宏定义中的文本替换和运算符优先级。
让我们逐步计算SUB(a++,++b)的展开过程:
1. 宏定义 SUB(X,Y) 会被展开为 (X)*Y
2. 将实参代入后得到: (a++)*++b
3. 根据运算符优先级:
- ++b 是前置递增,先将b加1变为5
- a++ 是后置递增,先使用a的值3,再将a加1变为4
- 最后计算乘法 3*5=15
所以最终结果为15,A选项正确。
分析其他选项:
B选项16:可能是误认为a先自增为4再参与运算
C选项20:可能是误认为a和b都完成自增(4*5)后再相乘
D选项12:可能是没考虑++b的前置自增效果,直接用3*4计算
这道题的关键点在于:
1. 宏定义是简单的文本替换
2. 理解前置++和后置++的区别
3. 正确把握运算符优先级
所以最终输出结果是15。知识点:C++、Java工程师、C++工程师、2016
题友讨论(22)
单选题
C++
C语言
14.
已知char *a[]={ "fortran", " basic", "pascal", "java", "c++" };,则cout<<a[3];的显示结果是()
A
t
B
一个地址值
C
java
D
javac++
正确答案:C
官方解析:
char *a[]定义了一个字符串数组,其中包含5个字符串元素:"fortran"、" basic"、"pascal"、"java"、"c++"。数组下标从0开始,a[3]表示访问数组中第4个元素,即"java"字符串。
因此,cout<
分析其他选项:
A错误:选项"t"是错误的,这是将a[3]误解为单个字符。a[3]指向的是一个完整的字符串。
B错误:虽然a[3]本质上是指向字符串"java"首地址的指针,但cout输出char*类型时会自动识别为字符串并输出完整内容,而不是输出地址值。
D错误:"javac++"是错误的,因为a[3]只会输出数组中第4个元素"java",不会连带输出后面的元素。
这道题目主要考察了:
1. 字符串数组的定义和访问
2. cout对字符指针(char*)的输出处理
3. 数组下标从0开始的基本概念知识点:C++、C语言
题友讨论(16)
单选题
C++
C语言
15.
设整形变量i,j值均为3,执行了j=i++,j++,++i后,i,j的值是()
A
3,3
B
5,4
C
4,5
D
6,6
正确答案:B
官方解析:
让我们逐步分析代码执行过程:
初始状态: i=3, j=3
1. j=i++
- i++是后自增,先使用i的值再加1
- 所以j先被赋值为3
- 然后i自增为4
此时: i=4, j=3
2. j++
- j自增1
此时: i=4, j=4
3. ++i
- i前自增1
最终状态: i=5, j=4
因此B选项(5,4)是正确答案。
分析其他选项:
A(3,3):只是初始状态的值,没有考虑到后续运算
C(4,5):把i和j的最终值弄反了
D(6,6):计算结果明显偏大,可能是把所有自增运算都重复计算了
这道题目主要考察了:
1. 后自增(i++)和前自增(++i)的区别
2. 赋值表达式和自增运算的优先级
3. 程序执行的顺序性
掌握这些基础知识点对理解和编写代码都很重要。知识点:C++、C语言
题友讨论(28)
单选题
C++
16.
设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为?
1
2
3
4
5
6
7
8
C c;
int
main()
{
A*pa=
new
A();
B b;
static
D d;
delete pa;
}
A
A B C D
B
A B D C
C
A C D B
D
A C B D
正确答案:B
官方解析:
这道题考察了C++对象析构顺序的基本知识。程序中有4个对象:全局对象c、堆对象pa、局部对象b和静态局部对象d,它们的析构顺序由C++语言规则决定。
选项B(A B D C)是正确的,析构顺序分析如下:
1. pa对象在delete语句处被显式析构,因此A最先析构
2. b是局部对象,在main函数结束时析构,因此B第二个析构
3. d是静态局部对象,在程序结束时析构,因此D第三个析构
4. c是全局对象,在程序结束时最后析构,因此C最后析构
析构顺序遵循以下规则:
- 显式删除的对象最先析构
- 局部对象按照作用域结束的逆序析构
- 静态对象(包括全局对象和静态局部对象)在程序结束时析构,顺序与构造顺序相反
其他选项错误原因:
A错误:没有考虑到对象的作用域和生命周期特点
C错误:打乱了局部对象和静态对象的析构顺序
D错误:全局对象c应该最后析构,而不是中间析构知识点:C++、C++工程师
题友讨论(73)
单选题
C++
17.
1
2
3
4
int
fun(
int
a){
a^=(1<<5)-1;
return
a;
}
fun(21)运行结果是()
A
10
B
5
C
3
D
8
正确答案:A
官方解析:暂无官方题目解析,去讨论区看看吧!
知识点:C++
题友讨论(29)
单选题
C++
18.
在下列选项中,istream类对象的是()
A
cerr
B
cin
C
clog
D
cout
正确答案:B
官方解析:
C++中的输入输出流分为istream(输入流)和ostream(输出流)两大类。其中cin是istream类的对象,专门用于从标准输入设备(通常是键盘)获取数据。
分析其他选项:
A. cerr 是 ostream 类的对象,用于标准错误输出,不是输入流对象
B. cin 是 istream 类的对象,用于标准输入,是正确答案
C. clog 是 ostream 类的对象,用于标准日志输出,不是输入流对象
D. cout 是 ostream 类的对象,用于标准输出,不是输入流对象
这些流对象都定义在 iostream 头文件中,他们的继承关系如下:
- istream 继承自 ios 类,用于输入操作
- ostream 继承自 ios 类,用于输出操作
- cin 是 istream 类的对象
- cout/cerr/clog 都是 ostream 类的对象
所以只有 cin 是 istream 类的对象,其他选项都属于 ostream 类。知识点:C++
题友讨论(4)
单选题
C++
C语言
19.
下面程序执行输出结果为()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int
fun(
int
i) {
int
cnt = 0;
while
(i) {
cnt++;
i = i&(i-1);
}
return
cnt;
}
int
main() {
printf
(
"%d\n"
, fun(2017));
return
0;
}
A
6
B
7
C
8
D
9
正确答案:B
官方解析:
这道题目主要考察位运算的知识点和一个经典的计算二进制中1的个数的算法。
函数fun的功能是计算一个整数的二进制表示中包含1的个数。其中使用了一个非常巧妙的位运算技巧:i & (i-1)。
让我们分析2017的计算过程:
2017的二进制表示为: 11111110001
执行i & (i-1)的过程如下:
1. 11111110001 & 11111110000 = 11111110000 cnt=1
2. 11111110000 & 11111101111 = 11111100000 cnt=2
3. 11111100000 & 11111011111 = 11111000000 cnt=3
4. 11111000000 & 11110111111 = 11110000000 cnt=4
5. 11110000000 & 11101111111 = 11100000000 cnt=5
6. 11100000000 & 11011111111 = 11000000000 cnt=6
7. 11000000000 & 10111111111 = 10000000000 cnt=7
8. 10000000000 & 01111111111 = 00000000000 cnt=7结束
每执行一次i & (i-1)操作,都会消除二进制表示中最右边的1。循环次数就是二进制中1的个数。
因此2017的二进制表示中恰好包含7个1,所以答案是B。
其他选项分析:
A(6):少统计了一个1
C(8):多统计了一个1
D(9):多统计了两个1知识点:C++、C++工程师、2019、C语言
题友讨论(29)
单选题
C++
20.
假定所有变量均已正确定义,则下列程序段运行后x的值是()
A
35
B
34
C
4
D
3
正确答案:C
官方解析:
这道题考察了Java中while循环和++/--运算符的执行顺序。让我们逐步分析代码的执行过程:
首先变量x=5,y=4。接下来进入while循环,条件判断为 (--x > 2)。
第一次循环:
--x先执行,x变为4,判断4>2为true
y=y--执行,先使用y的值4赋给y,然后y再减1变为3
此时x=4,y=4
第二次循环:
--x执行,x变为3,判断3>2为true
y=y--执行,先使用y的值4赋给y,然后y再减1变为3
此时x=3,y=4
第三次循环:
--x执行,x变为2,判断2>2为false
循环结束
最终x=2,y=4
循环结束后:
执行x=x+y
即2+4=6
最后执行x=x-2
即6-2=4
所以最终x的值为4,选C是正确的。
其他选项错误原因:
A(35)和B(34):这两个值远大于正确结果,没有正确理解循环和运算符执行顺序
D(3):这个值偏小,忽略了最后的加减运算过程知识点:C++、编程基础、机械、测试、后端开发、客户端开发、人工智能/算法、通信、芯片/半导体、硬件开发
题友讨论(14)
单选题
C++
C语言
21.
下面函数的时间复杂度是
1
2
3
4
long
foo(
long
x){
if
(x < 2)
return
1;
return
x * x * foo(x - 1);
}
A
O(N)
B
O(N^2)
C
O(N^3)
D
o(N!)
正确答案:A
官方解析:
这道题目考察了递归函数的时间复杂度分析。
函数 foo(x) 的时间复杂度是 O(N),原因如下:
1. 每次递归调用时,函数执行了以下操作:
- 一次比较操作 (x<2)
- 一次乘法运算 x*x
- 一次递归调用 foo(x-1)
2. 虽然函数中有 x*x 的平方运算,但这只是单次递归中的常数操作,不影响整体复杂度。
3. 递归的次数取决于输入值 x,从 x 开始每次减1,直到达到基本情况(x<2),因此递归深度是线性的,即 O(N)。
分析其他选项:
B选项 O(N^2) 错误:可能是因为看到了 x*x 的运算就认为是平方复杂度,但这是对时间复杂度分析的误解。
C选项 O(N^3) 错误:这个复杂度过高,函数并没有嵌套循环或者会导致立方增长的操作。
D选项 O(N!) 错误:阶乘复杂度通常出现在需要列举所有排列组合的算法中,这个递归函数的操作次数是线性增长的,不是阶乘增长。
需要注意的是,这里分析的是时间复杂度,即算法执行所需的操作次数的增长率,而不是考虑具体的返回值大小。虽然返回值可能会非常大,但这不影响时间复杂度的分析。知识点:C++、C语言
题友讨论(37)
单选题
C++
C语言
22.
对于以下结构定义,(*p)->str++中的++加在()
1
struct
{
int
len;
char
*str; } *p;
A
指针 str 上
B
指针 p 上
C
str 指向的内容上
D
语法错误
正确答案:D
你的答案:A
官方解析:
这道题考察C语言中指针运算和自增运算符的使用规则。D选项是正确的,因为这个表达式确实存在语法错误。
主要原因如下:
1. (*p)->str 得到的是一个指针值(字符指针)
2. 对指针使用++运算符时,会使指针指向下一个元素位置
3. 但在这种情况下,str是一个指针成员,直接对其使用++是没有实际意义的,因为不知道它指向的字符数组大小
其他选项分析:
A错误:str本身是指针没错,但++并不是作用在指针str上,而是试图作用在指向的内容上
B错误:++操作与指针p无关,它试图作用在str成员上
C错误:由于语法本身就存在问题,所以不能说++是作用在str指向的内容上
正确的用法应该是:
- 如果要移动str指向的位置:(*p)->str = (*p)->str + 1
- 如果要修改str指向的字符:(*(*p)->str)++
这个表达式的问题在于运算符使用不当,造成了语义模糊,因此是语法错误。知识点:C++、C语言
题友讨论(29)
单选题
C++
C语言
23.
以下有关C语言的说法中,错误的是________。
A
内存泄露一般是指程序申请了一块内存,使用完后,没有及时将这块内存释放,从而导致程序占用大量内存。
B
可以通过malloc(size_t)函数调用申请超过该机器物理内存大小的内存块。
C
无法通过内存释放函数free(void*)直接将某块已经使用完的物理内存直接还给操作系统。
D
可以通过内存分配函数malloc(size_t)直接申请物理内存。
正确答案:D
官方解析:
malloc()函数实际上是向操作系统申请虚拟内存,而不是直接申请物理内存。操作系统采用虚拟内存管理机制,程序中的内存地址是虚拟地址,需要通过页表映射才能转换为实际的物理地址。因此D选项说可以通过malloc()直接申请物理内存是错误的。
分析其他选项:
A正确:内存泄漏的定义准确。当程序申请内存后没有及时释放,就会造成内存资源的浪费,这种现象称为内存泄漏。
B正确:malloc()函数可以申请超过物理内存大小的内存空间,因为它申请的是虚拟内存。操作系统会根据实际使用情况进行内存分页和交换。
C正确:free()函数只是将内存归还给程序的堆空间,由操作系统统一管理,而不能直接释放物理内存。物理内存的分配和回收完全由操作系统控制。
这道题目考察了操作系统内存管理的基本概念,重点是理解虚拟内存和物理内存的区别,以及malloc()、free()等内存操作函数的实际工作原理。知识点:C++、C语言
题友讨论(50)
多选题
C++
24.
关于 C++ 中的 this 指针,下面说法正确的是()
A
每个非静态成员函数都隐含一个 this 指针
B
this 指针在成员函数中始终指向当前作用对象
C
在非静态成员函数中直接访问成员 m,相当于 this->m
D
非静态成员函数中访问成员,必须使用 this
正确答案:ABC
官方解析:暂无官方题目解析,去讨论区看看吧!
知识点:C++
题友讨论(0)
多选题
C++
C语言
25.
以下涉及到内存管理的代码段中,有错误的是()
A
int *a=new int(12); //..... free(a);B
int *ip=static_cast<int*>(malloc(sizeof(int))); *ip=10; //..... delete ip;C
double *a=new double[1]; //.... delete a;D
int *ip=new int(12); for(int i=0;i<12;++i){ ip[i]=i; } delete []ip;正确答案:ABD
你的答案:ABCD
参考答案: new和delete搭配,malloc和free搭配,所以A、B是错的。 关于D,注意new int(12)和new int[12]的区别。new int(12)是生成了一个值为12的int变量,new int[12]才是生成一个大小为12的数组。所以,delete []ip是错误的,D错。 再看C,乍一眼看过去,a是一个数组,应该用delete []a,但是在基本类型数组来说,delete a和delete []a的效果是一样的。如果,a是一个自定义对象的数组,那么只能用delete []a。 关于delete a和delete []a的区别,请参照 http://jazka.blog.51cto.com/809003/230220
知识点:C++、C语言
题友讨论(66)
多选题
C++
26.
在C++里,同一个模板的声明和定义是不能在不同文件中分别放置的,否则会报编译错误。为了解决这个问题,可以采取以下办法有()
A
模板的声明和定义都放在一个.h文件中。
B
模板的声明和定义可以分别放在.h和.cpp文件中,在使用的地方,引用定义該模板的cpp文件。
C
使用export使模板的声明实现分离。
D
以上说法都不对
正确答案:ABC
官方解析:
C++模板是一种强大的泛型编程机制,但它的声明和定义有其特殊规则。让我们分析每个选项:
A选项正确。将模板的声明和定义都放在同一个头文件(.h)中是最常用也是最推荐的做法。这样可以确保编译器在需要实例化模板时能够看到完整的模板定义。
B选项正确。虽然不太常见,但确实可以将模板的声明和定义分别放在.h和.cpp文件中,然后在使用模板的地方包含cpp文件。但这种方式会增加代码的耦合性,不推荐使用。
C选项正确。export关键字是C++标准中专门为解决模板声明和定义分离问题而设计的。通过export关键字,可以将模板的声明和实现分别放在不同的文件中。不过需要注意的是,很多编译器并不支持export关键字,使用时要谨慎。
这三种方法都是解决模板声明和定义分离问题的有效方案,各有其适用场景:
- 方案A最简单直接,是最推荐的做法
- 方案B可以用于特殊情况,但要注意维护成本
- 方案C是标准提供的解决方案,但受限于编译器支持情况
因此ABC都是正确答案。知识点:C++、C++工程师、2019
题友讨论(11)
多选题
C++
27.
观察下面一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class
ClassA
{
public
:
virtual ~ ClassA() {};
virtual
void
FunctionA() {};
};
class
ClassB
{
public
:
virtual
void
FunctionB() {};
};
class
ClassC :
public
ClassA,
public
ClassB
{
public
:
};
ClassC aObject;
ClassA* pA=&aObject;
ClassB* pB=&aObject;
ClassC* pC=&aObject;
关于pA,pB,pC的取值,下面的描述中正确的是:
A
pA,pB,pC的取值相同
B
pC=pA+pB
C
pA和pB不相同
D
pC不等于pA也不等于pB
E
pC和pA相同
正确答案:CE
官方解析:
在C++多重继承中,这个问题涉及到对象指针类型转换和内存布局的理解。
C选项正确:pA和pB确实不相同。这是因为在多重继承中,派生类ClassC会包含两个基类ClassA和ClassB的完整子对象。pA指向ClassC对象中的ClassA部分的起始地址,而pB指向ClassB部分的起始地址,它们在内存中的位置不同。
E选项正确:pC和pA相同。这是因为在标准的C++实现中,派生类对象的地址通常与其第一个基类子对象的地址相同。ClassA是ClassC的第一个基类,所以pC指向的地址与pA相同。
分析其他选项的错误原因:
A错误:pA、pB、pC的取值不可能都相同,因为至少pB与其他两个指针指向的地址不同。
B错误:pC=pA+pB这种说法在指针运算中没有实际意义,且完全不符合面向对象的内存模型。
D错误:因为pC确实等于pA(第一个基类的地址),所以说pC既不等于pA也不等于pB是错误的。
这种内存布局设计是C++多重继承实现虚函数和运行时多态的基础。知识点:C++、iOS工程师、2019
题友讨论(16)
多选题
C++
28.
下面 C++ 代码不能通过编译的有()
A
int x = 5;
const int& ref = x;
x = 10;B
int* ptr = nullptr;
int& ref = ptr;C
const int x = 5;
int& ref = x;D
const int x = 5;
x = 10;正确答案:BCD
官方解析:
让我们逐个分析每个选项的正确性:
A选项(不是错误答案):
int x = 5;
const int& ref = x;
x = 10;
这段代码是合法的。const引用可以绑定到非const变量,而且原变量x仍然可以通过其本身来修改。ref虽然是const的,但这只是保证通过ref不能修改x的值。
B选项(错误答案):
int* ptr = nullptr;
int& ref = ptr;
这段代码无法通过编译。引用不能指向指针,类型不匹配。int&类型的引用只能绑定到int类型的变量。
C选项(错误答案):
const int x = 5;
int& ref = x;
这段代码无法通过编译。非const引用不能绑定到const对象,因为这样可能会通过引用修改const对象的值,违反了const的语义。
D选项(错误答案):
const int x = 5;
x = 10;
这段代码无法通过编译。const变量声明后其值就不能被修改,这是const关键字的基本语义。
总结来说:
- B无法编译是因为类型不匹配问题
- C无法编译是因为试图用非const引用绑定const对象
- D无法编译是因为试图修改const对象的值
- 而A是完全合法的代码知识点:C++
题友讨论(1)
多选题
C++
29.
下面哪些特性可能导致代码体积膨胀()
A
宏定义
B
模板
C
内联函数
D
递归
正确答案:ABC
官方解析:
A选项 宏定义本质是文本替换;
B选项 模板在编译时生成对应的类或函数;
C选项 内联在编译时会替换;
因此A、B、C选项都可能导致代码体积膨胀;
而D选项只可能导致栈溢出,因此答案选A,B,C
知识点:C++
题友讨论(28)
多选题
C++
30.
以下哪些不是解释型语言
A
C/C++
B
Java
C
Go
D
Javascript
正确答案:ABC
你的答案:AC
官方解析:
- C/C++: 典型编译型语言,源代码经编译链接生成本机可执行文件,非解释型。
- Java: 先编译为字节码(.class),由 JVM 执行,主流通过解释+JIT,即“编译型到字节码 + 运行期执行”,一般不归类为解释型。
- Go: 直接编译生成本机二进制,典型编译型语言。
- JavaScript: 由引擎解释/即时编译执行,通常归为解释型语言。
因此不是解释型语言的是 A、B、C。