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(0==flag)

 

指針型數據:
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<stdlo.h>

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 ( next==NULL )? newHead: reverse( t, newHead ); 
}

 

19.簡述隊列和棧的異同

隊列和棧都是線性存儲結構,但是兩者的插入和刪除數據的操作不同,隊列是先進先出,棧是后進先出

注意:區別棧區和堆區,堆區的存取是順序隨意,而棧區是后進先出,棧由編譯器自動分配,存放函數的參數值,局部變量的值等,其操作方式類似數據結構中的棧,堆一般由程序員分配釋放,若程序員不釋放,程序結束時可能由os回收,分配方式類似於鏈表

它與本題的的堆和棧是兩回事,堆棧只是一種數據結構,而堆區和棧區是程序中的不同內存存儲區域。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM