微軟2013年筆試題詳解及深刻

Microsoftios

下面哪些調用轉換支持可變長度參數:c++

A. cdecl  B. stdcall  C. pascal  D. fastcall數組

幾種函數調用方式:多線程

         __cdecl C Declaration的縮寫,表示C語言默認的函數調用方法:全部參數從右到左依次入棧,這些參數由調用者清除,稱爲手動清棧。被調用函數不會要求調用者傳遞多少參數,調用者傳遞過多或者過少的參數,甚至徹底不一樣的參數都不會產生編譯階段的錯誤。併發

_stdcall StandardCall的縮寫,是C++的標準調用方式:全部參數從右到左依次入棧,若是是調用類成員的話,最後一個入棧的是this指針。這些堆棧中的參數由被調用的函數在返回後清除,稱爲自動清棧。函數在編譯的時候就必須肯定參數個數,而且調用者必須嚴格的控制參數的生成,不能多,不能少,不然返回後會出錯。函數

PASCAL Pascal語言的函數調用方式,也能夠在C/C++中使用,參數壓棧順序與前二者相反。返回時的清棧方式與_stdcall相同。this

_fastcall是編譯器指定的快速調用方式。因爲大多數的函數參數個數不多,使用堆棧傳遞比較費時。所以_fastcall一般規定將前兩個(或若干個)參數由寄存器傳遞,其他參數仍是經過堆棧傳遞。不一樣編譯器編譯的程序規定的寄存器不一樣。返回方式和_stdcall至關。spa

_thiscall 是爲了解決類成員調用中this指針傳遞而規定的。_thiscall要求把this指針放在特定寄存器中,該寄存器由編譯器決定。VC使用ecxBorlandC++編譯器使用eax。返回方式和_stdcall至關。操作系統

_fastcall _thiscall涉及的寄存器由編譯器決定,所以不能用做跨編譯器的接口。因此Windows上的COM對象接口都定義爲_stdcall調用方式。線程

C中不加說明默認函數爲_cdecl方式(C中也只能用這種方式),C++也同樣,可是默認的調用方式能夠在IDE環境中設置。

帶有可變參數的函數必須且只能使用_cdecl方式,例以下面的函數:

int printf(char * fmtStr, ...);

int scanf(char * fmtStr, ...);

 

如下代碼的輸出結果:

class A

{

public:

         virtual void f()

         {

                   cout<<"A:f()"<<endl;

         }

        

void f() const

         {

                   cout<<"A:f()const"<<endl;

         }

};

 

class B:public A

{

public:

         void f()

         {

                   cout<<"B:f()"<<endl;

         }

        

void f() const

         {

                   cout<<"B:f()const"<<endl;

         }

};

 

void  ga(const A *a)

{

a->f();

}

 

int _tmain(intargc, _TCHAR* argv[])

{

         A *a=new B();

         a->f();

         ga(a);

 

}

答案:B::f()A::f()const

第一個,b->f()爲動態綁定,輸出B::f沒問題

第二個,因爲函數ga的參數有const,因此調用成員函數也是調用const版本,可是const版本的不是虛函數,不存在動態綁定,因此輸出A::f const

const 修飾函數和沒有const是不一樣的重載,對於非const對象調用非const函數,固然也能夠調用const函數(優先前者);然而對於const對象則只能調用const函數;其次,A中的f ()函數標註爲 virtual,那麼子類 B 中跟它原模原樣聲明即便沒有標註爲 virtual的函數依然是 virtual 函數。(c++規定,當一個成員函數被聲明爲虛函數後,其派生類中的同名函數都自動成爲虛函數。)

const是函數類型的一部分。虛函數重載的時候這個const也必須一致。若是基類的虛函數帶有const,而在子類的實現中沒有帶const,則至關於在子類中從新定義了一個新的函數。

 

定義虛函數的限制:

