C++笔试易错题集(持续更新)

1.如下代码输出结果是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
char *myString()
{
    char buffer[6] = {0};
    char *s = "Hello World!";
    for (int i = 0; i < sizeof(buffer) - 1; i++)
    {
        buffer[i] = *(s + i);
    }
    return buffer;
}
int main(int argc, char **argv)
{
    printf("%s\n", myString());
    return 0;
}
  • Hello
  • Hello World!
  • Well
  • 以上全部不正确

解析:

答案:D

函数char *myString()中没有使用new或者malloc分配内存,所有buffer数组的内存区域在栈区

随着char *myString()的结束,栈区内存释放,字符数组也就不存在了,所以会产生野指针,输出结果未知 

 


 

2.

1
2
3
4
5
6
7
enum string{    
    x1,    
    x2,    
    x3=10,    
    x4,    
    x5,    
} x;
问x等于什么?(0)
在c语言中,这样写法一般是全局变量,程序初始化时会清零.

3.
设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为?
1
2
3
4
5
6
7
8
C c;
void main()
{
    A*pa=new A();
    B b;
    static D d;
    delete pa;
}
 
A B C D
A B D C(正确)
A C D B
A C B D
解析:
这道题主要考察的知识点是 :全局变量,静态局部变量,局部变量空间的堆分配和栈分配
其中全局变量和静态局部变量时从 静态存储区中划分的空间,
二者的区别在于作用域的不同,全局变量作用域大于静态局部变量(只用于声明它的函数中),
而之所以是先释放 D 在释放 C的原因是, 程序中首先调用的是 C的构造函数,然后调用的是 D 的构造函数,析构函数的调用与构造函数的调用顺序刚好相反。
局部变量A 是通过 new 从系统的堆空间中分配的,程序运行结束之后,系统是不会自动回收分配给它的空间的,需要程序员手动调用 delete 来释放。
局部变量 B 对象的空间来自于系统的栈空间,在该方法执行结束就会由系统自动通过调用析构方法将其空间释放。
之所以是 先 A  后 B 是因为,B 是在函数执行到 结尾 "}" 的时候才调用析构函数, 而语句 delete a ; 位于函数结尾 "}" 之前。

4.若char是一字节,int是4字节,指针类型是4字节,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
class CTest
{
    public:
        CTest():m_chData(‘\0’),m_nData(0)
        {
        }
        virtual void mem_fun(){}
    private:
        char m_chData;
        int m_nData;
        static char s_chData;
};
char CTest::s_chData=’\0’;
问:
(1)若按4字节对齐sizeof(CTest)的值是多少(12)?
(2)若按1字节对齐sizeof(CTest)的值是多少(9)?
请选择正确的答案。
解析:
答案分别是:12 和 9,对应C
考察点:c++ 类的内存布局。
上精华图:一张图说明类中成员变量,成员函数,静态变量与函数的空间位置。
 
 
理论如上,下面就是代码运行后真是执行结果。无pp无真相。这是4字节对齐,结果是12= 4(虚表指针)+1(char )+3(对齐补位)+4(int)
 
 
 
 
以下是1字节对齐,结果是9 =4(虚表指针)+1(char )+4(int):
 

 
5.
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
#include<iostream>
using namespace std;
class MyClass
{
public:
    MyClass(int i = 0)
    {
        cout << i;
    }
    MyClass(const MyClass &x)
    {
        cout << 2;
    }
    MyClass &operator=(const MyClass &x)
    {
        cout << 3;
        return *this;
    }
    ~MyClass()
    {
        cout << 4;
    }
};
int main()
{
    MyClass obj1(1), obj2(2);
    MyClass obj3 = obj1;
    return 0;
}
运行时的输出结果是()
  • 11214444
  • 11314444
  • 122444(正确)
  • 123444
解析:首先程序中存在三个MyClass对象。
前两个对象构造时分别输出1,2
第三个对象是这样构造的MyClass obj3 = obj1;这里会调用拷贝构造函数,输出2
然后三个对象依次析构,输出444
所以最终输出122444  MyClass obj3 = obj1;这里调用拷贝构造函数,如果是在这之前obj3,obj1都已声明,则此时调用的是coby assignment操作符

 


