1. 程式人生 > >c++基礎知識(C++Primer4th第四版中文版)

c++基礎知識(C++Primer4th第四版中文版)

學習C++使用的兩種開發工具
1、codeblocks
如果你希望開發工具的容量很小,建議使用這個工具。系統較小但功能很強,非常適合教學用。
2、VS2015(自帶Update2)

安裝檔案容量比較大,如果你希望學習和實際用的開發工具一致,建議使用這個開發工具。

Win32控制檯應用程式、Win32專案、MFC應用程式的區別與聯絡 - CSDN部落格  http://blog.csdn.net/zhao1999qian/article/details/57084143

什麼是運算子?C++中算數運算子、關係運算符、邏輯運算子等常用運算子講解 - CSDN部落格  http://blog.csdn.net/kingvon_liwei/article/details/65936927

C++控制檯應用程式視窗暫停
只需要在main函式裡新增
第一種方式:system("pause");
第二種方式:getchar();
第三種方式:sleep();
第四種方式:cin.get();

【C++】第1章 在VS2015中用C++編寫控制檯應用程式 - rainmj - 部落格園  https://www.cnblogs.com/rainmj/p/5578656.html
在VS2015中用C++編寫控制檯應用程式
1、新建專案
執行VS2015,在起始頁中選擇【新建專案】,在彈出的新建專案視窗中,選擇【其他語言】->【C++】->【Win32】->【Win32控制檯應用程式】
2、編寫程式碼
3、除錯執行
按<F5>鍵除錯執行。

程式碼格式
刪除最後一個大括號,然後重新鍵入,它就會自動重新調整程式碼的格式。
4、生成32位的exe還是64位的exe
除錯時有兩種生成方式,一種是生成32位的本機程式碼,另一種是生成64位的本機程式碼。

如果希望生成64位本機程式碼,只需要單擊x32右側的下拉框,選擇為x64即可:

讀書筆記:

1.2. 初窺輸入/輸出
C++ 並沒有直接定義進行輸入或輸出(IO)的任何語句,這種功能是由標準庫提供的。IO 庫提供了大量的設施。處理格式化輸入和輸出的 iostream 庫。
iostream 庫的基礎是兩種命名為 istream 和 ostream 的型別,分別表示輸入流和輸出流。流是指要從某種 IO 裝置上讀入或寫出的字元序列。術語“流”試圖說明字元是隨著時間順序生成或消耗的。
1.2.1. 標準輸入與輸出物件
標準庫定義了 4 個 IO 物件。cin、cout、cerr、clog。
一般情況下,系統將這些物件與執行程式的視窗聯絡起來。這樣,當我們從cin 讀入時,資料從執行程式的視窗讀入。
執行程式時,大部分作業系統都提供了重定向輸入或輸出流的方法。利用重定向可以將這些流與所選擇的檔案聯絡起來。
endl 是一個特殊值,稱為操縱符,將它寫入輸出流時,具有輸出換行的效果,並重新整理與裝置相關聯的 緩衝區。通過重新整理緩衝區,使用者可立即看到寫入到流中的輸出。

輸入操作符(>> 操作符)行為與輸出操作符相似。它接受一個 istream 物件作為其左運算元,接受一個物件作為其右運算元,它從 istream 運算元讀取資料並儲存到右運算元中。像輸出操作符一樣,輸入操作符返回其左運算元作為結果。

Sales_item.h
C++中我們通過定義類來定義自己的資料結構。類機制是 C++ 中最重要的特徵之一。
事實上, C++ 設計的主要焦點就是使所定義的類型別的行為可以像內建型別一樣自然。我們前面已看到的像 istream 和 ostream 這樣的庫型別,都是定義為類的,也就是說,它們嚴格說來不是語言的一部分。

我們假定類命名為 Sales_item 且類定義在命名為Sales_item.h 的標頭檔案中。

1.5.1.Sales_item 類
Sales_item 類的目的是儲存 ISBN 並儲存該書的銷售冊數、銷售收入和平均售價。我們不關心如何儲存或計算這些資料。使用類時我們不需要知道這個類是怎樣實現的,相反,我們需要知道的是該類提供什麼操作。正如我們所看到的,使用像 IO 一樣的庫工具,必須包含相關的標頭檔案。類似地,對於自定義的類,必須使得編譯器可以訪問和類相關的定義。這幾乎可以採用同樣的方式。一般來說,我們將類定義放入一個檔案中,要使用該類的任何程式都必須包含這個檔案。
依據慣例,類型別儲存在一個檔案中,其檔名如同程式的原始檔名一樣,由檔名和檔案字尾兩部分組成。通常檔名和定義在標頭檔案中的類名是一樣的。通常字尾是.h,但也有一些程式設計師用.H、.hpp 或.hxx。編譯器通常並不挑剔標頭檔案名,但 IDE 有時會。假設我們的類定義在名為 Sale_item.h 的檔案中。
Sales_item 物件上的操作
每個類定義一種型別,型別名與類名相同。因此,我們的 Sales_item 類定義了一種命名為 Sales_item 的型別。像使用內建型別一樣,可以定義類型別的變數。當寫下Sales_item item; 就表示 item 是型別 Sales_item 的一個物件。通常將“型別 Sales_item的一個物件”簡稱為“一個 Sales_item 物件”,或者更簡單地簡稱為“一個Sales_item”。除了可以定義 Sales_item 型別的變數,我們還可以執行 Sales_item 物件的以下操作:
• 使用加法操作符, + ,將兩個 Sales_item 相加。
• 使用輸入操作符, << ,來讀取一個 Sales_item 物件。
• 使用輸出操作符, >> ,來輸出一個 Sales_item 物件
• 使用賦值操作符, = ,將一個 Sales_item 物件賦值給另一個 Sales_item物件。
呼叫 same_isbn 函式確定兩個 Sales_item 是否指同一本書
呼叫命名為 item1 的 Sales_item 物件的成員函式。成員函式是由類定義的函式,有時稱為類方法。
成員函式只定義一次,但被視為每個物件的成員。我們將這些操作稱為成員函式,是因為它們(通常)在特定物件上操作。在這個意義上,它們是物件的成員,即使同一型別的所有物件共享同一個定義也是如此。

當呼叫成員函式時,(通常)指定函式要操作的物件。語法是使用點操作符(.):(p44)

一些程式設計語言,特別是Smalltalk 和 Python,在執行時才檢查語句中物件的型別。相反,C++ 是靜態
型別(statically typed)語言,在編譯時執行型別檢查。結果是程式中使用某
個名字之前,必須先告知編譯器該名字的型別。


