C/C++語言常見面試題匯總


1、變量的聲明和定義有什么區別?

變量的定義為變量分配地址和存儲空間,變量的聲明不會分配地址,一個變量可以在多個地方聲明,但是只能在一個地方定義,加入extern關鍵字修飾的是變量的聲明,說明此變量將在文件以外或者文件后面部分定義。

說明:很多時候一個變量,只是聲明不分配內存空間,直到具體使用時才初始化,分配內存空間,如外部變量。

int main()
{
  extern int A;
  //這是個聲明而不是定義,聲明A是一個已經定義了的外部變量

  dosth();//執行函數
}

int A;  //定義A變量

 

2、請簡述#ifdef、#else、#endif、和#ifndef的作用是?

  • 利用#ifdef、#endif將某程序功能模塊包括進去,以向特定用戶提供該功能,在不需要時,用戶可以輕易將其屏蔽;
#ifdef MATH
#include "math.c"
#endif
  • 在子程序上加上標記,以便於追蹤和調試;
#ifdef DEBUG
printf("Indebugging.......!\r\n");
#endif
  • 應對硬件的限制,由於一些具體應用環境的硬件不一樣,限於條件,本地缺乏某種設備,只能繞過硬件,直接寫出預期結果。

注意:雖然不用條件編譯命令而直接用if語句也能到達要求,但是這樣做的話,目標程序長(所有的語句都需要編譯),運行時間長(在程序運行時會對if語句進行測試),采用條件編譯,可以減少被編譯的語句,減少目標程序的長度,減少程序的運行時間。

 

3、請寫出int、bool、float、指針變量與"零值"比較的if語句?

//int類型與零值比較
if (n == 0)
if (n != 0)

//bool類型與零值比較
if (flag)    //表示flag為真
if (!flag)    //表示flag為假

//float類型與零值比較
const float EPSINON = 0.00001;
if ((x >= -EPSINON) && (x <= EPSINON))    //其中EPSINON是允許的誤差

//指針變量與零值比較
if (p == NULL)
if (p != NULL)

 

4、結構體是否可以直接賦值?

聲明時可以直接初始化,同一結構體的不同對象之間也可以直接賦值,但是當結構體中含有指針成員時一定要小心。

注意:當有多個指針指向同一段內存時,某個指針釋放這段內存可能會導致其它指針的非法操作,因此在釋放前一定要確保其它指針不再使用這段內存空間。

 

5、sizeof和strlen的區別?

  • sizeof是一個操作符,strlen是庫函數;
  • sizeof的參數可以是數據的類型,也可以是變量,而strlen只能以結尾為'\0'的字符串作為參數;
  • 編譯器在編譯時就計算出了sizeof的結果,而strlen函數必須在程序運行時才能計算出來,並且sizeof計算的是數據類型占內存的大小,而strlen計算的是字符串實際占用的內存大小;
  • 數組做sizeof的參數不退化,數組傳遞給strlen就退化為指針了。

 

6、C語言和C++語言中的關鍵字static有什么區別?

在C語言中static用來修飾局部靜態變量和外部靜態變量、函數,而C++中的static關鍵字除了具有上述功能外,還能用來定義類的成員變量和函數,也就是靜態成員和靜態成員函數。

注意:編程時static的記憶性和全局性特點可以讓在不同時期調用的函數進行通信、傳遞信息,而C++的靜態成員則可以在多個對象實例間進行通信、傳遞信息。

 

7、C語言的malloc和C++中的new有什么區別?

  • new和delete是操作符,可以重載,只能在C++中使用;
  • malloc和free是函數,可以覆蓋,C和C++都能使用;
  • new可以調用對象的構造函數,對應的delete調用對象的析構函數;
  • malloc僅僅分配內存,free則是回收內存,並不會執行構造函數和析構函數;
  • new、delete返回的是某種數據類型指針,malloc、free返回的是void指針。

注意:malloc申請的內存空間要使用free進行釋放,而new申請的內存空間要使用delete釋放,不能夠混用。

 

8、請寫一個標准宏MIN?

#define min(a, b)    ((a) <= (b) ? (a) : (b))

 

9、++i和i++的區別?

++i先自增1,再返回,i++先返回i,再自增1。

 

10、關鍵字volatile有什么作用?

  • 狀態寄存器一類的並行設備硬件寄存器;
  • 中斷服務子程序會訪問到的非自動變量;
  • 多線程間被幾個任務訪問共享變量。

注意:雖然volatile在嵌入式方面應用比較多,但是在PC軟件的多線程中,volatile修飾的臨界變量也是非常實用的。

 

