c++

來源:互聯網
上載者:User

標籤:使用   記憶   區分   指標常量   思想   pointer   net   mil   個數   

1.簡述變數聲明和定義的區別。 

       為變數分配地址和儲存空間的稱為定義,不分配地址的稱為聲明。一個變數可以在多個地方聲明,但是只在一個地方定義。加入extern修飾的是變數的聲明,說明此變數將在檔案以外或在檔案後面部分定義。 

 

2.簡述sizeof和strlen的區別

       最常考察的題目之一。主要區別如下:

              1)sizeof是一個操作符,strlen是庫函數。 

              2)sizeof的參數可以是資料的類型,也可以是變數,而strlen只能以結尾為‘\0‘的字串作參數。 

              3)編譯器在編譯時間就計算出了sizeof的結果。而strlen 函數必須在運行時才能計算出來。並且sizeof計算的是資料類型占記憶體的大小,而strlen計算的是字串實際的長度。 

              4)數組做sizeof的參數不退化,傳遞給strlen就退化為指標了。

 

3.說說C和C++中的static有什麼作用

       這個真的在面試的時候被問過。

       在C中static用來修飾局部靜態變數和外部靜態變數、函數。而C++中除了上述功能外,還用來定義類的成員變數和函數。即靜態成員和靜態成員函數。編程時最常用的是static的記憶性,和全域性的特點可以讓在不同時期調用的函數進行通訊,傳遞資訊,而C++的靜態成員則可以在多個對象執行個體間進行通訊,傳遞資訊。

 

4.C和C++中動態記憶體分配有什麼方法,有何區別

       C裡面一般用malloc/free,C++可用malloc/free和new/delete。區別見找工作筆試面試那些事兒(3)---記憶體管理那些事中的內容。

 

5.簡述C、C++程式編譯的記憶體配置情況

       之前提過,主要有靜態儲存區配置,在堆上和棧上分配三種,具體情境見找工作筆試面試那些事兒(3)---記憶體管理那些事中的內容。

 

6.說說strcpy、sprintf與memcpy三個函數

       三個函數的功能分別為:

       strcpy:實現字串變數間的拷貝
       sprintf:主要實現其他資料類型格式到字串的轉化

       Memcpy:主要是記憶體塊間的拷貝

       它們的區別有:

       (1)操作對象不同,strcpy的兩個操作對象均為字串,sprintf的操作來源物件可以是多種資料類型,目的操作對象是字串,memcpy 的兩個對象就是兩個任意可操作的記憶體位址,並不限於何種資料類型。 

       (2)執行效率不同,memcpy最高,strcpy次之,sprintf的效率最低。 

 

7.說說拷貝建構函式和賦值運算子

       拷貝建構函式和賦值運算子有以下兩個不同之處: 

       (1)拷貝建構函式產生新的類對象,而賦值運算子不能。 

       (2)由於拷貝建構函式是直接構造一個新的類對象,所以在初始化這個對象之前不用檢驗來源物件是否和建立對象相同。而賦值運算子則需要這個操作,另外賦值運算中如果原來的對象中有記憶體配置要先把記憶體釋放掉(這一點在之前找工作筆試面試那些事兒(5)---建構函式、解構函式和賦值函數中提到了)。

 

8.簡述類成員函數的重寫、重載和隱藏的區別

見找工作筆試面試那些事兒(4)---C++函數進階特徵中所述。

 

9.用遞迴和非遞迴兩種方法翻轉一個鏈表

先定義一下鏈表:

 

typedef struct node{ElemType data;struct node * next;}ListNode;typedef struct{ListNode *head;int size;ListNode *tail;}List;/*********************************************************非遞迴的翻轉實際上就是使用迴圈,依次後移指標,並將遇到的鏈表指標反轉*********************************************************/void ReserveList(List * plist)        //非遞迴實現,{ListNode * phead;//新鏈表的頭 開始的第一個節點ListNode * pt; //舊鏈表的頭 開始的第二個節點ListNode * pn; //舊鏈表頭的下一個phead = plist->head;if(phead && phead->next&& phead->next->next) //首先確定{phead = plist->head->next;//新鏈表就是以第一個節點開始,依次在表頭添加節點,添加的節點是舊鏈表的第一個節點pt = phead->next; //舊鏈表,舊鏈表被取走頭結點之後放入新鏈表的表頭,pn = pt->next;phead->next = 0;while(pt){pn = pt->next; //pn是舊鏈表的第二個節點pt ->next = phead;//取舊鏈表的第一個節點插入新鏈表phead = pt;pt = pn; //舊鏈表往後移動}}plist->head->next = phead; //新鏈表重新賦值到整個鏈表}/*********************************************************遞迴思想,原理也是從就鏈表上依次取元素放入到新鏈表直到原始鏈表被取完,得到新鏈表*********************************************************/ListNode * ReserveListRe(ListNode * oldlist,ListNode * newlist){ListNode * pt;pt = oldlist->next; //取舊鏈表的表頭,pt是現在的舊鏈表oldlist->next = newlist;//就舊鏈表插入到新鏈表newlist = oldlist; //如果舊鏈表是空,表示舊鏈表被取完了,新鏈表就是翻轉之後的鏈表return (pt == NULL) ? newlist : ReserveListRe(pt,newlist);} 

 

 

 