1)非類的成員函數不能定義爲虛函數,類的成員函數中靜態成員函數和構造函數也不能定義爲虛函數,但能夠將析構函數定義爲虛函數。構造函數不能是虛函數,內聯函數也不能是虛函數。構造函數不能是虛函數緣由在於:首先構造函數構造一個對象時必須知道對象的實際類型,其次,虛函數的執行依賴於虛函數表,而虛函數表在構造函數中進行初始化工做。

2)只須要在聲明函數的類體中使用關鍵字「virtual」將函數聲明爲虛函數,而定義函數時不須要使用關鍵字「virtual」。

3)當將基類中的某一成員函數聲明爲虛函數後,派生類中的同名函數自動成爲虛函數。

4)若是聲明瞭某個成員函數爲虛函數,則在該類中不能出現和這個成員函數同名而且返回值、參數個數、類型都相同的非虛函數。在以該類爲基類的派生類中,也不能出現這種同名函數。

 

子類中能夠不重寫父類中的虛函數:

class A

{

public:

         virtual void f()

         {

                   cout<<"A:f()"<<endl;

         }

};

class B:public A

{

public:

         void f2()

         {

                   cout<<"B:f()"<<endl;

         }

};

 

int main(){

        A *a=new B();

         a->f();

}

輸出結果:A:f()

但若是基類中定義的是純虛函數,而在子類中沒有實習,那麼在這個子類中,該函數仍然是純虛函數,且該子類也不能被實例化。

 

線程與進程

程序與進程的關係:程序是計算機指令的集合,它以文件的形式存儲在磁盤上,而進程一般被定義爲一個正在運行的程序的實例,是一個程序在其自身的地址空間中的一次執行活動。一個程序能夠對應多個進程,同時,在一個進程中也能夠同時訪問多個程序。

進程是資源申請、調度和獨立運行的單位,所以它使用系統中的運行資源。程序不能申請系統資源,不能被系統調度,也不能做爲獨立運行的單位,所以它不佔用系統的運行資源。

進程與線程的關係:

1)進程歷來不執行任何東西,它只是線程的容器。若要使進程完成某項操做,它必須擁有一個在它的環境中運行的線程,此線程負責執行包含在進程的地址空間中的代碼。也就是說,進程其實是線程的執行環境。

2)單個進程可能包含若干個線程,這些線程都「同時」(時間片)執行進程地址空間中的代碼。每一個進程至少擁有一個線程。當建立一個進程時,操做系統會自動建立這個進程的第一個線程,稱爲主線程,也就是執行主函數的線程。此後主線程能夠建立其餘線程。

3)進程和線程的主要差異在於它們是不一樣的操做系統資源管理方式。進程有獨立的地址空間,一個進程崩潰後,在保護模式下不會對其它進程產生影響,子進程和父進程有不一樣的代碼和數據空間。而線程只是一個進程中的不一樣執行路徑。線程有本身的堆棧和局部變量,但線程之間沒有單獨的地址空間,多個線程則共享數據空間,一個線程死掉就等於整個進程死掉,因此多進程的程序要比多線程的程序健壯。

4)在進程切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行而且又要共享某些變量的併發操做,只能用線程,不能用進程。

 

如下代碼的輸出結果

int x=10;

x= x++;

printf("%d /n", x);

不一樣編譯器編譯出的結果不一樣。可能爲10DevC++),也可能爲11VC6.0.

 

如下const用法正確的是:

A. const int a; // a 是常數

B. int const a; // a 是常數

C. int const *a; // a 指向常數的指針

D. const int *a; // a 是常指針

E. int const *a; // a 是常指針

答案:A B C

注:D E都是指向常量的指針,而 int * const a; 纔是常量指針。約束指針仍是約束常量主要看*的位置。

代碼驗證:

         const int a=10;

         int const b=11;

         cout<<a<<" "<<b<<endl;

輸出:10 11

 

爲何下面的例子在使用一個const變量來初始化數組,ANSI C的編譯器會報告一個錯誤呢?

const int n = 5;

int a[n];

答案與分析:

