c++筆試面試總結

C++:

1. c++的new可以指定地址
struct T:B
{
    public:
        void * operator new(size_t sz, T& t){}
};

int main()
{
    T tb;
    T * t = new(tb) T;    //必須是tb在前,因爲tb指明size,不知道這個有什麼用
}

2. c++中的=號必須是class的成員函數,不能是全局函數。
原因:
int operator=(int a, integer b);
這樣重載之後,語句2 = a; 表述也是正確的,但是卻是明顯的語法錯誤爲了避免此類錯誤,需要將賦值操作符重載爲成員函數

3.new的操作。
1:call operator new. if operator new is overridden by user then compiler willcall user-defined version. operator new return void *
2:call constructor to construct object
3:change void * to user-defined type(class type, withstatic_cast<class*>(void* address));
so we can override operator new and change the memory allocation in thefunction. we can pre-allocate a big block of memory and in the operator new wejust allocate from this memory instead of allocating from system memory. ofcourse we can override operator delete and release the memory back to thememory block instead of system memory. actually this is called memory pool.

4. placement new
new可以指定一個內存地址構造對象,而不是申請一個新的內存地址。
方法:new (address) type(parameters);
當然可以用placement new,但是沒有placement delete,所以當使用了placement new後,需要使用顯示調用析構函數清除對象本身,但是沒有釋放內存,因爲free不會調用析構函數。
所以說構造函數和析構函數都是可以顯示調用的。
placement new會調用帶兩個參數的void * operator new(size_t sz,void * t); //第二個參數不一定要void*,任何參數都可以,只要返回void*的內存地址就可以。
placement new的地址應該由申請address的人釋放,不建議new對象的人釋放。
參考:http://hi.baidu.com/qufuping1981/blog/item/81120df0e27091aca40f5213.html

5. c++中將user-defined類型轉成basic類型:
1. 寫個函數將兩個類型轉換
2. 在類中寫個類型轉換成員函數,比如
class T{
public;
operator int(){return 1;}    //貌似這個格式就是這樣的,必須int寫在()上,而不能寫在前面
};

 

6.c++ operator overloading:
http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html

 

7.c++中+號返回的是右值,不能當左值用。operator+操作符返回的是對象,不是引用,=號返回的引用,即左值,可以賦值。

 

8. &的優先級比==低,所以需要if((x&i)==x)用個括號將&括起來

+的優先級比<<高


9. shared condition variant.
1. require mutex
2. test predicate
3. if predicate is true then do something and release mutex
4. if predicate is false then cond_wait for the predicate. if it returns thencontinue to test predicate(jump to 2).

10. c++中交換兩個數不用臨時變量的方法:
1. a = a+b; b= a-b ; a=a-b
2. a = a^b; b= a^b;a=a^b;
挺無聊的題目,但是確實不用臨時變量。

 

11. 類非靜態成員變量不能作爲成員函數的默認參數

12. struct繼承默認是public的,class默認是private的。

13. uml中+號是public,-號是private,#是protected。

14. c++類的const方法可以由const對象調用。因爲const方法的this是const的,非const的this可以傳給const的this,即
const對象只能調用const函數。因爲const方法裏面的this是const的。非const方法裏面的this是非const的。
class T{
public:
    const void func()const{
    }
    void func(){
    }
    T(){}
};

int main(){
    T t;
    t.func();        //non constversion
    const T ct;
    ct.func();    //const version
}

這裏必須有構造函數,因爲如果不加的話,const T ct;通不過編譯的。因爲const對象是初始化一次,而且不能被修改,所以只能在構造函數中初始化,但是默認的構造函數是什麼都不做的,即它不會初始化 const對象,所以會報錯,而用戶自定義的構造函數雖然什麼都沒幹,但是編譯器會認爲它將const成員初始化了,所以編譯通過。

 

15. 爲什麼空類的sizeof不是0,而是1。
這就是我們剛纔所說的實例化的原因(空類同樣可以被實例化),每個實例在內存中都有一個獨一無二的地址,爲了達到這個目的,編譯器往往會給一個空類隱含的加一個字節,這樣空類在實例化後在內存得到了獨一無二的地址.所以a,b的大小爲1.
就是new 0的時候未定義。

 

16. C++ padding:

class T
{
public:
    int a;
    char b;
};

