C++筆面試題

1、.h頭文件中的ifndef/define/endif的作用?

       防止該頭文件被重複引用。

2、#include<file.h>與#incude“file.h”的區別?

     #include<file.h>:編譯器從標準庫路徑開始搜索和引用file.h;

     #include“file.h”:編譯器從當前工作路徑搜索並引用file.h;

3、在C++程序中調用被C編譯器編譯後的函數,爲什麼要加extern "C"?

      由於C++支持函數重載,C語言不支持函數重載,函數被C++編譯後在庫中的名字與C語言不同。假設某個函數的原型爲 void foo(int x,int y);該函數被C編譯器編譯後在庫中的名字爲_foo,而C++編譯器則會產生像_foo_int_int之類的名字。C++提供了C連接交換指定符號extern "C"來解決名字匹配問題。

     extern "C"的主要作用就是爲了能夠正確實現C++代碼調用其他C語言代碼。加上extern "C"後,會指示編譯器這部分代碼按C語言的進行編譯,而不是C++的。由於C++支持函數重載,因此編譯器編譯函數的過程中會將函數的參數類型也加到編譯後的代碼中,而不僅僅是函數名;而C語言並不支持函數重載,因此編譯C語言代碼的函數時不會帶上函數的參數類型,一般之包括函數名。這個功能十分有用處,因爲在C++出現以前,很多代碼都是C語言寫的,而且很底層的庫也是C語言寫的,爲了更好的支持原來的C代碼和已經寫好的C語言庫,需要在C++中儘可能的支持C,而extern "C"就是其中的一個策略。  這個功能主要用在下面的情況:  1、C++代碼調用C語言代碼  2、在C++的頭文件中使用  3、在多個人協同開發時,可能有的人比較擅長C語言,而有的人擅長C++,這樣的情況下也會有用到。

4、面向對象的三個基本特徵,並簡單敘述之?  

(1)封裝:將客觀事物抽象成類,每個類對自身的數據和方法實行protection(private, protected,public)  

(2)繼承:廣義的繼承有三種實現形式:實現繼承(指使用基類的屬性和方法而無需額外編碼的能力)、可視繼承(子窗體使用父窗體的外觀和實現代碼)、接口繼承(僅使用屬性和方法,實現滯後到子類實現)。前兩種(類繼承)和後一種(對象組合=>接口繼承以及純虛函數)構成了功能複用的兩種方式。  

(3)多態 :系統能夠在運行時,能夠根據其類型確定調用哪個重載的成員函數的能力,稱爲多態性。(見:C++中類的多態與虛函數的使用)

5、引用與指針有什麼區別?  

 1) 引用必須被初始化,指針不必。  2) 引用初始化以後不能被改變,指針可以改變所指的對象。  3) 不存在指向空值的引用,但是存在指向空值的指針。

6、描述實時系統的基本特性?

    在特定的時間完成特定的任務,實時性與可靠性。

7、全局變量與局部變量是否有區別,如果有,什麼區別?

   全局變量儲存在靜態數據區,局部變量存儲在堆棧中。

8、堆棧溢出一般是由什麼原因導致的?

     沒有回收垃圾資源

9、什麼函數不能聲明爲虛函數?

     構造函數

10、IP地址的編碼分爲哪兩部分?

     IP地址由兩部分組成,網絡號和主機號

11、不能做switch()的參數類型的是:

      switch()的參數類型不能爲實型。

12、對於一個頻繁使用的短小函數,在C語言中應用什麼實現?在C++中應用什麼實現?

     在C語言中,用宏定義;在C++中用inine 。

13、C++是不是類型安全的?

     不是類型安全的,兩個不同類型的指針之間可以強制轉換。

14、指針和數組的區別?

    數組要麼在靜態存儲區被創建(如全局數組),要麼在棧上被創建。指針可以隨時指向任意類型的內存塊。

