题目摘录-编程语言(C++)(一)

Question 1 :

题目:
    以下代码:
    class ClassA{
    public:
        virtual ~ClassA(){};
        virtual void FunctionA(){};
    };
    class ClassB{
    public:
        virtual void FunctionB(){};
    };
    class ClassC:public ClassA, public ClassB{
        public:
    };
    ClassC Object;
    ClassA* pA = &Object;
    ClassB* pB = &Object;
    ClassC* pC = &Object;
    关于pA,pB,pC的取值,下面的描述中正确的是:

答案:
    pA和pB不相同

解答:
    考察多继承且有虚函数情况下C++存储对象模型。
    1. 多继承按继承顺序组织对象模型,有虚函数时低地址包含指向虚函数表的指针。
    2. 对象Object的存储模型:类A虚函数表指针(ptrA) | 类A数据 | 类B虚函数表指针(ptrB) | 类B数据 | 类C数据。
    3. 子类的虚函数被放到了第一个基类的虚函数表最后(ptrA指向的虚函数表结构:类A虚函数 | 类C虚函数)。
    4. 有虚函数的继承,对象地址为指向虚函数表的指针的地址,即pC = &Object = &ptrA。
    6. pC = pA = &ptrA = &Object,(pC = pA) < pB。

Question 2 :

题目:
    下列程序的输出结果:
    #include <iostream>
    using namespace std;
    class A{
    public:
        void print(){
            cout << "A:print()";
        }
    };
    class B:private A{
    public:
        void print(){
          cout << "B:print()";
        }
    };
    class C:public B{
    public:
       void print(){
            A::print();
        }
    };
    int main(){
        C b;
        b.print();
    }

答案:
    编译出错

解答:
    考察C++继承问题。
    1. 类B私有继承类A。
    2. 私有继承:类A的公有成员和保护成员都作为类B的私有成员,并且不能被类B的子类(如类C)所访问。

Question 3 :

题目:
    下面两个结构体:
    struct One{
        double d;
        char c;
        int i;
    }
    struct Two{
        char c;
        double d;
        int i;
    }
    在#pragma pack(4)和#pragma pack(8)的情况下,结构体的大小分别是:

答案:
    16,16
    16,24

解答:
    考察结构体对齐。
    1. 4字节对齐:Struct One[8 + (1 + 3(pading)) + 4], struct Two[(1 + 3(pading)) + 8 + 4]。
    2. 8字节对齐:Struct One[8 + (1 + 3(pading) + 4)], struct Two[(1 + 7(pading)) + 8 + (4 + 4(pading))]。
    3. 一句话总结:按序存储,装得下尽量装,装不下换一行。

Question 4 :

题目:
    下列代码的输出为:
    #include "iostream"
    #include "vector"
    using namespace std;
    int main(void)
    {
        vector<int>array;
        array.push_back(100);
        array.push_back(300);
        array.push_back(300);
        array.push_back(500);
        vector<int>::iterator itor;
        for(itor = array.begin(); itor != array.end(); itor++){
            if(*itor == 300){
                itor = array.erase(itor);
            }
        }
        for(itor = array.begin(); itor != array.end(); itor++){
            cout << *itor << " ";
        }
        return 0;
    }

答案:
    100
    300
    500

解答:
    考察STL中erase和迭代器问题。
    1. erase返回值是一个迭代器,指向删除元素下一个元素。
    2. 删除第一个300时返回指向下一个300的迭代器,在循环体又被再加了一次,跳过了第二个300。

Question 5 :

题目:
    下面程序的输出是什么?
    int main(void)
    {
        int a[5] = {1, 2, 3, 4, 5};
        int *ptr = (int *)(&a + 1);
        printf("%d,%d", *(a + 1), *(ptr - 1));
        return 0;
    }

答案:
    2
    5

解答:
    1. a表示数组首元素的地址,对a的所有操作均是以一个元素为单位的。
    2. &a表示整个数组的地址,对&a的所有操作均是以一个数组为单位的。
    3. ptr类型为int *,所有对ptr的所有操作均是以int大小为单位进行的。
    4. (int *)(&a + 1)表示指向a数组最后一个元素后一个字节的int类型指针,*(ptr - 1)表示向前移动一个int类型的数据的位置。
    5. 所有指针类型操作先看右侧是以什么为单位,之后再转换为左侧定义的单位。

Question 6 :

题目:
    32位机上根据下面的代码,问哪些说法是正确的?
    signed char a = 0xe0;
    unsigned int b = a;
    unsigned char c = a;

答案:
    b的十六进制表示是:0xffffffe0

解答:
    考察有符号数和无符号数之间的转换。
    1. a : 1110 0000。
    2. 扩展问题:
        长 -> 短:低位对齐,按位复制。
        短 -> 长:符号位扩展。
    3. 精度提升:
        两个变量运算,表示范围小的变量精度达的变量提升(signed -> unsigned)。

Question 7 :

题目:
    下列代码的输出为:
    int* pint = 0;
    pint += 6;
    cout << pint << endl;

答案:
    24

解答:
    考察指针运算。
    1. 变量pint为指向int类型的指针,这里“+1”表示地址加4(pint值加4)。
    2. 变量pint初值为0,pint + 6后pint的值变为24。

Question 8 :

题目:
    如果两段内存重叠,用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 ( );
    }

答案:
    pStr1 < pStr2
    str1

解答:
    1. 逐字符自动不存在内存覆盖问题。

Question 9 :

题目:
    设x、y、t均为int型变量,则执行语句:t = 3; x = y = 2; t = x++ || ++y; 后,变量t和y的值分别为:

答案:
    t = 1
    y = 2

解答:
    考察逻辑短路和运算符优先级。
    1*. =的优先级最低,t = (x++ || ++y) = 1。
    2. x++和++y为或关系,因为x++的值非0,所以++y不执行,y不变。

Question 10 :

题目:
    指出下面程序哪里可能有问题?
    class CBuffer
    {
        char * m_pBuffer;
        int m_size;
    public:
        CBuffer(){
            m_pBuffer = NULL;
        }
        ~CBuffer(){
            Free();
        }
        void Allocte(int size) (1) {
            m_size = size;
            m_pBuffer = new char[size];
        }
    private:
        void Free(){
            if(m_pBuffer! = NULL) (2){
                delete[] m_pBuffer;
                m_pBuffer = NULL;
            }
        }
    public:
        void SaveString(const char* pText) const (3){
            strcpy(m_pBuffer, pText); (4)
        }
        char* GetBuffer() const{
            return m_pBuffer;
        }
    };
    void main (int argc, char* argv[])
    {
        CBuffer buffer1;
        buffer1.SaveString("Microsoft");
        printf(buffer1.GetBuffer());
    }

答案:
    1
    3
    4

解答:
    考察动态分配空间等周边细节处理。
    1. 分配内存时, 未检测m_pBuffer是否为空, 容易造成内存泄露。
    2. 常成员函数不应该对数据成员做出修改, 虽然可以修改指针数据成员指向的数据, 但原则上不应该这么做。
    3*. 字符串拷贝时, 未检测是否有足够空间, 可能造成程序崩溃。
03-18 14:22