10.談談對C++的引用和C語言的指標的認識

      簡單說來,引用即別名,指標即地址。具體的部分參見找工作筆試面試那些事兒(2)---函數那些事中的“關於指標和引用”。

重點談一下它們的區別吧: 

      (1)引用必須被初始化,但是不分配儲存空間。指標不聲明時初始化,在初始化的時候需要分配儲存空間。 

      (2)引用初始化以後不能被改變,指標可以改變所指的對象。 

      (3)不存在指向空值的引用,但是存在指向空值的指標。 

 

11.簡述指標常量與常量指標區別

      這是一個常見的問題。也就是const char *p和char * const p的差別,前者稱為常量指標(指標指向的內容不可變),後者是指標常量(指標本身不可再被重新賦值)。下面是一個比較好記的方法,根據const的位置確定其修飾的內容:

      const char* p : 因為const 修飾符在 * 號前面,因此const 修飾的是 (*p),因此p指向的字串是const的.

      char const* p : 等價於const char* p, 因為const 修飾符在 * 號前面,因此const 修飾的是 (*p),因此p指向的字串是const的.

      char* const p: const修飾的是變數p,而變數p是 char* 類型的,所以這個char* 變數本省是const,它的值初始化後就不能變了.

 

12.數組名和指標的區別

      指標是一個變數,有自己對應的儲存空間,而數組名僅僅是一個符號,不是變數,因而沒有自己對應的儲存空間。

      1、地址相同,大小不同
範例程式碼:

 

      int arr[10];      int* p=arr;      cout<<arr<<endl;      cout<<p<<endl;      cout<<sizeof(arr)<<endl;//結果為40      cout<<sizeof(p)<<endl;//結果為4

 

 

      2、都可以用指標作為形參

樣本程式: 

 

 void fun(int* p)  {      cout<<p[0]<<endl;  }  int main() {      int arr[10]={0};     int* p=arr;     fun(arr);     return 0; }

 

 

 

      3、指標可以自加,數組名不可以

      4、作為參數的數組名的大小和指標的大小相同

 

 

13.建構函式能否為虛函數,為什嗎?

      建構函式不能是虛函數。而且不能在建構函式中調用虛函數,因為那樣實際執行的是父類的對應函數,因為自己還沒有構造好。解構函式可以是虛函數,而且,在一個複雜類結構中,這往往是必須的。解構函式也可以是純虛函數,但純虛解構函式必須有定義體,因為解構函式的調用是在子類中隱含的。 

      虛函數的動態綁定特性是實現重載的關鍵技術,動態綁定根據實際的調用情況查詢相應類的虛函數表,調用相應的虛函數。

 

14.談談你對物件導向的認識

      說實話,這種開放式的題目實則挺考察對知識的深層把握程度的。

      物件導向可以理解成對待每一個問題,都是首先要確定這個問題由幾個部分組成,而每一個部分其實就是一個對象。然後再分別設計這些對象,最後得到整個程式。傳統的程式設計多是基於功能的思想來進行考慮和設計的,而物件導向的程式設計則是基於對象的角度來考慮問題。這樣做能夠使得程式更加的簡潔清晰。 

      編程中接觸最多的“物件導向編程技術”僅僅是物件導向技術中的一個組成部分。發揮物件導向技術的優勢是一個綜合的技術問題,不僅需要物件導向的分析,設計和編程技術,而且需要藉助必要的建模和開發工具。

 

15.delete 與 delete []有什麼區別? 

      這個特別在找工作筆試面試那些事兒(3)---記憶體管理那些事中提到了,簡單說來,delete[]刪除一個數組,delete 刪除一個指標。

 

16.寫個小程式確定一個數轉化成二進位後是1的位的個數

很久以前就開始流傳的一道微軟面試題。

 

int func(x)   {       int countx = 0;        while(x)        {              countx ++;              x = x&(x-1);         }        return countx;   }

 

 

 