1)這個問題討論的是「常量」與「只讀變量」的區別。常量,例如5 "abc",等,確定是只讀的,由於常量是被編譯器放在內存中的只讀區域,固然也就不可以去修改它。而「只讀變量」則是在內存中開闢一個地方來存放它的值,只不過這個值由編譯器限定不容許被修改。C語言關鍵字const就是用來限定一個變量不容許被改變的修飾符(Qualifier)。上述代碼中變量n被修飾爲只讀變量,惋惜再怎麼修飾也不是常量。而ANSI C規定數組定義時長度必須是「常量」,「只讀變量」也是不能夠的,「常量」不等於「不可變的變量」。

2)可是在標準C++中,這樣定義的是一個常量,這種寫法是對的。實際上,根據編譯過程及內存分配來看,這種用法原本就應該是合理的,只是ANSI C對數組的規定限制了它(實際上用GCCVS2005編譯以上代碼,確實沒有錯誤產生,也沒有給出警告)。

3)那麼,在ANSI C中用什麼來定義常量呢?答案是enum類型和#define宏,這兩個均可以用來定義常量。

 

例:下面的代碼編譯器會報一個錯誤,請問,哪個語句是錯誤的呢?

typedef char * pStr;

char string[4] = "abc";

const char *p1 = string; //1

const pStr p2 = string; //2

p1++;

p2++;

答案與分析:

問題出在p2++上。

1const使用的基本形式: const type m;

限定m不可變。

2)替換基本形式中的m1式中的*p1,替換後const char *p1;

限定*p1不可變,固然p1是可變的,所以問題中p1++是對的。

3)替換基本形式中的type2式中的pStr,替換後const pStr m;

限定m不可變,題中的pStr就是一種新類型,所以問題中p2不可變,p2++是錯誤的。

 

下面分別用const限定不可變的內容是什麼?

1const在前面

const int nValue //nValueconst

const char *pContent; //*pContentconst, pContent可變

const char* const pContent; //pContent*pContent都是const

2const在後面,與上面的聲明對等

int const nValue; //nValueconst

char const * pContent; //*pContentconst, pContent可變

char* const pContent; //pContentconst,*pContent可變

char const* const pContent; //pContent*pContent都是const

答案與分析:

const和指針一塊兒使用是C語言中一個很常見的困惑之處,在實際開發中,特別是在看別人代碼的時候,經常會由於這樣而很差判斷做者的意圖,下面講一下個人判斷原則:

const只修飾其後的變量,至於const放在類型前仍是類型後並無區別。如:const int aint const a都是修飾aconst*不是一種類型,若是*pType以前是某類型,那麼pType是指向該類型的指針

一個簡單的判斷方法:指針運算符*,是從右到左,那麼如:char const * pContent,能夠理解爲char const (* pContent),即* pContentconst,而pContent則是可變的。

 

int const * p1,p2;

p2const(*p1)是一總體,所以(*p1)const,但p1是可變的。int * p1,p2只表明p1是指向整型的指針,要表示p1p2都是指針是需寫成int * p1,* p2。因此不管是* const p1,p2仍是const * p1,p2,裏面的*都是屬於p1的。

 

int const * const p1,p2;

p2const,是前一個const修飾的,*p1也被前一個const修飾,而p1被後一個const修飾。

 

int * const p1,p2;

p1const,(* const p1)是總體,因此const不修飾p2

 

const*的左邊,則指針指向的變量的值不可變;在*的右邊,則指針的指向不可變。簡記爲「左定值,右定向」。

1)指針指向的變量的值不能變,指向可變

int x = 1;

int y = 2;

const int* px = &x;

int const* px = &x; //這兩句表達式同樣效果

px = &y; //正確,容許改變指向

*px = 3; //錯誤,不容許改變指針指向的變量的值

2)指針指向的變量的值能夠改變,指向不可變

int x = 1;

int y = 2;

int* const px = &x;

px = &y; //錯誤,不容許改變指針指向

*px = 3; //正確,容許改變指針指向的變量的值

3)指針指向的變量的值不可變,指向不可變

int x = 1;

int y = 2;

const int* const px = &x;

