第一部分:C++與C語言的差異(1-18)
1、C 和 C++ 中 struct 有什麼區別?
Protection行爲 | 能否定義函數 | |
C | 無 | 否,但可以有函數指針 |
C++ | 有 | 可以,默認是private |
2、C++中的 struct 和 class 有什麼區別?
【參考答案】從語法上講,class和struct做類型定義時只有兩點區別:
(一)默認繼承權限。如果不明確指定,來自class的繼承按照private繼承處理,來自struct的繼承按照public繼承處理;
(二)成員的默認訪問權限。class的成員默認是private權限,struct默認是public權限。 除了這兩點,class和struct基本就是一個東西。語法上沒有任何其它區別。
3、如何判斷一段程序是由C 編譯程序還是由C++編譯程序編譯的?
【標準答案】
#ifdef __cplusplus
cout<<“c++";
#else
printf("c");
#endif
複製代碼
4、 C和C++有什麼不同?
【參考答案】
從機制上:C是面向過程的(但C也可以編寫面向對象的程序);C++是面向對象的,提供了類。但是,C++編寫面向對象的程序比C容易。
從適用的方向:C適合要求代碼體積小的,效率高的場合,如嵌入式;C++適合更上層的,複雜的; llinux核心大部分是C寫的,因爲它是系統軟件,效率要求極高。
從名稱上也可以看出,C++比C多了+,說明C++是C的超集;那爲什麼不叫C+而叫C++呢,是因爲C++比C來說擴充的東西太多了,所以就在C後面放上兩個+;於是就成了C++。
C語言是結構化編程語言,C++是面向對象編程語言。 C++側重於對象而不是過程,側重於類的設計而不是邏輯的設計。
5、“引用”與指針的區別是什麼?
【參考答案】
指針通過某個指針變量指向一個對象後,對它所指向的變量間接操作。程序中使用指針,程序的可讀性差;
而引用本身就是目標變量的別名,對引用的操作就是對目標變量的操作。
6、虛函數
class A {
virtual void func1();
void func2();
} ;
class B: class A {
void func1() {
cout < < "fun1 in class B" < < endl;
}
virtual void func2() {
cout < < "fun2 in class B" < < endl;
}
}
複製代碼
A、A中的func1和B中的func2都是虛函數
B、A中的func1和B中的func2都不是虛函數.
C、A中的func2是虛函數.,B中的func1不是虛函數.
D、A中的func2不是虛函數,B中的func1是虛函數.
【標準答案】A
7、int id[sizeof(unsigned long)]; 這個對嗎?爲什麼?
【標準答案】正確 這個 sizeof是編譯時運算符,編譯時就確定了 可以看成和機器有關的常量。
8、某文件中定義的靜態全局變量(或稱靜態外部變量)其作用域是 () ?
A.只限某個函數 B.本文件
C.跨文件 D.不限制作用域
【參考答案】B。靜態全局變量則限制了其作用域, 即只在定義該變量的源文件內有效, 在同一源程序的其它源文件中不能使用它。
由於靜態全局變量的作用域侷限於一個源文件內,只能爲該源文件內的函數公用, 因此可以避免在其它源文件中引起錯誤。
9、C++函數中值的傳遞方式有哪幾種?
【標準答案】C++函數的三種傳遞方式爲:值傳遞、指針傳遞和引用傳遞。
10、對於一個頻繁使用的短小函數,在C語言中應用什麼實現,在C++中應用什麼實現?
【標準答案】C用宏定義,C++用 inline
11、引用與指針有什麼區別?
【參考答案】
1) 引用必須被初始化,指針不必。
2) 引用初始化以後不能被改變,指針可以改變所指的對象。
3) 不存在指向空值的引用,但是存在指向空值的指針
12、C++中 virtual 與 inline 的含義分別是什麼?
【參考答案】
在基類成員函數的聲明前加上virtual關鍵字,意味着將該成員函數聲明爲虛函數。
inline與函數的定義體放在一起,使該函數稱爲內聯。inline是一種用於實現的關鍵字,而不是用於聲明的關鍵字。
## 虛函數的特點;
如果希望派生類能夠重新定義基類的方法,則在基類中將該方法定義爲虛方法,這樣可以啓用動態聯編。
## 內聯函數的特點;
使用內聯函數的目的是爲了提高函數的運行效率。
內聯函數體的代碼不能過長,因爲內聯函數省去調用函數的時間是以代碼膨脹爲代價的。
內聯函數不能包含循環語句,因爲執行循環語句要比調用函數的開銷大。
13、VC 中,編譯工具條內的 Debug 與 Release 選項是什麼含義?
【參考答案】
Debug 通常稱爲調試版本,它包含調試信息,並且不作任何優化,便於程序員調試程序。
Release 稱爲發佈版本,它往往是進行了各種優化,使得程序在代碼大小和運行速度上都是最優的,以便用戶很好地使用。
Debug 帶有大量的調試代碼,運行時需要相應的運行庫,發佈模式程序緊湊不含有調試代碼和信息,直接可以運行(如果不需要運行庫)
14、函數 assert 的用法?
【參考答案】
斷言assert是僅在debug版本起作用的宏,用於檢查“不應該“發生的情況。
程序員可以把assert看成一個在任何系統狀態下都可以安全使用的無害測試手段。
15、 const 與 #define 的比較 ,const有什麼優點?
【參考答案】
(1) const 常量有數據類型,而宏常量沒有數據類型。編譯器可以對前者進行類型安全檢查。
而對後者只進行字符替換,沒有類型安全檢查,並且在字符替換可能會產生意料不到的錯誤(邊際效應) 。
(2)有些集成化的調試工具可以對 const 常量進行調試,但是不能對宏常量進行調試。
16、請你談談引用和指針的區別。
【參考答案】
(1)引用被創建的同時必須被初始化(指針則可以在任何時候被初始化) 。
(2)不能有 NULL 引用,引用必須與合法的存儲單元關聯(指針則可以是 NULL) 。
(3)一旦引用被初始化,就不能改變引用的關係(指針則可以隨時改變所指的對象) 。
17、有了 malloc/free 爲什麼還要 new/delete ?
【參考答案】
malloc 與 free 是 C++/C 語言的標準庫函數,new/delete 是 C++的運算符。它們都可用於申請動態內存和釋放內存。
對於非內部數據類型的對象而言,光用 maloc/free 無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。
由於malloc/free 是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加於 malloc/free。
因此 C++語言需要一個能完成動態內存分配和初始化工作的運算符 new,以及一個能完成清理與釋放內存工作的運算符 delete。
注意 new/delete 不是庫函數。
18、如果在申請動態內存時找不到足夠大的內存塊,malloc 和 new 將返回 NULL 指針,宣告內存申請失敗。你是怎麼處理內存耗盡的?
【參考答案】
(1)判斷指針是否爲 NULL,如果是則馬上用 return 語句終止本函數。
(2)判斷指針是否爲 NULL,如果是則馬上用 exit(1) 終止整個程序的運行
(3)爲 new 和 malloc 設置異常處理函數。例如 Visual C++可以用_set_new_hander 函數爲 new 設置用戶自己定義的異常處理函數,
也可以讓 malloc 享用與 new 相同的異常處理函數。
第二部分:數據類型、關鍵字(19-37)
19、C++是不是類型安全的?
【參考答案】不是。兩個不同類型的指針之間可以強制轉換(用reinterpret cast)。
20、const 符號常量;
(1)const char *p
(2)char const *p
(3)char * const p
說明上面三種描述的區別;
【參考答案】
(1) p是一個指向const char的指針,p是可以改變指向的,但是p指向的值是不能改變的;
(2) p指向的恰好是一個指向const的char的普通指針;
(3) p是一個指針,這個指針是指向char的const指針。
(1)和(2)的定義是一樣的。
21、用C++寫個程序,如何判斷一個操作系統是16位還是32位的?
【標準答案】
定義一個指針p,打印出sizeof(p),如果節後是4,則表示該操作系統是32位,打印結果是2,表示是16位。
22、用C++寫個程序,如何判斷一個操作系統是16位還是32位的?不能用 sizeof() 函數。
【參考答案】
int a = ~0;
if(a > 65536) {
cout<<"32 bit"<<endl;
} else {
cout<<"16 bit"<<endl;
}
複製代碼
23、識別函數或指針
void * ( * (*fp1)(int))[10];
float (*(* fp2)(int,int,int))(int);
int (* ( * fp3)())[10]();
分別表示什麼意思?
【標準答案】
1、void * ( * (*fp1)(int))[10]; fp1是一個指針,指向一個函數,這個函數的參數爲int型,函數的返回值是一個指針,這個指針指向一個數組,
這個數組有10個元素,每個元素是一個void*型指針。
2、float (*(* fp2)(int,int,int))(int); fp2是一個指針,指向一個函數,這個函數的參數爲3個int型,函數的返回值是一個指針,這個指針指向一個函數,
這個函數的參數爲int型,函數的返回值是float型。
3、int (* ( * fp3)())[10](); fp3是一個指針,指向一個函數,這個函數的參數爲空,函數的返回值是一個指針,這個指針指向一個數組,
這個數組有10個元素,每個元素是一個指針,指向一個函數,這個函數的參數爲空,函數的返回值是int型。
24、多態類中的虛函數表是 Compile-Time,還是 Run-Time 時建立的?
【標準答案】
虛擬函數表是在編譯期就建立了,各個虛擬函數這時被組織成了一個虛擬函數的入口地址的數組.而對象的隱藏成員--虛擬函數表指針是
在運行期--也就是構造函數被調用時進行初始化的,這是實現多態的關鍵。
25、錯誤的轉義字符是?
A、'\091'
B、'\\'
C、'\0' D.'\''
【標準答案】A
26、若數組名作實參而指針變量作形參,函數調用實參傳給形參的是?
A、數組的長度 B.數組第一個元素的值
C、數組所有元素的值
D、數組第一個元素的地址
【標準答案】D
27、變量的指針含意是指變量的?
A.值 B.地址 C.存儲 D.名字
【標準答案】B
28、內存的分配方式有幾種?
【參考答案】
一、從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量。
二、在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集中,效
率很高,但是分配的內存容量有限。
三、從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc或new申請任意多少的內存,程序員自己負責在何時用free或delete釋放內存。動態內存的生存期由我們
決定,使用非常靈活,但問題也最多。
29、float a,b,c , 問等式 (a+b)+c==(b+a)+c 和 (a+b)+c==(a+c)+b 能否成立?
【參考答案】
兩者都不行。在比較float或double時,不能簡單地比較。由於計算誤差,相等的概率很低。應判斷兩數之差是否落在區間(-e,e)內。
這個e應比浮點數的精度大一個數量級。
30、全局變量和局部變量有什麼區別?是怎麼實現的?操作系統和編譯器是怎麼知道的?
【參考答案】
生命週期不同:
全局變量隨主程序創建和創建,隨主程序銷燬而銷燬;
局部變量在局部函數內部,甚至局部循環體等內部存在,退出就不存在; 內存中分配在全局數據
區。
使用方式不同:
通過聲明後全局變量程序的各個部分都可以用到;局部變量只能在局部使用;分配在棧區。
操作系統和編譯器通過內存分配的位置來知道的,全局變量分配在全局數據段並且在程序開始運行的時候被加載。局部變量則分配在堆棧裏面 。
31、Heap 與 Stack 的差別
【參考答案】
Heap是堆,stack是棧。 Stack的空間由操作系統自動分配/釋放,Heap上的空間手動分配/釋放。
Stack空間有限,Heap是很大的自由存儲區 C中的malloc函數分配的內存空間即在堆上,C++中對應的是new操作符。
程序在編譯期對變量和函數分配內存都在棧上進行,且程序運行過程中函數調用時參數的傳遞也在棧上進行
32、In C++, what does "explicit" mean? what does "protected" mean?
【標準答案】
C++中的 explicit 關鍵字用來修飾類的構造函數,表明該構造函數是顯式的,在某些情況下,我們要求類的使用者必須顯示調用類的構造函數時就需要使用 explicit,反之默認類型轉換可能會造成無法預期的問題。
protected 控制的是一個函數對一個類的成員(包括成員變量及成員方法)的訪問權限。protected成員只有該類的成員函數及其派生類的成員函數可以訪問。
33、重複多次 fclose 一個打開過一次的 FILE *fp 指針會有什麼結果,並請解釋。
【參考答案】
考察點:導致文件描述符結構中指針指向的內存被重複釋放,進而導致一些不可預期的異常。
34、爲什麼數組名作爲參數,會改變數組的內容,而其它類型如int卻不會改變變量的值?
【參考答案】
當數組名作爲參數時,傳遞的實際上是地址。
而其他類型如int作爲參數時,由於函數參數值實質上是實參的一份拷貝,被調函數內部對形參的改變並不影響實參的值。
35、你覺得如果不使用常量,直接在程序中填寫數字或字符串,將會有什麼麻煩?
【參考答案】
(1) 程序的可讀性(可理解性)變差。程序員自己會忘記那些數字或字符串是什麼意思,用戶則更加不知它們從何處來、表示什麼。
(2) 在程序的很多地方輸入同樣的數字或字符串,難保不發生書寫錯誤。
(3) 如果要修改數字或字符串,則會在很多地方改動,既麻煩又容易出錯。
36、爲什麼需要使用堆,使用堆空間的原因?
【參考答案】
直到運行時才知道一個對象需要多少內存空間;不知道對象的生存期到底有多長。
37、 const關鍵字?有哪些作用?
【參考答案】
const關鍵字至少有下列n個作用:
(1)欲阻止一個變量被改變,可以使用const關鍵字。在定義該const變量時,通常需要對它進行初始化,因爲以後就沒有機會再去改變它了;
(2)對指針來說,可以指定指針本身爲const,也可以指定指針所指的數據爲const,或二者同時指定爲const;
(3)在一個函數聲明中,const可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值;
(4)對於類的成員函數,若指定其爲const類型,則表明其是一個常函數,不能修改類的成員變量;
(5)對於類的成員函數,有時候必須指定其返回值爲const類型,以使得其返回值不爲“左值”。
注: 這個題可以考查面試者對程序設計知識的掌握程度是初級、中級還是比較深入,沒有一定的知識廣度和深度,不可能對這個問題給出全面的解答。大多數人只能回答出 static 和 const 關鍵字的部分功能。
第三部分:C++面向對象的特性(38-61)
38、是不是一個父類寫了一個virtual 函數,如果子類覆蓋它的函數不加virtual ,也能實現多態?
【參考答案】
virtual修飾符會被隱形繼承的。virtual可加可不加。子類的空間裏有父類的所有變量(static除外)。同一個函數只存在一個實體(inline除外)。子類覆蓋它的函數不加virtual ,也能
實現多態。在子類的空間裏,有父類的私有變量。私有變量不能直接訪問。
39、面向對象的三個基本特徵,並簡單敘述之?
【參考答案】
1. 封裝:將客觀事物抽象成類,每個類對自身的數據和方法實行protection(private, protected, public)
2. 繼承:廣義的繼承有三種實現形式:
實現繼承(指使用基類的屬性和方法而無需額外編碼的能力)、
可視繼承(子窗體使用父窗體的外觀和實現代碼)、
接口繼承(僅使用屬性和方法,實現滯後到子類實現)。
前兩種(類繼承)和後一種(對象組合=>接口繼承以及純虛函數)構成了功能複用的兩種方式。
3. 多態:是將父對象設置成爲和一個或更多的與他的子對象相等的技術,賦值之後,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。
簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。
40、重載(overload)、重寫(override,有的書也叫做“覆蓋”)、重定義(redefinition)的區別?
【標準答案】
重載 同一名字空間 是指允許存在多個同名函數,而這些函數的參數表不同。
重定義/隱藏 不同名字空間 用於繼承,派生類與基類的函數同名,屏蔽基類的函數
重寫/覆蓋 不同名字空間
用於繼承,子類重新定義父類虛函數的方法
41、多態的作用?
【參考答案】
主要是兩個:
1. 隱藏實現細節,使得代碼能夠模塊化;擴展代碼模塊,實現代碼重用;
2. 接口重用:爲了類在繼承和派生的時候,保證使用家族中任一類的實例的某一屬性時的正確調用。
42、當一個類A 中沒有聲命任何成員變量與成員函數,這時sizeof(A)的值是多少,如果不是零,請解釋一下編譯器爲什麼沒有讓它爲零。
【標準答案】
sizeof(A) = 1;
43、如果 ClassA 中定義並實現虛函數 int func(void),ClassB 中也實現該函數,那麼上述變量 a->func() 將調用哪個類裏面的函數?如果 int func(void) 不是虛函數,情況又如何?爲什麼?
【參考答案】
第一問調用的是B的。第二問調用A的。
虛函數的一個典型應用,虛函數只能藉助於指針或者引用來達到多態的效果。
44、 C++裏面是不是所有的動作都是main()引起的?如果不是,請舉例。
【參考答案】
比如全局變量的初始化,就不是由 main 函數引起的。舉例:
class A{
};
A a; //a的構造函數限執行
int main() {
}
複製代碼
45、 內聯函數在編譯時是否做參數類型檢查
【參考答案】
內聯函數要做參數類型檢查, 這是內聯函數跟宏相比的優勢。
46、請講一講析構函數和虛函數的用法和作用?
【參考答案】
析構函數是特殊的類成員函數,它沒有返回類型,沒有參數,不能隨意調用,也沒有重載,只有在類對象的生命期結束的時候,由系統自動調用。
有適放內存空間的作用。
虛函數是C++多態的一種表現, 使用虛函數,我們可以靈活的進行動態綁定,當然是以一定的開銷爲代價。
47、“new”in c++ is a?
A. library function like malloc in c
B. key word
C. operator
D. none of the above
【參考答案】C。
malloc是庫函數,不在編譯器控制範圍之內;new是運算符,在編譯器控制範圍之內。
調用malloc時,從堆中申請內存;調用new時,從堆中申請內存併爲內存調用構造函數。
48、對於C++中類(class) 與結構(struct)的描述正確的爲:
A、類中的成員默認是private的,但是可以聲明public,private 和 protected,結構中定義的成員默認的都是public;
B、結構中不允許定義成員函數,但是類中可以定義成員函數;
C、結構實例使用malloc() 動態創建,類對象使用new 操作符動態分配內存;
D、結構和類對象都必須使用new 創建;
E、結構中不可以定義虛函數,但是類中可以定義虛函數.
F、結構不可以存在繼承關係,但是類可以存在繼承關係.
【標準答案】A,D
49、兩個互相獨立的類:ClassA 和 ClassB,都各自定義了非靜態的公有成員函數 PublicFunc() 和非靜態的私有成員函數 PrivateFunc(); 現在要在ClassA 中增加定義一個成員函數ClassA::AdditionalPunction(ClassA a,ClassB b);則可以在AdditionalPunction(ClassA x,ClassB y)的實現部分(函數功能體內部)出現的合法的表達是最全的是:
A、x.PrivateFunc();x.PublicFunc();y.PrivateFunc();y.PublicFunc();
B、x.PrivateFunc();x.PublicFunc();y.PublicFunc();
C、x.PrivateFunc();y.PrivateFunc();y.PublicFunc();
D、x.PublicFunc();y.PublicFunc();
【標準答案】B
50、C++程序下列說法正確的有:
A、對調用的虛函數和模板類都進行遲後編譯.
B、基類與子類中函數如果要構成虛函數,除了要求在基 類中用virtual 聲名,而且必須名字相同且參數類型相同返回類型相同。
C、重載的類成員函數都必須要:或者返回類型不同,或者參數數目不同,或者參數序列的類型不同.
D、靜態成員函數和內聯函數不能是虛函數,友員函數和構造函數也不能是虛函數,但是析構函數可以是虛函數.
【標準答案】A
51、在C++中有沒有純虛構造函數?
【標準答案】構造函數不能是虛的。只能有虛的析構函數。
52、下面的 throw 表達式哪些是錯誤的?
(a) class exceptionType { };
throw exceptionType { };
(b) enum mathErr { overflow, underflow, zeroDivide };
throw zeroDivide();
【標準答案】
(a) class exceptionType { };
throw exceptionType();
(b) enum mathErr { overflow, underflow, zeroDivide };
throw zeroDivide;
53、談談你是怎麼認識 C++ 中的模板的?
【參考答案】
模板使程序員能夠快速建立具有類型安全的類庫集合和函數集合,它的實現,方便了大規模的軟件開發。(結合stl更好)
54、在 C++的一個類中聲明一個 static 成員變量有沒有用?
【參考答案】
在C++類的成員變量被聲明爲 static(稱爲靜態成員變量),意味着它爲該類的所有實例所共享,也就是說當某個類的實例修改了該靜態成員變量,
也就是說不管創建多少對象,static修飾的變量只佔有一塊內存。其修改值爲該類的其它所有實例所見;而類的靜態成員函數也只能訪問靜態成員(變量或函數)。static是加了訪問控制的全局變量,不被繼承。
55、C++中爲什麼用模板類?
【參考答案】
(1)可用來創建動態增長和減小的數據結構
(2)它是類型無關的,因此具有很高的可複用性。
(3)它在編譯時而不是運行時檢查數據類型,保證了類型安全(4)它是平臺無關的,可移植性(5)可用於基本數據類型
56、函數模板與類模板有什麼區別?
【參考答案】
函數模板的實例化是由編譯程序在處理函數調用時自動完成的,而類模板的實例化必須由程序員在程序中顯式地指定。
58、請你談談你在類中如何使用 const 的。
【參考答案】
有時我們希望某些常量只在類中有效。由於#define 定義的宏常量是全局的,不能達到目的,於是想當然地覺得應該用 const 修飾數據成員來實現。
const 數據成員的確是存在的,但其含義卻不是我們所期望的。const 數據成員只在某個對象生存期內是常量,而對於整個類而言卻是可變的,因爲類可以創建多個對象,不同的對象其 const 數據成員的值可以不同。 不能在類聲明中初始化 const 數據成員。
const 數據成員的初始化只能在類構造函數的初始化表中進行。
59、函數重載,我們靠什麼來區分調用的那個函數?靠返回值判斷可以不可以?
【參考答案】
如果同名函數的參數不同(包括類型、順序不同) ,那麼容易區別出它們是不同的。如果同名函數僅僅是返回值類型不同,有時可以區分,有時卻不能。例如:
void Function(void);
int Function (void);
上述兩個函數,第一個沒有返回值,第二個的返回值是 int 類型。如果這樣調用函數:
int x = Function ();
則可以判斷出 Function 是第二個函數。問題是在 C++/C 程序中,我們可以忽略函數的返回值。在這種情況下,編譯器和程序員都不知道哪個 Function 函數被調用。 所以只能靠參數而不能靠返回值類型的不同來區分重載函數。
60、所有的運算符都能重載嗎?
【參考答案】
不能被重載的運算符
在 C++運算符集合中,有一些運算符是不允許被重載的。這種限制是出於安全方面的考慮,可防止錯誤和混亂。
(1)不能改變 C++內部數據類型(如 int,float 等)的運算符。
(2)不能重載‘.’,因爲‘.’在類中對任何成員都有意義,已經成爲標準用法。
(3)不能重載目前 C++運算符集合中沒有的符號,如#,@,$等。原因有兩點,一是難以理解,二是難以確定優先級。
(4)對已經存在的運算符進行重載時,不能改變優先級規則,否則將引起混亂。
61、基類的析構函數不是虛函數,會帶來什麼問題?
【參考答案】
派生類的析構函數用不上,會造成資源的泄漏。
第四部分:程序閱讀題(62-90)
62、main 函數執行以前,還會執行什麼代碼?
【參考答案】
全局對象的構造函數會在main 函數之前執行。
63、 There are two int variables: a and b, don't use“if”, “? :”, “switch”or other judgement statements, find out the biggest one of the two numbers.
【標準答案】
( ( a + b ) + abs( a - b ) ) / 2
64、如何打印出當前源文件的文件名以及源文件的當前行號?
【標準答案】
cout << __FILE__ ;
cout<<__LINE__ ;
__FILE__和__LINE__是系統預定義宏,這種宏並不是在某個文件中定義的,而是由編譯器定義的。(C也有)
65、下面兩種if語句判斷方式。請問哪種寫法更好?爲什麼?
int n;
if (n == 10) // 第一種判斷方式
if (10 == n) // 第二種判斷方式
【參考答案】
這是一個風格問題,第二種方式如果少了個=號,編譯時就會報錯,減少了出錯的可能行,可以檢測出是否少了=。
66、寫出運行結果:
{
// test1 char str[] = "world";
cout << sizeof(str) << ": ";
char *p = str;
cout << sizeof(p) << ": ";
char i = 10;
cout << sizeof(i) << ": ";
void *pp = malloc(10);
cout << sizeof(pp) << endl;
}
複製代碼
【標準答案】6:4:1:4
67、在不用第三方參數的情況下,交換兩個參數的值。
【參考答案】
a = a + b;
b = a – b; a = a – b;
68、以下代碼如果有錯,請該正,並寫出輸出結果?
void main(void)
{
int nArrLength(400), i = 546;
for (int i = 0; i< 99999999999; i++);
cout << nArrLength << endl;
cout << i << endl;
}
複製代碼
【標準答案】
void main(void)
{
int nArrLength(400), i = 546;
/*主要是考看對C++的基礎知識是否瞭解這裏的int nArrLength(400)是對整數的定義,當然,明名上有問題,這裏是故意這樣的,
但是,最好是變量名改爲 ....[還是您自己看着辦了]*/
for (int i = 0; i< 99999999999; i++);
/*這裏是考對變量越界理解,同時....,所以,999...應該改爲 ~((int)0),也就是整數中0取反考對變量塊作用域的理解,這裏的i,在循環後就不存在了*/
cout << nArrLength << endl; // 這裏輸出 400
cout << i << endl; // 這裏輸出 546
}
複製代碼
69、int i = 5, b = 7; cout << (i+++b) <<endl; 不用調試,請說出,以上代碼在gcc編譯過後的執行結果!
【標準答案】結果是12。
70、寫一個能做左值的函數(方法有很多)。
如:max(x, y) += 2874 + 55; drwline(x, y)++;
【參考答案】
int &max(int & x, int & y)
{
return x > y? x : y;
}
int x = 55, y = 77;
max(x, y) += 12 + 11; // 此時 y = 92;
cout << "x = "x << "; y = "<< y << endl; // 輸出 x = 55; y = 92;
複製代碼
71、程序輸出
class human
{
public:
~human()
{
cout << "human over......" << endl;
}
void Disp()
{
cout << "human disp ... ..." << endl;
}
};
class man : public human
{
public:
~man()
{
cout << "man over......" << endl;
}
void Disp()
{
cout << "man disp ... ..." << endl;
}
};
int main()
{
human* p = new human;
p->Disp();
delete p;
return 0;
}
複製代碼
【標準答案】
human disp ... ...
human over ......
72、下面的函數實現在一個固定的數上加上一個數,有什麼錯誤,改正:
int add_n(int n)
{
static int i = 100;
i += n;
return i;
}
複製代碼
【標準答案】
因爲static使得i的值會保留上次的值。以後的i會一直更新,使得第二次調用出現錯誤, 去掉static就可了
73、寫出打印結果
unsigned short array[]={1,2,3,4,5,6,7};
int i = 3;
*(array + i) = ?
【標準答案】4
74、寫一個函數計算當參數爲n(n很大)時的值 1-2+3-4+5-6+7......+n。
【參考答案】
long fn(long n)
{
if(n <= 0)
{
printf("error: n must > 0);
exit(1);
}
if(0 == n % 2)
return (n / 2) * (-1);
else
return (n / 2) * (-1) + n;
複製代碼
75、字符指針、浮點數指針、以及函數指針這三種類型的變量哪個佔用的內存最大?爲什麼?
【參考答案】
指針變量也佔用內存單元,而且所有指針變量佔用內存單元的數量都是相同的。
就是說,不管是指向何種對象的指針變量,它們佔用內存的字節數都是一樣的,並且要足夠把程序中所能用到的最大地址表示出來(通常是一個機器字長)。
76、以下三條輸出語句分別輸出什麼?
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char* str5 = "abc";
const char* str6 = "abc";
cout << boolalpha << ( str1==str2 ) << endl; // 輸出什麼?
cout << boolalpha << ( str3==str4 ) << endl; // 輸出什麼?
cout << boolalpha << ( str5==str6 ) << endl; // 輸出什麼?
複製代碼
【參考答案】
分別輸出 false,false,true。
str1和str2都是字符數組,每個都有其自己的存儲區,它們的值則是各存儲區首地址,不等;
str3和str4同上,只是按const語義,它們所指向的數據區不能修改。
str5和str6並非數組而是字符指針,並不分配存儲區,其後的“abc”以常量形式存於靜態數據區,而它們自己僅是指向該區首地址的指針,相等。
77、以下代碼有什麼問題?
cout << (true?1:"1") << endl;
複製代碼
【參考答案】
三元表達式“?:”問號後面的兩個操作數必須爲同一類型。
78、以下代碼能夠編譯通過嗎,爲什麼?
unsigned int const size1 = 2;
char str1[ size1 ];
unsigned int temp = 0;
cin >> temp;
unsigned int const size2 = temp;
char str2[ size2 ];
複製代碼
【標準答案】
str2定義出錯,size2非編譯器期間常量,而數組定義要求長度必須爲編譯期常量。
79、以下代碼中的輸出語句輸出0嗎,爲什麼?
struct CLS
{
int m_i;
CLS( int i ) : m_i(i) {}
CLS()
{
CLS(0);
}
};
CLS obj;
cout << obj.m_i << endl;
複製代碼
【標準答案】
不能。在默認構造函數內部再調用帶參的構造函數屬用戶行爲而非編譯器行爲,亦即僅執行函數調用,而不會執行其後的初始化表達式。
只有在生成對象時,初始化表達式纔會隨相應的構造函數一起調用。
80、How do you code an infinite loop in Cplus plus ?
【參考答案】
while(1){} or for(;1;)
81、What are the values of a, b, and c after the following instructions:
int a=5, b=7, c;
c = a+++b;
複製代碼
【標準答案】a=6,b=7,c=12
82、在排序方法中,關鍵碼比較次數與記錄地初始排列無關的是()
A. Shell排序
B. 歸併排序
C. 直接插入排序
D. 選擇排序
【標準答案】D
83、代碼:
void func() {
static int val;
}
中,變量 val 的內存地址位於:
A. 已初始化數據段
B.未初始化數據段
C.堆
D.棧
【標準答案】A
84、一個棧的入棧序列是 A,B,C,D,E,則棧的不可能的輸出序列是?
A、EDCBA;
B、DECBA;
C、DCEAB;
D、ABCDE
【標準答案】C
85、寫出判斷ABCD四個表達式的是否正確, 若正確, 寫出經過表達式中 a 的值。
int a = 4;
(A)、a += (a++);
(B)、a += (++a) ;
(C)、(a++) += a;
(D)、(++a) += (a++);
a = ?
複製代碼
【參考答案】
C錯誤,左側不是一個有效變量,不能賦值,可改爲 (++a) += a; 改後答案依次爲 9,10,10,11
86、請你談談你是如何使用 return 語句的。
【參考答案】
(1)return 語句不可返回指向“棧內存”的“指針”或者“引用” ,因爲該內存在函數體結束時被自動銷燬。
(2)要搞清楚返回的究竟是“值”、“指針”還是“引用” 。
(3)如果函數返回值是一個對象,要考慮 return 語句的效率。
87、① return String(s1 + s2); 和 ②String temp(s1 + s2); return temp; 一樣嗎?
【參考答案】
①這是臨時對象的語法,表示“創建一個臨時對象並返回它” 。
②將發生三件事。首先,temp 對象被創建,同時完成初始化;然後拷貝構造函數把 temp 拷貝到保存返回值的外部存儲單元中;
最後,temp 在函數結束時被銷燬(調用析構函數) 。然而“創建一個臨時對象並返回它”的過程是不同的,
編譯器直接把臨時對象創建並初始化在外部存儲單元中,省去了拷貝和析構的化費,提高了效率。
88、下列程序的運行結果是?
#include <iostream>
const char *str = "vermeer";
int main()
{
const char *pstr = str;
cout << "The address of pstr is: " << pstr << endl;
}
複製代碼
【標準答案】
The address of pstr is: vermeer
89、下列程序輸出結果是?
inline void max_out( int val1, int val2 )
{
cout << ( val1 > val2 ) ? val1 : val2;
}
int main()
{
int ix = 10, jx = 20;
cout << "The larger of " << ix;
cout << ", " << jx << " is ";
max_out( ix, jx );
cout << endl;
}
複製代碼
【標準答案】
The larger of 10, 20 is 0 ,
爲什麼不是20呢?問題在於輸出操作符的優先級高於條件操作符 所以輸出 val1 和 val2 比較結果的 true/false
90、int max( int *ia, int sz );
int max( int *, int = 10 );
算函數重載?還是重複聲明?
【標準答案】
如果在兩個函數的參數表中只有缺省實參不同則第二個聲明被視爲第一個的重複聲明 。
第六部分:編程練習(比C要難)(91-100)
91、請編寫一個 C++函數,該函數給出一個字節中被置 1 的位的個數。
【參考答案】
unsigned int TestAsOne0(char log)
{
int i;
unsigned int num = 0, val;
for (i = 0; i < 8; i++)
{
val = log >> i; //移位
val &= 0x01; //與1相與
if (val)
num++;
}
return num;
}
複製代碼
92、編寫一個函數,函數接收一個字符串,是由十六進制數組成的一組字符串,函數的功能是把接到的這組字符串轉換成十進制數字.並將十進制數字返回。
【參考答案】
BOOL HexToDec(LPCTSTR shex, int& idec)
{
int i, mid;
int len = lstrlen(shex);
if (len > 8)
return FALSE;
mid = 0;
idec = 0;
for (i = 0; i < len; i++)
{
if (shex[i] >= '0'&&shex[i] <= '9')
mid = shex[i] - '0';
else if (shex[i] >= 'a'&&shex[i] <= 'f')
mid = shex[i] - 'a' + 10;
else if (shex[i] >= 'A'&&shex[i] <= 'F')
mid = shex[i] - 'A' + 10;
else
return FALSE;
mid <<= ((len - i - 1) << 2); // 移位表示變爲2的n次方倍
idec = idc + mid;
}
return TRUE;
}
複製代碼
93、輸入一個字符串,將其逆序後輸出 。
【參考答案】
void main()
{
char a[50];
memset(a, 0, sizeof(a));
int i = 0, j;
char t;
cin.getline(a, 50, '\n');
for (i = 0, j = strlen(a) - 1; i < strlen(a) / 2; i++, j--)
{
t = a[i];
a[i] = a[j];
a[j] = t;
}
cout << a << endl;
}
複製代碼
94、編寫一個算法frequency,統計在一個輸入字符串中各個不同字符出現的頻度。用適當的測試數據來驗證這個算法。
【參考答案】
void frequency(String& s, char& A[], int& C[], int &k)
{
int i, j, len = s.length();
if (!len) { cout << "The string is empty. " << endl; k = 0; return; }
else
{
A[0] = s[0]; C[0] = 1; k = 1; /*語句s[i]是串的重載操作*/
for (i = 1; i < len; i++) C[i] = 0; /*初始化*/
for (i = 1; i < len; i++)
{ /*檢測串中所有字符*/
j = 0; while (j < k && A[j] != s[i]) j++; /*檢查s[i]是否已在A[ ]中*/
if (j == k)
{
A[k] = s[i]; C[k]++; k++
} /*s[i]從未檢測過*/
else C[j]++; /*s[i]已經檢測過*/
}
}
}
複製代碼
95、假設以數組Q[m]存放循環隊列中的元素, 同時以rear和length分別指示環形隊列中的隊尾位置和隊列中所含元素的個數。試給出該循環隊列的隊空條件和隊滿條件, 並寫出相應的插入(enqueue)和刪除(dlqueue)元素的操作。
【參考答案】循環隊列類定義
#include <assert.h>
template <class Type> class Queue { //循環隊列的類定義
public:
Queue ( int=10 );
~Queue ( ) { delete [ ] elements; }
void EnQueue ( Type & item );
Type DeQueue ( );
Type GetFront ( );
void MakeEmpty ( ) { length = 0; } //置空隊列
int IsEmpty ( ) const { return length == 0; } //判隊列空否
int IsFull ( ) const { return length == maxSize; } //判隊列滿否
private:
int rear, length; //隊尾指針和隊列長度
Type *elements; //存放隊列元素的數組
int maxSize; //隊列最大可容納元素個數
};
複製代碼
template <class Type>
Queue<Type>::Queue(int sz) : rear(maxSize - 1), length(0), maxSize(sz)
{
//建立一個最大具有maxSize個元素的空隊列。
elements = new Type[maxSize];//創建隊列空間
assert(elements != 0);//斷言: 動態存儲分配成功與否
}
template<class Type>
void Queue<Type>::EnQueue(Type &item)
{
assert(!IsFull());//判隊列是否不滿,滿則出錯處理
length++;//長度加1
rear = (rear + 1) % maxSize;//隊尾位置進1
elements[rear] = item;//進隊列
}
template<class Type>
Type Queue<Type> ::DeQueue()
{
assert(!IsEmpty());//判斷隊列是否不空,空則出錯處理
length--;//隊列長度減1
return elements[(rear - length + maxSize) % maxSize];//返回原隊頭元素值
}
template<class Type>
Type Queue<Type> ::GetFront()
{
assert(!IsEmpty());
return elements[(rear - length + 1 + maxSize) % maxSize];//返回隊頭元素值
}
複製代碼
96、已知A[n]爲整數數組,試寫出實現下列運算的遞歸算法:
(1) 求數組A中的最大整數。
(2) 求n個整數的和。
(3) 求n個整數的平均值。
【參考答案】
#include <iostream.h>
class RecurveArray
{ //數組類聲明
private: int *Elements; //數組指針
int ArraySize; //數組尺寸
int CurrentSize; //當前已有數組元素個數
public :
RecurveArray ( int MaxSize =10 ) :
ArraySize ( MaxSize ), Elements ( new int[MaxSize] ){ }
~RecurveArray ( ) { delete [ ] Elements; }
void InputArray(); //輸入數組的內容
int MaxKey ( int n ); //求最大值
int Sum ( int n ); //求數組元素之和
float Average ( int n ); //求數組元素的平均值
};
void RecurveArray :: InputArray ( )
{ //輸入數組的內容
cout << "Input the number of Array: \n";
for ( int i = 0; i < ArraySize; i++ ) cin >> Elements[i];
}
int RecurveArray :: MaxKey ( int n )
{ //遞歸求最大值
if ( n == 1 ) return Elements[0];
int temp = MaxKey ( n - 1 );
if ( Elements[n-1] > temp ) return Elements[n-1];
else return temp;
}
int RecurveArray :: Sum ( int n ) { //遞歸求數組之和
if ( n == 1) return Elements[0];
else return Elements[n-1] + Sum (n-1);
}
float RecurveArray :: Average ( int n ) { //遞歸求數組的平均值
if ( n == 1) return (float) Elements[0];
else return ( (float) Elements[n-1] + ( n - 1) * Average ( n - 1 ) ) / n;
}
int main ( int argc, char* argv [ ] ) {
int size = -1;
cout << "No. of the Elements : ";
while ( size < 1 ) cin >> size;
RecurveArray ra ( size );
ra.InputArray();
cout<< "\nThe max is: " << ra.MaxKey ( ra.MaxSize ) << endl;
cout<< "\nThe sum is: " << ra.Sum ( ra.MaxSize ) << endl;
cout<< "\nthe avr is: " << ra.Average ( ra.MaxSize ) << endl;
return 0;
}
複製代碼
97、已知f爲單鏈表的表頭指針, 鏈表中存儲的都是整型數據,試寫出實現下列運算的遞歸算法:
(1) 求鏈表中的最大整數。
(2) 求鏈表的結點個數。
(3) 求所有整數的平均值。
【標準答案】
#include <iostream.h> //定義在頭文件"RecurveList.h"中
class List;
class ListNode { //鏈表結點類
friend class List;
private:
int data; //結點數據
ListNode *link; //結點指針
ListNode ( const int item ) : data(item), link(NULL) { } //構造函數
};
class List { //鏈表類
private:
ListNode *first, current;
int Max ( ListNode *f );
int Num ( ListNode *f );
float Avg ( ListNode *f, int& n );
public:
List ( ) : first(NULL), current (NULL) { } //構造函數
~List ( ){ } //析構函數
ListNode* NewNode ( const int item ); //創建鏈表結點, 其值爲item
void NewList ( const int retvalue ); //建立鏈表, 以輸入retvalue結束
void PrintList ( ); //輸出鏈表所有結點數據
int GetMax ( ) { return Max ( first ); } //求鏈表所有數據的最大值
int GetNum ( ) { return Num ( first ); } //求鏈表中數據個數
float GetAvg ( ) { return Avg ( first ); } //求鏈表所有數據的平均值
};
ListNode* List :: NewNode ( const int item ) { //創建新鏈表結點
ListNode *newnode = new ListNode (item);
return newnode;
}
void List :: NewList ( const int retvalue ) { //建立鏈表, 以輸入retvalue結束
first = NULL; int value; ListNode *q;
cout << "Input your data:\n"; //提示
cin >> value; //輸入
while ( value != retvalue )
{ //輸入有效
q = NewNode ( value ); //建立包含value的新結點
if ( first == NULL ) first = current = q;//空表時, 新結點成爲鏈表第一個結點
else { current->link = q; current = q; } //非空表時, 新結點鏈入鏈尾
cin >> value; //再輸入
}
current->link = NULL; //鏈尾封閉
}
void List :: PrintList ( )
{ //輸出鏈表
cout << "\nThe List is : \n";
ListNode *p = first;
while ( p != NULL ) { cout << p->data << ' '; p = p->link; }
cout << ‘\n’;
}
int List :: Max ( ListNode *f )
{ //遞歸算法 : 求鏈表中的最大值
if ( f ->link == NULL ) return f ->data; //遞歸結束條件
int temp = Max ( f ->link ); //在當前結點的後繼鏈表中求最大值
if ( f ->data > temp )
return f ->data; //如果當前結點的值還要大, 返回當前檢點值
else return temp; //否則返回後繼鏈表中的最大值
}
int List :: Num ( ListNode *f )
{ //遞歸算法 : 求鏈表中結點個數
if ( f == NULL ) return 0; //空表, 返回0
return 1+ Num ( f ->link ); //否則, 返回後繼鏈表結點個數加1
}
float List :: Avg ( ListNode *f , int& n )
{ //遞歸算法 : 求鏈表中所有元素的平均值
if ( f ->link == NULL ) //鏈表中只有一個結點, 遞歸結束條件
{
n = 1; return ( float ) (f ->data );
}
else
{ float Sum = Avg ( f ->link, n ) * n; n++; return ( f ->data + Sum ) / n; }
}
#include "RecurveList.h" //定義在主文件中
int main ( int argc, char* argv[ ] )
{
List test; int finished;
cout << “輸入建表結束標誌數據 :”;
cin >> finished; //輸入建表結束標誌數據
test.NewList ( finished ); //建立鏈表
test.PrintList ( ); //打印鏈表
cout << "\nThe Max is : " << test.GetMax ( );
cout << "\nThe Num is : " << test.GetNum ( );
cout << "\nThe Ave is : " << test.GetAve () << '\n';
printf ( "Hello World!\n" );
return 0;
}
複製代碼
98、字符串的替換操作 replace(String &s, String &t, String &v) 是指:
若t是s的子串,則用串v替換串t在串s中的所有出現;若t不是s的子串,則串s不變。例如,若串s爲“aabbabcbaabaaacbab”,串t爲“bab”,串v爲“abdc”,則執行replace操作後,串s中的結果爲“aababdccbaabaaacabdc”。試利用字符串的基本運算實現這個替換操作。
【參考答案】
String & String::Replace(String & t, String &v)
{
if ((int id = Find(t)) == -1) //沒有找到,當前字符串不改,返回
{
cout << “The(replace) operation failed.” << endl; return *this;
}
String temp(ch);//用當前串建立一個空的臨時字符串
ch[0] = '\0'; curLen = 0; //當前串作爲結果串,初始爲空
int j, k = 0, l; //存放結果串的指針
while (id != -1)
{
for (j = 0; j < id; j++) ch[k++] = temp.ch[j];
curLen += id + v.curLen; //修改結果串連接後的長度
if (curLen <= maxLen) l = v.curLen; //確定替換串v傳送字符數l
else { l = curLen - maxLen; curLen = maxLen; }
for (j = 0; j < l; j++) ch[k++] = v.ch[j];
//連接替換串v到結果串ch後面
if (curLen == maxLen) break; //字符串超出範圍
for (j = id + t.curLen; j < temp.curLen; j++)
temp.ch[j - id - t.curLen] = temp.ch[j]; //刪改原來的字符串 temp.curLen -= ( id + t.curLen );
id = temp.Find(t);
}
return *this;
}
複製代碼
99、試編寫一個求解Josephus問題的函數。用整數序列1, 2, 3, ……, n表示順序圍坐在圓桌周圍的人,並採用數組表示作爲求解過程中使用的數據結構。然後使用n = 9, s = 1, m = 5,以及n = 9, s = 1, m = 0,或者n = 9, s = 1, m = 10作爲輸入數據,檢查你的程序的正確性和健壯性。
【參考答案】
void Josephus(int A[], int n, int s, int m)
{
int i, j, k, tmp;
if (m == 0)
{
cout << "m = 0是無效的參數!" << endl;
return;
}
for (i = 0; i < n; i++)
A[i] = i + 1; /*初始化,執行n次*/
i = s - 1; /*報名起始位置*/
for (k = n; k > 1; i--)
{ /*逐個出局,執行n-1次*/
if (i == k)
i = 0;
i = (i + m - 1) % k; /*尋找出局位置*/
if (i != k - 1)
{
tmp = A[i]; /*出局者交換到第k-1位置*/
for (j = i; j < k - 1; j++)
A[j] = A[j + 1];
A[k - 1] = tmp;
}
}
for (k = 0; k < n / 2; k++)
{ /*全部逆置, 得到出局序列*/
tmp = A[k]; A[k] = A[n - k + 1]; A[n - k + 1] = tmp;
}
}
複製代碼
100、編寫類 String 的構造函數、析構函數和賦值函數已知類 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 的上述 4 個函數。
【標準答案】
// 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]; // 若能加 NULL 判斷則更好
*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]; // 若能加 NULL 判斷則更好
strcpy(m_data, other.m_data);
}
// 賦值函數
String & String::operate = (const String &other)
{
if (this == &other)
return *this;
delete[] m_data;
int length = strlen(other.m_data);
m_data = new char[length + 1];
strcpy(m_data, other.m_data);
return *this;
}
原文地址:https://blog.csdn.net/weixin_41168353/article/details/80083861