C/C++ 筆試、面試題目彙總 - 程式人生

文章推薦指數: 80 %
投票人數:10人

C++的基礎知識,筆試面試必備. 1.求下面函式的返回值( 微軟). 複製程式碼 . int func(x) { int countx = 0 ; while (x) 程式人生>>C/C++筆試、面試題目彙總 C/C++筆試、面試題目彙總 阿新••發佈:2019-01-05 C++的基礎知識,筆試面試必備   1.求下面函式的返回值(微軟) . int  func(x) {  int  countx  = 0 ;  while (x) { countx  ++ ; x  =  x & (x - 1 ); }  return  countx; } 假定x=9999。

答案:8 思路:將x轉化為2進位制,看含有的1的個數。

  2. 什麼是“引用”?申明和使用“引用”要注意哪些問題? 答:引用就是某個目標變數的“別名”(alias),對應用的操作與對變數直接操作效果完全相同。

申明一個引用的時候,切記要對其進行初始化。

引用宣告完畢後,相當於目標變數名有兩個名稱,即該目標原名稱和引用名,不能再把該引用名作為其他變數名的別名。

宣告一個引用,不是新定義了一個變數,它只表示該引用名是目標變數名的一個別名,它本身不是一種資料型別,因此引用本身不佔儲存單元,系統也不給引用分配儲存單元。

不能建立陣列的引用。

  3. 將“引用”作為函式引數有哪些特點? (1)傳遞引用給函式與傳遞指標的效果是一樣的。

這時,被調函式的形參就成為原來主調函式中的實參變數或物件的一個別名來使用,所以在被調函式中對形參變數的操作就是對其相應的目標物件(在主調函式中)的操作。

(2)使用引用傳遞函式的引數,在記憶體中並沒有產生實參的副本,它是直接對實參操作;而使用一般變數傳遞函式的引數,當發生函式呼叫時,需要給形參分配儲存單元,形參變數是實參變數的副本;如果傳遞的是物件,還將呼叫拷貝建構函式。

因此,當引數傳遞的資料較大時,用引用比用一般變數傳遞引數的效率和所佔空間都好。

(3)使用指標作為函式的引數雖然也能達到與使用引用的效果,但是,在被調函式中同樣要給形參分配儲存單元,且需要重複使用"*指標變數名"的形式進行運算,這很容易產生錯誤且程式的閱讀性較差;另一方面,在主調函式的呼叫點處,必須用變數的地址作為實參。

而引用更容易使用,更清晰。

4. 在什麼時候需要使用“常引用”?  如果既要利用引用提高程式的效率,又要保護傳遞給函式的資料不在函式中被改變,就應使用常引用。

常引用宣告方式:const 型別識別符號&引用名=目標變數名; 例1 int  a; const int & ra  =  a;ra  =  1 ;  //  錯誤 a  =  1 ;  //  正確   例2 string  foo(); void  bar( string &s) //  那麼下面的表示式將是非法的: bar(foo());bar( " helloworld " ); 原因在於foo()和"helloworld"串都會產生一個臨時物件,而在C++中,這些臨時物件都是const型別的。

因此上面的表示式就是試圖將一個const型別的物件轉換為非const型別,這是非法的。

引用型引數應該在能被定義為const的情況下,儘量定義為const。

  5.將“引用”作為函式返回值型別的格式、好處和需要遵守的規則? 格式: 型別識別符號  & 函式名(形參列表及型別說明){    // 函式體 } 好處:在記憶體中不產生被返回值的副本;(注意:正是因為這點原因,所以返回一個區域性變數的引用是不可取的。

因為隨著該區域性變數生存期的結束,相應的引用也會失效,產生runtimeerror! 注意: (1)不能返回區域性變數的引用。

這條可以參照EffectiveC++[1]的Item31。

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

(2)不能返回函式內部new分配的記憶體的引用(這個要注意啦,很多人沒意識到,哈哈。





)。

這條可以參照EffectiveC++[1]的Item31。

雖然不存在區域性變數的被動銷燬問題,可對於這種情況(返回函式內部new分配記憶體的引用),又面臨其它尷尬局面。

例如,被函式返回的引用只是作為一個臨時變量出現,而沒有被賦予一個實際的變數,那麼這個引用所指向的空間(由new分配)就無法釋放,造成memoryleak。

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

這條原則可以參照EffectiveC++[1]的Item30。

主要原因是當物件的屬性是與某種業務規則(businessrule)相關聯的時候,其賦值常常與某些其它屬性或者物件的狀態有關,因此有必要將賦值操作封裝在一個業務規則當中。

如果其它物件可以獲得該屬性的非常量引用(或指標),那麼對該屬性的單純賦值就會破壞業務規則的完整性。

(4)流操作符過載返回值申明為“引用”的作用: 流操作符<>,這兩個操作符常常希望被連續使用,例如:cout< int & put( int  n); int  vals[ 10 ]; int  error  =- 1 ; void  main(){  put( 0 )  =  10 ;  //  以put(0)函式值作為左值,等價於vals[0]=10;   put( 9 )  =  20 ;  //  以put(9)函式值作為左值,等價於vals[9]=20;   cout  <= 0 &&  n <= 9  )    {       return  vals[n];      }   else     {     cout  <>、賦值操作符=的返回值、拷貝建構函式的引數、賦值操作符=的引數、其它情況都推薦使用引用。

  9. 結構與聯合有和區別?1.結構和聯合都是由多個不同的資料型別成員組成,但在任何同一時刻,聯合中只存放了一個被選中的成員(所有成員共用一塊地址空間),而結構的所有成員都存在(不同成員的存放地址不同)。

 2.對於聯合的不同成員賦值,將會對其它成員重寫, 原來成員的值就不存在了,而對於結構的不同成員賦值是互不影響的。

  10. 下面關於“聯合”的題目的輸出? a) #include  < stdio.h > union{   int  i;   char  x[ 2 ];}a; void  main(){  a.x[ 0 ]  = 10 ;   a.x[ 1 ]  = 1 ;  printf( " %d " ,a.i);} 答案:266(低位低地址,高位高地址,記憶體佔用情況是Ox010A)   b) main() { union{  /* 定義一個聯合 */   int  i;  struct {  /* 在聯合中定義一個結構 */   char  first;  char  second; }half; }number; number.i = 0x4241 ;  /* 聯合成員賦值 */  printf( " %c%c\n " ,number.half.first,mumber.half.second); number.half.first = ' a ' ;  /* 聯合中結構成員賦值 */  number.half.second = ' b ' ; printf( " %x\n " ,number.i); getch(); } 答案:AB  (0x41對應'A',是低位;Ox42對應'B',是高位)        6261(number.i和number.half共用一塊地址空間)   11. 已知strcpy的函式原型:char*strcpy(char*strDest,constchar*strSrc)其中strDest是目的字串,strSrc是源字串。

不呼叫C++/C的字串庫函式,請編寫函式strcpy。

答案: /* 編寫strcpy函式(10分)已知strcpy函式的原型是char*strcpy(char*strDest,constchar*strSrc);其中strDest是目的字串,strSrc是源字串。

(1)不呼叫C++/C的字串庫函式,請編寫函式strcpy(2)strcpy能把strSrc的內容複製到strDest,為什麼還要char*型別的返回值?答:為了實現鏈式表示式。

//2分例如intlength=strlen(strcpy(strDest,“helloworld”)); */ #include  < assert.h > #include  < stdio.h > char * strcpy( char * strDest,  const char * strSrc){assert((strDest != NULL)  &&  (strSrc  != NULL));  //  2分 char *  address  =  strDest;   //  2分 while (( * strDest ++ = * strSrc ++ )  != ' \0 '  )        //  2分 NULL;  return  address;    //  2分 }   另外strlen函式如下:   #include < stdio.h > #include < assert.h >   int  strlen(  const char * str)  //  輸入引數const {assert(str  !=  NULL);  //  斷言字串地址非0 int  len=0; while (( * str ++ )  != ' \0 '  ) { len ++ ; }  return  len;}       12.已知String類定義如下:                 class  String{ public :  String(constchar  * str  =  NULL);  //  通用建構函式   String(constString  & another);  //  拷貝建構函式   ~ String();  //  解構函式   String &  operater  = ( const  String  & rhs);  //  賦值函式 private :   char *  m_data;  //  用於儲存字串 };       嘗試寫出類的成員函式實現。

答案: String::String( const char * str){ if  (str  ==  NULL)  //  strlen在引數為NULL時會拋異常才會有這步判斷 {m_data  = new char [ 1 ];m_data[ 0 ]  = ' \0 '  ;} else {m_data  = new char [strlen(str)  + 1 ];strcpy(m_data,str);}} String::String( const  String  & another){m_data  = new char [strlen(another.m_data)  + 1 ];strcpy(m_data,other.m_data);}String &  String:: operator = ( const  String  & rhs){ if  (  this == & rhs) return * this  ;delete[]m_data;  // 刪除原來的資料,新開一塊記憶體 m_data  = new char [strlen(rhs.m_data)  + 1 ];strcpy(m_data,rhs.m_data); return * this  ;}String:: ~ String(){delete[]m_data;}   13..h標頭檔案中的ifndef/define/endif的作用? 答:防止該標頭檔案被重複引用。

  14. #include與#include"file.h"的區別? 答:前者是從StandardLibrary的路徑尋找和引用file.h,而後者是從當前工作路徑搜尋並引用file.h。

  15.在C++程式中呼叫被C編譯器編譯後的函式,為什麼要加extern“C”? 首先,作為extern是C/C++語言中表明函式和全域性變數作用範圍(可見性)的關鍵字,該關鍵字告訴編譯器,其宣告的函式和變數可以在本模組或其它模組中使用。

通常,在模組的標頭檔案中對本模組提供給其它模組引用的函式和全域性變數以關鍵字extern宣告。

例如,如果模組B欲引用該模組A中定義的全域性變數和函式時只需包含模組A的標頭檔案即可。

這樣,模組B中呼叫模組A中的函式時,在編譯階段,模組B雖然找不到該函式,但是並不會報錯;它會在連線階段中從模組A編譯生成的目的碼中找到此函式 extern"C"是連線申明(linkagedeclaration),被extern"C"修飾的變數和函式是按照C語言方式編譯和連線的,來看看C++中對類似。

  C的函式是怎樣編譯的: 作為一種面向物件的語言,C++支援函式過載,而過程式語言C則不支援。

函式被C++編譯後在符號庫中的名字與C語言的不同。

例如,假設某個函式的原型為: voidfoo(intx,inty); 該函式被C編譯器編譯後在符號庫中的名字為_foo,而C++編譯器則會產生像_foo_int_int之類的名字(不同的編譯器可能生成的名字不同,但是都採用了相同的機制,生成的新名字稱為“mangledname”)。

_foo_int_int這樣的名字包含了函式名、函式引數數量及型別資訊,C++就是靠這種機制來實現函式過載的。

例如,在C++中,函式voidfoo(intx,inty)與voidfoo(intx,floaty)編譯生成的符號是不相同的,後者為_foo_int_float。

同樣地,C++中的變數除支援區域性變數外,還支援類成員變數和全域性變數。

使用者所編寫程式的類成員變數可能與全域性變數同名,我們以"."來區分。

而本質上,編譯器在進行編譯時,與函式的處理相似,也為類中的變數取了一個獨一無二的名字,這個名字與使用者程式中同名的全域性變數名字不同。

未加extern"C"宣告時的連線方式 假設在C++中,模組A的標頭檔案如下: //  模組A標頭檔案 moduleA.h #ifndefMODULE_A_H #define  MODULE_A_H int  foo(  int  x,  int  y); #endif      在模組B中引用該函式: //  模組B實現檔案 moduleB.cpp #include  " moduleA.h " foo( 2 , 3 ); 實際上,在連線階段,聯結器會從模組A生成的目標檔案moduleA.obj中尋找_foo_int_int這樣的符號!   加extern"C"聲明後的編譯和連線方式 加extern"C"聲明後,模組A的標頭檔案變為: //  模組A標頭檔案 moduleA.h #ifndefMODULE_A_H #define  MODULE_A_H extern " C " int  foo(  int  x,  int  y); #endif   在模組B的實現檔案中仍然呼叫foo(2,3),其結果是:(1)模組A編譯生成foo的目的碼時,沒有對其名字進行特殊處理,採用了C語言的方式; (2)聯結器在為模組B的目的碼尋找foo(2,3)呼叫時,尋找的是未經修改的符號名_foo。

如果在模組A中函式聲明瞭foo為extern"C"型別,而模組B中包含的是externintfoo(intx,inty),則模組B找不到模組A中的函式;反之亦然。

所以,可以用一句話概括extern“C”這個宣告的真實目的(任何語言中的任何語法特性的誕生都不是隨意而為的,來源於真實世界的需求驅動。

我們在思考問題時,不能只停留在這個語言是怎麼做的,還要問一問它為什麼要這麼做,動機是什麼,這樣我們可以更深入地理解許多問題):實現C++與C及其它語言的混合程式設計。

   明白了C++中extern"C"的設立動機,我們下面來具體分析extern"C"通常的使用技巧: extern"C"的慣用法    (1)在C++中引用C語言中的函式和變數,在包含C語言標頭檔案(假設為cExample.h)時,需進行下列處理: extern " C " {  #include " cExample.h " } 而在C語言的標頭檔案中,對其外部函式只能指定為extern型別,C語言中不支援extern"C"宣告,在.c檔案中包含了extern"C"時會出現編譯語法錯誤。

  C++引用C函式例子工程中包含的三個檔案的原始碼如下: /*  c語言標頭檔案:cExample.h  */ #ifndefC_EXAMPLE_H #define  C_EXAMPLE_H extern int  add( int  x, inty); #endif   /*  c語言實現檔案:cExample.c  */ #include  " cExample.h " int  add(  int  x,  int  y){   return  x  +  y;}                   //  c++實現檔案,呼叫add:cppFile.cpp extern " C "  {  #include " cExample.h " } int  main( int  argc,  char *  argv[]){  add( 2 , 3 );    return 0 ;}       如果C++呼叫一個C語言編寫的.DLL時,當包括.DLL的標頭檔案或宣告介面函式時,應加extern"C"{ }。

  (2)在C中引用C++語言中的函式和變數時,C++的標頭檔案需新增extern"C",但是在C語言中不能直接引用聲明瞭extern"C"的該標頭檔案,應該僅將C檔案中將C++中定義的extern"C"函式宣告為extern型別。

C引用C++函式例子工程中包含的三個檔案的原始碼如下: // C++標頭檔案cppExample.h #ifndefCPP_EXAMPLE_H #define  CPP_EXAMPLE_H extern " C " int  add(  int  x,  int  y); #endif   // C++實現檔案cppExample.cpp #include " cppExample.h " int  add(  int  x,  int  y){   return  x  +  y;}   /*  C實現檔案cFile.c/*這樣會編譯出錯:#include"cExample.h"  */ extern int  add(  int  x,  int  y); int  main(  int  argc,  char *  argv[]){  add(  2 ,  3  );    return 0 ;}   16. 關聯、聚合(Aggregation)以及組合(Composition)的區別? 涉及到UML中的一些概念: 關聯是表示兩個類的一般性聯絡,比如“學生”和“老師”就是一種關聯關係; 聚合表示has-a的關係,是一種相對鬆散的關係,聚合類不需要對被聚合類負責,如下圖所示,用空的菱形表示聚合關係: 從實現的角度講,聚合可以表示為: classA{...} classB{A*a;.....} 組合表示contains-a的關係,關聯性強於聚合:組合類與被組合類有相同的生命週期,組合類要對被組合類負責,採用實心的菱形表示組合關係: 實現的形式是: classA{...}classB{Aa;...}   17.面向物件的三個基本特徵,並簡單敘述之? 1. 封裝:將客觀事物抽象成類,每個類對自身的資料和方法實行protection(private,protected,public) 2. 繼承:廣義的繼承有三種實現形式:實現繼承(指使用基類的屬性和方法而無需額外編碼的能力)、可視繼承(子窗體使用父窗體的外觀和實現程式碼)、介面繼承(僅使用屬性和方法,實現滯後到子類實現)。

前兩種(類繼承)和後一種(物件組合=>介面繼承以及純虛擬函式)構成了功能複用的兩種方式。

3. 多型:系統能夠在執行時,能夠根據其型別確定呼叫哪個過載的成員函式的能力,稱為多型性。

18. 過載(overload)和重寫(overried,有的書也叫做“覆蓋”)的區別? 常考的題目。

從定義上來說: C/C++筆試、面試題目彙總(續) «上一篇 有點意思的C/C++問題及解答:16-20下一篇» 相關推薦 計算機網路面試常考題目彙總 1:OSI七層模型,TCP/IP五層模型、四層模型? TCP/IP五層模型:物理層、資料鏈路層、網路層... C/C++筆試、面試題目彙總(續) 一.找錯題 試題1: void  test1(){  char string [ 10 ... C/C++筆試、面試題目彙總 C++的基礎知識,筆試面試必備   1.求下面函式的返回值(微軟) int ... LinuxC++後臺開發面試題目彙總 資料庫: 1.資料庫中什麼是事務?事務的隔離級別?... 面試題目彙總(JAVA演算法/資料結構) 1.題目:輸入一個正整數陣列,把數組裡所有數字拼接起來排成一個數,列印能拼接出的所有數字中最小的一個。

例如輸入陣列{3,32,321},則打印出這三個... Java面試2018常考題目彙總 因為最近在忙著找工作,看到了很多面試整理的文章,於是便有了自己也寫一篇,部分原創,大部分是我四處蒐集的,我想整理一份... python面試題目彙總 參考:https://www.cnblogs.com/JetpropelledSnake/p/9396511.html#_label1 1、常見的PEP8規範... Java面試2018常考題目彙總(一) 因為最近在忙著找工作,看到了很多面試整理的文章,於是便有了自己也寫一篇,部分原創,大部分是我四處蒐集的,我想整理... Java面試2018常考題目彙總(二) 1、servlet執行流程客戶端發出http請求,web伺服器將請求轉發到servlet容器,servlet容器解析url並根... 2017最新PHP經典面試題目彙總(上篇) 1、雙引號和單引號的區別 雙引號解釋變數,單引號不解釋變數 雙引號裡插入單引號,其中單引號裡如果有變數的話,變數解釋 雙引號... 搜尋 基礎教學 Mysql入門 Sql入門 Android入門 Docker入門 Go語言入門 Ruby程式入門 Python入門 Python進階 Django入門 Python爬蟲入門 最近訪問 C/C+++筆試、面試題目彙總 Bootstrap柵格系統初識 Goodbye+Wuxu+題解 mac下停止和啟動mysql命令 阻止點擊事件 tp5獲取不到get值 Android獲取可用記憶體(系統,sd卡,u盤) 再談XGBoost原理 比較一下Java+與+JavaScript pySpark讀寫CSV檔案、查重並寫入CSV檔案中



請為這篇文章評分?