# 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 = π // 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*/
```