C++基礎面試題

在網上看到的一份C++面試題,收藏一下:http://www.mianwww.com/html/2013/10/19128.html


1、const符號常量:
    (1)const char *p
    (2)char const *p
    (3)char * const p
      如果const位於星號的左側,則const就是用來修飾指針所指向的變量,即指針指向爲常量。
      如果const位於星號的右側,const就是修飾指針本身,即指針本身是常量。

2、析構函數和虛函數的用法和作用?
    析構函數的作用是當對象生命期結束時釋放對象所佔用的資源。析構函數用法:析構函數是特殊的類成員函數它的名字和類名相同,沒有返回值,沒有參數不能隨意調用也沒有重載。只是在類對象生命期結束時有系統自動用。
    虛函數用在繼承中,當在派生類中需要重新定義基類的函數時需要在基類中將該函數聲明爲虛函數,作用爲使程序支持動態聯遍。

3、堆和棧的區別
    棧(stack):由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。
    堆:一般由程序員分配釋放,若不釋放,程序結束時可能由OS回收。注意它與數據結構中的堆是兩回事,分配方式類似。

4、頭文件的作用是什麼?
    通過頭文件來調用庫功能。在很多場合,源代碼不便(或不準)向用戶公佈,只要向用戶提供頭文件和二進制的庫即可。用戶只需要按照頭文件中的接口聲明來調用庫功能,而不必關心接口怎麼實現的。編譯器會從庫中提取出相應的代碼。
    頭文件能加強類型安全檢查。如果某個接口被實現或被使用時,其方式與頭文件中的聲明不一致,編譯器就會指出錯誤,這一簡單的規則能大大減輕程序員調試、改錯的負擔。

5、內存的分配方式有幾種?
    從靜態存儲區域分配。內存在程序編譯的時候已經分配好,這塊內存在程序的整個運行期間都存在。如全局變量。
在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集中,效率高,但是分配的內存容量有限。
    從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc或new申請任意多少的內存,程序員自己負責在何時用free或delete釋放內存。動態內存的生存期由我們決定,使用非常靈活。

6、BOOL、float、指針變量與”零值比較的if語句”。
    BOOL:If(flag)或if(!flag)
    Float:const float EPSINON = 0.00001;
    If((x>=.EPSINON)&&(x<=EPSINON)) 說明:不可將浮點變量用”==”或”!=”與數字比較,應該設法轉化成”>=”或”<=”此類形式。

    指針*p:if(p==NULL) if(p!=NULL)

7、以下爲Windows NT下的32位C++程序,請計算sizeof的值

Char str[] = “Hello”;
Char *p = str;
Int n = 10
請計算:
Sizeof(str) = 6
Sizeof(p) = 4
Sizeof(n)=2

Void Func(char str[100])
{
    請計算:sizeof(str) = 4
}
Void *p = malloc(100)

請計算:sizeof(p) = 4

8、#include <filename.h>和#include “filename.h”有什麼區別
    對於#include <filename.h>,編譯器從標準庫路徑開始搜索filename.h,對於#include “filename.h”,編譯器從用戶的工作路徑中開始搜索filename.h

9、Const有什麼用途
    可以定義const常量
    Const可以修飾函數的參數、返回值,甚至函數的定義體。被const修飾的東西都受到強制保護,可以預防意外的變動,能提高程序的健壯性。

10、在C++程序中調用被C編譯器編譯後的函數,爲什麼要加extern “C”?
    C++語言支持函數重載,C語言不支持函數重載。函數被C++編譯後在庫中的名字與C語言的不同。假設某個函數的原型爲:void fee(int x,inty);
    該函數被C編譯器編譯後在庫中的名字爲_foo,而C++編譯器則會產生像_foo_int_int之類的名字。
    C++提供了C連接交換指定符號extern “C”來解決名字匹配的問題。

11、內存思考題

Void GetMemory(char *p)
{
P = (char *)malloc(100);
}

Void Test(void)
{
Char *str = NULL;
GetMemory(str);
Strcpy(str,”hello world”);
Printf(str);
}//函數內的變量是獨立於main的,對其改變不會影響main的變量

請問運行Test函數會有什麼樣的結果? 

程序會崩潰,因爲GetMemory並不能傳遞動態內存,Test函數中的str一直是NULL。

Strycpy(str,”hello world”);將使程序崩潰。



Char *GetMemory(void)
{
Char p[] = “hello world”;
Return p;
}

Void Test(void)
{
Char *str = NULL;
Str = GetMemory();
Printf(str);
}

請問Test函數會有什麼樣的結果?

可以是亂碼。因爲GetMemory返回的是指向”棧內存”的指針,該指針的地址不是NULL,但其原現的內容已經被清除,新內容不知。


