# Lecture 2:Variable and Basic Types - [Build-in Types](#Build-in-Types) - [Variable](#Variable) - [Reference](#Reference) - [Pointer](#Pointer) - [Const](#Const) - [Auto](#Auto) - [Decltype](#Decltype) - [Struct](#Struct) Build-in Types --- 1. Integral Types * Integers: short, int, long, long long --- signed, unsigned * Characters: char --- signed, unsigned * Extended Characters: wchar_t, char16_t, char32_t * Boolean values: bool * The unsigned int can be abbreviated as unsigned. 2. Floating-Point Types * float, double, long double 3. Character * char, wchar_t, char16_t, char32_t, (char8_t C++ 20 ) 以上的資料型態在記憶體中佔有的大小,依平台系統而有所差異,可以使用 sizeof() 運算子得到資料型態佔有多少的記憶體空間。 Variable --- 變數(Variable)提供一個有名稱的記憶體儲存空間,變數可包含的資訊包含變數資料型態、變數記憶體位址與變數儲存值;C++ 開發者也常用物件(object)來稱呼,因為變數對 C++ 開發者來說,不只是表示類別實例,而是代表著一塊記憶體區域,可能含有型態與值等資訊。 Reference --- 位址可視為一個物件的別名,如果被宣告為位址的物件,僅是已存在物件的另一個名稱。兩者指向一個物件,但卻有不同的稱號。其主要用途是函數的參數傳遞,可透過在變數前加上 & 進行定義,如: ``` int a = 10; int& r = a; //or int &r = a; ``` Pointer --- 指標(Pointer)是一種變數,指標可儲存特定的記憶體位址。宣告指標時使用以下的語法,但宣告指標但不指定初值,指標儲存的位址是未知的,存取未知位址的記憶體內容是危險的行為。因此一開始不儲存任何位址,可設定初值為 0,或者是使用 nullptr: ``` int *n = 0; float *s = nullptr; char *c = nullptr; ``` 雖然宣告指標時,C++ 習慣將 * 前置在變數名稱前,不過 n 的型態是 int*,s 的型態是 float*,而 c 的型態是 char*,指標的型態決定了位址上的資料如何解釋,以及如何進行指標運算(Pointer arithmetic)。如果想知道變數的位址為何,可以使用 & 取址運算子(Address-of operator);而如果想知道指標實際儲存的物件,則使用提取 (Dereference)運算子 * 如: ``` string s(“hello world”); string *sp = &s; cout << *sp; ``` #### 注意事項 1. 宣告方式 ``` int* p1, p2;// p1 is a int*, p2 is a int int *p3, *p4;// p3 is a int*, p4 is a int* ``` 2. 使用 const 宣告的變數,必須使用對應的 const 型態指標才可以: ``` const int n = 10; const int *p = &n; ``` 3. 想令指標儲存的值無法變動,必須建立指標常數。: ``` int n = 10; int m = 20; int* const p = &n; //若來源變數為 const ,又令想指標儲存的值無法變動 const int n = 10; const int m = 20; const int* const p = &n; ``` #### 指標的指標 還是指標!指標就是儲存記憶體位址,差別在於指標的型態。 Pointer with reference: ``` int ival = 1024; int *pi = &ival; // pi points to an int int **ppi = &pi; // ppi points to a pointer to int cout << "The value of ival\n" << "direct value: " << ival << "\n" << "indirect value: " << *pi << "\n" << "doubly indirect value: " << **ppi << endl; ``` 執行結果: ``` The value of ival direct value: 1024 indirect value: 1024 doubly indirect value: 1024 ``` Const --- const 關鍵字可以將物件轉換為唯讀的狀態,也就是只供讀取(read-only)而無法變動的狀態 ``` const double PI = 3.14159; PI = 3.14;//error: assignment of read-only variable 'PI' ``` 從 C++ 11 開始,可以使用 constexpr 請編譯器驗證常數初始時是在編譯時期決定,例如: ``` constexpr int A = 10; constexpr int B = sizeof(10); constexpr int C = sizeof(B); constexpr int D = rand();// error: call to non-'constexpr' function 'int rand()' ``` D 的實際值要在執行時期才能決定,而非編譯時期,因此發生錯誤;constexpr 的價值在於,在重重的運算式或函式呼叫下,編譯時期常數有時很難一眼看出,這時加上 constexpr 請編譯器來進行檢驗就方便多了。 Auto --- 在 C ++ 11 中,auto 讓編譯器從變量的初始值設定中推斷出變量的型態,是一個非常有用和方便的功能,尤其是當變數型態難以準確了解或編寫、鍵入時。使用 C ++ 11 的版本進行編譯需要在終端機輸入對應的編譯器版本,如下: `g++ -std=c++11` #### reference、const 與 auto 的關係 當使用 reference 作為 auto 的初始值設定時,編譯器會使用 reference 參照的變數型態進行推斷。若真的需要編譯器推斷出 reference 型態,則需要指名此變數是一個參照。 ``` int i = 0, &r = i; auto a = r;// a is an int (r is an alias for i, which has type int) auto& a = r;// a is now an int& ``` 同樣的使用 auto 的宣告方式會忽略初始值具有 const 的複合型態,因此也需要非常明確指出這是一個 const。 ``` const int ci = 40; const auto fi = ci; ``` Decltype --- decltype 告訴編譯器從表達式中推導出變數型態,編譯器分析表達式回傳的型態,但不計算表達式。(decltype 對於template programming非常有用。) ``` int i; const int ci = 0, &cj = ci; decltype(ci) x = 0; // x has type const int decltype (i) a; // a is an uninitialized int decltype(cj) y = x; // y has type const int& and is bound to x double f() {return 3.01;} decltype(f()) sum = x; // sum has whatever type f returns, double in this case ``` Assignment is an example of an expression that yields a reference type. ``` int a = 3, b = 4; decltype(a = b) d = a; // d is a int& and is bound to a ``` Struct --- 其中一種定義型態的方法是使用struct,在實作上將想要儲存不同型態的資料以資料抽象型態(Abstract Data Type,ADT)的方式集合成新的資料型態。而資料抽象化在解決問題時,引入相關事物的想像以幫助解決問題。 ``` struct Student { std::string name; int id = 0; int age = 0; }; int main() { Student s; s.name = "OOP"; s.id = 6; s.age = 21; std::cout << "Student info: \n"; std::cout << "\tname: " << s.name << "\n"; std::cout << "\t id: " << s.id << "\n"; std::cout << "\t age: " << s.age << "\n"; return 0; } //Output /* Student info: name: OOP id: 6 age: 21*/ ```