2013搜狗校园招聘笔试题

时间:2021-03-10 18:53:16


第一题:以下程序的输出是___________________

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;

 return 0;
}

 

此题输出:12.(在非虚函数中调用虚函数,将调用实际的虚函数)

 

第三题:以下程序的输出是___________________

int main()
{
 char num;
 for(num = 0;num < 255;)
  num += num;

 cout<<num<<endl;

 return 0;
}

 

此题是死循环,无输出。(for循环中将num赋值为0了,在for循环上面是一个随机的值。所以num+num还是0,此题说明无论在什么情况下一定要坚持自己的判断)。

 

第四题:程序出错在什么阶段:

#include
using namespace std;

int main()
{
 http://www.sogou.com
 cout<<"welcome to sogou"<<endl;

 return 0;
}

A:编译时;B:运行时;C:编译和运行时都出错;D程序运行正常

 

选D。因为http://www.sogou.com中//后面是注释,前面是标签(类似goto的标签)。(坑爹啊)

 

第五题:下面程序的执行结果是【说明:x86_64环境】(*间接访问的优先级大于-)

int a[4][4] = {
  {1,2,3,4},
  {50,60,70,80},
  {900,1000,1100,1200},
  {13000,14000,15000,16000}
 };

 int (*p1)[4] = a;
 int (*p2)[4] = &a[0];
 int *p3 = &a[0][0];

 cout<<*(*(a + 1) - 1)<<"  "<<*(*(p1 + 3) - 2) + 1
  <<" "<<*(*(p2 - 1) + 16) + 2<<" "
  <<*(p3 + sizeof(p1) - 3)<<endl;

 

输出结果为:4  1101 13002 2。

p1为指向一维数组的指针,所以a + 1指向{50,60,70,80}这一维的地址。减一则为4的地址;同理第二个输出1101。同理,由于数组的列是4,所以*(p2 - 1) + 16就相当于*(p2) + 12,所以第三个输出13002。

第四个由于p1是指针,所以sizeof(p1)为4,所以第四个输出2。

 

第六题:在32位操作系统gcc编译环境下,下面程序的运行结果为:

class A
{
public:
 int b;
 char c;
 virtual void print()
 {cout<<"this is a father's function!"<<endl;}
};

class B :public A
{
public:
 virtual void print()
 {cout<<"this is a children's function!"<<endl;}
};
int main()
{
 cout<<sizeof(A)<<"  "<<sizeof(B)<<endl;

 return 0;
}

输出为12,12.注意:子类继承父类的虚表并覆盖其中的条目。而且指向虚表的指针在每个类中也只有一个。

 

注意下面的情况(有两个虚表指针):

class A

{

public:

void foo(){}

};


class B:virtual public A

{

public:

void foo(){}

};


class C:virtual public A

{

public:

void foo(){}

};


class D: public B,public C

{

public:

void foo(){}

};


int main(int argc, char *argv[])

{

    cout<<"A 的大小为: "<<sizeof(A)<<endl;

cout<<"B 的大小为: "<<sizeof(B)<<endl;

cout<<"C 的大小为: "<<sizeof(C)<<endl;

cout<<"D 的大小为: "<<sizeof(D)<<endl;

    return 0;

}

输出1,4,4,8。前三个不解释。从第四个的输出可以看出,虚继承有两个虚表指针。


第八题:关于C++标准模板库,下列说法错误的有哪些:

A std::auto_ptr类型的对象,可以放到std::vector >容器中;

B std::shared_ptr类型的对象,可以放到std::vector >容器中;

C 对于复杂类型T的对象tObj,++tObj和tObj++的执行效率相比,前者更高

D 采用new操作符创建对象时,如果没有足够的内存空间而导致创建失败,则new操作符会返回NULL。

 

选择:A,D。A中auto是给别人东西而自己没有了。所以不符合vector的要求。而B可以。C不解释。D选项在谭浩强的C++程序设计上说是正确的(谭浩强写书时可能是正确的,那时C++的新标准还没出来),但是实际上市错误的。因为:new操作符有三种,(1)plain new/delete就是operator new/delete。这种在为标准化时,C++中的new运算符总是返回NULL表示分配失败,就像malloc一样,因此程序员不得不检查其返回值。标准C++修订了new的语义,plain new在失败后抛出标准异常std::bad_alloc而不是返回NULL。然而,现在很多使用C++的程序员还以为new是以前的老样子,于是通过检查其返回值是否为NULL来判断分配成功与否,显然这是徒劳的;(2) nothrow new就是不抛出异常的运算符new的形式,nothrow new在失败时返回NULL,所以使用它就不需要设置异常处理器。而是像过去一样检查返回值是否为NULL即可。(3)placement new/delete:在指定的内存地址调用构造函数和析构函数,不会引起内存的分配。


