1. 程式人生 > >程式設計師筆試題收集彙總(一)

程式設計師筆試題收集彙總(一)

收集的筆試題,各處摘抄加自己的理解 
相關文章: 
程式設計師筆試題收集彙總(一) 
http://blog.csdn.net/youyou1543724847/article/details/52383530 
程式設計師筆試題收集彙總(二) 
http://blog.csdn.net/youyou1543724847/article/details/52728001 
程式設計師筆試題收集彙總(三) 
http://blog.csdn.net/youyou1543724847/article/details/52728079

1.下列 C 程式碼中,不屬於未定義行為的有_ 
A: Int i=0;i=(i++); 
B: char *p=”hello”;p[1]=’E’; 
C: char *p=”hello”;char ch=*p++; 
D: int i=0;printf(“%d%d\n”,i++,i–); 
E: 都是未定義行為 
F: 都不是未定義行為 
正確答案: C 
解析:C語言中的未定義行為(Undefined Behavior)是指C語言標準未做規定的行為。同時,標準也從沒要求編譯器判斷未定義行為,所以這些行為有編譯器自行處理,在不同的編譯器可能會產生不同的結果,又或者如果程式呼叫未定義的行為,可能會成功編譯,甚至一開始執行時沒有錯誤,只會在另一個系統上,甚至是在另一個日期執行失敗。當一個未定義行為的例項發生時,正如語言標準所說,“什麼事情都可能發生”,也許什麼都沒有發生。 
所以,避免未定義行為,是個明智的決定。本文將介紹幾種未定義行為,同時歡迎讀者糾錯和補充。 
1.同一運算子中多個運算元的計算順序(&&、||、?和,運算子除外)

例如:x = f()+g(); //錯誤 
f()和g()誰先計算由編譯器決定,如果函式f或g改變了另一個函式所使用變數的值,那麼x的結果可能依賴於這兩個函式的計算順序。 
參考: 《C程式設計語言(第2版)》 P43 
2.函式各引數的求值順序

例如: printf(“%d,%d\n”,++n,power(2,n)); //錯誤 
在不同的編譯器可能產生不同的結果,這取決於n的自增運算和power呼叫誰在前誰在後。 
需要注意的是,不要和逗號表示式弄混,都好表示式可以參考這篇文章:c語言中逗號運算子和逗號表示式 
參考: 《C程式設計語言(第2版)》 P43 
3.通過指標直接修改 const 常量的值

直接通過賦值修改const變數的值,編譯器會報錯,但通過指標修改則不會

2. 6支筆,其筆身和筆帽顏色相同:但6支筆顏色各不相同,求全部筆身都戴錯筆帽的可能性有多少種? 
A:265 
B: 266 
C:267 
D:268 
答案:A 
解析:網上摘抄(排錯公式) 
第一步,把第n個元素放在一個位置,比如位置k,一共有n-1種方法; 
第二步,放編號為k的元素,這時有兩種情況:⑴把它放到位置n,那麼,對於剩下的n-1個元素,由於第k個元素放到了位置n,剩下n-2個元素就有D(n-2)種方法;⑵第k個元素不把它放到位置n,這時,對於這n-1個元素,有D(n-1)種方法(相當與K於原N的位置是一對,當時由於K不放在N的位置上,形成類似與“排錯,不能構成匹配的語言”,則有n-1個元素); 
綜上得到 
D(n) = (n-1) [D(n-2) + D(n-1)]

3. 假定變數I,f,d資料型別分別為int,float和double(int用補碼錶示,float和double分別用IEEE754單精度和雙精度浮 點資料格式表示),已知i=785,f=1.5678e^3,d=1.5e^100若在32位機器 中執行下列關係表示式,則結果為真是() 
(I)i==(int)(float)I 
(II)f==(float)(int)f 
(III)f==(float)(double) f 
(IV)(d+f)-d==f 
A:僅I和II 
B:僅I和III 
C:僅II和III 
D:僅III和IV 
答案:B 
(I)i==(int)(float)I 由於i(int)經過強制型別轉換從int->float->int和左邊相同 正確 
(II)f==(float)(int)f 由於f(float)經過強制型別轉換 從float->int,雖然int也強制型別轉換了但是小數點已經去掉,故精度丟失,和左邊不一樣,錯誤 
(III)f==(float)(double) f 由於f(float)經過強制型別轉換 從float->double->float和左邊相同 正確 
(IV)(d+f)-d==f 左邊為了儘量保證精度不丟失,一般會把低轉化為高精度從float->double 和右邊float不同 錯誤

4. 每份考卷都有一個8位二進位制序列號。當且僅當一個序列號含有偶數個1時,它才是有效的。例如,00000000、01010011都是有效的序列號,而11111110不是。那麼,有效的序列號共有() 個 
A:127 
B:128 
C:255 
D:256 
答案:B 
總共有2^8=256個序列,其中要麼含有偶數個1,要麼奇數個,所以對半分為128個。 
(可理解為二項分佈 (1 +(-1))^8, 由於 (1-1)^8=0,則 結果中有效的無效的對半)

5. 求輸出結果