11、一個參數可以既是const又是volatile嗎?

一個參數既可以是const又可以是volatile的,當使用const和volatile同時修飾變量時,表示這個變量在程序內部是只讀的,不能改變的,只在程序外部條件變化下改變,並且編譯器不會優化這個變量,每次使用這個變量時,都會小心地去內存讀取這個變量的值,而不是去寄存器讀取它的備份。

注意:在這一定要注意const的意思,const只是不允許程序中的代碼改變某一變量,其在程序編譯器發揮作用,它並沒有實際地禁止某段內存的讀寫特性。

 

12、*a和&a有什么區別?

&a:含義就是取變量a的地址

*a:使用在不同的地方,含義也不一樣

  • 在聲明語句中,*a只說明a是一個指針變量,例如int *a;
  • 在其它語句中,*a前面沒有操作數並且a是一個指針時,*a代表指針a指向的內存地址存放的數據,如b=*a;
  • *a前面有操作數並且a是一個普通變量時,*a代表乘以a,如c=b*a。

 

13、用C語言編寫一個死循環程序?

while (1)
{
  dosth();      
}

for (;;)
{
  dosth();  
}

注意:很多種途徑都可以實現同一種功能,但是不同的方式,時間和空間占用度不同,特別是對於嵌入式軟件,處理器速度比較慢,存儲空間有限,所以時間和空間優勢是選擇各種方法的首要考慮條件。

 

14、結構體內存對齊問題?

https://www.cnblogs.com/Cqlismy/p/11440057.html

 

15、全局變量和局部變量有什么區別?是怎么實現的?操作系統和編譯器是怎么知道的?

  • 全局變量是整個程序都可以訪問的變量,生存期是從整個程序運行道結束,在程序結束時,全局變量所占用的內存會被釋放;
  • 局部變量存在於模塊(子程序、函數)中,只有所在的模塊可以訪問,其它模塊不能訪問,模塊結束(函數調用完成),局部變量所占用的內存被釋放;
  • 操作系統和編譯器,可能是通過內存分配的位置來知道的,全局變量會被分配在全局數據段,並且在程序開始運行的時候被加載,局部變量則是在堆棧中進行分配的。

 

16、請簡述C/C++程序編譯的內存分配情況?

  • 從靜態存儲區域分配:內存在程序編譯時就已經分配好,這塊內存在程序的整個運行期間都存在,速度快,不容易出錯,例如:全局變量、static變量,常量字符串等;
  • 從棧上分配:在執行函數時,函數內部局部變量的存儲單元都在棧上創建,函數執行結束時,這些存儲單元自動釋放,棧內存分配運算內置於處理器的指令中,效率很高,但是分配的內存容量有限;
  • 從堆上分配:也就是動態內存分配,程序在運行時使用malloc或者new申請任意大小的內存,程序員自己負責何時使用free或者delete進行內存釋放,動態內存的生存期是由程序員決定的,使用非常靈活,如果在堆上分配了內存空間,就有責任回收它,否則運行的程序會出現內存泄漏,另外頻繁地分配和釋放不同大小的堆空間將會產生堆內碎塊。
  • 一個C/C++程序編譯時內存分為5大存儲區,分別是棧區、堆區、全局區、文字常量區、程序代碼區。

 

17、請簡述strcpy、sprintf和memcpy的區別?

  • 操作對象不同,strcpy的兩個操作對象均為字符串,sprintf的操作源對象可以是多種數據類型,目的操作對象是字符串,memcpy的兩個對象就是任意可操作的內存地址,並不限於何種數據類型;
  • 執行效率不同,memcpy的效率最高,strcpy次之,sprintf的效率最低;
  • 實現功能不同,strcpy主要實現字符串變量間的拷貝,sprintf主要實現其它數據類型格式化到字符串,memcpy主要用於內存塊間的拷貝;

注意:strcpy、sprintf和memcpy都可以實現拷貝的功能,但是針對的對象不同,需要根據實際需求,來選擇合適的函數區實現拷貝功能。

 

18、請解釋(*(void (*)())0)()的含義?

  • void (*0)():是一個返回值為void,參數為空的函數指針0;
  • (void (*)())0:把0轉變成一個返回值為void,參數為空的函數指針;
  • *(void (*)())0:在上句的基礎上加*表示整個是一個返回值為void,無參數,並且起始地址為0的函數的名字;
  • ((void (*)())0)():上句的函數名所對應的函數的調用。

 