布林字面值和字元字面值(p63):
單詞 true 和 false 是布林型的字面值:bool test = false;
可列印的字元型字面值通常用一對單引號來定義:'a' '2' ',' ' ' // blank
這些字面值都是 char 型別的。在字元字面值前加 L 就能夠得到 wchar_t型別的寬字元字面值。如:L'a'
非列印字元的轉義序列:
有些字元是不可列印的。不可列印字元實際上是不可顯示的字元,比如退格
或者控制符。還有一些在語言中有特殊意義的字元,例如單引號、雙引號和反斜
線符號。不可列印字元和特殊字元都用轉義字元書寫。轉義字元都以反斜線符號
開始,C++ 語言中定義瞭如下轉義字元:
換行符 \n 水平製表符 \t
縱向製表符 \v 退格符 \b
回車符 \r 進紙符 \f
報警(響鈴)符 \a 反斜線 \\
疑問號 \? 單引號 \'
雙引號 \
\ooo
這裡 ooo 表示三個八進位制數字,這三個數字表示字元的數字值。下面的例
子是用 ASCII 碼字符集表示字面值常量:
\7 (bell) \12 (newline) \40 (blank)
\0 (null) \062 ('2') \115 ('M')
字元’\0’通常表示“空字元(null character)”,我們將會看到它有著
非常特殊的意義。
同樣也可以用十六進位制轉義字元來定義字元:\xddd
它由一個反斜線符、一個 x 和一個或者多個十六進位制數字組成。

字串字面值:
之前見過的所有字面值都有基本內建型別。 還有一種字面值(字串字面值)
更加複雜。字串字面值是一串常量字元,這種型別將在第 4.3 節詳細說明。
字串字面值常量用雙引號括起來的零個或者多個字元表示。不可列印字元
表示成相應的轉義字元。
"Hello World!"
C++ 關鍵字:
C++ 操作符替代名:
變數命名習慣:

變數命名有許多被普遍接受的習慣,遵循這些習慣可以提高程式的可讀性。
• 變數名一般用小寫字母。例如,通常會寫成 index,而不寫成 Index 或INDEX。
• 識別符號應使用能幫助記憶的名字,也就是說,能夠提示其在程式中的用法的名字,如 on_loan 或 salary。
• 包含多個詞的識別符號書寫為在每個詞之間新增一個下劃線, 或者每個內嵌的詞的第一個字母都大寫。例如通常會寫成 student_loan 或studentLoan,而不寫成 studentloan。
變數初始化(p75,78):
初始化:變數定義指定了變數的型別和識別符號,也可以為物件提供初始值。定義時指定了初始值的物件被稱為是已初始化的。C++ 支援兩種初始化變數的形式: 複製初始化和直接初始化。複製初始化語法用等號(=),直接初始化則是把初始化
式放在括號中:
int ival(1024); // direct-initialization
int ival = 1024; // copy-initialization
這兩種情形中,ival 都被初始化為 1024。

使用多個初始化式
初始化內建型別的物件只有一種方法:提供一個值,並且把這個值複製到新定義的物件中。對內建型別來說,複製初始化和直接初始化幾乎沒有差別。
對類型別的物件來說,有些初始化僅能用直接初始化完成。要想理解其中緣由,需要初步瞭解類是如何控制初始化的。
警告:未初始化的變數引起執行問題
內建型別變數的初始化(p77)
類型別變數的初始化
變數宣告和定義(p79)
宣告和定義
正如將在第 2.9 節所看到的那樣,C++ 程式通常由許多檔案組成。為了讓多個檔案訪問相同的變數,C++ 區分了宣告和定義。
變數的定義用於為變數分配儲存空間,還可以為變數指定初始值。在一個程式中,變數有且僅有一個定義。
宣告用於向程式表明變數的型別和名字。定義也是宣告:當定義變數時我們聲明瞭它的型別和名字。可以通過使用 extern 關鍵字宣告變數名而不定義它。
不定義變數的宣告包括物件名、物件型別和物件型別前的關鍵字 extern:
extern int i; // declares but does not define i
int i; // declares and defines i
extern 宣告不是定義,也不分配儲存空間。事實上,它只是說明變數定義在程式的其他地方。程式中變數可以宣告多次,但只能定義一次。
名字的作用域:
第七章將詳細討論區域性作用域和全域性作用域,第六章將討論語句作用域。C++ 還有另外兩種不同級別的作用域:類作用域(第十二章將介紹)和名稱空間作用域(第 17.2 節將介紹)。

2.5. 引用(&用法p88)
引用就是物件的另一個名字。 任何對 id 的操作都會轉變為對object 的操作。在實際程式中, 引們將在第 7.2.2 節 再詳細介紹引用引數。在這並舉例說明引用的用法。

引用是一種複合型別,通過在變數名前新增“&”符號來定義。複合型別是指用其他型別定義的型別。在引用的情況下,每一種引用型別都“關聯到”某一其他型別。不能定義引用型別的引用,但可以定義任何其他型別的引用。

引用必須用與該引用同類型的物件初始化:

int ival = 1024;
int &refVal = ival; // ok: refVal refers to ival
int &refVal2; // error: a reference must be initialized
int &refVal3 = 10; // error: initializer must be an object
refVal += 2;
將 refVal 指向的物件 ival 加 2。

const 引用(p90)
const 引用是指向 const 物件的引用:
const int ival = 1024;
const int &refVal = ival;
可以讀取但不能修改 refVal ,因此,任何對 refVal 的賦值都是不合法的。
double dval = 3.14;
const int &ri = dval;
編譯器會把這些程式碼轉換成如以下形式的編碼:
int temp = dval; // create temporary int from the double
const int &ri = temp; // bind ri to that temporary
ri的值是3。
如果 ri 不是 const,那麼可以給 ri 賦一新值。這樣做不會修改 dval,而是修改了 temp。期望對 ri 的賦值會修改 dval 的程式設計師會發現 dval 並沒有被修改。僅允許 const 引用繫結到需要臨時使用的值完全避免了這個問題,
因為 const 引用是隻讀的。
非 const 引用只能繫結到與該引用同類型的物件。

const 引用則可以繫結到不同但相關的型別的物件或繫結到右值。

int i, &ri = i;
i = 5; ri =10;

std::cout << i << " " << ri << std::endl;

\\i、ri的值都為10。
對ri賦值10,就是對i賦值。

2.6. typedef 名字91
typedef 可以用來定義型別的同義詞:
typedef double wages; // wages is a synonym for double
typedef 通常被用於以下三種目的:
• 為了隱藏特定型別的實現,強調使用型別的目的。
• 簡化複雜的型別定義,使其更易理解。
• 允許一種型別用於多個目的,同時使得每次使用該型別的目的明確。

2.7. 列舉
定義和初始化列舉
列舉的定義包括關鍵字 enum,其後是一個可選的列舉型別名,和一個用花括號括起來、用逗號分開的列舉成員列表。
// input is 0, output is 1, and append is 2
enum open_modes {input, output, append};
預設地,第一個列舉成員賦值為 0,後面的每個列舉成員賦的值比前面的大1。

列舉成員值可以是不唯一的。每個 enum 都定義了一種新的型別。和其他型別一樣,可以定義和初始化Points 型別的物件,也可以以不同的方式使用這些物件。列舉型別的物件的初始化或賦值,只能通過其列舉成員或同一列舉型別的其他物件來進行。

2.8. 類型別(p93)
C++ 中,通過定義類來自定義資料型別。類定義了該型別的物件包含的資料和該型別的物件可以執行的操作。標準庫型別 string、istream 和 ostream 都定義成類。

