1. 面向對象的程序設計思想是什麼?
答:把數據結構和對數據結構進行操作的方法封裝形成一個個的對象。
2. 什麼是類?
答:把一些具有共性的對象歸類後形成一個集合,也就是所謂的類。
3. 對象都具有的兩方面特徵是什麼?分別是什麼含義?
答:對象都具有的特徵是:靜態特徵和動態特徵。
靜態特徵是指能描述對象的一些屬性(成員變量),動態特徵是指對象表現出來的行爲(成員函數)
4. 在頭文件中進行類的聲明,在對應的實現文件中進行類的定義有什麼意義?
答:這樣可以提高編譯效率,因爲分開的話只需要編譯一次生成對應的.obj文件後,再次應用該類的地方,這個類就不會被再次編譯,從而大大的提高了編譯效率。
5. 在類的內部定義成員函數的函數體,這種函數會具備那種屬性?
答:這種函數會自動爲內聯函數,這種函數在函數調用的地方在編譯階段都會進行代碼替換。
6. 成員函數通過什麼來區分不同對象的成員數據?爲什麼它能夠區分?
答:通過this指針指向對象的首地址來區分的。
7. C++編譯器自動爲類產生的四個缺省函數是什麼?
答:默認構造函數,拷貝構造函數,析構函數,賦值函數。
8. 拷貝構造函數在哪幾種情況下會被調用?
答:
1.當類的一個對象去初始化該類的另一個對象時;
2.如果函數的形參是類的對象,調用函數進行形參和實參結合時;
3.如果函數的返回值是類對象,函數調用完成返回時。
9. 構造函數與普通函數相比在形式上有什麼不同?(構造函數的作用,它的聲明形式來分析)
答:構造函數是類的一種特殊成員函數,一般情況下,它是專門用來初始化對象成員變量的。
構造函數的名字必須與類名相同,它不具有任何類型,不返回任何值。
10. 什麼時候必須重寫拷貝構造函數?
答:當構造函數涉及到動態存儲分配空間時,要自己寫拷貝構造函數,並且要深拷貝。
11. 構造函數的調用順序是什麼?
答:1.先調用基類構造函數
2.按聲明順序初始化數據成員
3.最後調用自己的構造函數。
12. 哪幾種情況必須用到初始化成員列表?
答:類的成員是常量成員初始化;
類的成員是對象成員初始化,而該對象沒有無參構造函數。
類的成員爲引用時。
13. 什麼是常對象?
答:常對象是指在任何場合都不能對其成員的值進行修改的對象。
14. 靜態函數存在的意義?
答:靜態私有成員在類外不能被訪問,可通過類的靜態成員函數來訪問;
當類的構造函數是私有的時,不像普通類那樣實例化自己,只能通過靜態成員函數來調用構造函數。
15. 在類外有什麼辦法可以訪問類的非公有成員?
答:友元,繼承,公有成員函數。
16. 什麼叫抽象類?
答:不用來定義對象而只作爲一種基本類型用作繼承的類。
17. 運算符重載的意義?
答:爲了對用戶自定義數據類型的數據的操作與內定義的數據類型的數據的操作形式一致。
18. 不允許重載的5個運算符是哪些?
答:
1. .*(成員指針訪問運算符號)
2. ::域運算符
3. Sizeof 長度運算符號
4. ?:條件運算符號
5. .(成員訪問符)
19. 運算符重載的三種方式?
答:普通函數,友元函數,類成員函數。
20. 流運算符爲什麼不能通過類的成員函數重載?一般怎麼解決?
答:因爲通過類的成員函數重載必須是運算符的第一個是自己,而對流運算的重載要求第一個參數是流對象。所以一般通過友元來解決。
21. 賦值運算符和拷貝構造函數的區別與聯繫?
答:相同點:都是將一個對象copy到另一箇中去。
不同點:拷貝構造函數涉及到要新建立一個對象。
22. 在哪種情況下要調用該類的析構函數?
答:對象生命週期結束時。
23. 對象間是怎樣實現數據的共享的?
答:通過類的靜態成員變量來實現對象間的數據共享。靜態成員變量佔有自己獨立的空間不爲某個對象所私有。
24. 友元關係有什麼特性?
答:單向的,非傳遞的,不能繼承的。
25. 對對象成員進行初始化的次序是什麼?
答:它的次序完全不受它們在初始化表中次序的影響,只有成員對象在類中聲明的次序來決定的。
26. 類和對象之間的關係是什麼?
答:類是對象的抽象,對象是類的實例。
27. 對類的成員的訪問屬性有什麼?
答:public,protected,private。
28.const char *p和char * const p; 的區別
答:
如果const位於星號的左側,則const就是用來修飾指針所指向的變量,即指針指向爲常量;
如果const位於星號的右側,const就是修飾指針本身,即指針本身是常量。
29. 是不是一個父類寫了一個virtual 函數,如果子類覆蓋它的函數不加virtual ,也能實現多態?
答:
virtual修飾符會被隱形繼承的。
virtual可加可不加,子類覆蓋它的函數不加virtual ,也能實現多態。
30. 函數重載是什麼意思?它與虛函數的概念有什麼區別?
答:函數重載是一個同名函數完成不同的功能,編譯系統在編譯階段通過函數參數個數、參數類型不同,函數的返回值來區分該調用哪一個函數,即實現的是靜態的多態性。但是記住:不能僅僅通過函數返回值不同來實現函數重載。而虛函數實現的是在基類中通過使用關鍵字virtual來申明一個函數爲虛函數,含義就是該函數的功能可能在將來的派生類中定義或者在基類的基礎之上進行擴展,系統只能在運行階段才能動態決定該調用哪一個函數,所以實現的是動態的多態性。它體現的是一個縱向的概念,也即在基類和派生類間實現。
31. 構造函數和析構函數是否可以被重載,爲什麼?
答:構造函數可以被重載,析構函數不可以被重載。因爲構造函數可以有多個且可以帶參數,而析構函數只能有一個,且不能帶參數。
32. 如何定義和實現一個類的成員函數爲回調函數?
答:
所謂的回調函數,就是預先在系統的對函數進行註冊,讓系統知道這個函數的存在,以後,當某個事件發生時,再調用這個函數對事件進行響應。
定義一個類的成員函數時在該函數前加CALLBACK即將其定義爲回調函數,函數的實現和普通成員函數沒有區別
33. 虛函數是怎麼實現的?
答:簡單說來使用了虛函數表.
34. 抽象類不會產生實例,所以不需要有構造函數。 錯
35. 從一個模板類可以派生新的模板類,也可以派生非模板類。 對
36. main 函數執行以前,還會執行什麼代碼?
答案:全局對象的構造函數會在main 函數之前執行。
37. 當一個類A 中沒有生命任何成員變量與成員函數,這時sizeof(A)的值是多少,如果不是零,請解釋一下編譯器爲什麼沒有讓它爲零。(Autodesk)
答案:肯定不是零。舉個反例,如果是零的話,聲明一個class A[10]對象數組,而每一個對象佔用的空間是零,這時就沒辦法區分A[0],A[1]…了。
38. delete與 delete []區別:
答:delete只會調用一次析構函數,而delete[]會調用每一個成員的析構函數。
39.子類析構時要調用父類的析構函數嗎?
答:會調用。析構函數調用的次序是先派生類的析構後基類的析構,也就是說在基類的的析構調用的時候,派生類的信息已經全部銷燬了
40. 繼承的優缺點。
1、類繼承是在編譯時刻靜態定義的,且可直接使用,
2、類繼承可以較方便地改變父類的實現。
缺點:
1、因爲繼承在編譯時刻就定義了,所以無法在運行時刻改變從父類繼承的實現
2、父類通常至少定義了子類的部分行爲,父類的任何改變都可能影響子類的行爲
3、如果繼承下來的實現不適合解決新的問題,則父類必須重寫或被其他更適合的類替換。這種依賴關係限制了靈活性並最終限制了複用性。
41. 解釋堆和棧的區別。
答:棧區(stack)— 由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。
堆(heap)一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。
42. 一個類的構造函數和析構函數什麼時候被調用,是否需要手工調用?
答:構造函數在創建類對象的時候被自動調用,析構函數在類對象生命期結束時,由系統自動調用。
43. 何時需要預編譯:
答:總是使用不經常改動的大型代碼體。
程序由多個模塊組成,所有模塊都使用一組標準的包含文件和相同的編譯選項。在這種情況下,可以將所有包含文件預編譯爲一個預編譯頭。
44. 多態的作用?
答:主要是兩個:
1. 隱藏實現細節,使得代碼能夠模塊化;擴展代碼模塊,實現代碼重用;
2. 接口重用:爲了類在繼承和派生的時候,保證使用家族中任一類的實例的某一屬性時的正確調用
45. 虛擬函數與普通成員函數的區別?內聯函數和構造函數能否爲虛擬函數?
答案:區別:虛擬函數有virtual關鍵字,有虛擬指針和虛函數表,虛擬指針就是虛擬函數的接口,而普通成員函數沒有。內聯函數和構造函數不能爲虛擬函數。
46. 構造函數和析構函數的調用順序? 析構函數爲什麼要虛擬?
答案:構造函數的調用順序:基類構造函數—對象成員構造函數—派生類構造函數;析構函數的調用順序與構造函數相反。析構函數虛擬是爲了防止析構不徹底,造成內存的泄漏。
47. C++中類型爲private的成員變量可以由哪些函數訪問?
答:只可以由本類中的成員函數和友元函數訪問
48. 請說出類中private,protect,public三種訪問限制類型的區別
答:private是私有類型,只有本類中的成員函數訪問;protect是保護型的,本類和繼承類可以訪問;public是公有類型,任何類都可以訪問.
49. 類中成員變量怎麼進行初始化?
答:可以通過構造函數的初始化列表或構造函數的函數體實現。
50. 在什麼時候需要使用“常引用”?
答:如果既要利用引用提高程序的效率,又要保護傳遞給函數的數據不在函數中被改變,就應使用常引用。
51. 引用與指針有什麼區別? 答 、1) 引用必須被初始化,指針不必。 2) 引用初始化以後不能被改變,指針可以改變所指的對象。 3) 不存在指向空值的引用,但是存在指向空值的指針。
52. 描述實時系統的基本特性 答 、在特定時間內完成特定的任務,實時性與可靠性。
54. 全局變量和局部變量在內存中是否有區別?如果有,是什麼區別? 答 、全局變量儲存在靜態數據區,局部變量在堆棧中。
55. 堆棧溢出一般是由什麼原因導致的? 答 、沒有回收垃圾資源
56. 什麼函數不能聲明爲虛函數? 答 構造函數(constructor)
57. IP地址的編碼分爲哪倆部分? 答 IP地址由兩部分組成,網絡號和主機號。
58. 不能做switch()的參數類型是: 答 、switch的參數不能爲實型。
59. 如何引用一個已經定義過的全局變量? 答 、可以用引用頭文件的方式,也可以用extern關鍵字,如果用引用頭文件方式來引用某個在頭文件中聲明的全局變理,假定你將那個變寫錯了,那麼在編譯期間會報錯,如果你用extern方式引用時,假定你犯了同樣的錯誤,那麼在編譯期間不會報錯,而在連接期間報錯
60. 對於一個頻繁使用的短小函數,在C語言中應用什麼實現,在C++中應用什麼實現? 答 、c用宏定義,c++用inline
61. C++是不是類型安全的? 答案:不是。兩個不同類型的指針之間可以強制轉換(用reinterpret cast)
62. 當一個類A 中沒有生命任何成員變量與成員函數,這時sizeof(A)的值是多少,請解釋一下編譯器爲什麼沒有讓它爲零。 答案:爲1。舉個反例,如果是零的話,聲明一個class A[10]對象數組,而每一個對象佔用的空間是零,這時就沒辦法區分A[0],A[1]…了。
63. 簡述數組與指針的區別? 答:數組要麼在靜態存儲區被創建(如全局數組),要麼在棧上被創建。指針可以隨時指向任意類型的內存塊。 (1)修改內容上的區別 char a[] = “hello”; a[0] = ‘X’; char *p = “world”; // 注意p 指向常量字符串 p[0] = ‘X’; // 編譯器不能發現該錯誤,運行時錯誤 (2) 用運算符sizeof 可以計算出數組的容量(字節數)。sizeof(p),p 爲指針得到的是一個指針變量的字節數,而不是p 所指的內存容量。
64. C++函數中值的傳遞方式 答:有三種方式:值傳遞、指針傳遞、引用傳遞
65. 內存的分配方式 答:分配方式有三種, 1、 靜態存儲區,是在程序編譯時就已經分配好的,在整個運行期間都存在,如全局變量、常量。 2、 棧上分配,函數內的局部變量就是從這分配的,但分配的內存容易有限。 3、 堆上分配,也稱動態分配,如我們用new,malloc分配內存,用delete,free來釋放的內存。
66. extern“C”有什麼作用? 答:Extern “C”是由C++提供的一個連接交換指定符號,用於告訴C++這段代碼是C函數。這是因爲C++編譯後庫中函數名會變得很長,與C生成的不一致,造成C++不能直接調用C函數,加上extren “c”後,C++就能直接調用C函數了。 Extern “C”主要使用正規DLL函數的引用和導出 和 在C++包含C函數或C頭文件時使用。使用時在前面加上extern “c” 關鍵字即可。可以用一句話概括extern “C”這個聲明的真實目的:實現C++與C及其它語言的混合編程。
67. 用什麼函數開啓新進程、線程。 答案: 線程:CreateThread/AfxBeginThread等 進程:CreateProcess等
68. SendMessage和PostMessage有什麼區別 答案:SendMessage是阻塞的,等消息被處理後,代碼才能走到SendMessage的下一行。PostMessage是非阻塞的,不管消息是否已被處理,代碼馬上走到PostMessage的下一行。
69. CMemoryState主要功能是什麼 答案:查看內存使用情況,解決內存泄露問題。
70. #include <filename.h> 和 #include “filename.h” 有什麼區別? 答:對於#include <filename.h> ,編譯器從標準庫路徑開始搜索 filename.h 對於#include “filename.h” ,編譯器從用戶的工作路徑開始搜索 filename.h
71. 處理器標識#error的目的是什麼? 答:編譯時輸出一條錯誤信息,並中止繼續編譯。
72. #if!defined(AFX_…_HADE_H) #define(AFX_…_HADE_H) …… #endif作用? 答:防止該頭文件被重複引用。
73. 在定義一個宏的時候要注意什麼? 答:定義部分的每個形參和整個表達式都必須用括號括起來,以避免不可預料的錯誤發生
74. 數組在做函數實參的時候會轉變爲什麼類型? 答:數組在做實參時會變成指針類型。
75. 系統會自動打開和關閉的3個標準的文件是? (1) 標準輸入----鍵盤---stdin (2) 標準輸出----顯示器---stdout (3) 標準出錯輸出----顯示器---stderr
76. .在Win32下 char, int, float, double各佔多少位? (1) Char 佔用8位 (2) Int 佔用32位 (3) Float 佔用32位 (4) Double 佔用64位
77. strcpy()和memcpy()的區別? 答:strcpy()和memcpy()都可以用來拷貝字符串,strcpy()拷貝以’\0’結束,但memcpy()必須指定拷貝的長度。
78. 說明define和const在語法和含義上有什麼不同? 答:(1) #define是C語法中定義符號變量的方法,符號常量只是用來表達一個值,在編譯階段符號就被值替換了,它沒有類型; (2) Const是C++語法中定義常變量的方法,常變量具有變量特性,它具有類型,內存中存在以它命名的存儲單元,可以用sizeof測出長度。
79. 說出字符常量和字符串常量的區別,並使用運算符sizeof計算有什麼不用? 答:字符常量是指單個字符,字符串常量以‘\0’結束,使用運算符sizeof計算多佔一字節的存儲空間。
80. 簡述全局變量的優缺點? 答:全局變量也稱爲外部變量,它是在函數外部定義的變量,它屬於一個源程序文件,它保存上一次被修改後的值,便於數據共享,但不方便管理,易引起意想不到的錯誤。
81. 總結static的應用和作用? 答:(1)函數體內static變量的作用範圍爲該函數體,不同於auto變量,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值; (2)在模塊內的static全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問; (3)在模塊內的static函數只可被這一模塊內的其它函數調用,這個函數的使用範圍被限制在聲明它的模塊內; (4)在類中的static成員變量屬於整個類所擁有,對類的所有對象只有一份拷貝; (5)在類中的static成員函數屬於整個類所擁有,這個函數不接收this指針,因而只能訪問類的static成員變量。
82. 總結const的應用和作用? 答:(1)欲阻止一個變量被改變,可以使用const關鍵字。在定義該const變量時,通常需要對它進行初始化,因爲以後就沒有機會再去改變它了; (2)對指針來說,可以指定指針本身爲const,也可以指定指針所指的數據爲const,或二者同時指定爲const; (3)在一個函數聲明中,const可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值; (4)對於類的成員函數,若指定其爲const類型,則表明其是一個常函數,不能修改類的成員變量; (5)對於類的成員函數,有時候必須指定其返回值爲const類型,以使得其返回值不爲“左值”。
83. 什麼是指針?談談你對指針的理解? 答:指針是一個變量,該變量專門存放內存地址; 指針變量的類型取決於其指向的數據類型,在所指數據類型前加* 指針變量的特點是它可以訪問所指向的內存。
84. 什麼是常指針,什麼是指向常變量的指針? 答:常指針的含義是該指針所指向的地址不能變,但該地址所指向的內容可以變化,使用常指針可以保證我們的指針不能指向其它的變量, 指向常變量的指針是指該指針的變量本身的地址可以變化,可以指向其它的變量,但是它所指的內容不可以被修改。指向長變量的指針定義,
85. 函數指針和指針函數的區別? 答:函數指針是指向一個函數入口的指針; 指針函數是函數的返回值是一個指針類型。
87. 簡述Debug版本和Release版本的區別? 答:Debug版本是調試版本,Release版本是發佈給用戶的最終非調試的版本,
88. 指針的幾種典型應用情況? 答: int *p[n];-----指針數組,每個元素均爲指向整型數據的指針。 int (*)p[n];---p爲指向一維數組的指針,這個一維數組有n個整型數據。 int *p();------函數帶回指針,指針指向返回的值。 int (*)p();----p爲指向函數的指針。
89. static函數與普通函數有什麼區別? 答:static函數在內存中只有一份,普通函數在每個被調用中維持一份拷貝
90. struct(結構) 和 union(聯合)的區別? 答:1. 結構和聯合都是由多個不同的數據類型成員組成, 但在任何同一時刻, 聯合中只存放了一個被選中的成員(所有成員共用一塊地址空間), 而結構的所有成員都存在(不同成員的存放地址不同)。 2. 對於聯合的不同成員賦值, 將會對其它成員重寫, 原來成員的值就不存在了, 而對於結構的不同成員賦值是互不影響的。
91. class 和 struct 的區別? 答:struct 的成員默認是公有的,而類的成員默認是私有的。
92. 簡述枚舉類型? 答:枚舉方便一次定義一組常量,使用起來很方便;
93. assert()的作用? 答:ASSERT()是一個調試程序時經常使用的宏,在程序運行時它計算括號內的表達式,如果表達式爲FALSE (0), 程序將報告錯誤,並終止執行。如果表達式不爲0,則繼續執行後面的語句。這個宏通常原來判斷程序中是否出現了明顯非法的數據,如果出現了終止程序以免導致嚴重後果,同時也便於查找錯誤。
94. 局部變量和全局變量是否可以同名? 答:能。局部會屏蔽全局。要用全局變量,需要使用"::"(域運算符)。
95. 程序的局部變量存在於(堆棧)中,全局變量存在於(靜態區 )中,動態申請數據存在於( 堆)中。
96. 在什麼時候使用常引用? 答:如果既要利用引用提高程序的效率,又要保護傳遞給函數的數據不在函數中被改變,就應使用常引用。
97. 類的聲明和實現的分開的好處? 答:1. 起保護作用; 2. 提高編譯的效率。
98. windows消息系統由哪幾部分構成? 答:由一下3部分組成: 1. 消息隊列:操作系統負責爲進程維護一個消息隊列,程序運行時不斷從該消息隊列中獲取消息、處理消息; 2. 消息循環:應用程序通過消息循環不斷獲取消息、處理消息。 3. 消息處理:消息循環負責將消息派發到相關的窗口上使用關聯的窗口過程函數進行處理。
99. 什麼是消息映射? 答:消息映射就是讓程序員指定MFC類(有消息處理能力的類)處理某個消息。然後由程序員完成對該處理函數的編寫,以實現消息處理功能。
100. 什麼是UDP和TCP的區別是什麼? 答:TCP的全稱爲傳輸控制協議。這種協議可以提供面向連接的、可靠的、點到點的通信。 UDP全稱爲用戶報文協議,它可以提供非連接的不可靠的點到多點的通信。用TCP還是UDP,那要看你的程序注重哪一個方面?可靠還是快速? |
101. winsock建立連接的主要實現步驟? 答: 服務器端:socket()建立套接字,綁定(bind)並監聽(listen),用accept()等待客戶端連接, accept()發現有客戶端連接,建立一個新的套接字,自身重新開始等待連接。該新產生的套接字使用send()和recv()寫讀數據,直至數據交換完畢,closesocket()關閉套接字。 客戶端:socket()建立套接字,連接(connect)服務器,連接上後使用send()和recv(),在套接字上寫讀數據,直至數據交換完畢,closesocket()關閉套接字。
102. 進程間主要的通訊方式? 答:信號量,管道,消息,共享內存
103. 構成Win32 API 函數的三個動態鏈接庫是什麼? 答:內核庫,用戶界面管理庫,圖形設備界面庫。
104. 創建一個窗口的步驟是? 答:填充一個窗口類結構->註冊這個窗口類->然後再創建窗口->顯示窗口->更新窗口。
105. 模態對話框和非模態對話框有什麼區別? 答:1.調用規則不同:前者是用DoModal()調用,後者通過屬性和ShowWindow()來顯示。 2.模態對話框在沒有關閉前用戶不能進行其他操作,而非模態對話框可以。 3.非模態對話框創建時必須編寫自己的共有構造函數,還要調用Create()函數。
106. 從EDIT框中取出數據給關聯的變量,已經把關聯的變量的數據顯示在EDIT框上的函數是什麼? 答: UpdateData(TRUE), Updatedata(FALSE).
107. 簡單介紹GDI? 答: GDI是Graphics Device Interface 的縮寫,譯爲:圖形設備接口;是一個在Windows應用程序中執行與設備無關的函數庫,這些函數在不同的輸出設備上產生圖形以及文字輸出。
108. windows消息分爲幾類?並對各類做簡單描述。 答: 1.窗口消息:與窗口相關的消息,除WM_COMMAND之外的所有以WM_開頭的消息; 2.命令消息;用於處理用戶請求,以WM_COMMAND表示的消息; 3.控件通知消息:統一由WM_NOTIFT表示, 4.用戶自定義消息。
109. 如何自定義消息? 答:使用WM_USER 和WM_APP兩個宏來自定義消息,
110. 簡述Visual C++ 、Win32 API和MFC之間的關係? 答:(1) Visual C+是一個以C++程序設計語言爲基礎的、集成的、可視化的編程環境; (2) Win32 API是32位Windows操作系以C/C++形式提供的一組應用程序接口; (3) MFC是對Win32 API的封裝,簡化了開發過程。
111.怎樣消除多重繼承中的二義性? 答: 1.成員限定符 2.虛基類
112什麼叫靜態關聯,什麼叫動態關聯 答:在多態中,如果程序在編譯階段就能確定實際執行動作,則稱靜態關聯, 如果等到程序運行才能確定叫動態關聯。
113多態的兩個必要條件 答:1.一個基類的指針或引用指向一個派生類對象 2.虛函數
114.什麼叫智能指針? 答:當一個類中,存在一個指向另一個類對象的指針時,對指針運算符進行重載,那麼當前類對象可以通過指針像調用自身成員一樣調用另一個類的成員。
115.什麼時候需要用虛析構函數? 答:當基類指針指向用new運算符生成的派生類對象時,delete基類指針時,派生類部分沒有釋放掉而造成釋放不徹底現象,需要虛析構函數。 補充:虛函數就是讓派生類調用基類的虛函數。
116. MFC中,大部分類是從哪個類繼承而來? 答:CObject
117.什麼是平衡二叉樹? 答:左右子樹都是平衡二叉樹,而且左右子樹的深度差值的約對值不大於1。
118.語句for( ;1 ;)有什麼問題?它是什麼意思? 答:無限循環,和while(1)相同。
119.派生新類的過程要經歷三個步驟 答:1.吸收基類成員 2.改造基類成員 3.添加新成員
121. TCP/IP 建立連接的過程 答:在TCP/IP協議中,TCP協議提供可靠的連接服務,採用三次握手建立一個連接。 第一次握手:建立連接時,客戶端發送連接請求到服務器,並進入SYN_SEND狀態,等待服務器確認; 第二次握手:服務器收到客戶端連接請求,向客戶端發送允許連接應答,此時服務器進入SYN_RECV狀態; 第三次握手:客戶端收到服務器的允許連接應答,向服務器發送確認,客戶端和服務器進入通信狀態,完成三次握手
122. memset ,memcpy 的區別 答:memset用來對一段內存空間全部設置爲某個字符,一般用在對定義的字符串進行初始化爲'\0'。 memcpy用來做內存拷貝,你可以拿它拷貝任何數據類型的對象,可以指定拷貝的數據長度;
123. 在C++ 程序中調用被 C 編譯器編譯後的函數,爲什麼要加 extern “C”? 答:C++語言支持函數重載,C 語言不支持函數重載。函數被C++編譯後在庫中的名字 與C 語言的不同。假設某個函數的原型爲: void foo(int x, int y);該函數被C 編譯器編譯後在庫中的名字爲_foo , 而C++編譯器則會產生像_foo_int_int 之類的名字。C++提供了C 連接交換指定符號extern“C”來解決名字匹配問題。
124怎樣定義一個純虛函數?含有純虛函數的類稱爲什麼? 答:在虛函數的後面加=0,含有虛函數的類稱爲抽象類。 抽象類和接口異同 相同點: 1. 都不能被直接實例化,通過繼承實現其抽象方法。 不同點:2. 接口只能定義抽象規則(函數不能提供實現 必須全部爲抽象函數);抽象類既可以定義規則,還可能提供已實現的成員(可以是抽象函數 也可以提供實現)。 3. 接口只包含方法、屬性、索引器、事件的簽名,但不能定義字段和包含實現的方法;抽象類可以定義字段、屬性、包含有實現的方法。 4. 一個類繼承了某個抽象類表示它“是什麼”,實現了某個接口表示它“有什麼功能”或者“會做什麼事”,如:燕子(具體類)是鳥(抽象類),會飛(接口),因此接口看起來就像是一個功能集規範的定義。 125.已知strcpy函數的原型是: char * strcpy(char * strDest,const char * strSrc);不調用庫函數,實現strcpy函數。其中,strSrc是原字符串,strDest是目標字符串 。 答案: char *strcpy(char *strDest, const char *strSrc) { if ( strDest == NULL || strSrc == NULL) return NULL ; if ( strDest == strSrc) return strDest ; char *tempptr = strDest ; //指針tempptr指向strDest的地址; while( (*strDest++ = *strSrc++) != ‘\\0’) //注意:別忘了轉義符; ; return tempptr ; //返回指針向的地址; }
126.已知類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(const char *str) { if ( str == NULL ) //strlen在參數爲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) { m_data = new char[strlen(other.m_data) + 1]; strcpy(m_data,other.m_data); } //賦值函數(重載運算符) String & String::operator =(const String &other) { if ( this == &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) { delete []m_data ; }
127.類成員函數的重載、覆蓋和隱藏的區別 答案: 成員函數被重載的特徵: (1)相同的範圍(在同一個類中); (2)函數名字相同; (3)參數不同; (4)virtual 關鍵字可有可無。 覆蓋是指派生類函數覆蓋基類函數,特徵是: (1)不同的範圍(分別位於派生類與基類); (2)函數名字相同; (3)參數相同; (4)基類函數必須有virtual 關鍵字。 “隱藏”是指派生類的函數屏蔽了與其同名的基類函數,規則如下: (1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual關鍵字,基類的函數將被隱藏(注意別與重載混淆)。 (2)如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有virtual 關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)
128.如何打印出當前源文件的文件名以及源文件的當前行號? 答案: cout << __FILE__ ; cout<<__LINE__ ; __FILE__和__LINE__是系統預定義宏,這種宏並不是在某個文件中定義的,而是由編譯器定義的。
129.文件中有一組整數,要求排序後輸出到另一個文件中 答案: void Order(vector<int> &data) //冒泡排序 { int count = data.size() ; int tag = false ; for ( int i = 0 ; i < count ; i++) { for ( int j = 0 ; j < count - i - 1 ; j++) { if ( data[j] > data[j+1]) { tag = true ; int temp = data[j] ; data[j] = data[j+1] ; data[j+1] = temp ; } } if ( !tag ) break ; } }
void main( void ) { vector<int>data; ifstream in("c:\\data.txt"); if ( !in) { cout<<"file error!"; exit(1); } int temp; while (!in.eof()) { in>>temp; data.push_back(temp); } in.close(); Order(data); ofstream out("c:\\result.txt"); if ( !out) { cout<<"file error!"; exit(1); } for ( i = 0 ; i < data.size() ; i++) out<<data[i]<<" "; out.close(); }
130.一個鏈表的結點結構 struct Node { int data ; Node *next ; }; typedef struct Node Node ; 已知鏈表的頭結點head,寫一個函數把這個鏈表逆序 ( Intel) 答案: Node * ReverseList(Node *head) //鏈表逆序 { if ( head == NULL || head->next == NULL ) return head; Node *p1 = head ; Node *p2 = p1->next ; Node *p3 = p2->next ; p1->next = NULL ; while ( p3 != NULL ) { p2->next = p1 ; p1 = p2 ; p2 = p3 ; p3 = p3->next ; } p2->next = p1 ; head = p2 ; return head ; }
131. 一個鏈表的結點結構 struct Node { int data ; Node *next ; }; typedef struct Node Node ; 已知兩個鏈表head1 和head2 各自有序,請把它們合併成一個鏈表依然有序。 答案: Node * Merge(Node *head1 , Node *head2) { if ( head1 == NULL) return head2 ; if ( head2 == NULL) return head1 ; Node *head = NULL ; Node *p1 = NULL; Node *p2 = NULL; if ( head1->data < head2->data ) { head = head1 ; p1 = head1->next; p2 = head2 ; } else { head = head2 ; p2 = head2->next ; p1 = head1 ; } Node *pcurrent = head ; while ( p1 != NULL && p2 != NULL) { if ( p1->data <= p2->data ) { pcurrent->next = p1 ; pcurrent = p1 ; p1 = p1->next ; } else { pcurrent->next = p2 ; pcurrent = p2 ; p2 = p2->next ; } } if ( p1 != NULL ) pcurrent->next = p1 ; if ( p2 != NULL ) pcurrent->next = p2 ; return head ; }
132.已知兩個鏈表head1 和head2 各自有序,請把它們合併成一個鏈表依然有序,這次要求用遞歸方法進行。 ( Autodesk) 答案: Node * MergeRecursive(Node *head1 , Node *head2) { if ( head1 == NULL ) return head2 ; if ( head2 == NULL) return head1 ; Node *head = NULL ; if ( head1->data < head2->data ) { head = head1 ; head->next = MergeRecursive(head1->next,head2); } else { head = head2 ; head->next = MergeRecursive(head1,head2->next); } return head ; }
133.分析一下這段程序的輸出 (Autodesk) class B { public: B() { cout<<"default constructor"<<endl; } ~B() { cout<<"destructed"<<endl; } B(int i):data(i) { cout<<"constructed by parameter" << data <<endl; } private: int data; }; B Play( B b) { return b ; } int main(int argc, char* argv[]) { B temp = Play(5); return 0; }
133 將“引用”作爲函數參數有哪些特點?
(1)傳遞引用給函數與傳遞指針的效果是一樣的。這時,被調函數的形參就成爲原來主調函數中的實參變量或對象的一個別名來使用,所以在被調函數中對形參變量的操作就是對其相應的目標對象(在主調函數中)的操作。
(2)使用引用傳遞函數的參數,在內存中並沒有產生實參的副本,它是直接對實參操作;而使用一般變量傳遞函數的參數,當發生函數調用時,需要給形參分配存儲單元,形參變量是實參變量的副本;如果傳遞的是對象,還將調用拷貝構造函數。因此,當參數傳遞的數據較大時,用引用比用一般變量傳遞參數的效率和所佔空間都好。
(3)使用指針作爲函數的參數雖然也能達到與使用引用的效果,但是,在被調函數中同樣要給形參分配存儲單元,且需要重複使用"*指針變量名"的形式進行運算,這很容易產生錯誤且程序的閱讀性較差;另一方面,在主調函數的調用點處,必須用變量的地址作爲實參。而引用更容易使用,更清晰。
134. 什麼時候需要“引用”? 流操作符(<<、>>)和賦值操作符(=)的返回值、拷貝構造函數的參數、賦值操作符的參數、其它情況都推薦使用引用。
135.面向對象的三個基本特徵,並簡單敘述之?
1. 封裝:將客觀事物抽象成類,每個類對自身的數據和方法實行protection(private, protected,public)
2. 繼承:廣義的繼承有三種實現形式:實現繼承(指使用基類的屬性和方法而無需額外編碼的能力)、可視繼承(子窗體使用父窗體的外觀和實現代碼)、接口繼承(僅使用屬性和方法,實現滯後到子類實現)。前兩種(類繼承)和後一種(對象組合=>接口繼承以及純虛函數)構成了功能複用的兩種方式。
3. 多態:是將父對象設置成爲和一個或更多的他的子對象相等的技術,賦值之後,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。
136.求下面函數的返回值(微軟)
int func(x) { int countx = 0; while(x) { countx ++; x = x&(x-1); } return countx; }
假定x = 9999。 答案:8 思路:將x轉化爲2進制,看含有的1的個數。
137、寫出下列代碼的輸出內容 #i nclude<stdio.h> int inc(int a) { return(++a); } int multi(int*a,int*b,int*c) { return(*c=*a**b); } typedef int(FUNC1)(int in); typedef int(FUNC2) (int*,int*,int*); void show(FUNC2 fun,int arg1, int*arg2) { INCp=&inc; int temp =p(arg1); fun(&temp,&arg1, arg2); printf("%d\n",*arg2); } main() { int a; show(multi,10,&a); return 0; } 答:110 138。編寫一個 C 函數,該函數在一個字符串中找到可能的最長的子字符串,且該字符串是由同一字符組成的。 char * search(char *cpSource, char ch) { char *cpTemp=NULL, *cpDest=NULL; int iTemp, iCount=0; while(*cpSource) { if(*cpSource == ch) { iTemp = 0; cpTemp = cpSource; while(*cpSource == ch) ++iTemp, ++cpSource; if(iTemp > iCount) iCount = iTemp, cpDest = cpTemp; if(!*cpSource) break; } ++cpSource; } return cpDest; }
139。請編寫一個 C 函數,該函數在給定的內存區域搜索給定的字符,並返回該字符所在位置索引值。 int search(char *cpSource, int n, char ch) { int i; for(i=0; i<n && *(cpSource+i) != ch; ++i); return i; } 140.一個單向鏈表,不知道頭節點,一個指針指向其中的一個節點,問如何刪除這個指針指向的節點? 將這個指針指向的next節點值copy到本節點,將next指向next->next,並隨後刪除原next指向的節點。 141、用指針的方法,將字符串“ABCD1234efgh”前後對調顯示 #i nclude <stdio.h> #i nclude <string.h> #i nclude <dos.h> int main() { char str[] = "ABCD1234efgh"; int length = strlen(str); char * p1 = str; char * p2 = str + length - 1; while(p1 < p2) { char c = *p1; *p1 = *p2; *p2 = c; ++p1; --p2; } printf("str now is %s\n",str); system("pause"); return 0; }
142、有一分數序列:1/2,1/4,1/6,1/8……,用函數調用的方法,求此數列前20項的和 #i nclude <stdio.h> double getValue() { double result = 0; int i = 2; while(i < 42) { result += 1.0 / i;//一定要使用1.0做除數,不能用1,否則結果將自動轉化成整數,即0.000000 i += 2; } return result; } int main() { printf("result is %f\n", getValue()); system("pause"); return 0; } 143、有一個數組a[1000]存放0--1000;要求每隔二個數刪掉一個數,到末尾時循環至開頭繼續進行,求最後一個被刪掉的數的原始下標位置。 以7個數爲例: {0,1,2,3,4,5,6,7} 0-->1-->2(刪除)-->3-->4-->5(刪除)-->6-->7-->0(刪除),如此循環直到最後一個數被刪除。 方法1:數組 #include <iostream> using namespace std; #define null 1000 int main() { int arr[1000]; for (int i=0;i<1000;++i) arr[i]=i; int j=0; int count=0; while(count<999) { while(arr[j%1000]==null) j=(++j)%1000; j=(++j)%1000; while(arr[j%1000]==null) j=(++j)%1000; j=(++j)%1000; while(arr[j%1000]==null) j=(++j)%1000; arr[j]=null; ++count; } while(arr[j]==null) j=(++j)%1000; cout<<j<<endl; return 0; } 方法2:鏈表 #i nclude<iostream> using namespace std; #define null 0 struct node { int data; node* next; }; int main() { node* head=new node; head->data=0; head->next=null; node* p=head; for(int i=1;i<1000;i++) { node* tmp=new node; tmp->data=i; tmp->next=null; head->next=tmp; head=head->next; } head->next=p; while(p!=p->next) { p->next->next=p->next->next->next; p=p->next->next; } cout<<p->data; return 0; }
方法3:通用算法 #i nclude <stdio.h> #define MAXLINE 1000 //元素個數 /* MAXLINE 元素個數 a[] 元素數組 R[] 指針場 suffix 下標 index 返回最後的下標序號 values 返回最後的下標對應的值 start 從第幾個開始 K 間隔 */ int find_n(int a[],int R[],int K,int& index,int& values,int s=0) { int suffix; int front_node,current_node; suffix=0; if(s==0) { current_node=0; front_node=MAXLINE-1; } else { current_node=s; front_node=s-1; } while(R[front_node]!=front_node) { printf("%d\n",a[current_node]); R[front_node]=R[current_node]; if(K==1) { current_node=R[front_node]; continue; } for(int i=0;i<K;i++){ front_node=R[front_node]; } current_node=R[front_node]; } index=front_node; values=a[front_node]; return 0; } int main(void) { int a[MAXLINE],R[MAXLINE],suffix,index,values,start,i,K; suffix=index=values=start=0; K=2; for(i=0;i<MAXLINE;i++) { a[i]=i; R[i]=i+1; } R[i-1]=0; find_n(a,R,K,index,values,2); printf("the value is %d,%d\n",index,values); return 0; } 144、指出下列程序有什麼錯誤: void test2() { char string[10], str1[10]; int i; for(i=0; i<10; i++) { str1[i] = 'a'; } strcpy( string, str1 ); } 解答:對試題2,如果面試者指出字符數組str1不能在數組內結束可以給3分;如果面試者指出strcpy(string, str1)調用使得從str1內存起復制到string內存起所複製的字節數具有不確定性可以給7分,在此基礎上指出庫函數strcpy工作方式的給10分; str1不能在數組內結束:因爲str1的存儲爲:{a,a,a,a,a,a,a,a,a,a},沒有'\0'(字符串結束符),所以不能結束 strcpy( char *s1,char *s2)他的工作原理是,掃描s2指向的內存,逐個字符付到s1所指向的內存,直到碰到'\0',因爲str1結尾沒有'\0',所以具有不確定性,不知道他後面還會付什麼東東。 正確應如下 void test2() { char string[10], str1[10]; int i; for(i=0; i<9; i++) { str1[i] = 'a'+i; //把abcdefghi賦值給字符數組 } str[i]='\0';//加上結束符 strcpy( string, str1 ); } 145、實現strcmp int StrCmp(const char *str1, const char *str2) { assert(str1 && srt2); while(*str1 && *str1++ = = *str2++); return *str1-*str2; } 146.符串A和B,輸出A和B中的最大公共子串。 比如A="aocdfe" B="pmcdfa" 則輸出"cdf" */ //Author: azhen #i nclude<stdio.h> #i nclude<stdlib.h> #i nclude<string.h> char *commanstring(char shortstring[], char longstring[]) { int i, j; char *substring=malloc(256); if(strstr(longstring, shortstring)!=NULL) //如果……,那麼返回shortstring return shortstring; for(i=strlen(shortstring)-1;i>0; i--) //否則,開始循環計算 { for(j=0; j<=strlen(shortstring)-i; j++){ memcpy(substring, &shortstring[j], i); substring[i]='\0'; if(strstr(longstring, substring)!=NULL) return substring; } } return NULL; }
main() { char *str1=malloc(256); char *str2=malloc(256); char *comman=NULL; gets(str1); gets(str2); if(strlen(str1)>strlen(str2)) //將短的字符串放前面 comman=commanstring(str2, str1); else comman=commanstring(str1, str2); printf("the longest comman string is: %s\n", comman); }
147、寫一個函數比較兩個字符串str1和str2的大小,若相等返回0,若str1大於 str2返回1,若str1小於str2返回-1 int strcmp ( const char * src,const char * dst) { int ret = 0 ; while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst) { ++src; ++dst; } if ( ret < 0 ) ret = -1 ; else if ( ret > 0 ) ret = 1 ; return( ret ); } 148、判斷一個字符串是不是迴文 int IsReverseStr(char *aStr) { int i,j; int found=1; if(aStr==NULL) return -1; j=strlen(aStr); for(i=0;i<j/2;i++) if(*(aStr+i)!=*(aStr+j-i-1)) { found=0; break; } return found;
149 #include main() { int c[3][3]={1,2,3,4,5,6,7,8,9}; for(int i=0;i<3;i++) for(int j=0;j<3;j++) printf("%ld\n",&c[j]); printf("-------------------------\n"); printf("%ld\n",(c+1)); printf("%ld\n",(*c+1)); printf("%ld\n",&c[0][0]); printf("%ld\n",**c); printf("%ld\n",*c[0]); if(int(c)==int(*c)) printf("equl"); } 爲什麼c,*c的值相等,(c+1),(*c+1)的值不等 c,*c,**c,代表什麼意思? 參考答案: c是第一個元素的地址,*c是第一行元素的首地址,其實第一行元素的地址就是第一個元素的地址,這容易理解。**c是提領第一個元素。 爲什麼c,*c的值相等? int c因爲直接用c表示數組c[0][0] printf("%ld\n",*c[0]);語句已將指針移到數組頭。 int(*c)表示c0的值爲1,所以相等。 數組c的存放空間示意如下:(機器中是行優先存放的) c[0][0] c[0][1] c[0][2] c[1][0] c[1][1] c[1][2] c[2][0] c[2][1] c[2][2] c是一個二維數組名,實際上它是一個指針常量,不能進行自加、自減運算,即:c++、c--、++c、--c 都是不允許的; c: 數組名;是一個二維指針,它的值就是數組的首地址,也即第一行元素的首地址(等於*c),也 等於第一行第一個元素的地址( & c[0][0]);可以說成是二維數組的行指針。 *c: 第一行元素的首地址;是一個一維指針,可以說成是二維數組的列指針。 **c:二維數組中的第一個元素的值;即:c[0][0] 所以: c 和 *c的值是相等的,但他們兩者不能相互賦值,(類型不同); (c + 1) :c是行指針,(c + 1)是在c的基礎上加上二維數組一行的地址長度,即從&c[0][0] 變到了&c[1][0]; (*c + 1):*c是列指針,(*c + 1)是在*c的基礎上加上二數組一個元素的所佔的長度,即從 &c[0][0]變到了&c[0][1] 從而(c + 1)和(*c + 1)的值就不相等了
150、定義 int **a[3][4], 則變量佔有的內存空間爲:__32___ 參考答案: int **p; /*16位下sizeof(p)=2, 32位下sizeof(p)=4*/ 總共 3*4*sizeof(p) |
151、寫出判斷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
152、某32位系統下, C++程序,請計算sizeof 的值
char str[] = “http://www.ibegroup.com/”
char *p = str ;
int n = 10;
請計算
(1)sizeof (str ) = ?
(2)sizeof ( p ) = ?
(3)sizeof ( n ) = ?
void Foo ( char str[100]){
請計算
sizeof( str ) = ?(4)
}
void *p = malloc( 100 );
請計算
sizeof ( p ) = ?(5)
答:(1)25 (2)4 (3) 4 (4)4 (5)4
153、 回答下面的問題
(1).Void GetMemory(char **p, int num){
*p = (char *)malloc(num);
}
void Test(void){
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
請問運行Test 函數會有什麼樣的結果?
答:輸出“hello”
154、 void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL){
strcpy(str, “world”);
printf(str);
}
}
請問運行Test 函數會有什麼樣的結果?
答:輸出“world”
155、 char *GetMemory(void){
char p[] = "hello world";
return p;
}
void Test(void){
char *str = NULL;
str = GetMemory();
printf(str);
}
請問運行Test 函數會有什麼樣的結果?
答:無效的指針,輸出不確定
156、編寫strcat函數
已知strcat函數的原型是char *strcat (char *strDest, const char *strSrc);
其中strDest 是目的字符串,strSrc 是源字符串。
(1)不調用C++/C 的字符串庫函數,請編寫函數 strcat
答:
VC源碼:
char * __cdecl strcat (char * dst, const char * src)
{
char * cp = dst;
while( *cp )
cp++;
while( *cp++ = *src++ ) ;
return( dst );
}
157、strcat能把strSrc 的內容連接到strDest,爲什麼還要char * 類型的返回值?
答:方便賦值給其他變量
158、MFC中CString是類型安全類麼?
答:不是,其它數據類型轉換到CString可以使用CString的成員函數Format來轉換
159.C++中什麼數據分配在棧或堆中?
答:棧: 存放局部變量,函數調用參數,函數返回值,函數返回地址。由系統管理
堆: 程序運行時動態申請,new 和malloc申請的內存就在堆上
160、函數模板與類模板有什麼區別?
答:函數模板的實例化是由編譯程序在處理函數調用時自動完成的,而類模板的實例化
必須由程序員在程序中顯式地指定。
161、 int i=10, j=10, k=3; k*=i+j; k最後的值是?
答:60,此題考察優先級,實際寫成: k*=(i+j);,賦值運算符優先級最低
162、do……while和while……do有什麼區別?
答 、前一個循環一遍再判斷,後一個判斷以後再循環
163、請寫出下列代碼的輸出內容
#i nclude
main()
{
int a,b,c,d;
a=10;
b=a++;
c=++a;
d=10*a++;
printf("b,c,d:%d,%d,%d",b,c,d);
return 0;
}
答 、10,12,120
164.在c語言庫函數中將一個字符轉換成整型的函數是atol()嗎,這個函數的原型是什麼?
答 、函數名: atol
功 能: 把字符串轉換成長整型數
用 法: long atol(const char *nptr);
程序例:
#include
#include
int main(void)
{
long l;
char *str = "98765432";
l = atol(lstr);
printf("string = %s integer = %ld\n", str, l);
return(0);
}
165. 以下三條輸出語句分別輸出什麼?
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”以常量形式存於靜態數據區,而它們自己僅是指向該區首地址的指針,相等。
166 以下代碼中的兩個sizeof用法有問題嗎?
void UpperCase( char str[] ) // 將 str 中的小寫字母轉換成大寫字母
{
for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i )
if( 'a'<=str[i] && str[i]<='z' )
str[i] -= ('a'-'A' );
}
char str[] = "aBcDe";
cout << "str字符長度爲: " << sizeof(str)/sizeof(str[0]) << endl;
UpperCase( str );
cout << str << endl;
答:函數內的sizeof有問題。根據語法,sizeof如用於數組,只能測出靜態數組的大小,無法檢測動態分配的或外部數組大小。函數外的str是一個靜態定義的數組,因此其大小爲6,函數內的str實際只是一個指向字符串的指針,沒有任何額外的與數組相關的信息,因此sizeof作用於上只將其當指針看,一個指針爲4個字節,因此返回4。
167 非C++內建型別 A 和 B,在哪幾種情況下B能隱式轉化爲A?
答:
a. class B : public A { ……} // B公有繼承自A,可以是間接繼承的
b. class B { operator A( ); } // B實現了隱式轉化爲A的轉化
c. class A { A( const B& ); } // A實現了non-explicit的參數爲B(可以有其他帶默認值的參數)構造函數
d. A& operator= ( const A& ); // 賦值操作,雖不是正宗的隱式類型轉換,但也可以勉強算一個
168.以下代碼有什麼問題?
struct Test
{
Test( int ) {}
Test() {}
void fun() {}
};
void main( void )
{
Test a(1);
a.fun();
Test b();
b.fun();
}
答:變量b定義出錯。按默認構造函數定義對象,不需要加括號。
169 以下代碼有什麼問題?
cout << (true?1:"1") << endl;
答:三元表達式“?:”問號後面的兩個操作數必須爲同一類型。
170 以下代碼能夠編譯通過嗎,爲什麼?
unsigned int const size1 = 2;
char str1[ size1 ];
unsigned int temp = 0;
cin >> temp;
unsigned int const size2 = temp;
char str2[ size2 ];
答:str2定義出錯,size2非編譯器期間常量,而數組定義要求長度必須爲編譯期常量。
171. 以下代碼中的輸出語句輸出0嗎,爲什麼?
struct CLS
{
int m_i;
CLS( int i ) : m_i(i) {}
CLS()
{
CLS(0);
}
};
CLS obj;
cout << obj.m_i << endl;
答:不能。在默認構造函數內部再調用帶參的構造函數屬用戶行爲而非編譯器行爲,亦即僅執行函數調用,而不會執行其後的初始化表達式。只有在生成對象時,初始化表達式纔會隨相應的構造函數一起調用。
172 C++中的空類,默認產生哪些類成員函數?
答:
class Empty
{
public:
Empty(); // 缺省構造函數
Empty( const Empty& ); // 拷貝構造函數
~Empty(); // 析構函數
Empty& operator=( const Empty& ); // 賦值運算符
Empty* operator&(); // 取址運算符
const Empty* operator&() const; // 取址運算符 const
};
173 以下兩條輸出語句分別輸出什麼?
float a = 1.0f;
cout << (int)a << endl;
cout << (int&)a << endl;
cout << boolalpha << ( (int)a == (int&)a ) << endl; // 輸出什麼?
float b = 0.0f;
cout << (int)b << endl;
cout << (int&)b << endl;
cout << boolalpha << ( (int)b == (int&)b ) << endl; // 輸出什麼?
答:分別輸出false和true。注意轉換的應用。(int)a實際上是以浮點數a爲參數構造了一個整型數,該整數的值是1,(int&)a則是告訴編譯器將a當作整數看(並沒有做任何實質上的轉換)。因爲1以整數形式存放和以浮點形式存放其內存數據是不一樣的,因此兩者不等。對b的兩種轉換意義同上,但是0的整數形式和浮點形式其內存數據是一樣的,因此在這種特殊情形下,兩者相等(僅僅在數值意義上)。
注意,程序的輸出會顯示(int&)a=1065353216,這個值是怎麼來的呢?前面已經說了,1以浮點數形式存放在內存中,按ieee754規定,其內容爲0x0000803F(已考慮字節反序)。這也就是a這個變量所佔據的內存單元的值。當(int&)a出現時,它相當於告訴它的上下文:“把這塊地址當做整數看待!不要管它原來是什麼。”這樣,內容0x0000803F按整數解釋,其值正好就是1065353216(十進制數)。
通過查看彙編代碼可以證實“(int)a相當於重新構造了一個值等於a的整型數”之說,而(int&)的作用則僅僅是表達了一個類型信息,意義在於爲cout<<及==選擇正確的重載版
174、請簡述以下兩個for循環的優缺點(5分)
for (i=0; i<N; i++)
{
if (condition)
DoSomething();
else
DoOtherthing();
}
if (condition)
{
for (i=0; i<N; i++)
DoSomething();
}
else
{
for (i=0; i<N; i++)
DoOtherthing();
}
優點:程序簡潔
缺點:多執行了N-1次邏輯判斷,並且打斷了循環“流水線”作業,使得編譯器不能對循環進行優化處理,降低了效率。
優點:循環的效率高
缺點:程序不簡潔
175
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
請問運行Test函數會有什麼樣的結果?
答:程序崩潰。
因爲GetMemory並不能傳遞動態內存,
Test函數中的 str一直都是 NULL。
strcpy(str, "hello world");將使程序崩潰。
|
201下面的代碼有什麼問題?並請給出正確的寫法。 void DoSomeThing(char* p) { char str[16]; int n; assert(NULL != p); sscanf(p, "%s%d", str, n); if (0 == strcmp(str, "something")) { } } A: sscanf(p, "%s%d", str, n); 這句該寫成: sscanf(p, "%s%d", str, &n); -------------------------------------------------------------------------- 202.下面代碼有什麼錯誤?
Void test1() {
char string[10]; char *str1="0123456789"; strcpy(string, str1);
} 數組越界
203.下面代碼有什麼問題?
Void test2()
{
char string[10], str1[10];
for(i=0; i<10;i++) { str1[i] ='a'; } strcpy(string, str1); } } 數組越界
204下面代碼有什麼問題?LUPA開源社區+j H2B F,c U
Void test3(char* str1) { char string[10]; if(strlen(str1)<=10) { strcpy(string, str1); } } ==數組越界 ==strcpy拷貝的結束標誌是查找字符串中的\0 因此如果字符串中沒有遇到\0的話 會一直複製,直到遇到\0,上面的123都因此產生越界的情況 建議使用 strncpy 和 memcpy
205.寫出運行結果: { char str[] = "world"; cout << sizeof(str) << ": "; char *p = str; cout << sizeof(p) << ": "; char i = 10; cout << sizeof(i) << ": "; void *pp = malloc(10); cout << sizeof(p) << endl; } 6:4:1:4
-------------------------------------------------------------------------- 206.C和C++有什麼不同? 從機制上:c是面向過程的(但c也可以編寫面向對象的程序);c++是面向對象的,提供了類。但是,c++編寫面向對象的程序比c容易 從適用的方向:c適合要求代碼體積小的,效率高的場合,如嵌入式;c++適合更上層的,複雜的; llinux核心大部分是c寫的,因爲它是系統軟件,效率要求極高。 從名稱上也可以看出,c++比c多了+,說明c++是c的超集;那爲什麼不叫c+而叫c++呢,是因爲c++比 c來說擴充的東西太多了,所以就在c後面放上兩個+;於是就成了c++ C語言是結構化編程語言,C++是面向對象編程語言。LUPA開源社區 } n*r2C/M8f C++側重於對象而不是過程,側重於類的設計而不是邏輯的設計。
207在不用第三方參數的情況下,交換兩個參數的值 #include <stdio.h> void main() { int i=60; int j=50; i=i+j; j=i-j; ) i=i-j; printf("i=%d\n",i); printf("j=%d\n",j); } 方法二: i^=j; j^=i; i^=j; 方法三: // 用加減實現,而且不會溢出 a = a+b-(b=a)
208.下面的函數實現在一個固定的數上加上一個數,有什麼錯誤,改正
int add_n(int n) { static int i=100; i+=n; return i; } 答: 因爲static使得i的值會保留上次的值。 去掉static就可了
209.union a { int a_int1; double a_double; int a_int2; }; typedef struct { a a1; char y; } b;
class c { double c_double; b b1; a a2; }; 輸出cout<<sizeof(c)<<endl;的結果? 答: VC6環境下得出的結果是32 我(sun)在VC6.0+win2k下做過試驗: int-4 float-4 double-8 指針-4
210. unsigned short array[]={1,2,3,4,5,6,7}; int i = 3; *(array + i) = ? 答:4
211. 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
212輸出下面程序結果。 #include <iostream.h> class A { public: virtual void print(void) { cout<<"A::print()"<<endl; } };
class B:public A { public: virtual void print(void) { cout<<"B::print()"<<endl;
}; }; class C:public { public: virtual void print(void) { cout<<"C::print()"<<endl; } }; void print(A a) { a.print(); }
void main(void) { A a, *pa,*pb,*pc; pa=&a; pb=&b; pc=&c;
a.print(); b.print(); c.print();
a->print(); pb->print(); pc->print();
print(a); print(b); print(c); } A::print() A::print()
B::print() C::print()
A::print()
B::print()
C::print()
A::print()
A::print()
A::print()
213 C++語言是在___ C ______語言的基礎上發展起來的。 214 C++語言的編譯單位是擴展名爲____ .cpp______的____程序______文件。 215. 行尾使用註釋的開始標記符爲____ //_____。 216 多行註釋的開始標記符和結束標記符分別爲_____ /*_____和___ */_______。 217. 用於輸出表達式值的標準輸出流對象是____ cout_____。 218 用於從鍵盤上爲變量輸入值的標準輸入流對象是__ cin______。 219. 一個完整程序中必須有一個名爲____ main____的函數。 220一個函數的函數體就是一條____複合_____語句。 221. 當執行cin語句時,從鍵盤上輸入每個數據後必須接着輸入一個___空白_____符,然後才能繼續輸入下一個數據。 222在C++程序中包含一個頭文件或程序文件的預編譯命令爲____#include ______。 223. 程序中的預處理命令是指以___#___字符開頭的命令。 224. 一條表達式語句必須以___分號___作爲結束符。 225. 在#include命令中所包含的頭文件,可以是系統定義的頭文件,也可以是___用戶(或編程者_____定義的頭文件。 226. 使用#include命令可以包含一個頭文件,也可以包含一個__程序____文件。 227.一個函數定義由__函數頭______和__函數體_____兩部分組成。 228.若一個函數的定義處於調用它的函數之前,則在程序開始可以省去該函數的__原型(或聲明)____語句。 229.C++頭文件和源程序文件的擴展名分別爲__.h ___和___.cpp ___。 230.程序文件的編譯錯誤分爲____警告(warning)____和____致命(error) ____兩類。 231.當使用___ void ____保留字作爲函數類型時,該函數不返回任何值。 232.當函數參數表用___ void __保留字表示時,則表示該參數表爲空。 233.從一條函數原型語句“int fun1(void);”可知,該函數的返回類型爲______,該函數帶有______個參數。 234. 當執行cout語句輸出endl數據項時,將使C++顯示輸出屏幕上的光標從當前位置移動到___下一行_____的開始位置。 235. 假定x=5,y=6,則表達式x++*++y的值爲___35_______。 236. 假定x=5,y=6,則表達式x--*--y的值爲___25_______。 237. 假定x=5,y=6,則執行表達式y*=x++計算後,x和y的值分別爲___6___和___30 _____。 238. 假定x=5,y=6,則執行表達式y+=x--計算後,x和y的值分別爲____4__和___11___。 239. C++常數0x145對應的十進制值爲___325 ___。 240. C++常數0345對應的十進制值爲____ 229__。 241. 十進制常數245對應的十六進制的C++表示爲____0xF5___。 242. 十進制常數245對應的八進制的C++表示爲___0365 ___。 243. signed char類型的值域範圍是__-128__至___+127 __之間的整數。 244. int和float類型的數據分別佔用___ 4___和____ 4___個字節。 245. float和double類型的數據分別佔用____ 4___和_____8___個字節。 246. bool和char類型的數據分別佔用_____1____和____1___個字節。 247. unsigned short int和int類型的長度分別爲____ 2___和____4___。 248. 字符串”This\’s a book.\n”的長度爲_____ 15____。 249. 字符串”\nThis\’s a pen\n\n”的長度爲_____ 15_____。 250. 在C++中存儲字符串”abcdef”至少需要___7 _____個字節。 251. 在C++中存儲字符串”a+b=c”至少需要_____6 ___個字節。 252. 假定x和y爲整型,其值分別爲16和5,則x%y和x/y的值分別爲___1_______和____3____。 253. 假定x和y爲整型,其值分別爲16和5,則x/y和double(x)/y的值分別爲____3____和___3.2____。 254. 假定x是一個邏輯量,則x && true的值爲___ x ____。 255. 假定x是一個邏輯量,則x || true的值爲_____ true(或1)_____。 256. 假定x是一個邏輯量,則x && false的值爲____ false(或0) ___。 257. 假定x是一個邏輯量,則x || false的值爲x。 258. 假定x是一個邏輯量,則!x || false的值爲____!x ____。 259. 假定x是一個邏輯量,則x && !x的值爲____ false(或0)____。 260. 假定x是一個邏輯量,則x || !x的值爲____ true(或1)___。 261. 設enum Printstatus{ready,busy,error}; 則 cout<<busy的輸出結果是_____1___。 262. 設enum Printstatus{ready=2,busy,error}; 則cout<<busy的輸出結果是____3____。 263. 常數-4.205和6.7E-9分別具有___4_____和____2___位有效數字。 264. 枚舉類型中的每個枚舉值都是一個____枚舉常量_____,它的值爲一個___整數____。 265. 常數100和3.62的數據類型分別爲____ int ___和_____ double ___。 266. 若x=5, y=10, 則計算y*=++x表達式後,x和y的值分別爲___6___和__60 ___。 267. 假定x和ch分別爲int型和char型,則sizeof(x)和sizeof(ch)的值分別爲__4__和__1__。 268. 假定x=10,則表達式x<=10?20:30的值爲__ 20 __。 269. 表達式sqrt(81)和pow(6,3)的值分別爲___9 ___和___216___。 270. 含隨機函數的表達式rand()%20的值在___0__至___ 19 __區間內。 271. 在switch語句中,每個語句標號所含關鍵字case後面的表達式必須是___常量___。 272. 在if語句中,每個else關鍵字與它前面同層次並且最接近的____ if ____關鍵字相配套。 273. 作爲語句標號使用的C++保留字case和defaule只能用於___ switch ___語句的定義體中。 274. 執行switch語句時,在進行作爲條件的表達式求值後,將從某個匹配的標號位置起向下執行,當碰到下一個標號位置時(停止/不停止)___不停止__執行。 275. 若while循環的“頭”爲“while(i++<=10)”,並且i的初值爲0,同時在循環體中不會修改i的值,則循環體將被重複執行__11___次後正常結束。 276. 若do循環的“尾”爲“while(++i<10)”,並且i的初值爲0,同時在循環體中不會修改i的值,則循環體將被重複執行___10 ___次後正常結束。 277. 當在程序中執行到break語句時,將結束本層循環類語句或switch語句的執行。 278. 當在程序中執行到___ continue___語句時,將結束所在循環語句中循環體的一次執行。 279. 在程序中執行到__ return ___語句時,將結束所在函數的執行過程,返回到調用該函數的位置。 280.在程序執行完____主(或main)__函數調用後,將結束整個程序的執行過程,返回到C++集成開發窗口。 281. 元素類型爲int的數組a[10]共佔用___ 40___字節的存儲空間。 282. 元素類型爲double的二維數組a[4][6]共佔用____192__字節的存儲空間。 283. 元素類型爲char的二維數組a[10][30]共佔用___300__字節的存儲空間。 284. 存儲字符’a’和字符串”a”分別需要佔用_____1___和____2 ___個字節。
|
285
#include "stdafx.h"
#define SQR(X) X*X
int main(int argc, char* argv[])
{
int a = 10;
int k = 2;
int m = 1;
a /= SQR(k+m)/SQR(k+m);
printf("%d\n",a);
return 0;
}
這道題目的結果是什麼啊?
define 只是定義而已,在編擇時只是簡單代換X*X而已,並不經過算術法則的
a /= (k+m)*(k+m)/(k+m)*(k+m);
=>a /= (k+m)*1*(k+m);
=>a = a/9;
=>a = 1;
286. 以面向對象方法構造的系統,其基本單位是_____對象___。
287. 每個對象都是所屬類的一個__實例__。
288. C++支持兩種多態性:___編譯____時的多態性和____運行__時的多態性。
289. 在C++中,編譯時的多態性是通過___重載___實現的,而運行時的多態性則是通過___虛函數____實現的。
290. 對於類中定義的任何成員,其隱含訪問權限爲___ private(或私有)__。
291. 對於結構中定義的任何成員,其隱含訪問權限爲__ public(或公有)_。
292. 若在類的定義體中給出了一個成員函數的完整定義,則該函數屬於__內聯__函數。
293. 爲了避免在調用成員函數時修改對象中的任何數據成員,則應在定義該成員函數時,在函數頭的後面加上__ const __關鍵字。
294. 若只需要通過一個成員函數讀取數據成員的值,而不需要修改它,則應在函數頭的後面加上__ const __關鍵字。
295.判斷一個字符串是不是迴文
int IsReverseStr(char *aStr)
{
int i,j;
int found=1;
if(aStr==NULL)
return -1;
j=strlen(aStr);
for(i=0;i<j/2;i++)
if(*(aStr+i)!=*(aStr+j-i-1))
{
found=0;
break;
}
return found;
}
296..寫出判斷ABCD四個表達式的是否正確, 若正確, 寫出經過表達式中 a的值(3分)
int a = 4;
(A)a += (a++); (B) a += (++a) ;(C) (a++) += a;(D) (++a) += (a++);
a = ?
答:C錯誤,左側不是一個有效變量,不能賦值,可改爲(++a) += a;
改後答案依次爲9,10,10,11
298.動態連接庫的兩種方式?
答:調用一個DLL中的函數有兩種方法:
1.載入時動態鏈接(load-time dynamic linking),模塊非常明確調用某個導出函數,使得他們就像本地函數一樣。這需要鏈接時鏈接那些函數所在DLL的導入庫,導入庫向系統提供了載入DLL時所需的信息及DLL函數定位。
2.運行時動態鏈接(run-time dynamic linking),運行時可以通過LoadLibrary或Loa
dLibraryEx函數載入DLL。DLL載入後,模塊可以通過調用GetProcAddress獲取DLL函數的出口地址,然後就可以通過返回的函數指針調用DLL函數了。如此即可避免導入庫文件了。
299.請寫出下列代碼的輸出內容
#i nclude
main()
{
int a,b,c,d;
a=10;
b=a++;
c=++a;
d=10*a++;
printf("b,c,d:%d,%d,%d",b,c,d);
return 0;
}
答 、10,12,120
300.設有以下說明和定義:
typedef union {long i; int k[5]; char c;} DATE;
struct data { int cat; DATE cow; double dog;} too;
DATE max;
則語句 printf("%d",sizeof(struct date)+sizeof(max));的執行結果是?
答 、結果是:___52____。DATE是一個union, 變量公用空間. 裏面最大的變量類型是int[5], 佔用20個字節. 所以它的大小是20
data是一個struct, 每個變量分開佔用空間. 依次爲int4 + DATE20 + double8 = 32.
所以結果是 20 + 32 = 52.
當然...在某些16位編輯器下, int可能是2字節,那麼結果是 int2 + DATE10 + double8 = 20
301. 以下代碼有什麼問題?
cout << (true?1:"1") << endl;
答:三元表達式“?:”問號後面的兩個操作數必須爲同一類型。
302.以下代碼能夠編譯通過嗎,爲什麼?
unsigned int const size1 = 2;
char str1[ size1 ];
unsigned int temp = 0;
cin >> temp;
unsigned int const size2 = temp;
char str2[ size2 ];
答:str2定義出錯,size2非編譯器期間常量,而數組定義要求長度必須爲編譯期常量。
303.以下反向遍歷array數組的方法有什麼錯誤?
vector array;
array.push_back( 1 );
array.push_back( 2 );
array.push_back( 3 );
for( vector::size_type i=array.size()-1; i>=0; --i ) // 反向遍歷array數組
{
cout << array[i] << endl;
}
答:首先數組定義有誤,應加上類型參數:vector<int> array。其次vector::size_type被定義爲unsigned int,即無符號數,這樣做爲循環變量的i爲0時再減1就會變成最大的整數,導致循環失去控制。
304. 以下代碼中的輸出語句輸出0嗎,爲什麼?
struct CLS
{
int m_i;
CLS( int i ) : m_i(i) {}
CLS()
{
CLS(0);
}
};
CLS obj;
cout << obj.m_i << endl;
答:不能。在默認構造函數內部再調用帶參的構造函數屬用戶行爲而非編譯器行爲,亦即僅執行函數調用,而不會執行其後的初始化表達式。只有在生成對象時,初始化表達式纔會隨相應的構造函數一起調用。