class T:Tpublic T
{
public:
    char c;
};
sizeof(T)=12,父類的padding被帶到了子類中,子類的padding自己重新算

17. 純虛類虛表:

存虛類沒有虛表
虛表放在代碼段
每個有虛函數的類有個虛表,如果不實例化對象,則沒有虛表簡歷(所以存虛函數沒有虛表).
如果父類子類都有自己的虛函數,則父類子類都有各自的虛表,只是各自的虛表裏面的內容可能不相同(所以可能有多態功能)
如果存虛函數被繼承了並且子類示例化了,子類有虛表,但是存虛父類依舊沒有虛表。

1. 單類的:
class T{
    virtual void vfunc(){}
    virtual void vvfucn(){}
};

//class T的虛表
_ZTV1T:
    .long   0
    .long   _ZTI1T
    .long   _ZN1T5vfuncEv       //這個是虛表,具體的函數實現在代碼段的其他地方。
    .long   _ZN1T6vvfucnEv       //兩個虛函數
    .weak   _ZTI1T
    .section   .rodata._ZTI1T,"aG",@progbits,_ZTI1T,comdat
    .align 4
    .type   _ZTI1T, @object
    .size   _ZTI1T, 8
有兩個virtual function:_ZN1T5vfuncEv,_ZN1T6vvfucnEv。

2. 有繼承的:
class T{
    virtual void vfunc(){}
    virtual void vvfucn(){}
};

class TT:public T{
    virtual void vfunc(){}
};

//class TT的虛表:
_ZTV2TT:
    .long   0
    .long   _ZTI2TT
    .long   _ZN2TT5vfuncEv    //vfunc使用classTT的vfunc
    .long   _ZN1T6vvfucnEv    //vvfunc是有父類classT的vvfunc
    .weak   _ZTI2TT
    .section   .rodata._ZTI2TT,"aG",@progbits,_ZTI2TT,comdat
    .align 4
    .type   _ZTI2TT, @object
    .size   _ZTI2TT, 12

//class T的虛表
_ZTV1T:
    .long   0
    .long   _ZTI1T
    .long   _ZN1T5vfuncEv    //父類的虛表不受繼承的影響
    .long   _ZN1T6vvfucnEv
    .section    .eh_frame,"a",@progbits

虛表指針是放在對象內存layout的頭部的。

 

C語言:

1.      int a[10]={0};      可以對a進行初始化全0,int a[10]={}同樣可以初始化a。

2.       

#define NUM 5
int main(){
   NUM++;    //錯誤的,不能對右值進行賦值
}

 

3.      printf("%03.1f\n",123.34);   //輸出 123.3,%03.1f表示最小長度爲3包含.號,不足的加0前面,小數點後面爲1位,多的小數點直接去除,不進位。

 

4.      printf("%3.5s\n","asdfsaf");   //就輸出5位,asdfs,沒有多餘的。最小3位。


5.  int n = 10;
int a[n] ;     不行,但是gcc現在可以的 ,面試官說c90不行,c99可以。Vs2008也不行,看來gcc還是做過改動的。

 

6.      int a[3] = {0x112233,0x334455,0x778899};
int * a1 = &a[0]+1;
printf("%p,%p,%p\n",a1,&a[0],a);
int * b = (int*)((int)a1+1);    //指向a1的地址+1的地方。
printf("%x\n",*b);    //輸出0x99003344   

 

7.      int n = 10;
typeof(n) b = 10;    //typeof(n) 即int   ,即int b=10;

 

8.      內核裏有很多#define(x) do{x}while(0);      //目的是保證x被執行一次。

 

9.      struct pair{int a,int b;};
struct pair g_pair;
  void test(struct pair & p){
     p = g_pair;
  }
it can work. first time to use this method. got confused with java.

 

10.   

#include<stdio.h>
#include <stdlib.h>
#include <string.h>
struct test
{
    int a:5;
       int:2;
    int b:2;
    int c:4;
};

int main()
{
    struct test t;
    struct test * tp = &t;
    tp+=1;
    memcpy(&t,"EMC EXAMINATION",sizeof(t));
    printf("%d,%d,%x,%x,%d\n",t.a,t.b,t,*tp,t.c);
}
EMC的筆試題目:在使用bit位操作時,如果一個int只用了k位,那麼剩餘的32-k位將被填上k位的最高位的值。
比如b只用了2位,那麼剩餘的30位會被填上1,因爲b的最後兩位是10.
c用了4位,剩餘28位被填上了0,因爲c的最後四位是0110

 