類定義以關鍵字 class 開始,其後是該類的名字識別符號。類體位於花括號裡面。
花括號後面必須要跟一個分號。!!!!!!!!!!!!!
類體可以為空。類體定義了組成該型別的資料和操作。這些操作和資料是類的一部分,也稱為類的成員。操作稱為成員函式(第 1.5.2 節),而資料則稱為資料成員。
類也可以包含 0 個到多個 private 或 public 訪問標號。訪問標號控制類的成員在類外部是否可訪問。使用該類的程式碼可能只能訪問 public 成員。
定義了類,也就定義了一種新的型別。類名就是該型別的名字。而且程式也可以定義該型別的變數。
每一個類都定義了它自己的作用域(第 2.3.6 節)。也就是說,資料和操作的名字在類的內部必須唯一,但可以重用定義在類外的名字。
class Sales_item {
public:
// operations on Sales_item objects will go here
private:
std::string isbn;
unsigned units_sold;
double revenue;
};//特別注意:花括號後面必須要跟一個分號!!!

定義類的資料成員和定義普通變數有些相似。但區別重大!!
定義變數和定義資料成員存在非常重要的區別:一般不能把類成員的初始化作為其定義的一部分。當定義資料成員時,只能指定該資料成員的名字和型別。類不是在類定義裡定義資料成員時初始化資料成員,而是通過稱為建構函式(第2.3.3 節)的特殊成員函式控制初始化。我們將在第 7.7.3 節定義 Sales_item的建構函式。
訪問標號public、private:
訪問標號負責控制使用該類的程式碼是否可以使用給定的成員。類的成員函式可以使用類的任何成員,而不管其訪問級別。訪問標號 public、private 可以多次出現在類定義中。給定的訪問標號應用到下一個訪問標號出現時為止。
類中 public 部分定義的成員在程式的任何部分都可以訪問。一般把操作放在 public 部分,這樣程式的任何程式碼都可以執行這些操作。
不是類的組成部分的程式碼不能訪問 private 成員。

使用 struct 關鍵字(p96)
C++ 支援另一個關鍵字 struct,它也可以定義類型別。struct 關鍵字是從C 語言中繼承過來的。
如果使用 class 關鍵字來定義類,那麼定義在第一個訪問標號前的任何成員都隱式指定為 private;如果使用 struct 關鍵字,那麼這些成員都是public。使用 class 還是 struct 關鍵字來定義類,僅僅影響預設的初始訪問級別。
2.9. 編寫自己的標頭檔案
一般類定義都會放入標頭檔案。

標頭檔案為相關宣告提供了一個集中存放的位置。標頭檔案一般包含類的定義、extern 變數的宣告和函式的宣告。函式的宣告將在第 7.4 節介紹。使用或定義這些實體的檔案要包含適當的標頭檔案。
標頭檔案的正確使用能夠帶來兩個好處:保證所有檔案使用給定實體的同一宣告;當宣告需要修改時,只有標頭檔案需要更新。
設計標頭檔案還需要注意以下幾點:標頭檔案中的宣告在邏輯上應該是統一的。
編譯標頭檔案需要一定的時間。如果標頭檔案太大,程式設計師可能不願意承受包含該標頭檔案所帶來的編譯時代價。
為了減少處理標頭檔案的編譯時間,有些 C++的實現支援預編譯標頭檔案。欲進一步瞭解詳細情況,請參考你的 C++ 實現的手冊。
標頭檔案用於宣告而不是用於定義
當設計標頭檔案時, 記住定義和宣告的區別是很重要的。 定義只可以出現一次,而宣告則可以出現多次(第 2.3.5 節)。下列語句是一些定義,所以不應該放在標頭檔案裡:
extern int ival = 10; // initializer, so it's a definition
double fica_rate; // no extern, so it's a definition
雖然 ival 宣告為 extern,但是它有初始化式,代表這條語句是一個定義。
類似地,fica_rate 的宣告雖然沒有初始化式,但也是一個定義,因為沒有關鍵字 extern。同一個程式中有兩個以上檔案含有上述任一個定義都會導致多重定義連結錯誤。
因為標頭檔案包含在多個原始檔中,所以不應該含有變數或函式的定義。
對於標頭檔案不應該含有定義這一規則,有三個例外。
標頭檔案可以定義類、值在編譯時就已知道的 const 物件和 inline 函式(第 7.6 節介紹 inline 函式)。這些實體可在多個原始檔中定義,只要每個原始檔中的定義是相同的。
在標頭檔案中定義這些實體,是因為編譯器需要它們的定義(不只是宣告)來產生程式碼。例如:為了產生能定義或使用類的物件的程式碼,編譯器需要知道組成該型別的資料成員。同樣還需要知道能夠在這些物件上執行的操作。類定義提供所需要的資訊。在標頭檔案中定義 const 物件則需要更多的解釋。
一些 const 物件定義在標頭檔案中
回想一下,const 變數(第 2.4 節)預設時是定義該變數的檔案的區域性變數。正如我們現在所看到的,這樣設定預設情況的原因在於允許 const 變數定義在標頭檔案中。
在 C++ 中,有些地方需要放置常量表達式(第 2.7 節)。例如,列舉成員的初始化式必須是常量表達式。在以後的章節中將會看到其他需要常量表達式的例子。
一般來說,常量表達式是編譯器在編譯時就能夠計算出結果的表示式。當const 整型變數通過常量表達式自我初始化時,這個 const 整型變數就可能是常量表達式。而 const 變數要成為常量表達式,初始化式必須為編譯器可見。
為了能夠讓多個檔案使用相同的常量值, const 變數和它的初始化式必須是每個檔案都可見的。而要使初始化式可見,一般都把這樣的 const 變數定義在標頭檔案中。那樣的話,無論該 const 變數何時使用,編譯器都能夠看見其初始化式。(p101)
但是,C++ 中的任何變數都只能定義一次(第 2.3.5 節)。定義會分配儲存空間,而所有對該變數的使用都關聯到同一儲存空間。因為 const 物件預設為定義它的檔案的區域性變數,所以把它們的定義放在標頭檔案中是合法的。
這種行為有一個很重要的含義:當我們在標頭檔案中定義了 const 變數後,每個包含該標頭檔案的原始檔都有了自己的 const 變數,其名稱和值都一樣。
當該 const 變數是用常量表達式初始化時,可以保證所有的變數都有相同的值。但是在實踐中,大部分的編譯器在編譯時都會用相應的常量表達式替換這些 const 變數的任何使用。所以,在實踐中不會有任何儲存空間用於儲存用常量表達式初始化的 const 變數。
如果 const 變數不是用常量表達式初始化,那麼它就不應該在標頭檔案中定義。相反,和其他的變數一樣,該 const 變數應該在一個原始檔中定義並初始化。應在標頭檔案中為它新增 extern 宣告,以使其能被多個檔案共享。

前處理器(P103)
#include 設施是 C++ 前處理器的一部分。
#include 指示只接受一個引數:標頭檔案名。前處理器用指定的標頭檔案的內容替代每個 #include。

標頭檔案經常需要其他標頭檔案
標頭檔案經常 #include 其他標頭檔案。
設計標頭檔案時,應使其可以多次包含在同一原始檔中,這一點很重要。我們必須保證多次包含同一標頭檔案不會引起該標頭檔案定義的類和物件被多次定義。使得標頭檔案安全的通用做法,是使用前處理器定義標頭檔案保護符。標頭檔案保護符用於避免在已經見到標頭檔案的情況下重新處理該標頭檔案的內容。

