1. 程式人生 > >C++程式設計中常遇到的問題

C++程式設計中常遇到的問題

1、路徑中不能存在空格

2、for等迴圈結構中,如果判斷條件的變數是size_t或者unsigned時,最好不要採用“--i”來遞減變數,因為這兩種型別沒有負數。

3、引用的引用不可用: int& &i ;(不合法,且注意兩個&之間有空格,否則就會被宣告為右值引用)。

4、int *p[10] ; sizeof(p) 是指陣列所佔的長度,雖然p本身是一個指標。

5、if判斷語句中,當要配合else使用時,最好不要在條件語句中同時存在多個判斷語句。

6、因為引用本身並非物件,所以不存在指向引用的指標: int& *ptr;(不合法)。

7、字面值常量字串 ”aaa“的經過sizeof函式後計算的空間是4,在其最後存在一個空字元。

8、在執行讀取操作時,string物件會自動忽略開頭的空白並從第一個真正的字元開始直至遇到下一個空白。

9、對於一個複雜型別的變數宣告(eg: int *&r),以變數名為中心,從右到左分析。如果有括號那麼先括號內然後遇括號跳出括號繼續從右到左分析。

10、常量表達式是值不會改變且在編譯過程中就能得知結果的表示式,陣列的維度必須是一個常量表達式。

11、指標也是迭代器,指標相減的結果型別是ptrdiff_t。

12、標準庫型別(string、vector)的下標索引必須是無符號型別,而內建的下標運算無此要求即可以是負數,如內建陣列,只要arr[-2]等價於*(arr-2)指向的元素還在陣列內就ok。

13、char *p = "abc", char p[] = "abc"; 這兩個p雖然都是都是指標,但不一樣。前者只想的是一個字串字面量,開闢的存放空間在常量區,所以不能用指標去修改其值。而後者不存在這樣的問題。

14、關於後置遞增運算子(i++),在語句中使用前,先求值產生一個等於原值的右值副本temp_i,然後將這個副本應用於這條語句中。執行完該語句後 i 在自加1。

15、C\C++中,當給cout一個字元指標的時候,它就一直輸出,直到遇到 ‘\0’ 這個結尾,如果不存在‘\0’ 則會發生輸出錯誤。

16、int a[10]{}; *(a+1)是a中的第一個元素,*(&a+1)指向的下一個型別int(*)[10]的陣列。

17、memset是以位元組為單位,初始化記憶體塊。void *memset(void *s, int ch, size_t n);將s中前n個位元組 (typedef unsigned int size_t )用ch替換並返回s.

18、無符號數與有符號數相比較,會將有符號書轉化為無符號數,負數會變成一個很大的無符號數。

19、二維陣列定義中,行可以省略,列不能。

20、程式佔用三種類型的記憶體:靜態記憶體、棧記憶體、堆記憶體; 
靜態記憶體: 
用來儲存區域性static物件、類static資料成員以及定義在任何函式之外的變數 
棧記憶體: 
用來儲存定義在函式內的非static物件。分配在靜態記憶體或棧記憶體中的物件由編譯器自動建立和銷燬。對於棧物件,僅在其定義的程式塊執行時才存在;static物件在使用之前分配,在程式結束時銷燬。
堆記憶體: 
在程式執行時分配。動態物件的生存週期由程式(使用者)來控制。

21、深拷貝是指源物件與拷貝物件互相獨立,其中任何一個物件的改動都不會對另外一個物件造成影響。淺拷貝是指源物件與拷貝物件共用一份實體,僅僅是引用的變數不同(名稱不同)。對其中任何一個物件的改動都會影響另外一個物件。

22、const int* const a = &b;等價於 int const* const a = &b;

23、傳引用、傳指標最終傳的都是地址。

24、回撥函式就是一個通過函式指標呼叫的函式。

25、使用volatile關鍵字宣告的變數,系統總是重新從它所在的記憶體中讀取資料,即使它前面的指令剛剛從該處讀取過資料,而且讀取的資料立刻被儲存;相反,若沒有使用volatile,編譯器可能會做優化處理,可能暫時使用暫存器中的值,而如果該變數由別的程式更新了的話,將會出現不一致的現象!