int const* const px = &x;

px = &y; //錯誤,不容許改變指針指向

*px = 3; //錯誤,不容許改變指針指向的變量的值

附:

c中,對於const定義的指針,不賦初值編譯不報錯,

int* const px;等不會報錯。

可是,在C++

int* const px;const int* const px;會報錯,const int* px;不報錯。

必須初始化指針的指向int* const px = &x;const int* const px=&x;

強烈建議在初始化時說明指針的指向,防止出現野指針

 

1000瓶水,其中有一瓶有毒,小白鼠只要嘗一點帶毒的水24小時後就會死亡至少要多少隻小白鼠才能在24小時鑑別出哪瓶水有毒。

1000個瓶分別標上以下標籤(10位長度):

0000000001 (第1瓶)

0000000010 (第2瓶)

0000000011 (第3瓶)

......

1111101000 (第1000瓶)

從編號最後1位是1的全部的瓶子裏面取出1滴混在一塊兒(好比從第一瓶,第三瓶,裏分別取出一滴混在一塊兒)並標上記號爲1。以此類推,從編號第一位是1的全部的瓶子裏面取出1滴混在一塊兒並標上記號爲10。如今獲得有10個編號的混合液,小白鼠排排站,分別標上109…1號,並分別給它們灌上對應號碼的混合液。24小時過去了,過來驗屍:

從左到右,死了的小白鼠貼上標籤1,沒死的貼上0,最後獲得一個序號,把這個序號換成10進制的數字,就是有毒的那瓶水的編號。

 

3*4的格子有幾個矩形:

M*N網格中有橫豎各M+1N+1條直線,其中,任意各取兩條均可以組成一個長方形。

C(4,2)*C(5,2)=6*10=60;

A(N,N)=N!

A(N,M)=N*(N-1)*…*(N-M+1)

C(N,M)=A(N,M)/A(M,M)

 

一條線把平面分紅兩塊,兩條線把平面分紅四塊,若是任意兩條線不平行,且沒有3條線交在同一點,問100條線將平面分紅多少塊。

答案:5051

1條直線最多將平面分紅2個部分;2條直線最多將平面分紅4個部分;3條直線最多將平面分紅7個部分;如今添上第4條直線.它與前面的3條直線最多有3個交點,這3個交點將第4條直線分紅4段,其中每一段將原來所在平面部分一分爲二,因此4條直線最多將平面分紅7+4=11個部分.

徹底相似地,5條直線最多將平面分紅11+5=16個部分;6條直線最多將平面分紅16+6=22個部分;7條直線最多將平面分紅22+7=29個部分;8條直線最多將平面分紅29+8=37個部分.

通常地,n條直線最多將平面分紅2+2+3....+N=N*N+N+2/2

 

N個球,其中只有一個是重量較輕的,用天平只稱三次就能找到較輕的球,如下的N值哪一個是可能的?

A 12

B 16

C 20

D 24

E 28

3 個一次能夠測出來,3*3 = 9個之內 2 次,3*3*3 = 27個之內,3次!

 

下列代碼的輸出是什麼?

#include <iostream>

using namespace std;

class A{

public:

    long a;

};

 

class B : public A

{

public:

    long b;

};

 

void seta(A* data, int idx)

{

    data[idx].a = 2;  // 形參爲A的指針。數組步長按A的大小來取。

}

 

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

{

    B data[4];

 

    for(int i=0; i<4; ++i){

        data[i].a = 1;

        data[i].b = 1;

        seta(data, i);

    }

 

        cout<<sizeof(A)<<endl; // 4

         cout<<sizeof(B)<<endl; // 8

    for(int i=0; i<4; ++i){

        std::cout  << data[i].a << data[i].b;

}

}

輸出爲22221111

附:

struct Test{

    short int a;

    short int b;

};

 

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

{

    int test = 0x12345678;

    printf("%x %x", (*(struct Test*)&test).a, (*(struct Test*)&test).b);    // 5678 1234

}

//Intel是小端處理器

相關文章
相關標籤/搜索