為了避免名字衝突,前處理器變數經常用全大寫字母表示。
前處理器變數有兩種狀態:已定義或未定義。定義前處理器變數和檢測其狀態所用的前處理器指示不同。#define 指示接受一個名字並定義該名字為前處理器變數。#ifndef 指示檢測指定的前處理器變數是否未定義。如果前處理器變數未定義,那麼跟在其後的所有指示都被處理,直到出現 #endif。
#ifndef SALESITEM_H
#define SALESITEM_H
// Definition of Sales_itemclass and related functions goes here
#endif
使用自定義的標頭檔案
#include 指示接受以下兩種形式:
#include <standard_header>
#include "my_file.h"
如果標頭檔案名括在尖括號(< >)裡,那麼認為該標頭檔案是標準標頭檔案。編譯器將會在預定義的位置集查詢該標頭檔案, 這些預定義的位置可以通過設定查詢路徑環境變數或者通過命令列選項來修改。使用的查詢方法因編譯器的不同而差別迥異。建議你諮詢同事或者查閱編譯器使用者指南來獲得更多的資訊。如果標頭檔案名括在一對引號裡,那麼認為它是非系統標頭檔案,非系統標頭檔案的查詢通常開始於原始檔所在的路徑。


小結
型別是 C++ 程式設計的基礎。105
每種型別都定義了其儲存空間要求和可以在該型別的所有物件上執行的操作。C++ 提供了一組基本內建型別,如 int、char 等。這些型別與它們在機器硬體上的表示方式緊密相關。
型別可以為 const 或非 const;const 物件必須要初始化,且其值不能被修改。另外,我們還可以定義複合型別,如引用。引用為物件提供了另一個名字。複合型別是用其他型別定義的型別。
C++ 語言支援通過定義類來自定義型別。標準庫使用類設施來提供一組高階的抽象概念,如 IO 和 string 型別。


C++ 是一種靜態型別語言:變數和函式在使用前必須先宣告。變數可以宣告多次但是隻能定義一次。定義變數時就進行初始化幾乎總是個好主意。

術語:

run time(執行時)指程式正執行的那段時間。
void type(空型別)
用於特殊目的的沒有操作也沒有值的型別。不可能定義一個 void 型別的變數。最經常用作不返回結果的函式的返回型別。
word(字)

機器上的自然的整型計算單元。通常一個字足以容納一個地址。一般在 32位的機器上,機器字長為 4 個位元組。

術語(C++Primer4th第四版中文版p53頁)

操作符、運算元:"."、"<<"、">>"等操作符,操作符左右為運算元。

argument(實參):傳遞給被呼叫函式的值
class:用於自定義資料結構的 C++ 機制。如 istream 和 ostream,都是類。
header(標頭檔案):使得類或其他名字的定義在多個程式中可用的一種機制。程式中通過#include 指示包含標頭檔案。
curly brace(花括號)
main function(主函式):執行 C++ 程式時,作業系統呼叫的函式。每一個程式有且僅有一個主函式 main。
manipulator(操縱符):在讀或寫時“操縱”流本身的物件,如 std::endl。A.3.1 節詳細講述操縱符。
member function(成員函式):類定義的操作。成員函式通常在特定的物件上進行操作。
method(方法):成員函式的同義詞。
namespace(名稱空間):將庫所定義的名字放至單獨一個地方的機制。名稱空間有助於避免無意的命名衝突。C++ 標準庫所定義的名字在名稱空間 std 中。
ostream(輸出流):提供面向流的輸出的庫型別。
parameter list(形參表):函式定義的組成部分。指明可以用什麼引數來呼叫函式,可能為空。
preprocessor directive(預處理指示):C++ 前處理器的指示。#include 是一個前處理器指示。前處理器指示必須出現在單獨的行中。第 2.9.2 節將對前處理器作詳細的介紹。
standard input(標準輸入):和程式執行視窗相關聯的輸入流,通常這種關聯由作業系統設定。
standard library(標準庫):每個 C++ 編譯器必須支援的型別和函式的集合。標準庫提供了強大的功能,包括支援 IO 的型別。C++ 程式設計師談到的“標準庫”,是指整個標準庫,當提到某個標準庫型別時也指標準庫中某個特定的部分。例如,程式設計師提到的“iostream 庫”, 專指標準庫中由 iostream 類定義的那部分。
standard output(標準輸出):和程式執行視窗相關聯的輸出流,通常這種關聯由作業系統設定。
statement(語句):C++ 程式中最小的獨立單元,類似於自然語言中的句子。C++ 中的語句一般以分號結束。
std:標準庫名稱空間的名字,std::cout 表明正在使用定義在 std 名稱空間中的名字 cout。
string literal(字串字面值):以雙引號括起來的字元序列。
uninitialized variable(未初始化變數):沒有指定初始值的變數。類型別沒有未初始化變數。沒有指定初始值的類型別變數由類定義初始化。在使用變數值之前必須給未初始化的變數賦值。未初始化變數是造成 bug 的主要原因之一。未實始化的變數賦值,可能由系統分配一個隨機值,導致系統發生錯誤
variable(變數):有名字的物件。
while statement(while 語句):一種迭代控制語句, 只要指定的條件為真就執行 while環體執行 0 次還是多次,依賴於條件的真值
() operator[()操作符]:呼叫操作符。跟在函式名後且成對出現的圓括號。該操作符導致函式被呼叫,給函式的實參可在括號裡傳遞。
++ operator(++操作符):自增操作符。將運算元加 1,++i 等價於 i = i + 1。
+= operator(+= 操作符):複合賦值操作符,將右運算元和左運算元相加,並將結果儲存到左運算元中;a += b 等價於 a = a + b。
. operator(. 操作符):點操作符。接受兩個運算元:左運算元是一個物件,而右邊是該物件的一個成員的名字。這個操作符從指定物件中取得成員。
:: operator(:: 操作符):作用域操作符。在 第二章中,我們將看到更多關於作用域的介紹。在其他的使用過程中, :: 操作符用於在名稱空間中訪問名字。例如, std::cout表示使用名稱空間 std 中的名字 cout。
= operator(= 操作符):表示把右運算元的值賦給左運算元表示的物件。
<< operator(<< 操作符):
輸出操作符。把右運算元寫到左運算元指定的輸出流: cout << "hi" 把 hi寫入到標準輸出流。輸出操作可以連結在一起使用:cout << "hi << "bye"輸出 hibye。

>> operator(>> 操作符):輸入操作符。從左運算元指定的輸入流讀入資料到右運算元:cin >> i 把標準輸入流中的下一個值讀入到 i 中。輸入操作能夠連結在一起使用:cin >> i >> j 先讀入 i 然後再讀入 j。

一些程式設計語言,特別是Smalltalk 和 Python,在執行時才檢查語句中物件的型別。相反,C++ 是靜態
型別(statically typed)語言,在編譯時執行型別檢查。結果是程式中使用某
個名字之前,必須先告知編譯器該名字的型別。

--------------------------------------------------------------------------

第三章 標準庫型別