6. 当参数*x==1, *y==1, *z==1时,下列不可能是函数add的返回值的( )?
1
2
3
4
5
6
int add(int *x, int *y, int *z){
    *x += *x;
    *y += *x;
    *z += *y;
    return *z;
 }
  • 4
  • 5
  • 6
  • 7
 解析:
D
开始不知道啥意思,后经牛客网的大神指点才知道这题要考虑的是,x,y,z三个参数是否指向同一地址(或者说调用该函数时是否实参相同),如:当a=b=c=1时,add(&a,&a,&a),add(&a,&b,&c)。
通过写程序测试得出结果,不可能得到答案7。
有以下5种情况
 

7. SQL语言集数据查询、数据操纵、数据定义和数据控制功能于一体,语句INSERT、DELETE、UPDATE实现( )功能。
  • 数据查询
  • 数据控制
  • 数据定义
  • 数据操纵
 D
解析:
DDL:数据库模式定义语言,关键字:create
DML:数据操纵语言,关键字:Insert、delete、update
DCL:数据库控制语言 ,关键字:grant、remove
DQL:数据库查询语言,关键字:select

 8. 观察下面一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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的取值,下面的描述中正确的是:
  • pA,pB,pC的取值相同.
  • pC=pA+pB
  • pA和pB不相同
  • pC不等于pA也不等于pB
 解析:
如果我们输出三个指针的值。
上面的代码在我的电脑上输出
0x7fff502f5aa80x7fff502f5ab00x7fff502f5aa8
 
可以看到pA和pC是相同的。
所以选择C。
 
实际上,在这个情况下,子类的指针和第一个基类的指针应该是一样的,和第二个基类是不一样的。
 
9. 连续整数之和为1000的共有几组?(m,n都为正整数)
  • 3
  • 4
  • 5
  • 8
答案:B
设从n加到m和为1000,则(n+m)(m-n+1)/2=1000,即(n+m)(m-n+1)=2000,即把2000分解成两个数的乘积,且这两个数为一奇一偶。2000=(2^4)*(5^3),于是奇数可能为5^0,5^1,5^2,5^3,即有四组解

10.
一个有序数列,序列中的每一个值都能够被2或者3或者5所整除,这个序列的初始值从1开始,但是1并不在这个数列中。求第1500个值是多少?
  • 2040
  • 2042
  • 2045
  • 2050
答案:C
2、3、5的最小公倍数是30。[ 1, 30]内符合条件的数有22个。如果能看出[ 31, 60]内也有22个符合条件的数,那问题就容易解决了。也就是说,这些数具有周期性,且周期为30.
第1500个数是:1500/22=68   1500%68=4。也就是说:第1500个数相当于经过了68个周期,然后再取下一个周期内的第4个数。一个周期内的前4个数:2,3,4,5。
故,结果为68*30=2040+5=2045

11.一个完全二叉树有770个节点,那么其叶子的个数为 :_____
解析:对于一个完全二叉树 如果总结点数为偶数,则度为1的结点数为1,如果总结点数为奇数且大于1,则度为1的结点数为0;本题总结点数我770为偶数,所以度为1的结点数n1 = 1;度为0的结点数与度为2的结点数:n0 = n2 + 1;所以总结点数:n0+n1+n2 = 2n0 - 1 + 1 = 770,所以n0 = 385,即叶子结点的个数

12.计算三个稠密矩阵 A、B、C 的乘积 ABC,假定三个矩阵的尺寸分别为 m*n, n*p,p*q,且 m<n<p<q,以下计算效率最高的是
    • (AB)C
    • A(BC)
    • (AC)B
    • (BC)A
    • (CA)B
 
解析:a*b,b*c两矩阵相乘效率为a*c*b ABC=(AB)C=A(BC).(AB)C = m*n*p + m*p*q,A(BC)=n*p*q + m*n*q.m*n*p<m*n*q,m*p*q<n*p*q,所以(AB)C最小