26、面向物件的五個基本原則: 

單一職責原則(Single-Resposibility Principle):一個類,最好只做一件事,只有一個引起它的變化。單一職責原則可以看做是低耦合、高內聚在面向物件原則上的引申,將職責定義為引起變化的原因,以提高內聚性來減少引起變化的原因。
開放封閉原則(Open-Closed principle):軟體實體應該是可擴充套件的,而不可修改的。也就是,對擴充套件開放,對修改封閉的。
Liskov替換原則(Liskov-Substituion Principle):子類必須能夠替換其基類。這一思想體現為對繼承機制的約束規範,只有子類能夠替換基類時,才能保證系統在執行期內識別子類,這是保證繼承複用的基礎。
依賴倒置原則(Dependecy-Inversion Principle):依賴於抽象。具體而言就是高層模組不依賴於底層模組,二者都同依賴於抽象;抽象不依賴於具體,具體依賴於抽象。
介面隔離原則(Interface-Segregation Principle):使用多個小的專門的介面,而不要使用一個大的總介面

27、建構函式不能宣告為虛擬函式的原因是: 

1 )構造一個物件的時候,必須知道物件的實際型別,而虛擬函式行為是在執行期間確定實際型別的。而在構造一個物件時,由於物件還未構造成功。編譯器無法知道物件 的實際型別,是該類本身,還是該類的一個派生類,或是更深層次的派生類。無法確定。
2) 虛擬函式的執行依賴於虛擬函式表。而虛擬函式表在建構函式中進行初始化工作,即初始化vptr,讓他指向正確的虛擬函式表。而在構造物件期間,虛擬函式表還沒有被初 始化,將無法進行。虛擬函式的意思就是開啟動態繫結,程式會根據物件的動態型別來選擇要呼叫的方法。然而在建構函式執行的時候,這個物件的動態型別還不完整,沒有辦法確定它到底是什麼型別,故建構函式不能動態繫結。(動態繫結是根據物件的動態型別而不是函式名,在呼叫建構函式之前,這個物件根本就不存在,它怎麼動態繫結?)
編譯器在呼叫基類的建構函式的時候並不知道你要構造的是一個基類的物件還是一個派生類的物件。

28、非常量引用定義時,其初始化的物件必須為左值!(int &a = 3;非法)

29、大小端:小端中低地址低位元組,高地址高位元組;大端相反。80X86是小端模式。

30、 派生類的建構函式執行過程,解構函式的執行過程一般與建構函式執行的過程相反。

       1)、建立派生類的物件,基類的建構函式函式優先被呼叫(也優先於派生類裡的成員類);
  2)、如果類裡面有成員類,成員類的建構函式優先被呼叫;
  3)、基類建構函式如果有多個基類則建構函式的呼叫順序是某類在類派生表中出現的順序而不是它們在成員初始化表中的順序;
  4)、成員類物件建構函式如果有多個成員類物件則建構函式的呼叫順序是物件在類中被宣告的順序而不是它們出現在成員初始化表中的順序;
  5)、派生類建構函式
  作為一般規則派生類建構函式應該不能直接向一個基類資料成員賦值而是把值傳遞給適當的基類建構函式否則兩個類的實現變成緊耦合的(tightly coupled)將更加難於正確地修改或擴充套件基類的實現。(基類設計者的責任是提供一組適當的基類建構函式)。

31、 函式的退出通常有兩種情況,正常退出和異常退出,無論是什麼情況下的退出,區域性物件都會被銷燬。但通過new開闢的記憶體空間,在對應的delete之前發生了異常是不會釋放該空間的。因此推薦使用智慧指標,總是能正確的釋放記憶體。

32、符號不明確:可能是因為定義的符號與名稱空間中的某些符號相同,換一個符號可能就行。

33、型別不完整,可能是由於未包含相關的標頭檔案。