除第二章介紹的基本資料型別外,C++ 還定義了一個內容豐富的抽象資料型別標準庫。
其中最重要的標準庫型別是 string 和 vector,它們分別定義了大小可變的字串和集合。string 和 vector 往往將迭代器用作配套型別(companion type),用於訪問 string 中的字元,或者 vector 中的元素。這些標準庫型別是語言組成部分中更基本的那些資料型別(如陣列和指標)的抽象。
另一種標準庫型別 bitset,提供了一種抽象方法來操作位的集合。與整型值上的內建位操作符相比,bitset 類型別提供了一種更方便的處理位的方式。
本章將介紹標準庫中的 vector、string 和 bitset 型別。
第四章將討論陣列和指標,第五章將講述內建位操作符
第二章所涉及的型別都是低層資料型別:這些型別表示數值或字元的抽象,並根據其具體機器表示來定義。
3.1. 名稱空間的 using 宣告
使用 using 宣告可以在不需要加字首 namespace_name:: 的情況下訪問名稱空間中的名字。using 宣告的形式如下:
using namespace::name;
using std::cin;
using std::string;
沒有 using 宣告,而直接使用名稱空間中名字的未限定版本是錯誤的,儘管有些編譯器也許無法檢測出這種錯誤。
一個 using 宣告一次只能作用於一個名稱空間成員。using 宣告可用來明確指定在程式中用到的名稱空間中的名字,如果希望使用 std(或其他的名稱空間)中的幾個名字,則必須為要用到的每個名字都提供一個 using 宣告。

有一種情況下,必須總是使用完全限定的標準庫名字:在標頭檔案中。理由是標頭檔案的內容會被前處理器複製到程式中。用 #include 包含檔案時,相當於標頭檔案中的文字將成為我們編寫的檔案的一部分。如果在標頭檔案中放置 using 宣告,就相當於在包含該標頭檔案 using 的每個程式中都放置了同一 using,不論該程式是否需要 using 宣告。

通常,標頭檔案中應該只定義確實必要的東西。請養成這個好習慣。
3.2. 標準庫 string 型別
string 型別支援長度可變的字串。
與其他的標準庫型別一樣,使用者程式要使用 string 型別物件,必須包含相關標頭檔案。如果提供了合適的 using 宣告,那麼編寫出來的程式將會變得簡短些:
#include <string>
using std::string;
3.2.1. string 物件的定義和初始化(p115)
string 標準庫支援幾個建構函式(第 2.3.3 節)。建構函式是一個特殊成員函式,定義如何初始化該型別的物件。表 3.1 列出了幾個 string 型別常用的建構函式。當沒有明確指定物件初始化式時,系統將使用預設建構函式(第2.3.4 節)。
幾種初始化 string 物件的方式
string s1; 預設建構函式 s1 為空串
string s2(s1); 將 s2 初始化為 s1 的一個副本
string s3("value"); 將 s3 初始化為一個字串字面值副本
string s4(n, 'c'); 將 s4 初始化為字元 'c' 的 n 個副本
警告:標準庫 string 型別和字串字面值(p116)
因為歷史原因以及為了與 C 語言相容,字串字面值標準庫 string 型別不是同一種類型。這一點很容易引起混亂,程式設計時一定要注意區分字串字面值和 string 資料型別的使用,這很重要。
string s;
cout << "please input a string:";
cin >> s;
cout <<"s is:" << s  <<endl;
從標準輸入讀取 string 並將讀入的串儲存在 s 中。string 型別的輸入操作符:
• 讀取並忽略開頭所有的空白字元(如空格,換行符,製表符)。
• 讀取字元直至再次遇到空白字元,讀取終止。
如果給定和上一個程式同樣的輸入,則輸出的結果是"Hello World!"(注意到開頭和結尾的空格),則螢幕上將輸出"Hello",而不含任何空格。

讀入未知數目的 string 物件
下面的程式將從標準輸入讀取一組 string 物件,然後在標準
輸出上逐行輸出:
string s;
cout << "please input a string:";
        while (cin >> s)
cout <<"s is:" << s  <<endl;
如果輸入:a b c
輸出:
s is a
s is b
s is c
上例中,用輸入操作符來讀取 string 物件。該操作符返回所讀的 istream 物件,並在讀取結束後,作為 while 的判斷條件。如果輸入流是有效的,即還未到達檔案尾且未遇到無效輸入,則執行 while 迴圈體,並將讀取到的字串輸出到標準輸出。如果到達了檔案尾,則跳出 while 迴圈。

使用 getline 讀取整行文字(p118)

使用 getline 讀取整行文字
另外還有一個有用的 string IO 操作: getline。這個函式接受兩個引數:一個輸入流物件和一個 string 物件。
getline(cin, line)
由於 line 不含換行符, 若要逐行輸出需要自行新增。照常, 我們用 endl 來輸出一個換行符並重新整理輸出緩衝區。
由於 getline 函式返回時丟棄換行符,換行符將不會儲存在 string 物件中。

3.2.4. string 物件中字元的處理(p125)
我們經常要對 string 物件中的單個字元進行處理,例如,通常需要知道某個特殊字元是否為空白字元、字母或數字。表 3.3 列出了各種字元操作函式,適用於 string 物件的字元(或其他任何 char 值),這些函式都在 cctype 標頭檔案中定義。

建議:採用 C 標準庫標頭檔案的 C++ 版本
C++ 標準庫除了定義了一些選定於 C++ 的設施外,還包括 C 標準庫。C++ 中的標頭檔案 cctype 其實就是利用了 C 標準庫函式, 這些庫函式就定義在 C 標準庫的 ctype.h 標頭檔案中。
C 標準庫標頭檔案命名形式為 name 而 C++ 版本則命名為 cname ,少了字尾, .h 而在標頭檔案名前加了 c 表示這個標頭檔案源自 C 標準庫。因此,cctype 與 ctype.h 檔案的內容是一樣的,只是採用了更適合 C++程式的形式。特別地, cname 標頭檔案中定義的名字都定義在名稱空間 std 內,而 .h 版本中的名字卻不是這樣。
通常,C++ 程式中應採用 cname 這種標頭檔案的版本,而不採用 name.h 版本,這樣,標準庫中的名字在名稱空間 std 中保持一致。
使用 .h 版本會給程式設計師帶來負擔,因為他們必須記得哪些標準庫名字是從 C 繼承來的,而哪些是 C++ 所特有的。

