---
# System prepended metadata

title: Lecture 2：Variable and Basic Types

---

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