AllieLee

导航

2013 微软校园实习生笔试题及详解(1-5题)

     或许你早已经是一等一的笔试面试高手,对于微软等众多互联网公司的笔试题的出题套路、给分方式早已了如指掌,那么大可略过下面的一些解释说明。

     首先,关于”霸笔“:因为微软是网申之后每人都有一个唯一的简历编号,这个编号貌似也会成为后期笔试、面试的一个Id。所以,亲们,如果真的想要亲身经历微软的笔试,也就别疏忽忘记定时投递简历哦(中文+英文)。

     其次,关于评分方式和答题时间:在连续的几年中,微软校园实习生招聘的笔试题均由20道选择题构成,根据题目难易程度的不同,不同的题目分数会有一些差异,20道题总分为100分。这里特别强调一点,这20道题的选项中至少有一个为正确的,也可以是多个正确选项。答对相应的题给满分,部分答对给部分分数,答错则扣分,不答则不给分。如题1满分3分,答对给3分,部分答对给2分,答错扣2分,不答为0分。

     最后,关于考察内容:虽然只有20道题,但是其内容相当的丰富,涵盖数据结构、算法、操作系统、C\C++\Java等编程语言的语法及编译等,所以想要交出一份漂亮的答卷,没有深厚扎实的基本功几乎是不可能的。 

    OK,不啰嗦,上题,拿事实说话~

1. Which of the following calling convention(s) support(s) supportvariable-length parameter(e.g. printf)?(3 Points)

  A. cdecl 

  B. stdcall    

  C. pascal    

  D. fastcall

 



 

 

 

 

问题解析:本题要求选出像printf一样支持变长参数的函数调用约定。

1.什么是函数调用约定?

答:当一个函数被调用时,函数的参数会被传递给被调用的函数,同时函数的返回值会被返回给调用函数。函数的调用约定就是用来描述参数(返回值)是怎么传递并且由谁来平衡堆栈的。

2.常见的函数调用约定有哪些?

答:__stdcall,__cdecl,__fastcall,__thiscall,__nakedcall,__pascal

     按参数的传递顺序对这些约定可划分为:
           a).
从右到左依次入栈:__stdcall,__cdecl,__thiscall
           b).
从左到右依次入栈:__pascal,__fastcall

3.支持变长的函数调用约定有哪些?

答:__cdecl,带有变长参数的函数必须是cdecl调用约定,由函数的调用者来清除栈,参数入栈的顺序是从右到左  

2. What's the output of the following code?(3 Points)

 

View Code
#include<iostream>
using namespace std;
class A  
{  
public:
    virtual void f()  
    {
        cout<<"A::f()";  
    }  
    void f() const  
    {
        cout<<"A::f() const"<<endl;  
     }  
 }; 
   
class B: public A  

{  

public:  

    void f()  
    {  
        cout<<"B::f()";  
    }  
    void f() const  
    {  
       cout<<"B::f() const"<<endl;  
    }  
 };  
   
void g(const A* a)
{ 
    a->f(); 
}  

int main()  
{ 
    A* a = new B(); 
    a->f(); 
    g(a);
    delete a ;  
    return 0;
}  

 

    A. B::f()B::f()const    

    B. B::f()A::f()const   

    C. A::f()B::f()const    

    D. A::f()A::f()const  

  

 

 

 

 

问题解析:本题主要考察C++的重载与多态

1.C++的多态性是如何体现的?

答: 在C++中,多态性仅用于通过继承而相关联的类型的引用或指针。

  • 通过继承我们能够定义这样的类,它们对类型之间的关系建模,共享公共的东西,仅仅特化本质上不同的东西。派生类能够继承基类定义的成员;派生类可以无需改变而使用那些鱼派生类型具体不相关的操作;派生类可以重定义那些与派生类型相关的成员函数,将函数特化,考虑派生类型的特性;最后,除了从基类继承的成员之外,派生类还可以定义更多的成员。

     在C++中,基类必须指出希望派生类重定义哪些函数,定义为virtual的函数是基类期待派生类重新定义的,基类希望派生类继承的函数不能定义为虚函数。

  • 通过动态绑定我们能够编写程序使用继承层次中任意类型的对象,无需关心对象的具体类型。使用这些类的程序无需区分函数是在积累还是在派生类中定义的。

  在C++中,通过基类的引用(或指针)调用虚函数时,发生动态绑定。引用(或指针)既可以指向基类对象也可以指向派生类对象,这一事实是动态绑定的关键。用引用(或)指针调用的虚函数在运行时确定,被调用的函数是引用(或指针)所指对象的实际类型所定义的。

   本例中代码同动态绑定相关联的代码为:

 A* a = new B();
a->f();

  基类A将函数void f()定义为virtual类型,A的派生类B重新定义void f()函数,这一点主要应用了继承这一特性。
  在main()函数中,定义一个A类型的指针a,将其指向派生类B,然后调用a->f()实质上应用的就是动态绑定了,即“用引用(或)指针调用的虚函数在运行时确定,被调用的函数是引用(或指针)所指对象的实际类型所定义的”,故第一次输出为:B::f()。

  此外,C++中的函数调用默认不使用动态绑定。要触发动态绑定,必须满足两个条件:第一,只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不进行动态绑定;第二,必须通过基类类型的引用或指针进行函数调用。