19、C語言的指針和引用和C++的有什么區別?

  • 指針有自己的一塊空間,而引用只是一個別名;
  • 使用sizeof看一個指針的大小是4字節,而引用則是被引用對象的大小;
  • 作為參數傳遞時,指針需要被解引用才可以對對象進行操作,而直接對引用的修改都會改變引用所指向的對象;
  • 可以有const指針,但是沒有const引用;
  • 指針在使用中可以指向其它對象,但是引用只能是一個對象的引用,不能被改變;
  • 指針可以有多級指針,而引用只有一級;
  • 指針和引用使用++運算符的意義不一樣;
  • 如果返回動態內存分配的對象或者內存,必須使用指針,引用可能會引起內存泄漏。

 

20、typedef和define有什么區別?

  • 用法不同:typedef用來定義一種數據類型的別名,增強程序的可讀性,define主要用來定義常量以及書寫復雜使用頻繁的宏;
  • 執行時間不同:typedef是編譯過程的一部分,有類型檢查的功能,define是宏定義,是預編譯的部分,其發生在編譯之前,只是簡單的進行字符串替換,不會進行類型的檢查;
  • 作用域不同:typedef有作用域限定,define不受作用域限定,只要是在define聲明后的引用,都是正確的;
  • 對指針的操作不同:typedef和define定義指針時有很大區別。

注意:typedef定義是語句,句尾需要加上分號,而define不是語句,不能在句尾加上分號。

 

21、指針常量和常量指針有什么區別?

指針常量是指定義了一個指針,這個指針的值只能在定義時初始化,其它地方不能改變。常量指針是指定義了一個指針,這個指針指向一個只讀的對象,不能通過常量指針來改變這個對象的值。指針常量強調的是指針的不可變性,而常量指針強調的是指針對其所指對象的不可變性。

注意:無論是指針常量還是常量指針,其最大的用途就是作為函數的形式參數,保證實參在被調用函數中的不可改變特性。

 

22、請簡述隊列和棧的異同?

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

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

 

23、如何設置地址為0x67a9的整型變量的值為0xaa66?

int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa66;

注意:這道題就是強制類型轉換的典型例子,無論在什么平台,地址長度和整型數據的長度是一樣的,既一個整型數據可以強制轉換成地址指針類型,只要有意義即可。

 

24、請編程實現字符串轉換為數字?

編碼實現函數atoi(),設計一個程序,把一個字符串轉化為一個整型數值,例如:字符串"5486321",轉化成整型5486321。

int myatoi(const char *str)
{
    int num = 0;  //保存轉換后的數值
    int isNegative = 0;  //記錄字符串中是否有負號
    int n = 0;
    char *p = str;

    if (p == NULL)  //判斷指針的合法性
        return -1;
    
    while (*p++ != '\0')  //計算字符串長度
        n++;
    
    p = str;
    if (p[0] == '-')  //判斷數組是否有負號
        isNegative = 1;

    for (int i = 0; i < n; i++)
    {
        char temp = *p++;
        if (temp > '9' || temp < '0')  //濾除非數字字符
            continue;
        
        if (num != 0 || temp != '0')  //濾除字符串開始的'0'字符
        {
            temp -= 0x30;   //將數字字轉換為數值
            num += temp * int(pow(10, n - 1 - i));
        }
    }

    if (isNegative)
         return (0 - num);
    else
        return num;
}

 

25、C語言的結構體和C++的有什么區別?

  • C語言的結構體中是不能有函數成員的,而C++的類可以有;
  • C語言的結構體中數據成員是沒有private、public和protected訪問限定的,而C++的類成員有這些訪問限定;
  • C語言的結構體是沒有繼承關系的,而C++的類卻有豐富的繼承關系。

注意:雖然C的結構體和C++的類有很大的相似度,但是類是實現面向對象的基礎,而結構體只可以簡單地理解為類的前身。

 

26、簡述指針常量與常量指針的區別?

  • 指針常量是指定義了一個指針,這個指針的值只能在定義時初始化,其它地方不能改變,常量指針是指定義了一個指針,這個指針指向一個只讀的對象,不能通過常量指針來改變這個對象的值;
  • 指針常量調調的是指針的不可變性,而常量指針強調的是指針對其所值對象的不可改變性。

注意:無論是指針常量還是常量指針,其最大的用途就是作為函數的形式參數,保證實參在被調用函數中的不可改變特性。

 