Void GetMemory2(char **p,int num)
{
*P = (char *)malloc(num);
}

Void Test(void)
{
Char *str = NULL;
GetMemory(&str,100);
Strcpy(str,”hello”);
Printf(str);
}

請問運行Test函數會有什麼樣的結果?

能夠輸出hello
內存泄露


Void Test(void)
{
Char *str = (char *) malloc(100);

Strcpy(str,”hello”);

Free(str);

If(str != NULL)
{

Strcpy((str,”world”);

Printf(str);

}

}

請問運行Test函數會有什麼樣的結果?

篡改動態內存區的內容,後果難以預料,非常危險。

因爲free(str);之後,str成爲野指針,if(str!=NULL)語句不起作用。

12、頭文件的作用是什麼?
    通過頭文件來調用庫功能。在很多場合,源代碼不便(不準)向用戶公佈,只要向用戶提供頭文件和二進制的庫即可。用戶只需要按照頭文件中的接口聲明來調用庫功能,而不必關心接口怎麼實現的。編譯器會從庫中提取相應的代碼。
    頭文件能加強類型安全檢查。如果某個接口被實現或被使用時,其方式與頭文件中的聲明不一致,編譯器就會指出錯誤,這一簡單的規則能減輕程序員調試、改錯的負擔。

13、C++裏面晃是不所有的動作都是main()引起的?如果不是,請舉例
    在運行C++程序時,通常從main()函數開始執行。因此如果沒有main(),程序將不完整,編譯器將指出未定義main()函數。
    例外情況:如,在windows編程中,可以編寫一個動態 連接庫(DLL)模塊,這是其他windows程序可以使用的代碼。由於DLL模塊不是獨立的程序,因此不需要main()。用於專用環境的程序――如機器人中的控制器芯片――可能不需要main(),但常規的獨立程序都需要main().

14、引用與指針的區別:
    引用總是指向某個對象,定義時沒有初始化是錯誤的;
    給引用賦值是修改引用所關聯的對象的值,所關聯的對象不變。

15、變量的聲明和定義有什麼區別
    從編譯原理上來說,聲明是僅僅告訴編譯器,有個某類型的變量會被使用,但是編譯器並不會爲它分配任何內存。而定義就是分配了內存。

16、Sizeof和strlen區別
    1、Sizeof操作符的結果類型是size_t,它在頭文件中typedef爲unsigned int類型。該類型保證能容納實現所建立的最大對象的字節大小。
    2、Sizeof是運算符,strlen是函數
    3、Sizeof可以用類型做參數,strlen只能用char*做參數,且必須是以換行符”\0″結尾的。
    4、Strlen的結果要在運行的時候才能計算出來,是用來計算字符串的長度,不是類型佔內存的大小。
    5、數組做sizeof的參數不退化,傳遞給strlen就退化爲指針;

17、C中malloc與new的區別
    new是C++中的操作符,malloc是C中的一個函數;
    new不僅是分配內存,而且會調用類的構造函數,同理delete會調用類析構函數,而malloc則只分配內存,不會進行初始化類成員的工作,同樣free也不會調用析構函數。
內存泄露對於malloc或者new都可以檢查出來的,區別在於new可以指明那個文件的那一行,而malloc沒有這些信息。

18、New和malloc效率比較
    New有三個字母,malloc有六個字母
    New可以認爲是malloc加構造函數的執行。
    New出來的指針是直接帶類型信息。
    而malloc返回的都是void指針。

19、關鍵字static在C和C++中的區別
    在C語言中,主要體現在靜態全局變量、靜態局部變量和靜態函數。
    在C++中,主要體現在靜態數據成員和靜態成員函數。

20、簡述#define #endif 和#ifndef的作用
    #define指示接受一個名字並定義該名字爲預處理器變量;
    #ifndef檢測指定的預處理變量是否定義;
    #endif預處理未定義

21、實現雙向鏈表刪除一個節點P,在節點P後插入一個節點,寫出這兩個函數;
    答:雙向鏈表刪除一個節點P

Template<class type> void list<type>::delnode(int p)
{
int k = 1;

listnode<type> *ptr,*t;

ptr = first;



While(ptr->next!=NULL&&k!=p)
{

ptr = ptr->next;

k++;

}

t = ptr->next;

cout <<”你已經將數據項”<<t->data<<”刪除”<<endl;

ptr->next = ptr->next->next;

length–;

delte t;

}



在節點P後插入一個節點:

Template<class type> bool list<type>::insert(type t,int p)
{
Listnode<type> *ptr;

Ptr = first;

int k = 1;

while(ptr != NULL && k < p)

{

ptr = ptr->next;

k++;

}

If(ptr == NULL && k!=p)

{

return false;

}
else
{
Listnode<type> *tp;

tp = new listnode<type>;

tp->data = t;

tp->next = ptr->next;

ptr->next = tp;

length++;

return true;

}
}

22、sizeof的使用場合
    sizeof操作符一個主要用途是存儲分配和I/O系統那樣的例程進行通信。可以查看某種類型的對象在內存中所佔單位字節;在動態分配一對象時,可以讓系統指導要分配多少內存;便於一些類型的擴充。

23、以下代碼有什麼問題[C++]
struct Test
{
Test(int){};

Test(){};

void fun(){};

};

void main(void)
{

Test a(1);

a.fun();

Test b();

b.fun();

}

Test b();//定義了一個函數 b不是一個類對象。

24、以下代碼有什麼問題?
    Cout <<(true?1:”I”<<endl;

    1:”1″不是同一類型
    :前後必須是同一類型or能隱式轉換的類型

25、以下三條輸出語句分別輸出什麼?

char str1[] = “abc”;

char str2[] = “abc”;

const char str3[] = “abc”;

const char str4[]] = “abc”;

const char* str5 = “abc”;

const char* str6 = “abc”;

cout << boolalpha <<(str==str2)<<endl;

cout <<boollalpha<<(str3==str4)<<endl;

cout <<boollalpha<<(str5==str6)<<endl;
    分別輸出false,false,true。Str1和str2都是字符數組,每個都有其自己的存儲區,它們的值則是各存儲區的首地址,不符;str3和str4同上,只是按const語義,它們所指向的數組區不能修改。Str5和str6並非數組而是字符指針,並不分配存儲區,其後”abc”以常量形式存於靜態數據區,而它們自己僅是指向該區首地址的指針,相符。

26、C++中的空類,默認產生哪些類成員函數?

class Empty
{
public:

Empty();//缺省構造函數

Empty(const Empty&);//拷貝構造函數

~Empty();//析構函數

Empty&operator=(const Empty&);//賦值運算符

Empty* operator&(); //取址運算符

Const Empty* operator&() const;//取址運算符 const

};


27、以下代碼能夠編譯通過嗎,爲什麼?
unsigned int const size1 = 2;

char str1[size1];

unsigned int temp = 0;

cin >>temp;

unsigned int const size2 = temp;

char str2[size2];
    str2定義出錯,size2非編譯器期間常量,而數組定義要求長度必須編譯期常量。

28、編寫strcpy函數

已知strcpy函數的原型是
char *strcpy(char *strDest,const char *strSrc);

其中strDest是目的字符串,strSrc是源字符串。

char *strcpy(char *strDest,const char *strSrc)
{

assert((strDest!=NULL)&&(strSrc!=NULL));

char *address = strDest;

while((*strDest ++=*strSrc++)!=’\0′)

{

NULL;

}

return address;

}
29、strycpy能把strSrc的內容複製到strDest,爲什麼還要char*類型的返回值?
    爲了實現鏈式表達式。
    如:int length = strlen(strcpy(strDest,”hello world”));

30、寫出下面這段代碼的輸出

#include <iostream>

Int main(void)
{

int a,b,c,d;

a = 10;

b = a++;

c = ++a;

d = 10 * a++;

printf(“b,c,d:%d,%d,%D”,a,b,c);

return 0;

}

10,12,120;

30、編寫類String的構造函數、析構函數和賦值函數
class String
{
public:

String(Const char *str = NULL);//普通構造函數

String(const String &other); //拷由構造函數

~String(void); //析構函數

String &operate = (const String &other);//賦值函數

private:

char *m_data;//用於保存字符串

};



//String的析構函數

String::~String(void)
{

delete[] m_data;//由於m_data是內部數據類型,也可以寫成delete m_data;

}

//String的普通構造函數

String::String(const char *str)
{

If(str == NULL)
{

m_data = new char[1];

*m_data = ‘\0′;

}
else
{

int length = strlen(str);

m_data = new char[length + 1];

strcpy(m_data,str);

}

}



//拷貝構造函數

String::String(const String &other)

{

int length = strlen(other.m_data);

m_data = new char[length + 1];

strcpy(m_data,other.m_data);

}

//賦值函數



String&String::operate=(const String&other)

{

//1.檢查自賦值

If(this == &other)\

return *this;

//2.釋放原有的內存資源

Delete[] m_data;

//3.分配新的內存資源,並複製內容

int length = strlen(other.m_data);

m_data = new char[length+1];

strcpy(m_data,other.m_data);

return *this;

}
31、全局變量可不可以定義在可被多個.C文件包含的頭文件中?爲什麼?
    可以,在不同的C文件中以static形式來聲明同名全局變更。可以在不同的C文件夾中聲明同名的全局變量,前提是其中只能有一個C文件中對此變量賦初值,此時連接不會出錯。

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

33、指出下面代碼的輸出,並解釋爲什麼

main()
{

int a[5] = {1,2,3,4,5};

int *ptr = (int *)(&a+1);

printf(“%d,%d”,*(a+1),*(ptr-1));

}

輸出:2,5

*(a+1)就是a[1],*(ptr-1)就是a[4],執行結果是2,5;

&a+1不是首地址+1,系統會認爲加一個a數組的偏移,是偏移了一個數組的大小(本例是5個int)

int *ptr = (int *)(&a+1);則ptr實際是&(a[5]),也就是a+5

原因如下:

&a是數組指針,其類型爲int(*)[5];

而指針加1要根據指針類型加一定的值,不同類型的指針+1之後增加的大小不同,a是長度爲5的int數組指針,所以要加5*sizeof(int)

所以ptr實際是a[5]

但是ptr與(&a+1)類型是不一樣的(這點很重要)

所以ptr-1只會減去sizeof(int*)

a,&a的地址是一樣的,但意思不一樣,a是數組首地址,也就是a[0]的地址,&a是對象(數組)首地址,a+1是數組下一元素的地址,即a[1],&a+1是下一個對象的地址,即a[5].
34、以下代碼中的兩個sizeof用法有問題嗎?
    sizeof如用於數組,只能測出靜態數組的大小,無法檢測動態分配的或外部數組大小。注意:數組名作爲函數參數時,退化爲指針。數組名作爲sizeof()參數時,數組名不退化,因爲sizeof不是函數。

35、請問以下代碼有什麼問題

int main()
{
        char a;

        char *str = &a;

        strcpy(str,”hello”);

        printf(str);

        return 0;
}

沒有爲str分配內存空間,將會發生異常

問題出在將一個字符串複製進一個字符變量指針所指地址。雖然可以正確輸出結果,但因爲越界進行內在讀寫而導致程序崩潰。

Strcpy的在庫函數string.h中,程序的主要程序在於越辦進行內存讀寫導致程序崩潰。

2.

const char* s = “AAA”;

Printf(“%s”,s);

S[0] = ‘B’;

Printf(“%s”,s);

“AAA”是字符串常量,S是指針,指向這個字符串常量,所以聲明s的時候就有問題。

Const char* s =”AAA”,然後又因爲是常量,所以對S[0]的賦值操作是不合法的。

Char szstr[10];
Strcpy(szstr,”0123456789″);

產生什麼結果?爲什麼?

正常輸出,長度不一樣,會造成非法的OS,覆蓋別的內容

交換兩個變量的值,不使用第三個變量。即a=3,b=5,交換之後a=5,b=3;
兩種解法,一種是用算術算法,一種是用^(異或)

a = a+b;

b = a-b;

a = a-b;

or

a = a^b;//只能對int ,char

b = a^b;

a = a^b;

or

a ^= b ^=a;

int a = 256;
char d =a;

pint(“%d”,d+1);

1

Char類型的變量賦值範圍是0~255.當把256賦值給a時,超出了a的有效取值範圍。此時a的實際值爲0.

36、將”引用”作爲函數返回值類型的格式、好處和需要遵守的規則
    格式:類型標識符 &函數名(形參列表及類型說明){//函數體}
    格式:在內存中不產生被返回值的副本:(注意:正是因爲這點原因,所以返回一個局部變量的引用是不可取的。因爲隨着該局部變量生存期的結束,相應的引用也會失效。)
    注意事項:
    1、不能返回局部變量的引用。主要原因是局部變量會在函數返回時被銷燬,因此被返回的引用就成爲了”無所指的”引用,程序會進入未知狀態。
    2、不能返回函數內部new分配的內存的引用。雖然不存在局部變量的被動銷燬問題,可對於這種情況(返回函數內部new分配內存的引用),又面臨其它尷尬的局面。如,被函數返回的引用只是作爲一個臨時變量出現,而沒有被賦予一個實際的變量,那麼這個引用所指向的空間(由new分配)就無法釋放。
    3、可以返回類成員的引用,但最好是const。主要原因是當對象的屬性是與某種業務規則相關聯時,其賦值常常與某些其它屬性或者對象的狀態有關,因此有必要將賦值操作封裝在一個業務規則當中。如果其它對象可以獲得該屬性的非常量引用(或指針),那麼對該屬性的單純賦值就會破壞業務規則的完整性。

37、多態的作用:
    1、隱藏實現細節,使得代碼能夠模塊化;擴展代碼模塊,實現代碼重用;
    2、接口重用:爲了類在繼承和派生的時候,保證使用家庭中任一類的實例的某一屬性時的正確調用。

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