17.將“引用”作為函數傳回值類型的格式、好處和需要遵守的規則?

      格式:類型標識符&函數名(形參列表及類型說明){ //函數體} 

      好處:在記憶體中不產生被傳回值的副本;(注意:正是因為這點原因,所以返回一個局部變數的引用是不可取的。因為隨著該局部變數生存期的結束,相應的引用也會失效,產生

runtime error!) 注意事項:

      (1)不能返回局部變數的引用。

主要原因是局部變數會在函數返回後被銷毀,因此被返回的引用就成為了"無所指"的引用,程式會進入未知狀態。

      (2)不能返回函數內部new分配的記憶體的引用。

雖然不存在局部變數的被動銷毀問題,可對於這種情況(返回函數內部new分配記憶體的引用),又面臨其它尷尬局面。例如,被函數返回的引用只是作為一個臨時變數出現,而沒有被賦予一個實際的變數,那麼這個引用所指向的空間(由new分配)就無法釋放,造成記憶體泄露。

      (3)可以返回類成員的引用,但最好是const。

      (4)流操作符重載傳回值申明為“引用”的作用:

      流操作符<<和>>,這兩個操作符常常希望被連續使用,例如:cout << "hello" << endl;

      因此這兩個操作符的傳回值應該是一個仍然支援這兩個操作符的流引用。

      (5)在另外的一些操作符中,卻千萬不能返回引用:+-*/ 四則運算子。它們不能返回引用。 主要原因是這四個操作符沒有side effect,因此,它們必須構造一個對象作為傳回值,可選的方案包括:返回一個對象、返回一個局部變數的引用,返回一個new分配的對象的引用、返回一個靜態對象引用。

 

18.談談對於關聯、彙總(Aggregation)以及組合(Composition)的認識

      涉及到UML中的一些概念:

      關聯是表示兩個類的一般性聯絡,比如“學生”和“老師”就是一種關聯關係;

      彙總表示has-a的關係,是一種相對鬆散的關係,彙總類不需要對被彙總類負責,用空的菱形表示彙總關係:從實現的角度講,彙總可以表示為: 

            class A {...}  class B { A* a; .....} 

      組合表示contains-a的關係,關聯性強於彙總:組合類別與被組合類別有相同的生命週期,組合類別要對被組合類別負責,採用實心的菱形表示組合關係:實現的形式是: 

            class A{...} class B{ A a; ...} 

 

19.當一個類C 中沒有任何成員變數與成員函數,這時sizeof(C)的值是多少。如果不是零,請解釋一下編譯器為什麼沒有讓它為零。

      一個空類對象的大小是1byte。這是被編譯器安插進去的一個位元組,這樣就使得這個空類的兩個執行個體得以在記憶體中配置獨一無二的地址。

20.用變數a給出下面的定義

a) 一個整型數(An integer)

b) 一個指向整型數的指標(A pointer to an integer)

c) 一個指向指標的的指標,它指向的指標是指向一個整型數(A pointer to a pointer to an 

integer)

d) 一個有10個整型數的數組(An array of 10 integers) 

e) 一個有10個指標的數組,該指標是指向一個整型數的(An array of 10 pointers to integers)

f) 一個指向有10個整型數數組的指標(A pointer to an array of 10 integers)

g) 一個指向函數的指標,該函數有一個整型參數並返回一個整型數(A pointer to a function 

that takes an integer as an argument and returns an integer)

h) 一個有10個指標的數組,該指標指向一個函數,該函數有一個整型參數並返回一個整型

數( An array of ten pointers to functions that take an integer argument and return an integer )

非常非常經典的一道題,很多筆試面試題是從上述a-h中的一個或者幾個,答案如下:

a) int a; // An integer 

b) int *a; // A pointer to an integer 

c) int **a; // A pointer to a pointer to an integer 

d) int a[10]; // An array of 10 integers 

e) int *a[10]; // An array of 10 pointers to integers 

f) int (*a)[10]; // A pointer to an array of 10 integers 

g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer 

h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return 

an integer 

 

21.成員函數通過什麼來區分不同對象的成員資料?為什麼它能夠區分?

      通過this指標來區分的, 因為它指向的是對象的首地址。

 

22.拷貝建構函式在哪幾種情況下會被調用?

      1).當類的一個對象去初始化該類的另一個對象時;

      2).如果函數的形參是類的對象,調用函數進行形參和實參結合時;

      3).如果函數的傳回值是類對象,函數調用完成返回時。

 

23. 流運算子為什麼不能通過類的成員函數重載?一般怎麼解決?

      因為通過類的成員函數重載必須是運算子的第一個是自己,而對流運算的重載要求第一個參數是流對象。一般通過友元來解決。

 

24. 虛擬函數與普通成員函數的區別?內嵌函式和建構函式能否為虛擬函數?

區別:虛擬函數有virtual關鍵字,有虛擬指標和虛函數表,虛擬指標就是虛擬函數的介面,而普通成員函數沒有。內嵌函式和建構函式不能為虛擬函數。

 

c++

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.