1. 程式人生 > >C/C++知識點之C/C++經典面試題一

C/C++知識點之C/C++經典面試題一

本文主要向大家介紹了 C/C++知識點之C/C++經典面試題一,通過具體的內容向大家展示,希望對大家學習C/C++知識點有所幫助。

1.變數的宣告和定義有什麼區別?
常量:在程式執行過程中,不會發生改變的量,不能被改變的量 變數:在程式執行過程中,可以被改變的量 定義變數的方式:資料型別 變數名 = 常量; int num = 10;//定義(分配儲存空間,初始化值為常量) int num;//定義性宣告defining declaration(分配儲存空間,分配垃圾值) extern int num;//引用性宣告referncing declaration,(不分配儲存空間,不分配垃圾值)不限於本檔案使用。 變數的定義用於為變數分配儲存空間,還可以為變數指定初始值。在一個程式中,變數有且僅有一個定義 一般的情況下我們常常這樣敘述,把建立空間的宣告稱之為“定義”,而把不需要建立儲存空間的宣告稱之為“宣告”。很明顯我們在這裡指的宣告是範圍比較窄的,即狹義上的宣告,也就是說非定義性質的宣告 函式宣告時,編譯器不給函式分配入口地址 函式定義時,函式程式碼段會被放到程式碼塊中,這時候就算給函式分配儲存空間了,函式名對映函式的入口地址。 宣告的最終目的是為了提前使用,即在定義之前使用,如果不需要提前使用就沒有單獨宣告的必要,變數是如此,函式也是如此,所以宣告不會分配儲存空間,只有定義時才會分配儲存空間 2.寫出 bool int float 指標變數與零值比較的if語句 Bool型資料 If(flag) If(!flag) Int型資料: if(0!=flag) If(0flag) 指標型資料: if(NULL