2.重载函数

  定义:出现在相同的作用域中的两个函数,如果具有相同的名字而形参表不用,则成为函数重载。注意函数重载不能基于不同的返回值类型进行重载。同时注意函数重载中的“形参表”不同,是指本质不同,不要被一些表象迷惑。main函数不能被重载。本例中的基类A和派生类都存在着重载,以基类A为例进行说明:

class A  
{  
public:
    virtual void f()  
    {
        cout<<"A::f()";  
    }  
    void f() const  
    {
        cout<<"A::f() const"<<endl;  
     }  
 }; 

  从代码中可以看到在A类中,f()函数是发生重载了,而且是合法的。在调用时,只用A类的const对象才能调用const版本的f函数,而非const对象可以调用任意一种,通常非const对象调用不是const版本的f()函数。

  是不是感到很困惑了,按照重载函数的定义知不同返回值类型的函数不能进行重载,这里为什么又是重载呢?

  这里可以重载的原因是:按照函数重载的定义,函数名相同而形参表有本质不同的函数称为重载。在类中,由于隐含的this形参的存在,const版本的f()函数使得作为形参的this指针的类型变为指向const对象的指针,而非const版本的使得作为形参的this指针就是正常版本的指针。此处是发生重载的本质。重载函数在最佳匹配过程中,对于const对象调用的就选取const版本的成员函数,而普通的对象调用就选取非const版本的成员函数。

(注:this指针是一个const指针,地址不能改,但能改变其指向的对象或者变量) 

 

3. What is the difference between a linked list and an array?(3 Points)

    A. Search complexity when both are sorted

    B. Dynamically add/remove

    C. Random access efficiency

    D. Data storage type

 

 

 

 

 

 

问题解析:本题考查基本的数据结构内容,比较链表和数组的区别。下面从逻辑结构和内存存储 两个方面进行详细的描述:

  • 从逻辑结构来看
    • 数组必须事先定义固定的长度,即元素的个数,不能适应数据的动态增减;
    • 链表动态地分配存储空间,可以适应数据动态的增减。

  这种逻辑结构导致的结果:
    1)随机访问效率不同:数组可以根据下标直接存取数据,实现高效的随机访问,而链表必须通过遍历节点才能取得数据。
    2)数据基本有序的情况下查找数据的时间效率也不同:在数据基本有序的情况下访问数组可以
利用折半查找方法先确定下标,然后通过下标快速得到数据,而链表则需要遍历整个表才能得到数据;
    3)动态插入和删除的效率不同:数组中插入、删除数据项时,需要移动其他数据项,非常繁琐;而链表可以根据next指针找到下一个元素,实现动态的插入和删除效率较高。

  • 从内存存储来看
    • (静态)数组从栈中分配空间,自由度小,并且数组的各个元素之间的物理位置是相邻的。
    • 链表从堆中分配空间,自由度大,链表中各个节点的物理位置可以不是相邻的。

 

4. About the Thread and Process in Windows, which description(s) is(are) correct:(3 Points)

    A. One application in OS must have one Process, but not a necessary to have one Thread

    B. The Process could have its own Stack but the thread only could share the Stack of its parent Process

    C. Thread must belongs to a Process

    D. Thread could change its belonging Process

 

 

 

 

 

 

问题解析:

 

 

5. What is the output of the following code?(3 Points)

 

{  
    int x = 10 ;  
    int y = 10 ;  
    x = x++ ;  
    y = ++y ;  
    printf("%d, %d\n",x,y);  
} 

    A. 10, 10

    B. 10, 11

    C. 11, 10

    D. 11, 11

 

 

 

 

 

问题解析:本题主要考察队编程语言的基本语法的理解。

在C语言和C++语言中,自增运算符的使用可以是程序看着简洁,思路也比较清晰。自增运算符又分为前自增和后自增两类,即定义一个变量,如int i=10;

前自增可以表示为:++i; 

后自增可以表示为:i++;

单纯的看这两条语句,在执行完毕之后i值并没有太大的区别,均为11。下面来点不同的:

int i = 10, j = 10;
int x, y;
x = i++;
y = ++j;

问x和y值是否相等?结论是x=10,y=11,所以他们不等。语句x = i++;的执行流程是先将i值赋给x(x=10),然后i值再加1(i=11)。而语句y = ++j;的流程则是j先加1(j=11),然后再将j值赋给y(y=j=11)。所以本题答案为D选项。

  另外,做一些关于java语言处理前自增和后自增的补充说明。java语言中

int i = 10;
i = i++;
system.out.println(i);

执行如上代码输出结果为10,所以很多同学认为选项B也是正确的,但这里注意题目中输出语句采用的是printf()函数,故可以理解为C语言代码或C++代码,所以本题的唯一解为选项D。

 

 

 

 

 

 

 

 

 

 

posted on 2013-04-06 22:47  AllieLee  阅读(884)  评论(2编辑  收藏  举报