PS:auto_ptr和shared_ptr的定义方法: auto_ptr<对象> pInv(对象的指针);shared_ptr<对象> pInv(对象的指针)。如果要得到对象的指针,使用pInv.get()成员函数。

 

第十题:在Inter CPU上,以下多线程对int型变量x的操作,哪几个不是原子操作,假定变量的地址都是对齐的。

A x = y               B x++             C ++x            D x=1

 

选ABC。看下在VC++6.0下的汇编命令即可:从图可以看出本题只有D选项才是原子操作。

2013搜狗校园招聘笔试题

 2013搜狗校园招聘笔试题

附(大牛博客 http://blog.csdn.net/morewindows/article/details/7392749):

在VC++6.0下看汇编命令的方法:

VC6.0编译器对g_nLoginCount++()(例子而已);这一语句打个断点,再按F5进入调试状态,然后按下Debug工具栏的Disassembly按钮,这样就出现了汇编代码窗口。可以发现在C/C++语言中一条简单的自增语句其实是由三条汇编代码组成的,如下图所示。

2013搜狗校园招聘笔试题

第十一题:

class A
{
 string a;
 void f1(){printf("Hello World");}
 void f2(){a = "Hello World"; printf("%s",a.c_str());}
 virtual void f3(){printf("Hello World");}
 virtual void f4(){a = "Hello World";printf("%s",a.c_str());}

 

public:

 static int i;
 static void f5(){cout<<i<<endl;}
};

一般情况下,下面哪些操作会执行失败?

A A* aptr = NULL;aptr->f1();

B A* aptr = NULL;aptr->f2();

C A* aptr = NULL;aptr->f3();

D A* aptr = NULL;aptr->f4();

 

选:A,B,C,D。我选的B,C, D。至于A为什么正确,因为A没有使用任何成员变量,而成员函数是不属于对象的,所以A正确。其实,A* aptr = NULL;aptr->f5();也是正确的,因为静态成员也是不属于任何对象的。至于BCD,在B中使用了成员变量,而成员变量只能存在于对象,C有虚表指针,所以也只存在于对象中。D就更是一样了。但是,坑爹啊,在Class A中没有写public,所以全是private,以至于选项中所以的都将失败。真是一个坑加一个坑啊。

 

第十二题:下列哪些template实例化使用,会引起编译错误?

template
class stack;

void fi(stack); //A

class Ex
{
 stack& rs; //B

 stack si; //C
};

int main()
{
 stack* sc; //D
 fi(*sc);   //E
 int i = sizeof(stack); //F

 return 0;
}

 

选C E F;  请注意stack和fi都只是声明不是定义。我还以为在此处申明后,会在其他地方定义呢,坑爹啊。

由于stack只是声明,所以C是错误的,stack不能定义对象。E也是一样,stack只是申明,所以不能执行拷贝构造函数,至于F,由于stack只是声明,不知道stack的大小,所以错误。如果stack定义了,将全是正确的。


第九题:

class A

{

public:

virtual void foo(){}

};

class B

{

public:

virtual void foo(){}

};


class C : public A,public B

{

public:

virtual void foo(){}

};


void bar1(A* pa)

{

B* pc = dynamic_cast<B*>(pa);

}


void bar2(A* pa)

{

B* pc = static_cast<B*>(pa);

}


void bar3()

{

C c;

A* pa = &c;

B* pb = static_cast<B*>(static_cast<C*>(pa));

}


A bar1无法通过编译                B bar2无法通过编译

C bar3无法通过编译                D bar1可以正确运行,但是采用了错误的cast方法


选B。dynamic_cast是在运行时遍历继承树,所以,在编译时不会报错。但是因为A和B没啥关系,所以运行时报错(所以A和D都是错误的)。static_cast:编译器隐式执行的任何类型转换都可由它显示完成。其中对于:(1)基本类型。如可以将int转换为double(编译器会执行隐式转换),但是不能将int*用它转换到double*(没有此隐式转换)。(2)对于用户自定义类型,如果两个类无关,则会出错(所以B正确),如果存在继承关系,则可以在基类和派生类之间进行任何转型,在编译期间不会出错。所以bar3可以通过编译(C选项是错误的)。


第三十二题(MFC):

int func(){char b[2] = {0};strcpy(b,"aaaa");}

以下说法哪个正确:

A Debug版崩溃,Release版正常

Debug版正常,Release版崩溃

Debug版崩溃,Release版崩溃

Debug版正常,Release版正常


选A。因为在Debug中有ASSERT断言保护,所以要崩溃,而在Release中就会删掉ASSERT,所以会出现正常运行。但是不推荐如此做,因为这样会覆盖不属于自己的内存,这是搭上了程序崩溃的列车。以上的原因只是猜测,如果读者觉得还有更好的原因可以解释,请回复,谢谢。