《C/C++工程师综合练习卷》之小试牛刀

第一套练习之感受

刚刚注册了牛客网的账号,准备在此衡量一下水平,好好磨练一番。看到推荐练习《C/C++工程师综合练习卷》,oh,20道题,2个小时。由于木有经验,好一番紧张~
结果用了20分钟,点完了20道选择题,真的是太草率了,都没有返回检查一下,手一抖就交了卷!!!
成绩可想而知,只做对了一半的题目,真的是要哭了。。。返回头思考一下,感觉题目考察的都是基础的牢固程度,还是基础知识不扎实!
毕竟是第一次,不可以气馁,未来一年时间内,必须稳扎稳打,定期测验自己,一点一滴的积累与进步!

错题分析与总结

1. 补充下面函数代码:

如果两段内存重叠,用memcpy函数可能会导致行为未定义。 而memmove函数能够避免这种问题,下面是一种实现方式,请补充代码。

#include <iostream>
using namespace std;
void* memmove(void* str1,const void* str2,size_t n)
{
    char* pStr1= (char*) str1;
    const char* pStr2=(const char*)str2;
    if  ( ) {
        for(size_t i=0;i!=n;++i){
            *(pStr1++)=*(pStr2++);
        }
    }
    else{
        pStr1+=n-1;
        pStr2+=n-1;
        for(size_t i=0;i!=n;++i){
            *(pStr1--)=*(pStr2--);
        }
    }
    return ( );
}

A. pStr1 < Pstr2 str1

B. pStr1+n < pStr2 str2

C. pStr1+n < pStr2 || pStr2+n < pStr1 str2

D. pStr2+n < pStr1 str1

分析:这是一道内存拷贝相关习题,显然,str2为源地址,str1为目标地址,分为两种情况拷贝:

i. 如果pStr1 < pStr2时,从前向后拷贝

ii. 如果pStr1 > pStr2时,若同样从前向后拷贝,那么可能会导致pStr1的初始值填充内容会被pStr2后部分的内容覆盖,所以此时应该采用从最后一个元素依次向前拷贝的方式。

答案:A

总结:看到这个题目,根本没有深入思考,不知道想什么呢,选了错误答案C。

3. 下面有关C++中为什么用模板类的原因,描述错误的是?

A. 可用来创建动态增长和减小的数据结构

B. 它是类型无关的,因此具有很高的可复用性

C. 它运行时检查数据类型,保证了类型安全

D. 它是平台无关的,可移植性

分析:模板类在编译时检查数据类型,保证了类型安全。
答案:C
4. 在下面函数执行后,func(1)=?

int func(int a)
{
    int b;
    switch (a)
    {
        case 1: b = 30;
        case 2: b = 20;
        case 3: b = 16;
        default: b = 0;
    }
    return b;
}

A. 30

B. 20

C. 16

D. 0

分析:这一题考察C语言基础,switch与case结合,正确的表达方式为,case n:语句;break;而题目中缺少了break,则导致判断没有作用,程序会一直执行到最后一条,返回0。
答案:D

总结:这一题选了A,还在想怎么会有这么简单的题目,唉,跳进了坑里!只能怪自己,基础不牢靠,做题不仔细!

5. 在32位机器上用gcc编译下面代码,求sizeof(A) sizeof(B) 分别为多少?

class A
{
        int a;
        short b;
        int c;
        char d;
};
class B
{
        double a;
        short b;
        int c;
        char d;
};

A. 12 16

B. 12 12

C. 16 24

D. 16 20

分析:遵循下面三个条件(1)结构体的大小等于结构体内最大成员大小的整数倍;(2)结构体内的成员的首地址相对于结构体首地址的偏移量是其类型大小的整数倍,比如double型成员相对于结构体的首地址的地址偏移量应该是8的整数倍;(3)为了满足规则1和2,编译器会在结构体成员之后进行字节填充;
题目中,结构体A中a占4B,b占2B,但是由于C占4B,为了满足条件2,b多占用2B,为了满足条件1,d占用4B,所以最终占用16B;
结构体B,a占8B,b占2B,但是由于c占用4B,则b将多占用2B,则abc总占用8+4+4=16B,为了满足条件1,d占用8B,所以最终占用24B。

答案:C

总结:错选了A,确实了解,存储对齐以及字节填充这回事,但是掌握的不够详细,不够牢固!

7. 下面有关C++线程安全,说法错误的是?

A. 线程安全都是由全局变量及静态变量引起的。