3.3. 標準庫 vector 型別
vector 是同一種類型的物件的集合,每個物件都有一個對應的整數索引值。
和 string 物件一樣, 標準庫將負責管理與儲存元素相關的記憶體。我們把 vector
稱為容器,是因為它可以包含其他物件。一個容器中的所有物件都必須是同一種
型別的。我們將在第九章更詳細地介紹容器。
使用 vector 之前,必須包含相應的標頭檔案。本書給出的例子,都是假設已
作了相應的 using 宣告:
#include <vector>
using std::vector;
vector 是一個類模板(class template) 。使用模板可以編寫一個類定義或函式定義,而用於多個不同的資料型別。因此,我
們可以定義儲存 string 物件的 vector,或儲存 int 值的 vector,又或是儲存自定義的類型別物件(如Sales_items 物件)
的 vector。將在第十六章介紹如何定義程式設計師自己的類模板。
宣告從類模板產生的某種型別的物件,需要提供附加資訊,資訊的種類取決於模板。以 vector 為例,必須說明 vector 儲存何
種物件的型別,通過將型別放在型別放在類模板名稱後面的尖括號中來指定型別:
vector<int> ivec; // ivec holds objects of type int
vector<Sales_item> Sales_vec; // holds Sales_items
和其他變數定義一樣,定義 vector 物件要指定型別和一個變數的列表。上面的第一個定義,型別是 vector<int>,該型別即是
含有若干 int 型別物件的vector,變數名為 ivec。第二個定義的變數名是 Sales_vec,它所儲存的元素是 Sales_item 型別的物件。
vector 不是一種資料型別,而只是一個類模板,可用來定義任意多種資料型別。vector 型別的每一種都指定了其儲存元素的
型別。因此,vector<int> 和 vector<string> 都是資料型別。
3.3.1. vector 物件的定義和初始化
vector 類定義了好幾種建構函式(2.3.3 節),用來定義和初始化 vector物件。表 3.4 列出了這些建構函式。129
表 3.4. 初始化 vector
vector<T> v1; vector 儲存型別為 T 物件。
預設建構函式 v1 為空。
vector<T> v2(v1); v2 是 v1 的一個副本。
vector<T> v3(n, i); v3 包含 n 個值為 i 的元素。
vector<T> v4(n); v4 含有值初始化的元素的 n 個副本
值初始化
如果沒有指定元素的初始化式,那麼標準庫將自行提供一個元素初始值進行值初始化(value initializationd) 。這個由庫生成的初始值將用來初始化容器中的每個元素,具體值為何,取決於儲存在 vector 中元素的資料型別。
如果 vector 儲存內建型別(如 int 型別)的元素,那麼標準庫將用 0 值建立元素初始化式:
如果 vector 儲存的是含有建構函式的類型別(如 string)的元素,標準庫將用該型別的預設建構函式建立元素初始化式:
第十二章將介紹一些有自定義建構函式但沒有預設建構函式的類,在初始化這種型別的 vector 物件時,程式設計師就不能僅提供元素個數,還需要提供元素初始值。
還有第三種可能性:元素型別可能是沒有定義任何建構函式的類型別。這種情況下,標準庫仍產生一個帶初始值的物件,這個物件的每個成員進行了值初始化。
3.3.2. vector 物件的操作
vector 標準庫提供了許多類似於 string 物件的操作,表 3.5 列出了幾種
最重要的 vector 操作。
表 3.5. vector 操作
v.empty() 如果 v 為空,則返回 true,否則返回 false。
v.size() 返回 v 中元素的個數。
v.empty() 如果 v 為空,則返回 true,否則返回 false。
v.push_back(t) 在 v 的末尾增加一個值為 t 的元素。
v[n] 返回 v 中位置為 n 的元素。
v1 = v2 把 v1 的元素替換為 v2 中元素的副本。
v1 == v2 如果 v1 與 v2 相等,則返回 true。
!=, <, <=,>, and >=保持這些操作符慣有的含義。
vector 物件的 size
empty 和 size 操作類似於 string 的相關操作(3.2.3 節)。成員函式
size 返回相應 vector 類定義的 size_type 的值。
使用 size_type 型別時,必須指出該型別是在哪裡定義的。
vector 型別總是包括總是包括 vector 的元素型別:
vector<int>::size_type // ok
vector::size_type // error
vector 的下標操作
關鍵概念:安全的泛型程式設計
習慣於 C 或 Java 程式設計的 C++ 程式設計師可能會覺得難以理解,for 迴圈的判斷條件用 != 而不是用 < 來測試 vector 下標值是否越界。C 程式設計師難以理解的還有, 上例中沒有在 for 迴圈之前就呼叫 size 成員函式並儲存其返回的值,而是在 for 語句頭中呼叫 size 成員函式。
C++ 程式設計師習慣於優先選用 != 而不是 < 來編寫迴圈判斷條件。在上例中,選用或不用某種操作符並沒有特別的取捨理由。學習完本書第二部分的泛型程式設計後,你將會明白這種習慣的合理性。
呼叫 size 成員函式而不儲存它返回的值,在這個例子中同樣不是必需的,但這反映了一種良好的程式設計習慣。在 C++ 中,有些資料結構(如vector)可以動態增長。上例中迴圈僅需要讀取元素,而不需要增加新的元素。但是,迴圈可以容易地增加新元素,如果確實增加了新元素的話,那麼測試已儲存的 size 值作為迴圈的結束條件就會有問題,因為沒有將新加入的元素計算在內。所以我們傾向於在每次迴圈中測試 size的當前值,而不是在進入迴圈前,儲存 size 值的副本。
我們將在第七章學習到,C++ 中有些函式可以宣告為內聯(inline)函式。編譯器遇到行內函數時就會直接擴充套件相應程式碼,而不是進行實際的函式呼叫。像 size 這樣的小庫函式幾乎都定義為行內函數,所以每次迴圈過程中呼叫它的執行時代價是比較小的。
3.4. 迭代器簡介
除了使用下標來訪問 vector 物件的元素外,標準庫還提供了另一種訪問元素的方法:使用迭代器(iterator) 。迭代器是一種檢查容器內元素並遍歷元素的資料型別。
標準庫為每一種標準容器(包括 vector)定義了一種迭代器型別。迭代器型別提供了比下標操作更通用化的方法: 所有的標準庫容器都定義了相應的迭代器型別,而只有少數的容器支援下標操作。因為迭代器對所有的容器都適用,現代 C++ 程式更傾向於使用迭代器而不是下標操作訪問容器元素,即使對支援下標操作的 vector 型別也是這樣。

容器的 iterator 型別每種容器型別都定義了自己的迭代器型別,如 vector:

vector<int>::iterator iter;
術語:迭代器和迭代器型別
程式設計師首次遇到有關迭代器的術語時可能會困惑不解,原因之一是由於同一個術語 iterator 往往表示兩個不同的事物。一般意義上指的是迭代器的概念;而具體而言時指的則是由容器定義的具體的 iterator 型別,如 vector<int>。
重點要理解的是,有許多用作迭代器的型別,這些型別在概念上是相關的。若一種型別支援一組確定的操作(這些操作可用來遍歷容器內的元素,並訪問這些元素的值),我們就稱這種型別為迭代器。
各容器類都定義了自己的 iterator 型別,用於訪問容器內的元素。換句話說,每個容器都定義了一個名為 iterator 的型別,而這種型別支援(概念上的)迭代器的各種操作。
begin 和 end 操作:每種容器都定義了一對命名為 begin 和 end 的函式,用於返回迭代器。如果容器中有元素的話,由 begin 返回的迭代器指向第一個元素:
vector<int>::iterator iter = ivec.begin();
上述語句把 iter 初始化為由名為 vector 操作返回的值。假設 vector 不空,初始化後,iter 即指該元素為 ivec[0]。
由 end 操作返回的迭代器指向 vector 的“末端元素的下一個”。 “超出末端迭代器”(off-the-end iterator) 。表明它指向了一個不存在的元素。
如果 vector 為空,begin 返回的迭代器與 end 返回的迭代器相同。
由 end 操作返回的迭代器並不指向 vector 中任何實際的元素,相反,它只是起一個哨兵(sentinel) 的作用,表示我們已處理完 vector 中所有元素。