15、內存的分配方式?

     分配方式有三種:(1)靜態存儲區,是在程序編譯時就已經分配好的,在整個程序運行期間都存在,如全局變量和常量。(2)棧上分配,函數內的局部變量就是從這分配的,但是分配的內存有限。(3)堆上分配:也稱動態分配,如我們用的new 和malloc分配內存,delete和free釋放內存。

16、C++中值的傳遞方式:

     值傳遞、指針傳遞、引用傳遞

19、數組在做函數實參時會變成什麼類型?

     會變成指針類型

20、在Win32下,char、int、float以及double各佔幾個字節?

      char :1個字節

      int:4個字節

     float :4個字節

     double: 8個字節

21、簡述debug和release版本的區別?

     debug是調試版本,release是發佈給用戶的最終非調試版本。

22、class和struct的區別?

    struct的成員默認是公有的。而類的成員默認是私有的。

23、當一個類A中沒有任何成員變量和成員函數時,這是sizeof(A)的值是多少?並解釋編譯器爲什麼沒有讓它爲0?

  此時sizeof(A)=1;舉個反例:如果是0的話,聲明一個class A[10]對象數組,而每一個對象佔用的空間爲0,這時就沒有辦法區分A[0],A[1]......了

24、請寫出BOOL flag與“零值”比較的if語句。

    if(flag)或者if(!flag)

25、請寫出float x與int  y與“零值”比較的if語句。

  float:   const float EPSINON=0.000001;

    if((x>=-EPSINON)&&(x<=EPSINON))

  int:  if(y==0)

26、請寫出char *p與“零值”比較的if語句。

    if(p==NULL)

    if(p!=NULL)

27、以下爲Windows下的32位C++應用程序,請計算sizeof的值。

      先對sizeof作一下簡要的說明:

(1)sizeof不是一個函數 只是一個操作符,像new和delete一樣。
(2)char *s是一個指針,所以sizeof(s)的結果是s指針本身所佔用的真實空間4個字節。strlen(s)纔是求s指向的字符串的長度。
(3)若操作數具有類型char、unsigned char或signed char時,結果爲1。
(4)當sizeof作用於一個class 、struct時,返回這些類型對象所佔字節數。當一個類A中沒有任何數據成員和成員函數時,sizeof(A)=1;

(5)char a[100];對於32位程序,sizeof(a)=4;對於64位程序,sizeof(a)=8;而不是100;

  test sizeof代碼如下:

  #include<iostream>
 using namespace std;
 int main()
 {
char str[]="hello";
char *p=str;
int i=100;
float f=0.4;
double d=4.21;
cout<<"sizeof(str)="<<sizeof(str)<<endl;
cout<<"sizeof(p)="<<sizeof(p)<<endl;
cout<<"strlen(p)="<<strlen(p)<<endl;
cout<<"sizeof(i)="<<sizeof(i)<<endl;
cout<<"sizeof(f)="<<sizeof(f)<<endl;
cout<<"sizeof(d)="<<sizeof(d)<<endl;
cout<<"str[0]="<<str[0]<<endl;
cout<<"sizeof(str[0])="<<sizeof(str[0])<<endl;
void *p1=malloc(100);
cout<<"sizeof(p1)="<<sizeof(p1)<<endl;
 }

結果如下:


若將上面的代碼更改爲64位C++代碼,結果如下:


sizeof(p)和sizeof(p1)由32位下的4變成了8。

28、const有什麼用途?(至少寫兩種)

   (1)可以定義const常量。

    (2)可以修飾函數的參數、返回值、甚至函數的定義體,被const修飾的東西都受到強制保護,可以預防意外的變動,能提高程序的健壯性。

29、編寫類String的構造函數、析構函數和賦值函數。   

       已知類String的原型爲:

      class String
     {

        public:
                String(const char *str=NULL);//普通構造函數
                String(const String & other);//拷貝構造函數
                ~String(void);
               String &operator=(const String &other);//賦值函數
       private:
              char *m_data;
   };