B. 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全

C. C++标准库里面的string是保证线程安全的

D. POSIX线程标准要求C标准库中的大多数函数具备线程安全性

分析:关于线程安全问题的理解,参考 http://blog.csdn.net/ghevinn/article/details/37764791 的讲解,而对于C++标准库中的string,查了些许资料,也没有明确的说法,既然此处它是错误的,就说明不可以说string是线程安全的。

答案:C

总结:错选A,对线程安全问题不了解。

8.以下程序的输出是?

class Base {
    public:
    Base(int j): i(j)  {}
    virtual~Base() {}
    void func1() {
        i *= 10;
        func2();
    }
    int getValue() {
        return  i;
    }
    protected:
    virtual void func2() {
        i++;
    }
    protected:
    int i;
};
class Child: public Base {
    public:
    Child(int j): Base(j) {}
    void func1() {
        i *= 100;
        func2();
    }
    protected:
    void func2() {
        i += 2;
    }
};
int main() {
    Base * pb = new Child(1);
    pb->func1();
    cout << pb->getValue() << endl; delete pb; }

A.11

B. 101

C.12

D.102

分析:考察基类与派生类函数调用问题,要看是基类对象还是派生类对象,另外还要看基类哪些函数是虚拟的,会被派生类覆盖,题目中pb是派生类对象,调用Child构造函数->Base构造函数,初始化为1,当调用函数func1()时,调用的是基类的函数,func1()不是虚函数,所以pb->func1()执行的是基类的func1函数,i= 10,然后调用func2()函数;这里的func2是虚函数,要往下派生类寻找,找到后执行派生类中的func2(),此时,i = 12;最后执行pb->getValue(),结果为12。

答案:C

总结:错选A,对继承的知识含糊不清。

9.下面对静态数据成员的描述中,正确的是?

A. 静态数据成员可以在类内进行初始化

B. 静态数据成员不可以被类的对象调用

C. 静态数据成员不受private控制符的作用

D. 静态数据成员可以直接用类名调用

分析:该题目考察类内静态数据成员,它类外初始化,通常在定义时进行初始化,但是当类型为const static时的整形时可以在类体内进行初始化。它同普通数据成员一样受到控制符的作用,可以使用类名直接调用或者使用对象调用。

答案:D

总结:这个题目错的离谱,貌似是看错选项,反正就是马虎!错选了C,呜呜呜。。。。

14. C++类体系中不能被派生类继承的是?

A. 构造函数

B. 静态成员函数

C. 非静态成员函数

D. 赋值操作函数

分析:构造函数是不能被继承的,但是可以被调用,如果父类重新定义了构造函数,也就是没有了默认的构造函数,子类创建自己的构造函数的时候必须显式的调用父类的构造函数。而其余的三个在我们平常的使用中都可以被继承使用。

答案:A

总结:错选了D,错以为派生类调用基类的构造函数,可以说继承,纠正这个错误!

18. 在32位的小端机器上,如下代码输出是什么?

 char array[12] = {0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 , 0x08};     
 short *pshort = (short *)array;     
 int *pint = (int *)array;     
 int64 *pint64 = (int64 *)array;     
 printf("0x%x , 0x%x , 0x%x , 0x%x", *pshort , *(pshort+2) , *pint64 , *(pint+2));

A. 0x201 , 0x403 , 0x807060504030201 , 0x0
B. 0x201 , 0x605 , 0x807060504030201 , 0x0
C. 0x201 , 0x605 , 0x4030201 , 0x8070605
D. 0x102 , 0x506 , 0x102030405060708 , 0x0

分析:
小端机器的数据高位字节放在高地址,低位字节放在低地址。x86结构为小端模式。
pshort占用2个字节,在内存中的16进制为0x01 0x02,对应的16进制数为0x0201。
pshort + 2指向array数组的下标为4的元素,占用2个字节,在内存中的16进制为0x05 0x06,对应的16进制数为0x0605。
pint64的int64类型不确定,但根据名字可以看出占用8个字节,对应的16进制形式为0x807060504030201。
pint + 2占用4个字节,指向的array数组的下标为8的元素,8-11个元素没有指定数组的初始化值,默认为0,因此*(pint + 2)对应的16进制为0。

答案:B

总结:错选C,蒙的。。。

总结

第一次做笔试题目就错了这么一堆堆,虽然很受挫,但是也激起了奋起直追的勇气,加油!

原文地址:https://www.cnblogs.com/shine-yr/p/5214951.html