flag) If(NUJLL!=flag) Float 型資料: Define NORM 0.00001; if(flag>=-NORM && flag<=NORM) 注意:應特別注意在int,指標型變數和零值比較的時候,把零值放在左邊,這樣當把誤寫成=時,編譯器可以報錯,否則這樣邏輯錯誤不容易發現,並且可能導致很嚴重的後果。 3.sizeof和strlen的區別 sizeof和strlen有一下區別: sizeof是一個操作符,strlen是庫函式 sizeof的引數可以使資料的型別,也可以是變數,而strlen只能是以‘\0’為結尾的字串作引數。 編譯器編譯是就計算出了sizeof的結果,而strlen函式必須在執行是才能計算出來。並且sizeof計算的是資料型別佔記憶體的大小,而strlen計算的是字串實際的長度 陣列做sizeof的引數不退化,傳遞strlen就退化成為指標了。 注意:有些操作符看起來像是函式,而有些函式名看起來又像操作符,這類容易混淆的名稱一定要加以區分,否則遇到陣列名這類特殊資料型別做引數時就很容易出錯。最容易混淆為函式的操作符就是sizeof。 4.C語言的關鍵字static和c++的關鍵字static有什麼區別 在c中static用來修飾區域性靜態變數和外部靜態變數,函式。而c++中除了上述功能外,還用來定義類的成員變數和函式,即靜態成員變數和靜態成員函式 注意:程式設計時static的記憶性,和全域性性的特點可以讓在不同時期呼叫的函式進行通訊,傳遞資訊,而c++的靜態成員則可以在多個物件例項間進行通訊,傳遞資訊。 5.c中的malloc和c++中的new有什麼區別 Malloc和new有一下不同: new,delete是操作符,可以過載,只能在c++中使用 Malloc,free是函式,可以覆蓋,c,c++中都可以使用 New可以呼叫物件的建構函式,對應的delete呼叫相應的解構函式 Malloc僅僅分配記憶體,free僅僅回收記憶體,並不執行建構函式和解構函式 New delete返回的是某種資料型別指標,malloc free返回的是void指標 注意:malloc申請的記憶體空間要用free釋放,而new申請的記憶體空間要用delete釋放,不要混淆,因為兩者實現的機理不同 6.寫一個標準的巨集MIN #define min(a,b)((a)<=(b)?(a):(b)) 注意:在呼叫時一定要注意這個巨集定義的副作用,如下呼叫 (++*p)<(x)?(++*p):(x) P指標就自加了兩次,違背了MIN的本意。 7.一個指標可以使volatile嗎 volatile用在如下的幾個地方: 1、中斷服務程式中修改的供其它程式檢測的變數需要加volatile; 2、多工環境下各任務間共享的標誌應該加volatile; 3、儲存器對映的硬體暫存器通常也要加volatile說明,因為每次對它的讀寫都可能由不同意義; 8.a和&a有什麼區別 請寫出以下程式碼的列印結果,主要目的是考察a和&a的區別 #include Void main() { Int a[5]={1,2,3,4,5}; Int ptr=(int )(&a+1); Printf(“%d,%d”,(a+1),
(ptr-1)); Return ; } 輸出結果:2,5 注意:陣列名a可以作陣列的首地址,而&a是陣列的指標。 思考,將原式的int
ptr=(int *)(&a+1); 該為int *ptr=(int *)(a+1)時輸出的結果將是什麼呢 9簡述C,C++程式編譯的記憶體分配情況 (1)從靜態儲存區域分配: 記憶體在程式編譯時就已經分配好,這塊記憶體在程式的整個執行期間都存在,速度快,不容出錯,因為有系統會善後,例如,全域性變數,static變數等 (2)在棧上分配: 在執行函式時,函式內區域性變數的儲存單元都在棧上建立,函式在執行結束時這些儲存單元自動被釋放,棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。 (3)從堆上分配: 即動態記憶體分配,程式在執行的時候用malloc或new申請任意大小的記憶體,程式設計師自己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由程式設計師決定,使用非常靈活,如果在堆上分配了空間,就有責任回收它,否則執行的程式會出現記憶體洩露,另外頻繁地分配和釋放不同大小的堆空間將會產生堆內碎片。 一個C,C++程式編譯時記憶體分為5大儲存區:堆區,棧區,全域性區,文字常量區,程式程式碼區 10簡述strcpy,sprintf與memecpy的區別 三者主要有以下不同之處 (1) 操作物件不同:strcpy的兩個操作物件均為字串,sprintf的操作物件可以是多種資料型別,目的操作物件是字串,memcpy的兩個物件是兩個任意可操作的記憶體地址,並不限於何種資料型別。 (2) 執行功能不同:strcpy主要實現字串變數間的拷貝,sprintf主要實現其他資料型別格式到字串型別的轉化,memcpy主要是記憶體塊間的拷貝 (3) 執行效率不同:memcpy最高,sprintf最低 說明:strcpy,sprintf,memcpy都可以實現拷貝的功能,但是針對的物件不同,根據實際需求,來選擇合適的函式實現拷貝功能 11.設定地址為ox67a9的整形變數的值為oxaa66 int *ptr; Ptr=(int )ox67a9; Ptr=oxaa66; 說明:這道題就是強制型別轉換的典型例子,無論在什麼平臺地址長度和整型資料的長度是一樣的,即一個整型資料可以強制轉換成地址指標型別,只要有意義即可。 12.面向物件的三大特徵 面向物件的三大特徵是封裝性,繼承性,多型性。 13.C++的空類有哪些成員函式 (1)預設的建構函式 (2)預設的拷貝建構函式 (3)預設的解構函式 (4)預設的賦值運算子 (5)預設取址運算子 (6)預設取址運算子const 注意:有些書上只是簡單的介紹了前四個函式,沒有提及後面兩個函式,但後兩個函式也是空類的預設函式。另外西藥注意的是,只有當實際使用這些函式的時候,編譯器才會定義他們。 14.談談你對拷貝建構函式和賦值運算子的認識 拷貝建構函式和複製運算子過載有以下兩個不同之處: (1)拷貝建構函式生成新的類物件,而賦值運算不能 (2)由於拷貝 建構函式是直接構造一個新的類物件,所以在初始化這個物件之前不用檢驗源物件是否和新建物件相同,而賦值運算子則需要這個操作,另外賦值運算子中如果原來的物件中記憶體非配要先把記憶體釋放掉 注意:當類中 有指標型別的成員變數時,一定要重寫拷貝建構函式和賦值運算子,不要使用預設的。 15.簡述類成員函式的重寫,過載和隱藏的區別 (1) 重寫和過載主要有以下幾點不同: 範圍區別:被重寫的和重寫的函式在兩個類中,而過載和被過載的函式在同一個類中 引數的區別:被重寫的函式和重寫的函式的引數列表一定相同,而被過載函式和過載函式的引數列表一定不同 Virtual的區別:重寫的基類中被重寫的函式必須要有virtual修飾,而過載函式和被過載函式可以被virtual修飾,也可以沒有。 (2)隱藏和重寫,過載有以下幾點不同: 與過載的範圍不同,和重寫一樣,隱藏函式和被隱藏函式不在同一個類中 引數的區別:隱藏函式和被隱藏的函式的引數列表可以相同,也可以不同,但是函式名肯定要相同。當引數不相同是,無論基類中的引數是否被virtual修飾,基類的函式都是被隱藏,而不是被重寫。 說明:雖然過載和覆蓋都是實現多型的基礎,但是兩者實現的技術完全不同,達到的目的也是完全不同的,覆蓋是動態繫結的多型,而過載是靜態繫結的多型 16.簡述多型實現的原理 編譯器發現一個類中有虛擬函式,便會立即為此類生成虛擬函式表vtable,虛擬函式表的各表項為指向對應虛擬函式的指標,編譯器還會在此類中隱含插入一個指標vptr(對vc編譯器來說,它插在類中的第一個位置上)指向虛擬函式表,呼叫此類的建構函式時,編譯器會隱含執行vptr與vtable的關聯程式碼,將vptr指向對應的vtable,將類與此類的vtable聯絡起來,另外在呼叫類的建構函式時,指向基類的指標此時已經變成指向具體的類的this指標,這樣依靠此this指標即可得到正確的vtable,如此才能真正與函式體進行連線,這就是動態聯編,實現多型的基本原理。 注意:一定要區分虛擬函式,純虛擬函式,虛擬繼承的關係和區別。牢記虛擬函式實現原理,因為多型C++面試的重要考點之一,而虛擬函式是實現多型的基礎。 17.連結串列和陣列有什麼區別 陣列和連結串列有以下幾點不同: (1)儲存形式:陣列是一塊連續的空間,宣告時就要確定長度,連結串列是一塊不連續的動態空間,長度可變,每個結點要儲存相鄰結點的指標。 (2)資料查詢:陣列的線性查詢速度快,查詢操作直接使用偏移地址,連結串列需要按順序檢索結點,效率低 (3)資料插入和刪除:連結串列可以快速插入和刪除結點,而陣列則可能需要大量資料移動。 (4)越界問題:連結串列不存在越界問題,陣列有越界問題 說明:在選擇陣列或連結串列資料結構時,一定要根據實際需要進行選擇,陣列便於查詢,連結串列便於插入和刪除,陣列節省空間但長度固定,連結串列雖然變長但是佔了更多的儲存空間 18.怎麼把一個單鏈表反序 一、反轉單鏈表之迴圈演算法 1. 連結串列有兩種: 帶頭結點的:頭結點儲存長度資訊,頭結點的next指向第一個實際節點; 不帶頭結點的,頭結點即第一個節點; 這裡使用帶頭結點的連結串列; 2. 需要三個指標,記錄當前節點(反轉用)、前一個節點、後一個節點(反轉之後前進用)。 程式碼如下: /
連結串列 1.帶頭結點的:head裡面存放連結串列長度(或其他資訊),head->next指向第一個實際節點; 2.不帶頭結點的:head即第一個實際節點
/ typedef struct Node{ int data; Node * next;}; void reverseList(Node *head){ if ((head
NULL)||((head->next)NULL)) return ; //如果head為空,或者頭結點指向空節點(連結串列長度為0),則退出。 Node *pre,*cur,*next; //cur 記錄當前位置,pre記錄上一個位置,為cur->next的值;next記錄下一個位置,反轉後cur不等於cur->next cur=head->next; pre=NULL; //逆轉之後,頭結點變為尾節點,其next為Null while (cur!=NULL) { next=cur->next; //反轉後不能再用cur->next,所以先記錄下這個節點 cur->next=pre; pre=cur; cur=next; } head->next=pre; //cur已經為空,所以pre為尾節點。head->next指向它。 return ;} 二、反轉單鏈表之遞迴演算法 程式碼如下: List *reverse( List *oldList, List *newHead = NULL ){ List *next = oldList-> next; //記錄上次翻轉後的連結串列 oldList-> next = newHead; //將當前結點插入到翻轉後連結串列的開頭 newHead = oldList; //遞迴處理剩餘的連結串列 return ( nextNULL )? newHead: reverse( t, newHead ); } 19.簡述佇列和棧的異同 佇列和棧都是線性儲存結構,但是兩者的插入和刪除資料的操作不同,佇列是先進先出,棧是後進先出 注意:區別棧區和堆區,堆區的存取是順序隨意,而棧區是後進先出,棧由編譯器自動分配,存放函式的引數值,區域性變數的值等,其操作方式類似資料結構中的棧,堆一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os回收,分配方式類似於連結串列 它與本題的的堆和棧是兩回事,堆疊只是一種資料結構,而堆區和棧區是程式中的不同記憶體儲存區域。