int a[2][2][3]= { {{1,2,3},{4,5,6}},{{7,8,9},{10,11,12}}};
int *ptr=(int *)(&a+1);
printf(“%d %d”, *(int*)(a+1), *(ptr-1));
1
2
3
A:7 12 
B:1 6 
C:1 3 
D:7 9 
正確答案: A 
6. 有哪幾種情況只能用intialization list 而不能用assignment?

A:當類中含有const成員變數 
B:基類無預設建構函式時,有參的建構函式都需要初始化表。 
C:當類中含有reference成員變數 
D:當類中含有static成員變數 
正確答案: A B C 
因為const物件以及引用只能初始化而不能賦值,所以只能使用成員初始化列表。 
對於非內建型別,在進入函式體之前,如果沒有提供顯式初始化,會呼叫預設建構函式進行初始化。若沒有預設建構函式,則編譯器嘗試呼叫預設建構函式將會失敗,所以如果沒有預設建構函式,則必須在初始化列表中顯示的呼叫建構函式。 
static 成員在執行建構函式前就已經構造好了,即使不存在類物件,也可以被使用,不需要初始化列表 
7. 下列TCP連線建立過程描述正確的是: 
A:服務端收到客戶端的SYN包後等待2*ml時間後就會進入SYN_SENT狀態 
B:服務端收到客戶端的ACK包後會進入SYN_RCVD狀態 
C:當客戶端處於ESTABLISHED狀態時,服務端可能仍然處於SYN_RCVD狀態 
D:服務端未收到客戶端確認包,等待2*ml時間後會直接關閉連線 
正確答案: C 
關於D,如果伺服器處於SYN_Recv狀態,傳送了同步+確認包後,沒有收到客戶端的確認包,則一般會重試,重新發送同步+確認包後,並等待一段時間後丟棄這個未完成的連線,這段時間的長度我們稱為SYN Timeout,一般來說這個時間是分鐘的數量級(大約為30秒-2分鐘);一個使用者出現異常導致伺服器的一個執行緒等待1分鐘並不是什麼很大的問題,但如果有一個惡意的攻擊者大量模擬這種情況,伺服器端將為了維護一個非常大的半連線列表而消耗非常多的資源—-數以萬計的半連線,即使是簡單的儲存並遍歷也會消耗非常多的CPU時間和記憶體,何況還要不斷對這個列表中的IP進行SYN+ACK的重試。此時從正常客戶的角度看來,伺服器失去響應,這種情況我們稱做:伺服器端受到了SYN Flood攻擊(SYN洪水攻擊)

8. 以下對CSMA/CD描述正確的是? 
A:在資料傳送前對網路是否空閒進行檢測 
B:在資料傳送時對網路是否空閒進行檢測 
C:在資料傳送時對傳送資料進行衝突檢測 
D:發生碰撞後MAC地址小的主機擁有傳送優先權 
答案:AC 
CSMA/CD協議即帶衝突檢測的載波監聽多路訪問協議。 
A,傳送前空閒檢測,只有通道空閒才傳送資料 
B,傳送時當前訊號佔據通道,通道必定不為空閒,檢測空閒沒意義 
C,傳送過程中衝突檢測,如果發生衝突,立即停止傳送,隨機避讓。 
D,衝突傳送後,兩個傳送端都隨機避讓一段時間,避讓的時間是隨機的,優先順序相等,沒有哪個優先權高的說法。 
9.以下哪些執行緒同步鎖可以為遞迴鎖 
1.訊號量 2.讀寫鎖 3.互斥量 4.事件 5.臨界區(Critical Section) 
A: 1,3,4,5 
B:5 
C:3,5 
D:1,3,5 
正確答案: C 
程序/執行緒同步方法 
常見的程序/執行緒同步方法有互斥鎖(或稱互斥量Mutex)、讀寫鎖(rdlock)、條件變數(cond)、訊號量(Semophore)等。 
在windows系統中,臨界區(Critical Section)和事件物件(Event)也是常用的同步方法。 
遞迴鎖/非遞迴鎖 
Mutex可以分為遞迴鎖(recursive mutex)和非遞迴鎖(non-recursive mutex)。 遞迴鎖也叫可重入鎖(reentrant mutex),非遞迴鎖也叫不可重入鎖(non-reentrant mutex)。 
二者唯一的區別是: 
同一個執行緒可以多次獲取同一個遞迴鎖,不會產生死鎖。 
如果一個執行緒多次獲取同一個非遞迴鎖,則會產生死鎖。 
Windows下的Mutex和Critical Section是可遞迴的。 
Linux下的pthread_mutex_t鎖是預設是非遞迴的。可以通過設定PTHREAD_MUTEX_RECURSIVE屬性,將pthread_mutex_t鎖設定為遞迴鎖。 
10. A、B、C、D四人應聘一個程式設計師職位,此職務的要求條件是:Java熟練;懂資料庫開發;會Web開發;有C++經驗。誰滿足的條件最多,誰就被僱用。(1)把上面四個要求條件兩兩組合,每個組合都恰有一人滿足。同時已知(2)A和Bjava熟練(3)B和C會Web(4)C和D懂資料庫(5)D有C++經驗那麼,被僱用的是__。 
A:A 
B:B 
C:C 
D:D 
E:四人機會均等 
F:以上均錯 
解析:經過推測為(s為資料庫) 
A B C D 
java java X X 
X web web X 
S X S S 
X C X C 
所以為B 
11. 下面程式的結果是:

