部分真题整理3
1、 java語言中,按照一定格式生成程序的文檔的工具是?
javac
javah
javadoc
jar
2、下列關于java抽象類的說法哪個正確?(D)
某個抽象類的父類是抽象類,則這個子類必須重載父類的所有抽象方法
接口和抽象類是同一回事
可以用抽象類直接去實例化創建對象
一個類只能繼承一個抽象類
解析:
如果一個類中有抽象方法,那么這個類必須聲明為 抽象類
若父類包含有抽象方法(父類肯定是 抽象類 了), 子類必須去實現它
若父類是 抽象類 ,但某個方法是非抽象的, 那么子類可以直接繼承這個方法(不用實現)
抽象類一般不能被實例化;
抽象類通常不是由程序員定義的,而是由項目經理或模塊設計人 設計抽象類的原因通常是為了規范方法名 抽象類必須要繼承,不然沒法用,作為模塊設計者,可以把讓底層程序員直接用得方法直接調用,而一些需要讓程序員覆蓋后自己做得方法則定義稱抽象方法
Java不支持多繼承,但是通過一些巧妙的設計來達到和多繼承同樣的效果
通過接口、內隱類,繼承、實現,互相配合,達到多繼承的效果
1、Java中一個類不能繼承多個具體class。
2、一個類只可繼承自一個具體 class,但可實現多個接口。
interface不涉及到實現細節,不與任何存儲空間有關連。
可以實現合并多個 interface ,達到可向上轉型為多種基類的目的。
新類可繼承自一個具象class,其余繼承都得是interfaces。
3、outer class不可繼承自多個具體 class,可在其內部設多個inner class,每個inner class都能各自繼承某一實現類。
inner class不受限于outer class 是否已經繼承自某一實現類。
4、inner class可以說是多重繼承問題的完整解決方案。
inner class 可 “繼承自多個具象或抽象類”。
一個類不能繼承自多個一般類。但我們可以讓其內部的多個inner class各自繼承某一實現類達到類似的目的。
3、兩個等價線程并發的執行下列程序,a為全局變量,初始為0,假設printf、++、--操作都是原子性的,則輸出肯定不是哪個?(A)
void foo() { if(a <= 0) { a++; } else { a--; } printf("%d", a); }01
10
12
22
解析:
每個線程進foo函數不止一次,那么我們暫且假設兩個線程分別進入foo函數X次,
假設給線程編號,線程1有m次被堵在a++,線程2有n次被堵在a++處,
那么線程1必然會執行(X-m)次a- -,線程2必然會執行(X-n)次a- -,
那么最終a的值為(m+n)-((X-m)+(X-n))=2(m+n)-2X,
那么a必然是偶數
對于B選項:P1執行程序,輸入1,P2執行程序,輸出0;
對于C選項:初始為0,P1執行完判斷語句,決定要執行a++,中斷,P2進行判斷,此時a仍然等于0,執行判斷語句,并執行輸入,得到1,P1然后繼續執行,此時它該執行a++,這時a=1,執行并輸出,結果為2;
對于D答案:初始為0,P1執行完判斷語句,決定要執行a++,中斷,P2進行判斷,此時a仍然等于0,執行a++,得到a=1,中斷,P1繼續執行a++,a=2,P1輸出,得到2,P1結束,P2繼續執行輸出語句,得到2;
4、
void swap_int(int *a,int *b){ *a=*a+*b; *b=*a-*b; *a=*a-*b; }以下說法正確的是:(B)
結果不正確,因為會溢出,用位與的方式就沒問題
結果正確,即使會溢出
結果正確,不會溢出
其他選項都不對
解析:
設整形變量*a、*b的位表示為
*a = n31n30 ??? n0
*b = m31m30 ??? m0
只有當*a > 0 && *b > 0 或 *a < 0 && *b < 0時才會發生溢出。兩者類似,只證明均大于0時的情況。必須擴展額外一位才能夠容納正確的結果,'|'左邊為擴展位。
*a = 0|0n30 ??? n0 = n30*230 + n29*229 + ??? + n0*20 = N
*b = 0|0m30 ??? m0 = m30*230 + m29*229 + ??? + m0*20 = M
若和溢出,則33位表示必為
*a + *b = 0|1b30 ??? b0 = -231 + b30*230 + b29*229 + ??? + b0*20 = 2 31 + B ①
計算機將得到的33位結果truncate回原來的32位,即丟棄第33位(0)變為:
*a + *b = 1b30 ??? b0 = -231 + b30*230 + b29*229 + ??? + b0*20 = -2 31 + B ②
正確的真實值是①,溢出結果為②,可見溢出結果=真實值-2 32
則*b = *a - *b = ② - *b = ① - 232 - *b = *a + *b - 232 - *b = -232 + *a
最后一步,來看 -232 + *a == *a 成立否?
0 < *a < 231, 則 -232 < -232 + *a < -231,和仍需要擴展1位方能表示:
*a = 0|0n30 ??? n0 = n30*230 + n29*229 + ??? + n0*20 = N
-232 = 1|0000 ??? 00
和的位表示為
-232 + *a = 1|0n30 ??? n0 = n30*230 + n29*229 + ??? + n0*20
同樣,計算機把33位結果truncate回32位(丟棄第33位)得到:
-232 + *a = 0n30 ??? n0 = n30*230 + n29*229 + ??? + n0*20 = *a
可見-232 + *a == *a 是成立的。因此盡管溢出了,但仍能正確交換。
可能經驗上的某種直覺告訴我們:加減法可能會溢出。其實不然,第一步的加運算可能會造成溢出,但它所造成的溢出會在后邊的減運算中被溢出回來。
5、 下面有關java的一些細節問題,描述錯誤的是?(B)
構造方法不需要同步化
一個子類不可以覆蓋掉父類的同步方法
定義在接口中的方法默認是public的
容器保存的是對象的引用
6、 2014! 的末尾有 1 個0? 501
解析:
末尾為0,主要看乘積項中2和5的個數,由于2的個數明顯比5多,則只需看5的個數即可
2014/5 = 402....4
2014/25 = 80....14
2014/125 = 16....14
2014/625 = 3....19
故2014!末尾0的個數為402+80+16+3 = 501
7、 關于排序算法的以下說法,錯誤的是___(D)___。
快速排序的平均時間復雜度為O(nlogn),最壞時間復雜度為O(n2)
堆排序的平均時間復雜度為O(nlogn),最壞時間復雜度為O(nlogn)
冒泡排序的平均時間復雜度為O(n2),最壞時間復雜度為O(n2)
歸并排序的平均時間復雜度為O(nlogn),最壞時間復雜度為O(n2)
解析:
歸并排序是穩定的排序方法。最壞和最好沒區別!O(nlogn)
8、下列代碼的輸出為:(B)
#include<iostream> #include<vector> using namespace std;int main(void) { vector<int>array; array.push_back(100); array.push_back(300); array.push_back(300); array.push_back(500); vector<int>::iterator itor; for (itor = array.begin(); itor != array.end(); itor++) { if (*itor == 300) { itor = array.erase(itor); } } for (itor = array.begin(); itor != array.end(); itor++) { cout << *itor << " "; } return 0; } 100 300 300 500
100 300 500
100 500
程序錯誤
解析:
vector 的erase函數 刪除指定位置的元素時, 返回值是一個迭代器,指向刪除元素下一個元素。刪除第一個300后,itor指向其后的300,然后執行itor++,指向了500.
9、下列程序的輸出結果:(C)
#include <iostream> using namespace std; class A { public: void print() { cout << "A:print()"; } }; class B: private A { public: void print() { cout << "B:print()"; } }; class C: public B { public: void print() { A: print(); } }; int main() { C b; b.print(); } A:print()
B:print()
編譯出錯
解析:
B的繼承為私有繼承,對于C已經不能再調用A的所有方法了
10、用戶雙擊鼠標時產生的消息序列,下面正確的是(D)
WM_LBUTTONDOWN,WM_LBUTTONUP,WM_LBUTTONDOWN,WM_LBUTTONUP
WM_LBUTTONDOWN,WM_LBUTTONUP,WM_LBUTTONUP,WM_LBUTTONDBLCLK
WM_LBUTTONDOWN,WM_LBUTTONUP,WM_LBUTTONDOWN,WM_LBUTTONDBLCLK
WM_LBUTTONDOWN,WM_LBUTTONUP,WM_LBUTTONDBLCLK,WM_LBUTTONUP
解析:
雙擊即點擊左鍵兩下,第一次觸發LBUTTONDOWN和LBUTTONUP,第二次點擊時觸發雙擊事件LBUTTONDBLCLK(doubleclick),放掉再觸發LBUTTONUP
11、下面有關繼承、多態、組合的描述,說法錯誤的是?(D)
封裝,把客觀事物封裝成抽象的類,并且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏
繼承可以使用現有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進行擴展
隱藏是指派生類中的函數把基類中相同名字的函數屏蔽掉了
覆蓋是指不同的函數使用相同的函數名,但是函數的參數個數或類型不同
解析:
重載:
只有在 同一類定義中的同名成員函數才存在重載關系 ,主要特點是 函數的參數類型和數目有所不同 ,但 不能出現函數參數的個數和類型均相同 ,僅僅依靠返回值類型不同來區分的函數,這和普通函數的重載是完全一致的。另外,重載和成員函數是否是虛函數無關
覆蓋:
在派生類中覆蓋基類中的同名函數,要求兩個函數的參數個數、參數類型、返回類型都相同,且基類函數必須是虛函數。
隱藏:
派生類中的函數屏蔽了基類中的同名函數,
2個函數參數相同,但基類函數不是虛函數(和覆蓋的區別在于基類函數是否是虛函數)。2個函數參數不同,無論基類函數是否是虛函數,基類函數都會被屏蔽(和重載的區別在于兩個函數不在同一類中)。
12、
char *p1;int64 *p2; p1=(char *)0x800000; p2=(int64 *)0x800000; char *a=p1+2 int64_t *b=p2+2那么a= 1 0x800002 ,b= 2 0x800010
解析:
我們定義指針的時候給指針一個類型就是為了方便指針的加減操作。p1是char類型指針,每個char占一個字節,所以p1+2就是在p1的基礎上加2個char的長度,就是兩個字節。p2是指向64位int型的指針,所以p2+2就是p2加上兩個64位int的長度,也就是加上128位,即16個字節。用16進制表示是0x10
所以a=0x800000+0x2=0x800002
b=0x800000+0x10=0x800010
指針里面存的是地址,所以指針的加減也是為了求得變化后的地址,即假設指針的類型是T,那么新的地址應該就是原地址+sizeof(T)個字節后得到的地址,也就是說它加的實質還是相應的字節數,而這個字節數是多少得看指針的類型,本題中第一個是char類型,那么加2就是倆個字節,第二個是64位的int,那么相應的指針類型就是8字節,因為指針就是為了尋地址的,與cpu的位數有關,一個字節8位,因此它加2就是加2*sizeof(int64),轉16進制為0x1
13、 請問以下說法,哪個是正確的:(C)
每個類都有一個無參數的構造函數。
每個類都有一個拷貝構造的函數。
每個類能有多個構造函數。
每個類能有多個析構函數。
解析:
A:用戶自定義了構造函數編譯器不會合成無參構造函數
B:?一個類可以有多個拷貝構造函數
class A{}; class B: public A{ public: B(const B&); B(const A&); };class A{}; class B: public A{ public: B(const B&); B(const A&); };D:一個類只能有一個析構函數
14、選擇填空:(D)
#include void test(void *data) { unsigned int value = (此處應填入) printf("%u", value); } using namespace std; int main() { unsigned int value = 10; test(&value); return 0; }*data
(unsigned int)(*data)
(unsigned*)data
*((unsigned int *)data)
解析:
注意,參數類型是void, 所以先要進行指針轉換:(unsigned int *)然后再取值。
15、 在C++語言中,下列說法正確的是:(D)
inline函數表示編譯器一定會將函數體直接插入到調用此函數的地方,這樣可以加快程序的運行速度
局部變量和全局變量不能重名
靜態局部變量內存是在運行期分配的,存儲在堆棧區
C++不是類型安全的語言
解析:
首先,可以排除B和C。B選項,因為局部變量和全局變量是可以重名的,而且一般來說在某個函數體內,局部變量是會覆蓋全局變量的。C選項,靜態局部變量存在靜態存儲區,而局部變量存儲在堆棧區,確切的說是棧區。再看A選項,內聯函數與其他普通函數的區別是,內聯函數在生成可執行文件時,其代碼塊是直接嵌入到調用處的,以此減少函數調用的開銷提高程序性能,它與宏很類似。但是,C++ primer 上明明白白的寫過這么一句話:內聯說明(inline specification)對于編譯器來說只是一個建議,編譯器可以選擇忽略這個建議。也就是說,是否以嵌入式方式存在,是由編譯器決定的,并不是一定。最后看D選項,什么叫類型安全的語言?本人很淺陋的認識是:就C++而言,我們可以把0作為false,非零作為true。一個函數就算是bool類型的,我們還是可以返回int類型,并且自動把0轉化成false,非零轉化成true。相比之下java不能把int類型轉化成bool類型。所以java是一種類型安全的語言,而C++并不是。 答案選D
16、關于Spring MVC的核心控制器DispatcherServlet的作用,以下說法錯誤的是(C)?
它負責接收HTTP請求
加載配置文件
實現業務操作
初始化上下應用對象ApplicationContext
解析:
DispatcherServlet是的servlet,所以肯定負責手http
可以在web.xml中配置spring-mvc.xml,用于加載配置信息。
當沒有上下文時,該它會新創建一個上下文。
DispatcherServlet用于分發http到具體的業務方法,所以實現業務的其實是具體的bean的方法。
17、以下代碼的輸出結果是?(A)
#define a 10void foo(); main(){printf("%d..",a); foo(); printf("%d",a); } void foo(){ #undef a #define a 50 }10..10
10..50
Error
0
解析:
選A,define在預處理階段就把main中的a全部替換為10了.
另外,不管是在某個函數內,還是在函數外,define都是從定義開始知道文件結尾,所以如果把foo函數放到main上面的話,則結果會是50 ,50
18、 1000 個瓶子中有一瓶毒藥,一只老鼠吃到毒藥一周之內會死,如果要在一周之內檢測出有毒藥的一瓶,問至少需要幾只老鼠?(B)
8
10
32
999
解析:
1000個瓶子編號1-1000, 每個編號會有一個10位的二進制數字。 10只老鼠,依次喝掉所有二進制第一位是1的瓶子,第二位是1的瓶子。。。第十位是1的瓶子。 一周之后,死掉的老鼠說明毒藥瓶子編號在對應二進制位置是1,否則是0??梢越M合出毒藥的編號。(每位相同的混一起)
1000分為2組,每組500樣物品,取一點放在一起,每組放一只白鼠。 犧牲一只小白鼠 ,保留下500分可能是毒藥的,繼續分 2 , 250 3 , 125 4 , 62或63 5 , 31或32 6 , 15或16 7 , 7或8 8 , 3或4 9 , 1或2 10 。所以至少為10次(不能保證一周內。)
19、有如下模板定義:
template <class T> T fun(T x,T y){ return x*x+y*y; }在下列對fun的調用中,錯誤的是(B)
fun(1, 2)
fun(1.0, 2)
fun(2.0, 1.0)
fun<float>(1, 2.0)
解析:
模板函數應該定義為(加返回值類似聲明):
template <class T> T fun(T x,T y){ return x*x+y*y;}然后這里T要求類型一致
A,類型一致,為int型
B,類型不一致,錯我
C,類型一致,為folat型
D,用<float>進行聲明,后面的實參會強制類型轉換為float,所以也是類型一致的。
20、對于以下代碼(C)
char * p= new char[100]p 和 new出來的內存都在棧上
p 和 new出來的內存都在堆上
p在棧上 new出來的在堆上
p在堆上 new出來的在棧上
解析:
動態分配就在堆區,其他都不在堆區
21、有字符序列 {Q,H,C,Y,P,A,M,S,R,D,F,X} ,新序列{F,H,C,D,P,A,M,Q,R,S,Y,X},是下列(B)____排序算法一趟掃描的結果。
二路歸并排序
快速排序
步長為 4 的希爾排序
步長為 2 的希爾排序
冒泡排序
堆排序
解析:
拿Q作為分割點,快速排序一輪
二路歸并:H Q C Y A P M S D R F X
快速排序:F,H,C,D,P,A,M,Q,R,S,Y,X
冒泡排序:第一趟有A在第一位
堆排序:第一趟Y排在最后
如果是二路歸并的話,那么第一趟結束后每四個都是有序的
如果是快速排序的話,第一個元素將會被放到一個最準確的位置,且第一個元素前面的都比它小,后面的都比它大
如果是shell排序的話,那么每個小分組內將會是有序的
如果是堆排序的話,那么把它構成一顆二叉樹的時候,該堆要么就是大根堆,要么就是小根堆
如果是冒泡的話,那么肯定會有數據下沉的動作
22、下面代碼的輸出結果是?(C)
void main(void) { int a[5]={1,2,3,4,5}; int *ptr=(int *)(&a+1); printf("%d,%d",*(a+1),*(ptr-1)); }1,2
2,4
2,5
出錯
解析:
*(a+1)其實很簡單就是指a[1],輸出為2.
問題關鍵就在于第二個點,*(ptr-1)輸出為多少?
解釋如下,&a+1不是首地址+1,系統會認為加了一個整個a數組,偏移了整個數組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]。
23、 下列關于AOE網的敘述中,不正確的是(B)
關鍵活動不按期完成就會影響整個工程的完成時間
任何一個關鍵活動提前完成,那么整個工程將會提前完成
所有的關鍵活動提前完成,那么整個工程將會提前完成
某些關鍵活動若提前完成,那么整個工程將會提前完成
解析:
關鍵活動組成了關鍵路徑,關鍵路徑是圖中的最長路徑,關鍵路徑長度代表整個工期的最短完成時間,關鍵活動延期完成,必將導致關鍵路徑長度增加,即整個工期的最短完成時間增加,因此A正確。關鍵路徑并不唯一,當有多條關鍵路徑存在時,其中一條關鍵路徑上的關鍵活動時間縮短,只能導致本條關鍵路徑變成非關鍵路徑,而無法縮短整個工期,因為其他關鍵路徑沒有變化,因此B項不正確。對于A,B兩項要搞懂的是,任何一條關鍵路徑上的關鍵活動變長了,都會使這條關鍵路徑變成更長的關鍵路徑,并且導致其他關鍵路徑變成非關鍵路徑(如果關鍵路徑不唯一),因此整個工期延長。而某些關鍵活動縮短則不一定縮短整個工期。理解了A,B兩項,C,D就很容易理解了
24、int main(){fork()||fork();}共創建幾個進程:_C____
1
2
3
4
5
6
解析:
fork()給子進程返回一個零值,而給父進程返回一個非零值;
在main這個主進程中,首先執行 fork() || fork(), 左邊的fork()返回一個非零值,根據||的短路原則,前面的表達式為真時,后面的表達式不執行,故包含main的這個主進程創建了一個子進程,
由于子進程會復制父進程,而且子進程會根據其返回值繼續執行,就是說,在子進程中, fork() ||fork()這條語句左邊表達式的返回值是0, 所以||右邊的表達式要執行,這時在子進程中又創建了一個進程,
即main進程->子進程->子進程,一共創建了3個進程。
25、下列說法錯誤的有(ACD )
在類方法中可用this來調用本類的類方法
在類方法中調用本類的類方法時可直接調用
在類方法中只能調用本類中的類方法
在類方法中絕對不能調用實例方法
解析:
A:類方法是指類中被static修飾的方法,無this指針。
C:類方法是可以調用其他類的static方法的。
D:可以在類方法中生成實例對象再調用實例方法。(這個我也打錯了,想想應該是這個意思)
首先:
成員方法又稱為實例方法
靜態方法又稱為類方法
其次:
a,靜態方法中沒有this指針
c,可以通過類名作用域的方式調用Class::fun();
d,太絕對化了,在類中申請一個類對象或者參數傳遞一個對象或者指針都可以調用;
:this代表的是本類的對象,即實例。類方法之所以不能用this,是因為類方法是隨著類的加載而加載,在對象創建之前就已經存在。
A:類方法是類中被static修飾的方法,沒有this指針。C++的this指針:一個對象的this指針并不是對象本身的一部分,不會影響sizeof(對象)的結果。this作用域是在類內部,當在類的非靜態成員函數中訪問類的非靜態成員的時候,編譯器會自動將對象本身的地址作為一個隱含參數傳遞給函數。
C:類方法是可以調用其他類的static方法的。
D:可以在類方法中生成實例對象再調用實例方法。
26、12個元素的排序數組進行二分查找,每個元素被查找的概率是相等的,平均比較次數為 13 。37/12
解析:
平均查找長度公式為:ASL={[(n+1)/n]*log2^(n+1)}-1,也可以直接算出來,1*1+2*2+3*4+4*5=37,故其次數為37/12。
javac
javah
javadoc
jar
2、下列關于java抽象類的說法哪個正確?(D)
某個抽象類的父類是抽象類,則這個子類必須重載父類的所有抽象方法
接口和抽象類是同一回事
可以用抽象類直接去實例化創建對象
一個類只能繼承一個抽象類
解析:
如果一個類中有抽象方法,那么這個類必須聲明為 抽象類
若父類包含有抽象方法(父類肯定是 抽象類 了), 子類必須去實現它
若父類是 抽象類 ,但某個方法是非抽象的, 那么子類可以直接繼承這個方法(不用實現)
抽象類一般不能被實例化;
抽象類通常不是由程序員定義的,而是由項目經理或模塊設計人 設計抽象類的原因通常是為了規范方法名 抽象類必須要繼承,不然沒法用,作為模塊設計者,可以把讓底層程序員直接用得方法直接調用,而一些需要讓程序員覆蓋后自己做得方法則定義稱抽象方法
Java不支持多繼承,但是通過一些巧妙的設計來達到和多繼承同樣的效果
通過接口、內隱類,繼承、實現,互相配合,達到多繼承的效果
1、Java中一個類不能繼承多個具體class。
2、一個類只可繼承自一個具體 class,但可實現多個接口。
interface不涉及到實現細節,不與任何存儲空間有關連。
可以實現合并多個 interface ,達到可向上轉型為多種基類的目的。
新類可繼承自一個具象class,其余繼承都得是interfaces。
3、outer class不可繼承自多個具體 class,可在其內部設多個inner class,每個inner class都能各自繼承某一實現類。
inner class不受限于outer class 是否已經繼承自某一實現類。
4、inner class可以說是多重繼承問題的完整解決方案。
inner class 可 “繼承自多個具象或抽象類”。
一個類不能繼承自多個一般類。但我們可以讓其內部的多個inner class各自繼承某一實現類達到類似的目的。
3、兩個等價線程并發的執行下列程序,a為全局變量,初始為0,假設printf、++、--操作都是原子性的,則輸出肯定不是哪個?(A)
void foo() { if(a <= 0) { a++; } else { a--; } printf("%d", a); }01
10
12
22
解析:
每個線程進foo函數不止一次,那么我們暫且假設兩個線程分別進入foo函數X次,
假設給線程編號,線程1有m次被堵在a++,線程2有n次被堵在a++處,
那么線程1必然會執行(X-m)次a- -,線程2必然會執行(X-n)次a- -,
那么最終a的值為(m+n)-((X-m)+(X-n))=2(m+n)-2X,
那么a必然是偶數
對于B選項:P1執行程序,輸入1,P2執行程序,輸出0;
對于C選項:初始為0,P1執行完判斷語句,決定要執行a++,中斷,P2進行判斷,此時a仍然等于0,執行判斷語句,并執行輸入,得到1,P1然后繼續執行,此時它該執行a++,這時a=1,執行并輸出,結果為2;
對于D答案:初始為0,P1執行完判斷語句,決定要執行a++,中斷,P2進行判斷,此時a仍然等于0,執行a++,得到a=1,中斷,P1繼續執行a++,a=2,P1輸出,得到2,P1結束,P2繼續執行輸出語句,得到2;
4、
void swap_int(int *a,int *b){ *a=*a+*b; *b=*a-*b; *a=*a-*b; }以下說法正確的是:(B)
結果不正確,因為會溢出,用位與的方式就沒問題
結果正確,即使會溢出
結果正確,不會溢出
其他選項都不對
解析:
設整形變量*a、*b的位表示為
*a = n31n30 ??? n0
*b = m31m30 ??? m0
只有當*a > 0 && *b > 0 或 *a < 0 && *b < 0時才會發生溢出。兩者類似,只證明均大于0時的情況。必須擴展額外一位才能夠容納正確的結果,'|'左邊為擴展位。
*a = 0|0n30 ??? n0 = n30*230 + n29*229 + ??? + n0*20 = N
*b = 0|0m30 ??? m0 = m30*230 + m29*229 + ??? + m0*20 = M
若和溢出,則33位表示必為
*a + *b = 0|1b30 ??? b0 = -231 + b30*230 + b29*229 + ??? + b0*20 = 2 31 + B ①
計算機將得到的33位結果truncate回原來的32位,即丟棄第33位(0)變為:
*a + *b = 1b30 ??? b0 = -231 + b30*230 + b29*229 + ??? + b0*20 = -2 31 + B ②
正確的真實值是①,溢出結果為②,可見溢出結果=真實值-2 32
則*b = *a - *b = ② - *b = ① - 232 - *b = *a + *b - 232 - *b = -232 + *a
最后一步,來看 -232 + *a == *a 成立否?
0 < *a < 231, 則 -232 < -232 + *a < -231,和仍需要擴展1位方能表示:
*a = 0|0n30 ??? n0 = n30*230 + n29*229 + ??? + n0*20 = N
-232 = 1|0000 ??? 00
和的位表示為
-232 + *a = 1|0n30 ??? n0 = n30*230 + n29*229 + ??? + n0*20
同樣,計算機把33位結果truncate回32位(丟棄第33位)得到:
-232 + *a = 0n30 ??? n0 = n30*230 + n29*229 + ??? + n0*20 = *a
可見-232 + *a == *a 是成立的。因此盡管溢出了,但仍能正確交換。
可能經驗上的某種直覺告訴我們:加減法可能會溢出。其實不然,第一步的加運算可能會造成溢出,但它所造成的溢出會在后邊的減運算中被溢出回來。
5、 下面有關java的一些細節問題,描述錯誤的是?(B)
構造方法不需要同步化
一個子類不可以覆蓋掉父類的同步方法
定義在接口中的方法默認是public的
容器保存的是對象的引用
6、 2014! 的末尾有 1 個0? 501
解析:
末尾為0,主要看乘積項中2和5的個數,由于2的個數明顯比5多,則只需看5的個數即可
2014/5 = 402....4
2014/25 = 80....14
2014/125 = 16....14
2014/625 = 3....19
故2014!末尾0的個數為402+80+16+3 = 501
7、 關于排序算法的以下說法,錯誤的是___(D)___。
快速排序的平均時間復雜度為O(nlogn),最壞時間復雜度為O(n2)
堆排序的平均時間復雜度為O(nlogn),最壞時間復雜度為O(nlogn)
冒泡排序的平均時間復雜度為O(n2),最壞時間復雜度為O(n2)
歸并排序的平均時間復雜度為O(nlogn),最壞時間復雜度為O(n2)
解析:
歸并排序是穩定的排序方法。最壞和最好沒區別!O(nlogn)
8、下列代碼的輸出為:(B)
#include<iostream> #include<vector> using namespace std;int main(void) { vector<int>array; array.push_back(100); array.push_back(300); array.push_back(300); array.push_back(500); vector<int>::iterator itor; for (itor = array.begin(); itor != array.end(); itor++) { if (*itor == 300) { itor = array.erase(itor); } } for (itor = array.begin(); itor != array.end(); itor++) { cout << *itor << " "; } return 0; } 100 300 300 500
100 300 500
100 500
程序錯誤
解析:
vector 的erase函數 刪除指定位置的元素時, 返回值是一個迭代器,指向刪除元素下一個元素。刪除第一個300后,itor指向其后的300,然后執行itor++,指向了500.
9、下列程序的輸出結果:(C)
#include <iostream> using namespace std; class A { public: void print() { cout << "A:print()"; } }; class B: private A { public: void print() { cout << "B:print()"; } }; class C: public B { public: void print() { A: print(); } }; int main() { C b; b.print(); } A:print()
B:print()
編譯出錯
解析:
B的繼承為私有繼承,對于C已經不能再調用A的所有方法了
10、用戶雙擊鼠標時產生的消息序列,下面正確的是(D)
WM_LBUTTONDOWN,WM_LBUTTONUP,WM_LBUTTONDOWN,WM_LBUTTONUP
WM_LBUTTONDOWN,WM_LBUTTONUP,WM_LBUTTONUP,WM_LBUTTONDBLCLK
WM_LBUTTONDOWN,WM_LBUTTONUP,WM_LBUTTONDOWN,WM_LBUTTONDBLCLK
WM_LBUTTONDOWN,WM_LBUTTONUP,WM_LBUTTONDBLCLK,WM_LBUTTONUP
解析:
雙擊即點擊左鍵兩下,第一次觸發LBUTTONDOWN和LBUTTONUP,第二次點擊時觸發雙擊事件LBUTTONDBLCLK(doubleclick),放掉再觸發LBUTTONUP
11、下面有關繼承、多態、組合的描述,說法錯誤的是?(D)
封裝,把客觀事物封裝成抽象的類,并且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏
繼承可以使用現有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進行擴展
隱藏是指派生類中的函數把基類中相同名字的函數屏蔽掉了
覆蓋是指不同的函數使用相同的函數名,但是函數的參數個數或類型不同
解析:
重載:
只有在 同一類定義中的同名成員函數才存在重載關系 ,主要特點是 函數的參數類型和數目有所不同 ,但 不能出現函數參數的個數和類型均相同 ,僅僅依靠返回值類型不同來區分的函數,這和普通函數的重載是完全一致的。另外,重載和成員函數是否是虛函數無關
覆蓋:
在派生類中覆蓋基類中的同名函數,要求兩個函數的參數個數、參數類型、返回類型都相同,且基類函數必須是虛函數。
隱藏:
派生類中的函數屏蔽了基類中的同名函數,
2個函數參數相同,但基類函數不是虛函數(和覆蓋的區別在于基類函數是否是虛函數)。2個函數參數不同,無論基類函數是否是虛函數,基類函數都會被屏蔽(和重載的區別在于兩個函數不在同一類中)。
12、
char *p1;int64 *p2; p1=(char *)0x800000; p2=(int64 *)0x800000; char *a=p1+2 int64_t *b=p2+2那么a= 1 0x800002 ,b= 2 0x800010
解析:
我們定義指針的時候給指針一個類型就是為了方便指針的加減操作。p1是char類型指針,每個char占一個字節,所以p1+2就是在p1的基礎上加2個char的長度,就是兩個字節。p2是指向64位int型的指針,所以p2+2就是p2加上兩個64位int的長度,也就是加上128位,即16個字節。用16進制表示是0x10
所以a=0x800000+0x2=0x800002
b=0x800000+0x10=0x800010
指針里面存的是地址,所以指針的加減也是為了求得變化后的地址,即假設指針的類型是T,那么新的地址應該就是原地址+sizeof(T)個字節后得到的地址,也就是說它加的實質還是相應的字節數,而這個字節數是多少得看指針的類型,本題中第一個是char類型,那么加2就是倆個字節,第二個是64位的int,那么相應的指針類型就是8字節,因為指針就是為了尋地址的,與cpu的位數有關,一個字節8位,因此它加2就是加2*sizeof(int64),轉16進制為0x1
13、 請問以下說法,哪個是正確的:(C)
每個類都有一個無參數的構造函數。
每個類都有一個拷貝構造的函數。
每個類能有多個構造函數。
每個類能有多個析構函數。
解析:
A:用戶自定義了構造函數編譯器不會合成無參構造函數
B:?一個類可以有多個拷貝構造函數
class A{}; class B: public A{ public: B(const B&); B(const A&); };class A{}; class B: public A{ public: B(const B&); B(const A&); };D:一個類只能有一個析構函數
14、選擇填空:(D)
#include void test(void *data) { unsigned int value = (此處應填入) printf("%u", value); } using namespace std; int main() { unsigned int value = 10; test(&value); return 0; }*data
(unsigned int)(*data)
(unsigned*)data
*((unsigned int *)data)
解析:
注意,參數類型是void, 所以先要進行指針轉換:(unsigned int *)然后再取值。
15、 在C++語言中,下列說法正確的是:(D)
inline函數表示編譯器一定會將函數體直接插入到調用此函數的地方,這樣可以加快程序的運行速度
局部變量和全局變量不能重名
靜態局部變量內存是在運行期分配的,存儲在堆棧區
C++不是類型安全的語言
解析:
首先,可以排除B和C。B選項,因為局部變量和全局變量是可以重名的,而且一般來說在某個函數體內,局部變量是會覆蓋全局變量的。C選項,靜態局部變量存在靜態存儲區,而局部變量存儲在堆棧區,確切的說是棧區。再看A選項,內聯函數與其他普通函數的區別是,內聯函數在生成可執行文件時,其代碼塊是直接嵌入到調用處的,以此減少函數調用的開銷提高程序性能,它與宏很類似。但是,C++ primer 上明明白白的寫過這么一句話:內聯說明(inline specification)對于編譯器來說只是一個建議,編譯器可以選擇忽略這個建議。也就是說,是否以嵌入式方式存在,是由編譯器決定的,并不是一定。最后看D選項,什么叫類型安全的語言?本人很淺陋的認識是:就C++而言,我們可以把0作為false,非零作為true。一個函數就算是bool類型的,我們還是可以返回int類型,并且自動把0轉化成false,非零轉化成true。相比之下java不能把int類型轉化成bool類型。所以java是一種類型安全的語言,而C++并不是。 答案選D
16、關于Spring MVC的核心控制器DispatcherServlet的作用,以下說法錯誤的是(C)?
它負責接收HTTP請求
加載配置文件
實現業務操作
初始化上下應用對象ApplicationContext
解析:
DispatcherServlet是的servlet,所以肯定負責手http
可以在web.xml中配置spring-mvc.xml,用于加載配置信息。
當沒有上下文時,該它會新創建一個上下文。
DispatcherServlet用于分發http到具體的業務方法,所以實現業務的其實是具體的bean的方法。
17、以下代碼的輸出結果是?(A)
#define a 10void foo(); main(){printf("%d..",a); foo(); printf("%d",a); } void foo(){ #undef a #define a 50 }10..10
10..50
Error
0
解析:
選A,define在預處理階段就把main中的a全部替換為10了.
另外,不管是在某個函數內,還是在函數外,define都是從定義開始知道文件結尾,所以如果把foo函數放到main上面的話,則結果會是50 ,50
18、 1000 個瓶子中有一瓶毒藥,一只老鼠吃到毒藥一周之內會死,如果要在一周之內檢測出有毒藥的一瓶,問至少需要幾只老鼠?(B)
8
10
32
999
解析:
1000個瓶子編號1-1000, 每個編號會有一個10位的二進制數字。 10只老鼠,依次喝掉所有二進制第一位是1的瓶子,第二位是1的瓶子。。。第十位是1的瓶子。 一周之后,死掉的老鼠說明毒藥瓶子編號在對應二進制位置是1,否則是0??梢越M合出毒藥的編號。(每位相同的混一起)
1000分為2組,每組500樣物品,取一點放在一起,每組放一只白鼠。 犧牲一只小白鼠 ,保留下500分可能是毒藥的,繼續分 2 , 250 3 , 125 4 , 62或63 5 , 31或32 6 , 15或16 7 , 7或8 8 , 3或4 9 , 1或2 10 。所以至少為10次(不能保證一周內。)
19、有如下模板定義:
template <class T> T fun(T x,T y){ return x*x+y*y; }在下列對fun的調用中,錯誤的是(B)
fun(1, 2)
fun(1.0, 2)
fun(2.0, 1.0)
fun<float>(1, 2.0)
解析:
模板函數應該定義為(加返回值類似聲明):
template <class T> T fun(T x,T y){ return x*x+y*y;}然后這里T要求類型一致
A,類型一致,為int型
B,類型不一致,錯我
C,類型一致,為folat型
D,用<float>進行聲明,后面的實參會強制類型轉換為float,所以也是類型一致的。
20、對于以下代碼(C)
char * p= new char[100]p 和 new出來的內存都在棧上
p 和 new出來的內存都在堆上
p在棧上 new出來的在堆上
p在堆上 new出來的在棧上
解析:
動態分配就在堆區,其他都不在堆區
21、有字符序列 {Q,H,C,Y,P,A,M,S,R,D,F,X} ,新序列{F,H,C,D,P,A,M,Q,R,S,Y,X},是下列(B)____排序算法一趟掃描的結果。
二路歸并排序
快速排序
步長為 4 的希爾排序
步長為 2 的希爾排序
冒泡排序
堆排序
解析:
拿Q作為分割點,快速排序一輪
二路歸并:H Q C Y A P M S D R F X
快速排序:F,H,C,D,P,A,M,Q,R,S,Y,X
冒泡排序:第一趟有A在第一位
堆排序:第一趟Y排在最后
如果是二路歸并的話,那么第一趟結束后每四個都是有序的
如果是快速排序的話,第一個元素將會被放到一個最準確的位置,且第一個元素前面的都比它小,后面的都比它大
如果是shell排序的話,那么每個小分組內將會是有序的
如果是堆排序的話,那么把它構成一顆二叉樹的時候,該堆要么就是大根堆,要么就是小根堆
如果是冒泡的話,那么肯定會有數據下沉的動作
22、下面代碼的輸出結果是?(C)
void main(void) { int a[5]={1,2,3,4,5}; int *ptr=(int *)(&a+1); printf("%d,%d",*(a+1),*(ptr-1)); }1,2
2,4
2,5
出錯
解析:
*(a+1)其實很簡單就是指a[1],輸出為2.
問題關鍵就在于第二個點,*(ptr-1)輸出為多少?
解釋如下,&a+1不是首地址+1,系統會認為加了一個整個a數組,偏移了整個數組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]。
23、 下列關于AOE網的敘述中,不正確的是(B)
關鍵活動不按期完成就會影響整個工程的完成時間
任何一個關鍵活動提前完成,那么整個工程將會提前完成
所有的關鍵活動提前完成,那么整個工程將會提前完成
某些關鍵活動若提前完成,那么整個工程將會提前完成
解析:
關鍵活動組成了關鍵路徑,關鍵路徑是圖中的最長路徑,關鍵路徑長度代表整個工期的最短完成時間,關鍵活動延期完成,必將導致關鍵路徑長度增加,即整個工期的最短完成時間增加,因此A正確。關鍵路徑并不唯一,當有多條關鍵路徑存在時,其中一條關鍵路徑上的關鍵活動時間縮短,只能導致本條關鍵路徑變成非關鍵路徑,而無法縮短整個工期,因為其他關鍵路徑沒有變化,因此B項不正確。對于A,B兩項要搞懂的是,任何一條關鍵路徑上的關鍵活動變長了,都會使這條關鍵路徑變成更長的關鍵路徑,并且導致其他關鍵路徑變成非關鍵路徑(如果關鍵路徑不唯一),因此整個工期延長。而某些關鍵活動縮短則不一定縮短整個工期。理解了A,B兩項,C,D就很容易理解了
24、int main(){fork()||fork();}共創建幾個進程:_C____
1
2
3
4
5
6
解析:
fork()給子進程返回一個零值,而給父進程返回一個非零值;
在main這個主進程中,首先執行 fork() || fork(), 左邊的fork()返回一個非零值,根據||的短路原則,前面的表達式為真時,后面的表達式不執行,故包含main的這個主進程創建了一個子進程,
由于子進程會復制父進程,而且子進程會根據其返回值繼續執行,就是說,在子進程中, fork() ||fork()這條語句左邊表達式的返回值是0, 所以||右邊的表達式要執行,這時在子進程中又創建了一個進程,
即main進程->子進程->子進程,一共創建了3個進程。
25、下列說法錯誤的有(ACD )
在類方法中可用this來調用本類的類方法
在類方法中調用本類的類方法時可直接調用
在類方法中只能調用本類中的類方法
在類方法中絕對不能調用實例方法
解析:
A:類方法是指類中被static修飾的方法,無this指針。
C:類方法是可以調用其他類的static方法的。
D:可以在類方法中生成實例對象再調用實例方法。(這個我也打錯了,想想應該是這個意思)
首先:
成員方法又稱為實例方法
靜態方法又稱為類方法
其次:
a,靜態方法中沒有this指針
c,可以通過類名作用域的方式調用Class::fun();
d,太絕對化了,在類中申請一個類對象或者參數傳遞一個對象或者指針都可以調用;
:this代表的是本類的對象,即實例。類方法之所以不能用this,是因為類方法是隨著類的加載而加載,在對象創建之前就已經存在。
A:類方法是類中被static修飾的方法,沒有this指針。C++的this指針:一個對象的this指針并不是對象本身的一部分,不會影響sizeof(對象)的結果。this作用域是在類內部,當在類的非靜態成員函數中訪問類的非靜態成員的時候,編譯器會自動將對象本身的地址作為一個隱含參數傳遞給函數。
C:類方法是可以調用其他類的static方法的。
D:可以在類方法中生成實例對象再調用實例方法。
26、12個元素的排序數組進行二分查找,每個元素被查找的概率是相等的,平均比較次數為 13 。37/12
解析:
平均查找長度公式為:ASL={[(n+1)/n]*log2^(n+1)}-1,也可以直接算出來,1*1+2*2+3*4+4*5=37,故其次數為37/12。
總結