13.通过算法生成的随机数是“伪随机”的,也就是说,在设定好第一个数之后,后面的数字的序列是确定的,并且经过一个非常大的循环会回到第一个数的状态,然后周而复始。显然,摇号、抽奖的程序是不能通过伪随机数来实现的。现实中常常基于某种热噪声来实现真正的随机数。假定某热噪声是标准正态分布,那么能否将它转换成(0,1)区间上的均匀分布______?
  • 忽略测量和计算误差,可以转换为(0,1)区间上的均匀分布
  • 无法转换为(0,1)区间上的均匀分布
  • 信息不足,无法判断
  • 借助伪随机数生成算法可以转换为(0,1)区间上的均匀分布
  • 仅仅靠伪随机数生成算法,就可以生成(0,1)区间上的均匀分布
  • 以上说法都不对
 解析:http://www.zhihu.com/question/25111423

14.二分查找树里查询一个关键字的最坏时间复杂度是______
  • O(n)
  • O(n log n)
  • O(n^2)
  • O(n^3)
  • O(logn)
  • 不确定
解析:最坏的情况就是这个二分查找树的所有节点只有左子树或者只有右子树,就相当于一个线性链表,所以是O(n)

15.下列 C 代码中,不属于未定义行为的有:______。
  • int i=0;i=(i++);
  • char *p=”hello”;p[1]=’E’
  • char *p=”hello”;char ch=*p++
  • int i=0;printf(“%d%d\n”,i++ i--)
  • 都是未定义行为
  • 都不是未定义行为
解析:C

16.C++内存分配中说法错误的是:______。
  • 对于栈来讲,生长方向是向上的,也就是向着内存地址增加的方向
  • 对于堆,大量的 new/delete 操作会造成内存空间的不连续
  • 堆容易产生 memory leak D,堆的效率比栈要低的多
  • 堆的效率比栈要低得多
  • 栈变量引用容易逃逸
  • 以上都对
解析:堆的生长方向向上,栈的生长方向向下17.在小端序的机器中,如果 
1
2
3
4
union X{
    int x;
    char y[4];
};
如果:
X a;
a.x=0x11223344;//16 进制 则:______
    • a.y[0]=11
    • a.y[1]=11
    • a.y[2]=11
    • a.y[3]=11
    • a.y[0]=22
    • a.y[3]=22
解析:小端是数据低字节存储在内存低位,所以y[0]=0x44,y[3] = 0x1118.下面的排序算法中,初始数据集的排列顺序对算法的性能无影响的是
  • 插入排序
  • 堆排序
  • 冒泡排序
  • 快速排序
解析:
B,堆排序
有影响就是这个排序算法最好情况和最差情况的时间复杂度不同。对于无影响,我们只要找最好情况和最差情况时间复杂度一样的算法就可以了,
根据各种排序算法的流程,对于插入排序,如果几乎有序的话,每个节点的初始位置就最终位置,所以几乎不需要移动节点。
对于冒泡排序,如果节点几乎有序的话,对于一次遍历设置标记为,如果不交换元素的话即结束排序过程。
对于快速排序,如果以初始序列是逆序的话,时间复杂度变为n^2.
综上,时间堆排序的最差和最优时间复杂度都为nlogn,所以堆排序是最优的,还有归并排序对元素的初始位置也不敏感,都是nlogn。

19.下列的进程状态变化中,哪些是不可能发生的?
  • 运行→就绪
  • 运行→等待
  • 等待→运行
  • 等待→就绪
解析:选C ,就绪状态是可以和运行状态相互转换的,超时的时候就会从运行状态转为就绪状态。但是一旦是等待状态(阻塞)就必须选转为就绪才能够运行。

20.使用 char* p = new char[100]申请一段内存,然后使用delete p释放,有什么问题?
  • 会有内存泄露
  • 不会有内存泄露,但不建议用
  • 编译就会报错,必须使用delete []p;
  • 编译没问题,运行会直接崩溃
解析:the answer is B ,  if the type is int,char,float, both delete[]p and delete p are ok,but if the type is class object, the answer will be A
 

 21.x为整型,请用位运算实现x%8解析:
当我们求余的时候,相当于除以2的N次冥,也就是相当于把数本身右移N位,但是右移掉的那些位需要通过位运算进行保留;用以上例子来说,X%8即X%2^3,那么就需要右移三次,那么移去的三位需要保留下来,而8=1000,刚好,可以使用0111来保留下来后三位,于是,对于除数都是2的整数次幂的情况,可以使用x & (2^n-1)的方法进行与运算,保留下来的最末尾的n位就是余数。
该题中,结果为x&7.

 

转载于:https://www.cnblogs.com/90zeng/p/cpp_interview.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值