vector 迭代器的自增和解引用運算
迭代器型別定義了一些操作來獲取迭代器所指向的元素,並允許程式設計師將迭代器從一個元素移動到另一個元素。
迭代器型別可使用解引用操作符(dereference operator)(*)來訪問迭代器所指向的元素:*iter = 0;
解引用操作符返回迭代器當前所指向的元素假設 iter 指向 vector 物件 ivec 的第一元素,那麼 *iter 和 ivec[0] 就是指向同一個元素。上面這個語句的效果就是把這個元素的值賦為 0。
迭代器使用自增操作符(1.4.1 節)向前移動迭代器指向容器中下一個元素。
從邏輯上說,迭代器的自增操作和 int 型物件的自增操作類似。對 int 物件來說,操作結果就是把 int 型值“加 1”,而對迭代器物件則是把容器中的迭代器“向前移動一個位置”。因此,如果 iter 指向第一個元素,則 ++iter 指向第二個元素。
由於 end 操作返回的迭代器不指向任何元素,因此不能對它進行解引用或自增操作。

迭代器的其他操作
另一對可執行於迭代器的操作就是比較:用 == 或 != 操作符來比較兩個迭代器,如果兩個迭代器物件指向同一個元素,則它們相等,否則就不相等。

const_iterator
前面的程式用 vector::iterator 改變 vector 中的元素值。每種容器型別還定義了一種名為 const_iterator 的型別,該型別只能用於讀取容器內元素,但不能改變其值。


3.4.1. 迭代器的算術操作(p142)
除了一次移動迭代器的一個元素的增量操作符外,vector 迭代器(其他標準庫容器迭代器很少)也支援其他的算術操作。這些操作稱為迭代器算術操作(iterator arithmetic)

3.5. 標準庫 bitset

有些程式要處理二進位制位的有序集,每個位可能包含 0(關)1(開)值。
位是用來儲存一組項或條件的 yes/no 資訊(有時也稱標誌)的簡潔方法。標準庫提供的 bitset 類簡化了位集的處理。要使用 bitset 類就必須包含相關的標頭檔案。在本書提供的例子中,假設都使用 std::bitset 的 using 宣告:
#include <bitset>
using std::bitset;


-------------------------------------------------------------------------------------------------------

第四章 陣列和指標


C++ 語言提供了兩種類似於 vector 和迭代器型別的低階複合型別——陣列和指標。與 vector 型別相似,陣列也可以儲存某種型別的一組物件;而它們的區別在於,陣列的長度是固定的。陣列一經建立,就不允許新增新的元素。指標則可以像迭代器一樣用於遍歷和檢查陣列中的元素。
現代 C++ 程式應儘量使用 vector 和迭代器型別,而避免使用低階的陣列和指標。設計良好的程式只有在強調速度時才在類實現的內部使用陣列和指標。

陣列是 C++ 語言中類似於標準庫 vector 型別的內建資料結構。與 vector類似,陣列也是一種儲存單一資料型別物件的容器,其中每個物件都沒有單獨的名字,而是通過它在陣列中的位置對它進行訪問。
vector 型別相比,陣列的顯著缺陷在於:陣列的長度是固定的,而且程式設計師無法知道一個給定陣列的長度。陣列沒有獲取其容量大小的 size 操作,也不提供 push_back 操作在其中自動新增元素。如果需要更改陣列的長度,程式設計師只能建立一個更大的新陣列,然後把原陣列的所有元素複製到新陣列空間中去。
4.1. 陣列
4.1.1. 陣列的定義和初始化
字元陣列既可以用一組由花括號括起來、逗號隔開的字元字面值進行初始
化,也可以用一個字串字面值進行初始化。然而,要注意這兩種初始化形式並
不完全相同,字串字面值(第 2.2 節)包含一個額外的空字元(null)用於
結束字串。當使用字串字面值來初始化建立的新陣列時,將在新陣列中加入
空字元:
char ca1[] = {'C', '+', '+'}; // no null
char ca2[] = {'C', '+', '+', '\0'}; // explicit null
char ca3[] = "C++"; // null terminator added automatically


ca1 的維數是 3,而 ca2 和 ca3 的維數則是 4。使用一組字元字面值初始化字元陣列時,一定要記得新增結束字串的空字元。例如,下面的初始化將導致編譯時的錯誤:
不允許陣列直接複製和賦值
警告:陣列的長度是固定的
與 vector 型別不同,陣列不提供 push_back 或者其他的操作在陣列中新增新元素,陣列一經定義,就不允許再新增新元素。
如果必須在陣列中新增新元素,程式設計師就必須自己管理記憶體:要求系統重新分配一個新的記憶體空間用於存放更大的陣列,然後把原陣列的所有元素複製到新分配的記憶體空間中。我們將會在第 4.3.1 節學習如何去實現。
4.1.2. 陣列操作


4.2. 指標的引入(p163)
vector 的遍歷可使用下標或迭代器實現,同理,也可用下標或指標來遍歷陣列。指標是指向某種型別物件的複合資料型別,是用於陣列的迭代器:指向陣列中的一個元素。在指向陣列元素的指標上使用解引用操作符 *(dereference operator)和自增操作符 ++(increment operator),與在迭代器上的用法類似。對指標進行解引用操作,可獲得該指標所指物件的值。而當指標做自增操作時,則移動指標使其指向陣列中的下一個元素。在使用指標編寫程式之前,我們需進一步瞭解一下指標。
4.2.1. 什麼是指標
指標的概念很簡單:指標用於指向物件。與迭代器一樣,指標提供對其所指物件的間接訪問,只是指標結構更通用一些。與迭代器不同的是,指標用於指向單個物件,而迭代器只能用於訪問容器內的元素
具體來說,指標儲存的是另一個物件的地址:
string s("hello world");
string *sp = &s; // sp holds the address of s
第二條語句定義了一個指向 string 型別的指標 sp,並初始化 sp 使其指向 string 型別的物件 s。*sp 中的 * 操作符表明 sp 是一個指標變數,&s 中的 & 符號是取地址操作符,當此操作符用於一個物件上時,返回的是該物件的儲存地址。取地址操作符只能用於左值(第 2.3.1 節),因為只有當變數用作左值時,才能取其地址。同樣地,由於用於 vector 型別、string 型別或內建陣列的下標操作和解引用操作生成左值, 因此可對這兩種操作的結果做取地址操作,這樣即可獲取某一特定物件的儲存地址。
左值_百度百科  https://baike.baidu.com/item/%E5%B7%A6%E5%80%BC/2327412?fr=aladdin
C/C++中的左值  http://www.caole.net/diary/lvalue.html
建議:儘量避免使用指標和陣列
指標變數的定義
C++ 語言使用 * 符號把一個識別符號宣告為指標:double *dp; // dp can point to a double
理解指標宣告語句時,請從右向左閱讀。
string *pstring;
語句把 pstring 定義為一個指向 string 型別物件的指標變數。
另一種宣告指標的風格
在定義指標變數時,可用空格將符號 * 與其後的識別符號分隔開來。下面的
寫法是合法的:
string* ps; // legal but can be misleading該語句把 ps 定義為一個指向 string 型別物件的指標。