27、如何避免"野指針"?

  • 指針變量聲明時沒有被初始化,解決辦法為,指針聲明時初始化,初始值可以是具體的地址值,也可以讓它指向NULL;
  • 指針p被free或者delete之后,沒有設置為NULL,解決辦法為,指針指向的內存空間被釋放后指針應該指向NULL;
  • 指針操作超越了變量的作用范圍,解決辦法為,在變量的作用域結束前釋放掉變量的地址空間,並且讓指針指向NULL。

 

28、句柄和指針的區別和聯系是什么?

句柄和指針其實是兩個截然不同的概念,Windows系統用句柄標記系統資源,隱藏系統的信息,只要知道有這個東西,然后去調用就行了,是32bit的uint。指針則標記某個內存地址,兩者是不同的概念。

 

29、new/delete與malloc/free的區別是什么?

  • new能自動計算需要分配的內存空間,而malloc需要手工計算字節數;
int *p = new int[2];
int *q = (int *)malloc(2 * sizeof(int));
  • new與delete直接帶具體類型的指針,malloc與free返回void類型的指針;
  • new類型是安全的,而malloc不是,例如,int * p = new float[2];就會報錯,而int *p = malloc(2 * sizeof(float));編譯時編譯器無法指出錯誤來;
  • new一般分為兩步,new操作和構造,new操作對應與malloc,但new操作可以重載,可以自定義內存分配策略,步做內存分配,甚至分配到非內存設備上,而malloc步行;
  • new調用構造函數,malloc不會調用構造函數,delete調用析構函數,而free不會調用析構函數;
  • malloc/free需要庫文件stdlib.h支持,而new/delete則不需要。

注意:delete和free被調用后,內存不會立即回收,指針也不會指向空,delete或free僅僅是告訴操作系統,這一塊內存被釋放了,可以用作其它用途,但是由於沒有重新對這塊內存進行寫操作,所以內存中的變量數值並沒有發生變化,出現野指針的情況,因此,釋放完內存后,應該將該指針指向NULL。

 

30、請說一說extern "C"?

extern "C"的主要作用就是為了能夠正確實現C++代碼調用其它C語言代碼,加上extern "C"后,會指示編譯器這部分代碼按C語言的方式進行編譯,而不是C++。由於C++支持函數重載,因此編譯器編譯函數的過程中會將函數的參數類型也加到編譯后的代碼中,而不僅僅是函數名,而C語言不支持函數重載,因此編譯C語言代碼的函數時,不會帶上函數的參數類型,一般只包括函數名。

該功能十分有用處,因為在C++出現以前,很多代碼都是C語言編寫的,而且很底層的庫也是C語言寫的,為了更好地支持原來的C代碼和已經寫好的C語言庫,需要在C++中盡可能地支持C,而extern "C"就是其中的一個策略。

  • C++代碼調用C語言代碼;
  • 在C++的頭文件中使用;
  • 在多個人的協同開發時,可能有人擅長C語言,有的人擅長C++,在這樣的情況下也會用到。

 

31、請說一說C++中struct和class的區別是什么?

在C++中,class和struct做類型定義時只有兩點區別:

  • 默認的繼承權限不同,class默認繼承權限是private繼承,而struct默認是public繼承;
  • class還可用於定義模板參數,像typename,但是關鍵字struct不能定義模板參數。

C++之所以保留struct關鍵字,原因是:

  • 保證與C語言的向下兼容性,C++必須提供一個struct;
  • C++中的struct定義必須百分百地保證與C語言中的sruct的向下兼容性,把C++中的最基本的對象單元規定為class而不是struct,就是為了避免各種兼容性要求的限制;
  • 對struct定義的拓展性使C語言的代碼能夠更容易地移植到C++中。

 

32、C++類內可以定義引用數據成員嗎?

 

 

33、C++中類成員的訪問權限?

34、什么是右值引用,跟左值又有什么區別?

35、面向對象的三大特征?

36、請說一說C++中四種cast轉換?

37、C++中的空類有哪些成員函數?

38、對C++中的smart pointer四個智能指針:shared_ptr、unique_ptr、weak_ptr、auto_ptr的理解?

39、請說說強制類型轉換運算符?

40、談談你對拷貝構造函數和賦值運算符的認識?

41、在C++中,使用malloc申請的內存是否能通過delete釋放?使用new申請的內存是否能用free釋放?

42、用C++設計一個不能被繼承的類?

43、用C++自己實現一個String類?

44、訪問基類的私有虛函數?

45、對虛函數和多態的理解?

46、請簡述類成員函數的重寫、重載和隱藏的區別?

47、鏈表和數組有什么區別?

48、用兩個棧實現一個隊列的功能?

49、vector的底層原理?

50、vector中的reserve和resize的區別是什么?


免責聲明!

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



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