詳見如下示例代碼:

#include<iostream>
using namespace std;
//
char *STRCPY(char *strDest,const char *strSrc)
{
_ASSERT((strDest!=NULL)&&(strSrc!=NULL));
char *address=strDest;
while((*strDest++=*strSrc++)!='\0')//'\0'是終止符,當編譯器看到它,就會認爲字符串已結束了。
NULL;
       return address;
}
class String
{
public:
String(const char *str=NULL);//普通構造函數
    String(const String & other);//拷貝構造函數
~String(void);//析構函數
String &operator=(const String &other);//賦值函數
private:
char *m_data;

};
String::String(const char *str)
{
cout<<"Constructing"<<endl;
if(str==NULL)
{
m_data=new char[1];
*m_data='\0';
}
else
{
m_data=new char[strlen(str)+1];
STRCPY(m_data,str);
}
}
String::String(const String & other)
{
cout<<"Constructing copy"<<endl;
m_data=new char[strlen(other.m_data)+1];
STRCPY(m_data,other.m_data);
}
String &String::operator=(const String &other)
{
cout<<"Operate = Function"<<endl;
if(this==&other)//如果對象與other是同一個對象,直接返回本身
{
return *this;
}
delete[]m_data;
m_data=new char[strlen(other.m_data)+1];
STRCPY(m_data,other.m_data);
return *this;
}
String::~String(void)
{
cout<<"Destructing"<<endl;
if(m_data!=NULL) //如果m_data不爲NULL,釋放堆內存
{
delete []m_data;
m_data=NULL;
}
}
int main()
{
String obj1("hello");//調用普通構造函數
String obj2("world");//調用普通構造函數
String obj3(obj1);
obj3=obj2;
return 0;
}

結果如下:


30、簡述以下兩個for循環的優缺點。

(1)

for(int i=0;i<N;i++)

{

   if(condition)

         DoSomething();

   else

         DoOtherThing();

}

(2)

if(condition)

{

        for(int i=0;i<N;i++)

              DoSomething();

}

else

{

        for(int i=0;i<N;i++)

            DoOtherThing();

}

(1)優點:程序簡潔;

      缺點:比(2)多執行了N-1次邏輯判斷,並且打斷了循環“流水線”作業,使得編譯器不能對循環進行優化處理,降低了程序的效率。

(2) 優點:循環效率高

      缺點:程序不簡潔

31、編寫strcpy函數。

       已知strcpy函數的原型爲char *strcpy(char *strDest,const char *strSrc); 其中strDest爲目的字符串,strSrc爲源字符串。

       (1)不調用C/C++的字符串庫函數,請編寫strcpy,詳見29中的STRCPY函數。

       (2)strcpy能把strSrc的內容複製到strDest,爲什麼還要char *類型的返回值?

           爲了實現鏈式表達式

例如:int length=strlen(strcpy(strDest,"hello world"));

31、CMemoryState的主要功能是什麼?

       查看內存使用情況,解決內存泄漏問題。

32、處理器標識#error的目的是什麼?

       編譯器輸出一條錯誤信息,並終止繼續編譯。

33、在定義一個宏的時候應注意些什麼?

       定義部分的每個形參和整個表達式都必須用括號括起來,以避免不可預料的事情發生。

34、系統會自動打開和關閉的三個標準文件是什麼?

      標準輸入--鍵盤--stdin

      標準輸出--顯示器--stdout

     標準錯誤輸出--顯示器-stderr

35、static有什麼用途?

      (1)在函數體內,一個被聲明爲靜態的變量在函數被調用的過程中維持其值不變;

       (2)在模塊內(但在函數體外),一個被聲明爲靜態的變量可以被模塊內所有函數調用,但不能被模塊外的函數所調用。

       (3)在模塊內,一個被聲明爲靜態的函數只可被該模塊內的其他函數調用,也就是該函數被限制在聲明它的模塊內的本地範圍內使用。


           

 




   


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章