指標可能的取值
一個有效的指標必然是以下三種狀態之一:儲存一個特定物件的地址;指向某個物件後面的另一物件;或者是 0 值。若指標儲存 0 值,表明它不指向任何物件。未初始化的指標是無效的,直到給該指標賦值後,才可使用它。
對大多數的編譯器來說,如果使用未初始化的指標,會將指標中存放的不確定值視為地址,然後操縱該記憶體地址中存放的位內容。使用未初始化的指標相當於操縱這個不確定地址中儲存的基礎資料。因此,在對未初始化的指標進行解引用時,通常會導致程式崩潰。
C++ 語言無法檢測指標是否未被初始化,也無法區分有效地址和由指標分配到的儲存空間中存放的二進位制位形成的地址。建議程式設計師在使用之前初始化所有的變數,尤其是指標。
如果可能的話,除非所指向的物件已經存在,否則不要先定義指標,這樣可避免定義一個未初始化的指標。
如果必須分開定義指標和其所指向的物件,則將指標初始化為 0。因為編譯器可檢測出 0 值的指標,程式可判斷該指標並未指向一個物件。
指標初始化和賦值操作的約束
對指標進行初始化或賦值只能使用以下四種類型的值:
1. 0 值常量表達式(第 2.7 節), 例如, 在編譯時可獲得 0 值的整型 const物件或字面值常量 0。
2. 型別匹配的物件的地址。
3. 另一物件末的下一地址。
4. 同類型的另一個有效指標。
把 int 型變數賦給指標是非法的,儘管此 int 型變數的值可能為 0。但允許把數值 0 或在編譯時可獲得 0 值的 const 量賦給指標。
除了使用數值 0 或在編譯時值為 0 的 const 量外,還可以使用 C++ 語言從 C 語言中繼承下來的前處理器變數 NULL(第 2.9.2 節) , 該變數在 cstdlib標頭檔案中定義,其值為 0。如果在程式碼中使用了這個前處理器變數,則編譯時會自動被數值 0 替換。因此,把指標初始化為 NULL 等效於初始化為 0 值。正如其他的前處理器變數一樣(第 2.9.2 節),不可以使用 NULL 這個識別符號給自定義的變數命名。
前處理器變數不是在 std 名稱空間中定義的,因此其名字應為NULL,而非 std::NULL。


除了將在第 4.2.5 節和第 15.3 節介紹的兩種例外情況之外,指標只能初
始化或賦值為同類型的變數地址或另一指標:
double dval;
double *pd = &dval; // ok: initializer is address of a double
double *pd2 = pd; // ok: initializer is a pointer to double

指標用於間接訪問物件,並基於指標的型別提供可執行的操作,例如,int 型指標只能把其指向的物件當作 int 型資料來處理,如果該指標確實指向了其他型別(如 double 型別)的物件,則在指標上執行的任何操作都有可能出錯。
void* 指標:C++ 提供了一種特殊的指標型別 void*,它可以儲存任何型別物件的地址。
void* 表明該指標與一地址值相關,但不清楚儲存在此地址上的物件的型別。
void* 指標只支援幾種有限的操作:與另一個指標進行比較;向函式傳遞void* 指標或從函式返回 void* 指標;給另一個 void* 指標賦值。不允許使用void* 指標操縱它所指向的物件。我們將在第 5.12.4 節討論如何重新獲取儲存在 void* 指標中的地址。


4.2.3. 指標操作
指標提供間接操縱其所指物件的功能。與對迭代器進行解引用操作(第 3.4節)一樣,對指標進行解引用可訪問它所指的物件,* 操作符(解引用操作符)將獲取指標所指的物件:
string s("hello world");
string *sp = &s; // sp holds the address of s
cout <<*sp; // prints hello world














VS2015IDE中C++程式設計問題集:

1、VS2015 編譯程式時“無法查詢或開啟PDB檔案”解決方法:除錯-選項-符號-Microsoft符號伺服器打鉤,然後確定,就OK了。

2、C++中建立一個控制檯程式,執行提示:error C2976: “std::array”: 模板 引數太少。
追蹤到int main(array<System::String ^> ^args)這個語句位置,這個語法不是c++的,是c++.net的,也就是微軟的.net平臺針對c++語言的一種語法。實際上很少人用,大部分都去用C#了。只是C++.net的一個main函式定義而已。

本來目的是建立一個Win32控制檯應用程式,卻在建立專案時選擇了CLR程式(注:通用語言執行時),造成以上結果。

託管C++ - CSDN部落格  http://blog.csdn.net/gao271003105/article/details/72875093
1、什麼是託管C++?
  在回答這個問題,首先要搞清楚什麼是"託管"(Managed)。託管是.NET的一個專門概念,它是融於通用語言執行時(CLR)中的一種新的程式設計理念,因此我們完全可以把"託管"視為".NET"。那麼什麼是"通用語言執行時"?通用語言執行時是.NET 框架應用程式的執行引摯。它提供了許多服務,其中包括:程式碼管理(裝入和執行)、型別安全性驗證、元資料(高階型別資訊)訪問、為管理物件管理記憶體、管理程式碼,COM物件和預生成的DLLs(非管理程式碼和資料)的互動操作性、對開發人員服務的支援等等。
  也就是說,使用託管C++意味著,我們的程式碼可以被CLR所管理,並能開發出具有最新特性如垃圾自動收集、程式間相互訪問等的.NET框架應用程式。
  由託管概念所引發的C++應用程式包括託管程式碼、託管資料和託管類三個組成部分。

C/C++中*和&的用法 - CSDN部落格  http://blog.csdn.net/caozixuan98724/article/details/73395598

C++中運算子 &和&&、|和|| 的區別 - CSDN部落格  http://blog.csdn.net/violet_echo_0908/article/details/47395875
C++ 位運算 & | << >> ^ ~ % - CSDN部落格  http://blog.csdn.net/fox64194167/article/details/20692645

C++ 中 * 和 *& 的區別 - kala111的部落格 - CSDN部落格  http://blog.csdn.net/kala111/article/details/52442752

C++類成員指標(指向類成員的指標) - prettyshuang - 部落格園  https://www.cnblogs.com/prettyshuang/p/5427689.html

所謂野指標:指向一個已刪除的物件或未申請訪問受限記憶體區域的指標。
與空指標不同,野指標無法通過簡單地判斷是否為 NULL避免,而只能通過養成良好的程式設計習慣來盡力減少。對野指標進行操作很容易造成程式錯誤。
野指標的成因主要有兩種: 
    (1)指標變數沒有被初始化。任何指標變數剛被建立時不會自動成為NULL指標,它的預設值是隨機的,它會亂指一氣。所以,指標變數在建立的同時應當被初始化,要麼將指標設定為NULL,要麼讓它指向合法的記憶體。 
    (2)指標p被free或者delete之後,沒有置為NULL,讓人誤以為p是個合法的指標。別看free和delete的名字惡狠狠的(尤其是delete),它們只是把指標所指的記憶體給釋放掉,但並沒有把指標本身幹掉。通常會用語句if (p != NULL)進行防錯處理。很遺憾,此時if語句起不到防錯作用,因為即便p不是NULL指標,它也不指向合法的記憶體塊。
例: 
char *p = (char *) malloc(100); 
strcpy(p, “hello”); 
free(p); // p 所指的記憶體被釋放,但是p所指的地址仍然不變 
if(p != NULL) // 沒有起到防錯作用 
strcpy(p, “world”); // 出錯

C程式中可怕的野指標  https://zhuanlan.zhihu.com/p/24764641

http://blog.csdn.net/soonfly/article/details/51131141