11.   

int a = 0;
~a = -1;
-a = 0;
所以判斷一個數是不是unsigned必須使用取反~

 

12.  貌似!的優先級比>高,所以
int a = 1;
k = !~a++>3; 所以!~a++用於等於0只要a不等於0,而0>3用於等於0,所以k用於等於零。

13.  指針不能相加的。
int a[]={1,23,23};
int * p  = a;
int * q = a+1;
p = q+p;        //compilation error

14.  動態存儲方式,就是程序運行時分配釋放的,不是編譯時。

15.  const char * a = "sdf";   //*a是const,不能變,但a可以變。
char * const a = "sdf";    //a不可以變,但是*a能變。

16.  'A'=65,'0'=30,'a'=97

17.  char*strs[N]={"01010101","0101010","001010","01010101001"};一維數組,每個元素是個char*指針。

18.  二維數組不能對第一維度賦值。 因爲不能對數組賦值,即char a[]="asdf",char b[]="sdf";不能a=b。

19.   

char a[]="abcdfd"; a的大小爲7,6個字符+1個0.

a^b=c==> a=c^b    //learn from sohu campus hire

 

20.   

判斷一個數n是否有2個冪:
 n&&!(n&(n-1))    //先要判斷n是否爲0

21.  -1的表示爲0xffffffff, 但是如果是有符號數,則輸出-1, 無符號數輸出4294967295

22.  memcpy不能overlap
memmove可以overlap 

23.   

c++ 負數取模:a%b=a-(a/b)*b
負數取模:1%-3 = 1-(1/(-3))*(-3) = 1
         -8%5 = -8 - ((-8)/5)*5 = -3

24.   

#include <stdio.h>  

struct node{  

  node* next;  

  node* prev;  

};  

int main()  

{  

    node n[2];  

    node* p1 = &n[0];  

    node* p2 = p1++;  

    printf("%d,",p1 - p2);  

    printf("%d,", (unsigned long)&(p1->next) - (unsigned long)&(p2->next));  

    printf("%d,", (unsigned long)&(p1->prev) - (unsigned long)&(p2->next));  

    return 0;  

這道題目是考察對指針+1與-1時跨度的問題。
對結構體指針p1,當p1++時跨度是8個字節,因爲sizeof(struct node)是8,同樣p2-p1跨度是8個字節,但是差只有1,因爲他們的計算對象是結構體。
而對於printf("%d,", (unsigned long)&(p1->next) - (unsigned long)&(p2->next)); 這個應該是8因爲他將地址轉成了long型,則將地址作爲整數進行計算,所以地址跨度即變量差值,結果爲8。
如果是printf("%d,",  &(p1->next) - &(p2->next));  則兩個變量的地址跨度是8字節,但是變量的sizeof爲4,則變量差距爲2。
所以由上可知,變量的跨度是地址的跨度/sizeof(變量)。

 

25.  問int **a[10]; 的意思   //1維數組,維度10,每一個元素是int**,指向個二維數組。 //二維指針數組

 

26.  int *(*a)[10];           //a是個指針,指向一個數組,數組元素爲int*
其實二個都是3三維數組

27.  int (*a[10])()函數指針數組

指針相關的:太牛了
int   f()         f是一個函數,返回一個整型值
int   *f()        f是一個函數,返回一個整型指針
int   (*f)()       f是一個函數指針,所指向的函數返回一個整型值
int   *(*f)()      f是一個函數指針,所指向的函數返回一個整型指針
int   f[]         f是一個整型數組
int   *f[]       f是一個指針數組,數組元素的類型是整型指針
int   (*f)[]       f是指針,指向一個數組,數組元素為整型
int   f()[]        非法。f是一個函數,但是函數不可能返回一個數組,函數只能返回標量值。
int   (*f[])()      f是一個數組,數組元素類型為函數指針,所指向的函數返回整型值
int   *(*f[])()    f是一個指針數組,指針所指向的類型是返回值為整型指針的函數

 

28.   

l-value:storage represented by an expression. //a place that is writable.
r-value: the value contained in the storage.     // just a valuewhich cannot be writable.

發佈了81 篇原創文章 · 獲贊 22 · 訪問量 36萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章