class Supper{
    public Integer get()
    {
        System.out.println("s");
        return 4;
    }
}
public class test extends Supper{
    public Long get()
    {
        System.out.println("b");
        return new Long("5");
    }
     public static void main(String args[])
     {
         Supper s=new Supper();
         test test=new test();
         s.get();
         test.get();
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
答案:編譯錯誤

擴充套件: 
11. 1下面程式的結果是:

class Supper{
    public Integer get()
    {
        System.out.println("Supper");
        return new Integer("5");
    }
}
public class Sub{
    public int get()
    {
        System.out.println("Sub");
        return 5;
    }
     public static void main(String args[]) {
         new Supper().get();
         new Sub().get();

     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
答案:Supper Sub

11. 2下面程式的結果是:

class Supper{
    public int get()
    {
        System.out.println("Supper");
        return 5;
    }
}
public class Sub{
    public int get()
    {
        System.out.println("Sub");
        return new Integer("5");

    }
     public static void main(String args[]) {
         new Supper().get();
         new Sub().get();

     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
答案:Supper Sub 
12. 以上程式的執行結果是:

int* pint = 0; 
pint += 6; 
cout << pint << endl;
1
2
3
A:12 
B:72 
C:24 
D:0 
E:6 
F:任意數 
答案:C 
13. 以上程式的執行結果是:

public class Base {
    static Base a=new Base();
    {System.out.print("C");}
    static{ System.out.print("S"); }
    Base(){}
     public static void main(String args[]) {
         new Base();
     }
}
1
2
3
4
5
6
7
8
9
答案:CSC 
14. 字串 alibaba 有多少個不同的排列 
思路:先有序排列:aaabbli。首先遞迴a(aabbli), b(aaabli), l(aaabbli) ,i(aaabbl)…依 次交換不相同的。 http://blog.csdn.net/a45872055555/article/details/38490785 只計算個數的話,就用:A(7,7) / (A(3,3)*A(2,2)) = 420 
15. 某校園網使用者無法訪問外部站點210.102.58.74,管理人員在windows 作業系統 下可以使用( )判斷故障發生在校園網內還是校園網外

16. 那些應用層協議採用的UDP,那些是TCP 
21/tcp FTP 檔案傳輸協議 
22/tcp SSH 安全登入、檔案傳送(SCP)和埠重定向 
23/tcp Telnet 不安全的文字傳送 
25/tcp SMTP Simple Mail Transfer Protocol (E-mail) 
69/udp TFTP Trivial File Transfer Protocol 
79/tcp finger Finger 
80/tcp HTTP 超文字傳送協議 (WWW) 
88/tcp Kerberos Authenticating agent 
110/tcp POP3 Post Office Protocol (E-mail) 
113/tcp ident old identification server system 
119/tcp NNTP used for usenet newsgroups 
220/tcp IMAP3 
443/tcp HTTPS used for securely transferring web pages

UDP支援的應用層協議主要有:NFS(網路檔案系統)、SNMP(簡單網路管理協議)、DNS(主域名稱系統)、TFTP(通用檔案傳輸協議)等

PS:DNS伺服器在更新資料時採用的是TCP,其他查詢的時候使用的是TCP 
17. 寫出new和malloc、delete和free的區別

從面向物件來說,new/delete和malloc/free的區別是:malloc/free只是單純的進行內 存空間的分配和釋放,而使用new/delete時,不僅分配了記憶體空間,若new/delete的 是一個類,還會呼叫類(經測試,基本型別好像不會進行預設初始化)的建構函式或析 構函式。   簡單來說,兩者的區別主要有: 
1. malloc與free是C++/C語言的標準庫函式,new/delete是C++的運算子, 與”+“、”-“、”*“、”/“有一樣的地位。 
2. new/delete是可以過載的,而過載之後,就成為了函式。 
3. malloc在申請記憶體的時候,必須要提供申請的長度,而且返回的指標是void* 型,必須要強轉成需要的型別。 
4. 當new/delete在類中被過載的時候,可以自定義申請過程,比如記錄所申請內 存的總長度,以及跟蹤每個物件的指標。 
5. new/delete,其實內部也呼叫了malloc/free。

兩者的共同點有: 1. 都必須配對使用,防止記憶體洩露。 2. 都可用於申請動態記憶體和釋放記憶體,都是在堆中分配記憶體。

18. 下面程式輸出: 
Object o1 = true ? new Integer(1) : new Double(2.0);

Object o2; 
if (true) 
o2 = new Integer(1); 
else 
o2 = new Double(2.0); 
System.out.println(o1); 
System.out.println(o2);

答案: 
1.0 

解析:當第二第三操作時可轉化成數值型別時,可能發生型別提升、自動拆裝箱 
參考:https://blog.jooq.org/2013/10/08/java-auto-unboxing-gotcha-beware/

19. 下面程式輸出:


class Y{
    public Y(){
        System.out.println("Y");
    }
}
class Supper{
    Y y=new Y();
    public Supper(){
        System.out.println("Supper");
    }
}
public class Sub extends Supper{
    Y y=new Y();
    public Sub(){
        System.out.println("Sub");
    }
     public static void main(String args[]) {
        new Sub();   
     }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
答案: 

Supper 

Sub

20. 存在使i + 1 < i的數嗎() 
答案:存在 解析:如果i為int型,那麼當i為int能表示的最大整數時,i+1就溢位變成負數了,此時不就< i了嗎。 
擴充套件:存在使i > j || i <= j不成立的數嗎() 
答案:存在 解析:比如Double.NaN或Float.NaN

21. 0.6332的資料型別是() 
A float B double C Float D Double 
答案:B 解析:預設為double型,如果為float型需要加上f顯示說明,即0.6332f 
擴充套件:34892234343的資料型別為int,即使在使用是可能存在溢位,如果要定義成Long,則需要加上l,如34L.

22. 不通過建構函式也能建立物件嗎() 
A 是 B 否 
答案:A 解析:Java建立物件的幾種方式(重要): 
(1) 用new語句建立物件,這是最常見的建立物件的方法。 
(2) 運用反射手段,呼叫java.lang.Class或者java.lang.reflect.Constructor類的newInstance()例項方法。
(3) 呼叫物件的clone()方法。 
(4) 運用反序列化手段,呼叫java.io.ObjectInputStream物件的 readObject()方法。 (1)和(2)都會明確的顯式的呼叫建構函式 ;(3)是在記憶體上對已有物件的影印,所以不會呼叫建構函式 ; (4)是從檔案中還原類的物件,也不會呼叫建構函式。

23.

     public static void main(String args[]) {
        String s;
        System.out.println("s:"+s);
     }
1
2
3
4
A 程式碼得到編譯,並輸出“s=” 
B 程式碼得到編譯,並輸出“s=null” 
C 由於String s沒有初始化,程式碼不能編譯通過 
D 程式碼得到編譯,但捕獲到 NullPointException異常 
答案:C 解析:開始以為會輸出null什麼的,執行後才發現Java中所有定義的基本型別或物件都必須初始化才能輸 出值。

24. Java中如何實現代理機制(JDK、CGLIB) 
JDK動態代理:代理類和目標類實現了共同的介面,用到InvocationHandler介面(重新invoke方法)。缺點:只能代理介面,不能代理類。 
CGLIB動態代理:代理類是目標類的子類, 用到MethodInterceptor介面

25. 多執行緒的實現方式 
繼承Thread類、實現Runnable介面、使用ExecutorService、Callable、Future實現有返回結果的多執行緒。

26. 如何停止一個執行緒 
不建議使用Thread的stop,suspend等相關方法(這些都是廢棄了的方法,會導致不確定的狀態) 
可以使用Thread.interrupt()方法,設定中斷標註。該方法能引數不同的結果: 
1.如果執行緒處於阻塞在 waitXX(), join(XX), sleep(XX)系統放上,則執行緒的中斷標誌會被清楚,並丟擲InterruptedException異常。 
2.如果執行緒阻塞在某些IO操作上(如 InterruptibleChannel, Selector),則會設定中斷狀態,並從IO操作中返回,並丟擲相應的異常(ClosedByInterruptException)。 
3.普通狀態:只會設定interrupt標誌(即如果你不做狀態檢查並做相應的處理,和沒有收到是一回事) 
4.如果執行緒已經死亡,則不會有任何效果。

27. 什麼是執行緒安全 
執行緒安全就是多執行緒訪問同一程式碼,不會產生不確定的結果。

28. 如何保證執行緒安全 
將共享變數變成區域性變數,或是用ThreadLocal(其實是一個map,key為thread標識) 
使用執行緒安全的類 
自己控制,如加鎖等。

29. Synchronized如何使用 
synchronized是Java中的關鍵字,是一種同步鎖。它修飾的物件有以下幾種: 
一. 修飾一個程式碼塊,被修飾的程式碼塊稱為同步語句塊,其作用的範圍是大括號{}括起來的程式碼,作用的物件是呼叫這個程式碼塊的物件; 
二. 修飾一個方法,被修飾的方法稱為同步方法,其作用的範圍是整個方法,作用的物件是呼叫這個方法的物件; 
三. 修改一個靜態的方法,其作用的範圍是整個靜態方法,作用的物件是這個類物件;

30. 多執行緒如何進行資訊互動 
void notify() 喚醒在此物件監視器上等待的單個執行緒。 
void notifyAll() 喚醒在此物件監視器上等待的所有執行緒。 
void wait() 導致當前的執行緒等待,直到其他執行緒呼叫此物件的notify()方法或notifyAll()方法。 
void wait(long timeout) 導致當前的執行緒等待,直到其他執行緒呼叫此物件的notify()方法或notifyAll()方法,或者超過指定的時間量。 
void wait(long timeout, int nanos) 導致當前的執行緒等待,直到其他執行緒呼叫此物件的notify()方法或notifyAll()方法,或者其他某個執行緒中斷當前執行緒,或者已超過某個實際時間量。

31. sleep和wait的區別(考察的方向是是否會釋放鎖) 
都會丟擲InterruptedException異常 
sleep()方法是Thread類中方法,而wait()方法是Object類中的方法。 
sleep()方法導致了程式暫停執行指定的時間,讓出cpu該其他執行緒,但是他的監控狀態依然保持者,當指定的時間到了又會自動恢復執行狀態,在呼叫sleep()方法的過程中,執行緒不會釋放物件鎖。而當呼叫wait()方法的時候,執行緒會放棄物件鎖,進入等待此物件的等待鎖定池,只有針對此物件呼叫notify()方法後本執行緒才進入物件鎖定池準備 
32. 多執行緒與死鎖 
死鎖是指兩個或兩個以上的程序在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。 
產生死鎖的原因: 
一.因為系統資源不足。 
二.程序執行推進的順序不合適。 
三.資源分配不當。

33. 如何才能產生死鎖 
一.互斥條件:所謂互斥就是程序在某一時間內獨佔資源。 
二.不剝奪條件:程序已獲得資源,在末使用完之前,不能強行剝奪。 
三.請求與保持條件:一個程序因請求資源而阻塞時,對已獲得的資源保持不放。 
四.迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係。

34. 死鎖的預防 
一.打破互斥條件。即允許程序同時訪問某些資源。但是,有的資源是不允許被同時訪問的,像印表機等等,這是由資源本身的屬性所決定的。所以,這種辦法並無實用價值。 
二.打破不可搶佔條件。即允許程序強行從佔有者那裡奪取某些資源。就是說,當一個程序已佔有了某些資源,它又申請新的資源,但不能立即被滿足時,它必須釋放所佔有的全部資源,以後再重新申請。它所釋放的資源可以分配給其它程序。這就相當於該程序佔有的資源被隱蔽地強佔了。這種預防死鎖的方法實現起來困難,會降低系統性能。 
三.打破佔有且申請條件。可以實行資源預先分配策略。即程序在執行前一次性地向系統申請它所需要的全部資源。如果某個程序所需的全部資源得不到滿足,則不分配任何資源,此程序暫不執行。只有當系統能夠滿足當前程序的全部資源需求時,才一次性地將所申請的資源全部分配給該程序。由於執行的程序已佔有了它所需的全部資源,所以不會發生佔有資源又申請資源的現象,因此不會發生死鎖。 
四.打破迴圈等待條件,實行資源有序分配策略。採用這種策略,即把資源事先分類編號,按號分配,使程序在申請,佔用資源時不會形成環路。所有程序對資源的請求必須嚴格按資源序號遞增的順序提出。程序佔用了小號資源,才能申請大號資源,就不會產生環路,從而預防了死鎖。

35. 什麼叫守護執行緒,用什麼方法實現守護執行緒 
守護執行緒是為其他執行緒的執行提供服務的執行緒。 
setDaemon(boolean on)方法可以方便的設定執行緒的Daemon模式,true為守護模式,false為使用者模式。 必須線上程啟動前設定才有效

36. Java執行緒池技術及原理 
http://www.importnew.com/19011.html 
http://www.cnblogs.com/dolphin0520/p/3932921.html

37. java併發包concurrent及常用的類 
併發包諸類概覽:http://www.raychase.net/1912 
執行緒池:http://www.cnblogs.com/dolphin0520/p/3932921.html 
鎖:http://www.cnblogs.com/dolphin0520/p/3923167.html 
集合:http://www.cnblogs.com/huangfox/archive/2012/08/16/2642666.html

38. volatile關鍵字 
用volatile修飾的變數,執行緒在每次使用變數的時候,都會讀取變數修改後的最的值。volatile很容易被誤用,用來進行原子性操作。 
Java語言中的volatile變數可以被看作是一種 “程度較輕的 synchronized”;與 synchronized 塊相比,volatile 變數所需的編碼較少,並且執行時開銷也較少,但是它所能實現的功能也僅是synchronized的一部分。鎖提供了兩種主要特性:互斥(mutual exclusion)和可見性(visibility)。互斥即一次只允許一個執行緒持有某個特定的鎖,因此可使用該特性實現對共享資料的協調訪問協議,這樣,一次就只有一個執行緒能夠使用該共享資料。可見性必須確保釋放鎖之前對共享資料做出的更改對於隨後獲得該鎖的另一個執行緒是可見的,如果沒有同步機制提供的這種可見性保證,執行緒看到的共享變數可能是修改前的值或不一致的值,這將引發許多嚴重問題。Volatile變數具有synchronized的可見性特性,但是不具備原子特性。這就是說執行緒能夠自動發現 volatile 變數的最新值。 
要使volatile變數提供理想的執行緒安全,必須同時滿足下面兩個條件:對變數的寫操作不依賴於當前值;該變數沒有包含在具有其他變數的不變式中。 
第一個條件的限制使volatile變數不能用作執行緒安全計數器。雖然增量操作(x++)看上去類似一個單獨操作,實際上它是一個由讀取-修改-寫入操作序列組成的組合操作,必須以原子方式執行,而volatile不能提供必須的原子特性。實現正確的操作需要使 x 的值在操作期間保持不變,而 volatile 變數無法實現這點。 
每一個執行緒執行時都有一個執行緒棧,執行緒棧儲存了執行緒執行時候變數值資訊。當執行緒訪問某一個物件時候值的時候,首先通過物件的引用找到對應在堆記憶體的變數的值,然後把堆記憶體變數的具體值load到執行緒本地記憶體中,建立一個變數副本,之後執行緒就不再和物件在堆記憶體變數值有任何關係,而是直接修改副本變數的值,在修改完之後的某一個時刻(執行緒退出之前),自動把執行緒變數副本的值回寫到物件在堆中變數。這樣在堆中的物件的值就產生變化了。

一下來源於“程式設計師面試寶典”
39 i++問題、&&和||運算優化 
&&運算中,如果第一運算元為假,就不會執行第二個條件判斷,||運算中,如果第一運算元為真,則不會進行第二個條件判斷。

40 printf計算引數時,是從右到左壓棧的

   int *p={1,2,3};
   printf("%d,%d",*p,*(++p));
1
2
列印2,2

41 注意型別擴充套件和型別轉化,知道那些型別是有符號的還是無符號的(c++中沒有byte型別) 
右移時,進行的是符號右移(即如果是負數,則添1,否則補0)

42 運算的優先順序 
總體來說,一元運算子優先順序大於二元運算子 
對於一元運算子:() > [] > -> > . > :: > 字尾++,– > !如if(!done) > ~,如flags=~flags > 字首++,– > -,+(如int i=+1)> 取地址,指標*(如data=*p,address=&obj)> type,sizeof

    對於二元運算子:乘除>加減>移位
1
Java中的無符號右移:>>> 
int x=-1; 
System.out.println(Integer.toBinaryString(x>>>3 )); 
System.out.println(Integer.toBinaryString((x>>>3)<<3)); 
System.out.println(Integer.toBinaryString(x>>3));

結果: 
11111111111111111111111111111 
11111111111111111111111111111000 
11111111111111111111111111111111

運算子優先順序:括號,下標,->和.(成員)最高; 
         單目的比雙目的高; 
         算術雙目的比其他雙目的高; 
         移位運算 高於 關係運算(比較大小); 
         關係運算 高於 按位運算(按位與,或,異或); 
         按位運算 高於 邏輯運算(邏輯與,邏輯或); 
         三目的只有一個 條件運算,低於邏輯運算; 
         賦值運算僅比 , (順序運算)高。

43 X&(X-1)的作用 
將X最右邊的一個1清零

44 不用比較判斷,輸出a,b中的大數

方法一:int max=( (a+b)  +abs(a-b)  )/2
方法二:    char *strs[2]={"a Large","b Large"};
           int c=a-b;
           c=unsinged(c) >>(sizeof(int)*8 -1);
           cout << strs[c];
1
2
3
4
5
45 不用中間變數,將a,b交換

-   方法一:(缺點:將a+b的結果可能會溢位)
                a=a+b;
                b=a-b;
                a=a-b;
    方法二:
                a=a^b;
                b=a^b;
                a=a^b;
1
2
3
4
5
6
7
8
46 在C++中呼叫被C編譯器編譯後的函式,為什麼後面要交extern“c”

被不同的編譯器編譯後的程式碼會和語言支援的功能相關,如C++支援過載,編譯器需要將函式重新命名來達到區分不同的函式的目的,但是C中就沒有過載的概念,函式編譯命名規則就會和C++不同。因此,使用extern “c”,就可以告訴編譯器這些差別,不要讓他找不到這些符號
47 求結構體某個變數相對於struct的偏移 
- (size_t) &( ((struct *)0) ->var ),將0轉化成struct型別的指標變數*P,用該變數取var成員變數的偏移地址。 
*p的起始地址為0,則成員變數var的地址即是它的偏移。

48 使用sizeof計算類的大小時,不要考慮static變數 
- 類、結構體最小大小為1byte,就算沒有任何成員變數

49 使用sizeof計算類、結構體大小時,需要考慮對齊問題 
- 所佔的大小為最大長度變數的整數倍(考慮陣列型別的變數能夠好取),且內部地址也要對齊,如int型別的成員變數地址必須是4的整數倍,如:

struct A{
   bool m;
   int  n;
   bool k;
}

struct B{
   int  n;
   bool m;
   bool k;
}
1
2
3
4
5
6
7
8
9
10
11
則A佔用12,B佔用8位元組(考慮B,如果B只佔用6位元組,如果有 B bb[2],則bb[0]地址為0,bb[1]地址為6,則bb[1]中的int變數n地址為6,不是int型別長度的整數倍,不好管理,則B編譯器會將B變成佔用8byte的,沒有使用到的用0填充)

50 區別如下指標的含義

-       int *a,一個指向int型別的指標
        int **a,一個二級指標,它指向一個指標(該指標指向一個int)
        int *a[10]:一個數組,裡面有10個指向int型別的指標
        int (*a)[10]:一個指標,指向一個有10個元素的int陣列
        int (*a)(int):函式指標,返回值為int,引數一個int的函式指標
        int  (*a[10])int :一個數組,裡面有10個函式指標,函式指標指向返回值為int,引數一個int的函式
1
2
3
4
5
6
51 注意容器元素中拷貝帶來的問題(淺拷貝、深拷貝)

特別是容器中存放的型別類成員中還有指標時,使用淺拷貝,則會導致容器中的資料指標懸掛,如
   Vecotr <A>v=new Vector<A>()
   A a;
   a.p=new char[32];
   v.push_back(a)
   delete a//這裡會釋放掉a.p所指向的記憶體,但由於是淺拷貝,則容器中的資料temp.p成了懸掛指標。
1
2
3
4
5
6
當類中還有指標型別的資料成員時,則需要仔細考慮它的建構函式(如何初始化),解構函式(如果該指標不為null,則需要delete掉),拷貝建構函式,賦值操作符函式(是否需要進行深拷貝)
52 C++中如何阻止 一個類被例項化 
- 使用抽象類,或者將建構函式宣告為private

53 一般在什麼時候將建構函式宣告為private 
- 比如需要阻止編譯器生成預設的建構函式的時候(或是某種型別的建構函式只是為其他過載形式的建構函式呼叫的時候)

54 什麼時候編譯器會生成預設的copy constructor 
- 如果你沒有寫,而又需要使用,則會自動生成

55 如果某個方法沒有使用任何成員變數,不需要this指標,不需要動態繫結(一般來說非virtual方法),則使用null就能啟用

- 如 SomeType *p =null;
   p->a();//能正常執行
       ( (X*)0 )->x(); //能正常執行

        ((X*)NULL)->x();//能正常執行
1
2
3
4
5
JAVA 裡是不可以的,因為Java方法都是動態繫結的

以下來源於“關於C++的222個問題”
56 C++支援多重繼承,為了解決多重繼承中的資料多份拷貝的情況,C++採用虛基類 
- 虛基類:基類定義方式不變,子類在繼承時,加上virtual關鍵字,如:Sub A:virtual Super B

57 多型,又分為靜態多型和動態多型 
- 靜態多型主要是模版(編譯期就處理好實際採用的型別) 
動態多型:主要是通過virtual關鍵字的

58 C++中的RTTI(Runtime Type identifier) 
- C++中的動態型別標識,主要是typeid操作符和dynamic_cast的使用。注意:使用動態型別標識需要在執行時重新編譯部分程式碼或是在編譯時,保留一些型別資訊,導致效率比較低,且轉換不安全。在使用dynamic_cast進行型別轉化時,需要在類中至少有一個virtual函式。

59 C++中的強制型別轉換運算子 
- 有4中: 
dynamic_cast: 
static_cast: 
reinterpret_cast: 
const_cast:

60 面向物件的主要思想 
- 抽象、封裝、繼承、多型

61 多型的型別 
- 強制多型(型別轉換)、過載、型別引數化多型(模版)、包含多型(類繼承和虛擬函式)

61 C++的動態性 
- C++中的動態性包括:虛擬函式、多型性、動態聯編 
關於虛擬函式:為了讓通過基類指標呼叫的方法和子類方法對應,如Super A=new Sub(); A->func(),為了讓A是呼叫的Sub中的func版本,需要將func宣告為virtual的,這是通過vtbl,vptr實現的) 
關於動態聯編:即有的資訊需要在執行時進行繫結,又叫晚期聯編。

62 陣列建立:

   int *a=new int[3];//建立了一個指向int陣列的指標,該陣列長度為3,對應刪除方式為delete []a;
   int *b=new int(3);//建立了一個int型指標,且指向的值為 3,對應刪除方式為delete b;
   int  c[3];//聲明瞭一個數組長度為3的int型陣列,該中宣告方式將c放在棧上,且這個時候,陣列的長度必須為常量。
1
2
3
63 常用型別比較

   int直接比較 : a==b
   char直接比較 : a==b
   float,double: abs(a-b)<=某個誤差值
   char *p,或是char []:strcmp( a,b)==0
   string : a==b
1
2
3
4
5
64 在自動計算大小的char陣列中,最終得到的長度=實際長度+1 
(會補充一個\0進去,不管實際串中是否存在\0),但是輸出串時,遇到\0,就不輸出了。 


65 使用sizeof計算類的大小時,不要考慮static變數,不需要考慮它的方法 
使用sizeof計算類、結構體變數時,需要考慮對其問題(按最長的欄位的整數倍(如果最長長度的變數超過了cpu長度,則按照cpu長度對其))

sizeof和strlen()的區別

        strlen:是函式,引數為char*,計算規則是從字串開始,遇到\0結束,長度不包括\0。如char a[]="ab\0\0",strlen(a)=2,sizeof(a)=5;
        sizeof:類似於巨集,大部分編譯程式在編譯期就可以計算出其值,而strlen是在執行期得出結果。
        (int *p = (int*)malloc(sizeof(int) * 100);
            cout << sizeof(p) << endl;sizeof計算是指標的空間,32位系統下為4)(關於這點:如果對沒有經過初始化的動態char*使用strlen,則結果是未定義的,這是strlen的邏輯,只有遇到\0才結束)

         sizeof:
1
2
3
4
5
6
66 virtual修飾符會被隱形繼承的 
即在父類中方法是virtual的,子類中重寫方法時,沒有加virtual關鍵字,但是該方法還是虛擬函式。

67 基本資料型別所佔位元組數 
16位編譯器

char :1個位元組
char*(即指標變數): 2個位元組
short int : 2個位元組
int:  2個位元組
unsigned int : 2個位元組
float:  4個位元組
long:   4個位元組
unsigned long:  4個位元組
long long:  8個位元組
double:   8個位元組
1
2
3
4
5
6
7
8
9
10
32位編譯器

char :1個位元組
char*(即指標變數): 4個位元組(32位的定址空間是2^32, 即32個bit,也就是4個位元組。同理64位編譯器)
short int : 2個位元組
int:  4個位元組
unsigned int : 4個位元組
float:  4個位元組
long:   4個位元組
unsigned long:  4個位元組
long long:  8個位元組
double:   8個位元組
1
2
3
4
5
6
7
8
9
10
64位編譯器

char :1個位元組
char*(即指標變數): 8個位元組
short int : 2個位元組
int:  4個位元組
unsigned int : 4個位元組
float:  4個位元組
long:   8個位元組
unsigned long:  8個位元組
long long:  8個位元組
double:   8個位元組
1
2
3
4
5
6
7
8
9
10
68 STL常用標頭檔案

#include <algorithm>    //STL 通用演算法   
#include <bitset>     //STL 位集容器   
#include <cctype>   
#include <cerrno>   
#include <clocale>   
#include <cmath>   
#include <complex>     //複數類   
#include <cstdio>   
#include <cstdlib>   
#include <cstring>   
#include <ctime>   
#include <deque>      //STL 雙端佇列容器   
#include <exception>    //異常處理類   
#include <fstream>   
#include <functional>   //STL 定義運算函式(代替運算子)   
#include <limits>   
#include <list>      //STL 線性列表容器   
#include <map>       //STL 對映容器   
#include <iomanip>   
#include <ios>       //基本輸入/輸出支援   
#include <iosfwd>     //輸入/輸出系統使用的前置宣告   
#include <iostream>   
#include <istream>     //基本輸入流   
#include <ostream>     //基本輸出流   
#include <queue>      //STL 佇列容器   
#include <set>       //STL 集合容器   
#include <sstream>     //基於字串的流   
#include <stack>      //STL 堆疊容器       
#include <stdexcept>    //標準異常類   
#include <streambuf>    //底層輸入/輸出支援   
#include <string>     //字串類   
#include <utility>     //STL 通用模板類   
#include <vector>     //STL 動態陣列容器   
#include <cwchar>   
#include <cwctype>   
using namespace std;   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
69 常用C標頭檔案

#include <assert.h>    //設定插入點
#include <ctype.h>     //字元處理
#include <errno.h>     //定義錯誤碼
#include <float.h>     //浮點數處理
#include <iso646.h>        //對應各種運算子的巨集
#include <limits.h>    //定義各種資料型別最值的常量
#include <locale.h>    //定義本地化C函式
#include <math.h>     //定義數學函式
#include <setjmp.h>        //異常處理支援
#include <signal.h>        //訊號機制支援
#include <stdarg.h>        //不定引數列表支援
#include <stddef.h>        //常用常量
#include <stdio.h>     //定義輸入/輸出函式
#include <stdlib.h>    //定義雜項函式及記憶體分配函式
#include <string.h>    //字串處理
#include <time.h>     //定義關於時間的函式
#include <wchar.h>     //寬字元處理及輸入/輸出
#include <wctype.h>    //寬字元分類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
70 包含檔案的多種寫法的區別

<>僅僅在系統指定的路徑下面尋找,”“會首先在原始檔的路徑查詢,找不到就到系統路徑中尋找

include包含標頭檔案的語句中,雙引號和尖括號的區別是什麼?
include <>格式:引用標準庫標頭檔案,編譯器從標準庫目錄開始搜尋
incluce “”格式:引用非標準庫的標頭檔案,編譯器從使用者的工作目錄開始搜尋
有木有h都無所謂,只要include這個檔名,確實存在就行。 
比如經常寫的#include ,那麼系統的包含路徑下,是確實有iostream這個檔案存在的。 
.h只是一個慣例,提示這是個標頭檔案,並非強制。
C++標頭檔案加H和不加H有什麼區別 
iostream是C++的標頭檔案,iostream.h是C的標頭檔案,即標準的C++標頭檔案沒有.h副檔名,將以前的C的標頭檔案轉化為C++的標頭檔案後,有時加上c的字首表示來自於c,例如cmath就是由math.h變來的。 iostream.h裡面定義的所有類以及物件都是在全域性空間裡,所以你可以直接用cout 但在iostream裡面,它所定義的東西都在名字空間std裡面,所以你必須加上 using namespace std才能使用cout 一般一個C++的老的帶“.h”副檔名的庫檔案,比如iostream.h,在新標準後的標準庫中都有一個不帶“.h”副檔名的相對應,區別除了後者的好多改進之外,還有一點就是後者的東東都塞進了“std”名字空間中。 但唯獨string特別。 問題在於C++要相容C的標準庫,而C的標準庫裡碰巧也已經有一個名字叫做“string.h”的標頭檔案,包含一些常用的C字串處理函式,比如strcmp。 這個標頭檔案跟C++的string類半點關係也沒有,所以並非的“升級版本”,他們是毫無關係的兩個標頭檔案。
--------------------- 
作者:安然_隨心 
來源:CSDN 
原文:https://blog.csdn.net/youyou1543724847/article/details/52383530 
版權宣告:本文為博主原創文章,轉載請附上博文連結!