---
# System prepended metadata

title: Python C C++

---

---
title: Python C C++ bestmark520
autoHeadingNumber: true
---
[TOC]
<!-- 按 Ctrl+Shift+P → Markdown: Create Table of Contents-->

# Python C C++
## for 迴圈 (要加冒號)
### for 迴圈 + range
```python
for i in range(stop) # 同 range(0, stop, 1)
for i in range(start, stop) # 同 range(start, stop, 1)
for i in range(start, stop, step) # 完整版

for _ in range(3): # 若迴圈的變數之後不會用到，可以用 `_`

for i in range(0, n):  # 0到 n-1，數量不會減少，輸出n個數字

for j in error:
# 迴圈中把每一個項目都掃一次 `for A in B`
# `error` 可以是str, list, tuple, dict, set

for (int j : error) #c++
```

#### C++ 跟 Python 迴圈的整數範圍：
C++ 的中間可以自己決定是 `<=` 還是 `<`，
Python 的中間隨遞增/遞減固定是 `<` 或 `>`。
```python
for j in range(1, 10):
for (int j = 1; j < 10; j = j + 1) #c++
# 滿足 j < 10 的最小整數，即 j = 9

for j in range(1, 10):
for (int j = 1; j <= 9; j = j + 1) #c++
# 滿足 j < 10 的最小整數，即 j = 9

for j in range(10, -1, -1):
for (int j = 10; j > -1; j = j - 1) #c++
```

### 迴圈中的迴圈
```python
for i in range(4):  # i 遍歷 0 到 3（half-1）
    for j in range(2):  # j 遍歷 0 到 1（col-1）
        for k in range(3):  # k 遍歷 0、1、2（三個通道：紅、綠、藍）
            print(f"i={i}, j={j}, k={k}")
```

![001](https://hackmd.io/_uploads/H18K6Briel.png)

```python
for i in range(0, 4, 1):
    for j in range(3, -1, -1):
```
如圖，`col` = `0`，`row` = `3`、`2`、`1` → `col` = `1`，`row` = `3`、`2`、`1`，`i` 是外圈，`j` 是內圈：
![002](https://hackmd.io/_uploads/B1aqTrBjel.png =40%x)

#### Bubble Sort 寫法一：由 i 配合 j (較直觀)

```python
def bubble_sort(nums: list[int]):
    n = len(nums)
    print(nums)
    for i in range(n - 1, 0, -1):
        for j in range(i):
            if nums[j] > nums[j + 1]:
                nums[j], nums[j + 1] = nums[j + 1], nums[j]
                print(nums)
            else:
                print(f'{nums}, nochange')
```

#### Bubble Sort 寫法二：由 j 配合 i（Jack 寫法）
```python
def bubble_sort_Jack(nums: list[int]):
    n = len(nums)
    print(nums)
    for i in range(0, n-1, 1):
        for j in range(0, n-1-i, 1):
            if nums[j] > nums[j + 1]:
                nums[j], nums[j + 1] = nums[j + 1], nums[j]
                print(nums)
            else:
                print(f'{nums}, nochange')
```
### Iteration and Recursive 迴圈與遞迴 
iteration迭代：
- 迭代就是迴圈
- For迴圈：指定次數
- while迴圈：指定條件

![046](https://hackmd.io/_uploads/HJoK-XPugg.png =55%x)

recursive遞迴：
- 遞迴透過函式呼叫自身來解決問題，可以參考merge sort程式的流程圖
- 遞：程式不斷深入地呼叫自身
- 迴：觸發終止條件後，程式從最深層的遞迴函式開始逐層返回
- 遞迴與堆疊的先入後出原則異曲同工
```python
def quick_sort(arr):
    if len(arr) <= 1:
        return arr  # 遞迴要給最底層回傳的東西
    
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quick_sort(left) + middle + quick_sort(right)
```
```cpp
void insertion_sort_recursive(int nums[], int n) {
    if (n <= 1) return; // 遞迴要給最底層回傳的東西

    // 先遞迴排序前面 n-1 個
    insertion_sort_recursive(nums, n - 1);
    int base = nums[n - 1];
    int j = n - 2;
    while (j >= 0 && nums[j] > base) {
        nums[j + 1] = nums[j];
        j--;
    }
    nums[j + 1] = base;
}
``` 
## while 迴圈 (要加冒號)
### while 數值範圍漸漸縮小
```c
// i 跟 j 的範圍逐漸縮小
while (left <right){
    // func
    left++;
    right--;
}
```
![image](https://hackmd.io/_uploads/rJur84mBWg.png =60%x)

```c
// 當list.next不是null就work
// 直到list.next是null為止
while (ListArray[found_entry].NextPtr != NULL)
```

### while 條件達成時執行

```python
while rest >= c:  # 達成 rest>=c時，不斷地run #不斷迴圈直到rest < c
    sum += rest // c
    rest = rest // c + rest % c
print(sum) # 廣達面試題目，if迴圈是有指定次數；while迴圈是指定條件
```

CPE 11689
```python
t = int(input())
for case in range(1, t + 1):
    e, f, c = map(int, input().split())
    soda = 0
    bottles = e + f
    while bottles >= c: # 如果瓶子數 >=兌換數，就繼續換
        soda += bottles // c
        bottles = bottles // c + bottles % c
    print(soda)

while B: #表示只要B不是0(真數)時，就繼續run
```

### While Ture:，搭配if break確保不會無限循環
```python
while True:
    user_input = input("請輸入 'quit' 來退出迴圈: ")
    if user_input == 'quit':
        break
print("迴圈已退出")
```

CPE 11428，20230919例題2
找x^3 - y^3的xy解
x^3 - y^3 =(x-y)(x^2 +xy+y^2 ) <10^5  →x-y <100  →x < y+100

```python
while True:
    N = int(input())
    if N == 0:
        break # 使這個while停止
    a = 0
    for j in range(1, 100):
        for i in range(j, 100 + j):
            if i**3 - j**3 == N:
                print(i, j)
                a = 1
                break # 上面for迴圈停止，不代表這個while停止
    if a == 0:
        print("No solution")
        break # 如果沒加這個，輸入0 while也不會停止，可以一直輸入值
```

### while True + try/except EOFError
20231205 第二題，except EOFError:，放在整個程式最後面
無限輸入迴圈：
```python
while True:
    try:
        #程式碼
    except EOFError:
        break
```

### C:do while
```c
do { 
    // 程式碼區塊 
    // 會先執行一次程式區域，在看有沒有符合條件
} 
while (condition);
```
群聯 UFS 考古第一題
```c
int i,x,y;
i=x=y=0;
do{
    ++i;
    if(i%2 != 0) x = x + i++;
    y = y + i++;
}
while(i<=7)；
printf("%d %d\n", x, y); // 1 20

// x = 0 + 1
// y = 0 + 2 + 4 + 6 + 8
```

## if（要加冒號），條件判斷
### if、elif、else 用法
```python
if x > 5:
    print("x 大於 5")
elif x == 5:
    print("x 等於 5")
else:
    print("x 小於 5")
```

CPE 11942 正確寫法（if + elif + else）
CPE 11942 錯誤寫法（if + if + else）
如果是 if + if + else，那第二個if會跟else變成一組
要讓程式1、2、3合在一起，就要if + elif +else

C++：
```cpp
if (nums[i] == val) // 要有括號
    {
    nums.erase(nums.begin() + i); 
    }
```

### 條件式
| 類別| 意義| C| C++| Python| Verilog|
| - | - | - | - | - | - |
| **if 結構**   | 條件判斷          | `if (cond) {}` | `if (cond) {}` | `if cond:`      | `if (cond) begin end` |   |   |      |   |   |   |
| **else**    | 否則            | `else {}`      | `else {}`      | `else:`         | `else begin end`      |   |   |      |   |   |   |
| **AND**     | 且             | `&&`           | `&&`           | `and`           | `&&`                  |   |   |      |   |   |   |
|**OR**| 或|`｜｜`| `｜｜` | `or` | `｜｜` |
| **NOT**     | 非             | `!`            | `!`            | `not`           | `!`                   |   |   |      |   |   |   |
| **等於**      | equal         | `==`           | `==`           | `==`            | `==`                  |   |   |      |   |   |   |
| **不等於**     | not equal     | `!=`           | `!=`           | `!=`            | `!=`                  |   |   |      |   |   |   |
| **大於**      | greater than  | `>`            | `>`            | `>`             | `>`                   |   |   |      |   |   |   |
| **小於**      | less than     | `<`            | `<`            | `<`             | `<`                   |   |   |      |   |   |   |
| **大於等於**    | ≥             | `>=`           | `>=`           | `>=`            | `>=`                  |   |   |      |   |   |   |
| **小於等於**    | ≤             | `<=`           | `<=`           | `<=`            | `<=`                  |   |   |      |   |   |   |
| **True 值**  | 布林真           | 非 0            | `true`         | `True`          | `1'b1`                |   |   |      |   |   |   |
| **False 值** | 布林假           | `0`            | `false`        | `False`         | `1'b0`                |   |   |      |   |   |   |
| **三元運算**    | 條件指派          | `a ? b : c`    | `a ? b : c`    | `b if a else c` | `a ? b : c`           |   |   |      |   |   |   |

```python
if a > 0 or b < 5:
```
```c
if (a > 0 || b < 5)
```

#### 條件的等於與不等於
條件的等於 `if t == 1:`；條件的不等於 `if t !=0:`

c++數學式
```c++
if (nums_dict.find(val) != nums_dict.end()) // != .end() 不在.end()表示存在
if val in self.nums_dict: // python

if (nums_dict.find(val) == nums_dict.end()) // == .end() 表示不存在
if val not in self.nums_dict: // python
```

## OOP 物件導向，struct、class
### python class
```python
# class定義不放input
class mathperson:
    def __init__(self):
        self.age = None
        self.name = None

p1 = mathperson()
p1.age =  18
p1.name = Jack

# class定義放input
class mathperson: # class將相同類型的程式放在一起
    def __init__(self, name, age): 
    # __init__ 是當class被直接呼叫時，會做的動作
    # 如person1 = mathperson("Alice", 30)
    # self是物件引用初始值
    # 當class被呼叫後，self變成person1
        self.name = name 
        self.age = age
        self.count = 0

    def n_years_pass(self, n): # 過了n年後，年紀是多少
        self.count += 1
        self.age += n

    def add(self, a, b): # 計算新輸入的a, b相加
        self.count += 1
        return a + b

    def get_count(self):
        return self.count

person1 = mathperson("Alice", 30)
person2 = mathperson ("Bob", 25)
```
```python
from test import mathperson # 引入test.py中的mathperson這個class
from test import * # 引入test.py中的所有class
from method.test import * # method資料夾內的test.py

person1 = mathperson("Alice", 30) # 創建一個新的 Person 物件
#__init__ 使 Person("Alice", 30) 等同 __init__(1, "Alice", 30)，但不能真的直接呼叫__init__
print(person1.name) #在創建過程中，__init__ 方法被呼叫，並且設定了 name 和 age 屬性
print(person1.age)
answer1 = person1.add(5, 3) # 使用class中的函式語法，直接加 .func
print(f"計算次數：, {person1.get_count()} and 兩數字相加：, { {answer1}")  # 獲取計算次數 

person2 = mathperson ("Bob", 25) # __init__ 再次work
print(person2.name)
print(person2.age)
```

### C C++ OOP名詞

| 名稱  | 說明 |
 | --- | --- |
 | Encapsulation（封裝）|函式有回傳值叫`Getter`，僅寫入叫`Setter`|
| Inheritance（繼承） |子類別使用父類別的函式，如蘋果繼承水果，不會繼承父類別的private、建構子、解構子|
| Polymorphism（多型） | 配合virtual，動態繫結 (dynamic binding)。使用父類別指標宣告，那個指標隨時可以改成別的子類別，main裡執行時期才決定要呼叫哪個子版本的 speak() |
| Abstraction（抽象）  | 定義一個父類別不能被實例化（new），只能被繼承，如人類、形狀、水果這種父類別，通常透過 抽象類別或 純虛擬函式`virtual void draw() = 0;`實現|
| Interface | 純虛擬類別，提供統一介面，抽象只要有一個純虛函式即可，Interface一定要全部都是純虛函式  |
| Virtual Function（虛擬函式） | 允許子類別覆寫父類別函式，父類別語法，`virtual void draw() = 0;` 支援 動態繫結（dynamic binding），也就是 執行期決定呼叫哪個版本的函式，可以實現多型跟抽象 |
| Pure Virtual Function | 強制子類別實作，用於抽象類別  |
| Override（複寫）| 子類別重新定義父類別虛擬函式，子類別使用`override`這個語法|
| Overloading（多載） | 相同名稱，參數型態或數量不同，呼叫同個函式很多次|
| Access Specifiers（private/public/protected） |private:不能被修改且不能被繼承，protected:不能被修改但可以被繼承，class 預設 private，struct 預設 public |
| Constructor / Destructor | 建立與銷毀物件的初始化與清理，一個class裡面可以有很多種建構子，C沒有建構子 |
| this 指標 | 怕有名稱衝突，指向當前創建的物件的變數  |
|Function Hiding（函式遮蔽）|父與子都有同名的函式（沒有 virtual）時，子類別的版本會蓋掉父類別的版本|

### Encapsulation（封裝）
透過 Getter / Setter 隱藏內部資料，函式名稱不一定要取名叫get / set

```cpp
class Person {
private:
    int age;
public:
    void setAge(int a) { age = a; }
    int getAge() { return age; }
};

int main() {
    Person p;
    p.setAge(25);
    cout << p.getAge();
}
```

### Interface、Abstraction、Pure Virtual Function、Virtual Function、Inheritance、Override、Polymorphism
- Interface（介面）：純虛擬類別，提供統一介面
- Abstraction（抽象）：定義介面或純虛擬函式
- Pure Virtual Function（純虛擬函式）：強制子類別實作，用於抽象類別
- Virtual Function（虛擬函式）：子類別可以修改
- Inheritance（繼承）：子類別可使用父類別的方法
- Override（複寫）：子類別重新定義父類別虛擬函式
- Polymorphism（多型）：配合 `virtual`，執行時期才會決定呼叫哪個子版本的函式
```cpp
class Animal {
public:
    virtual void speak() = 0; // 純虛擬函式 → 抽象
    int age = 25; // 有非純虛函式，不是interface
};
// Animal a; // 會報錯，只能被繼承 // 是抽象不是interface

class Animal2 { // class裡面只有純虛函式，是抽象也是interface
public:
    virtual void speak() = 0;
    virtual void breathe() = 0;
};

class Animal3 {
public:
    virtual void speak() { cout << "Animal sound" << endl; }
};
// Animal3 a; // 不會報錯 // 不是抽象

class Dog : public Animal {  // Inheritance語法
public:
    void speak() override { cout << "Woof!" << endl; } // override寫在子類別裡面
};

class Cat : public Animal {
public:
    void speak() override { cout << "Meow!" << endl; }
};

int main() {
    Dog d;  // 這不是多型，Dog d已經寫死是dog了
    d.speak(); // 編譯前就知道一定是Dog

    Animal* a = new Dog();
    delete a;        // 釋放 Dog
    a = new Cat();   // 指向 Cat
    a->speak(); // 執行時才知道是Cat // a可以隨時變換
}
```

### Overloading（多載）
相同名稱但參數型態或數量不同

```cpp
class Math {
public:
    int add(int a, int b) { return a + b; }
    double add(double a, double b) { return a + b; }
};

int main() {
    Math m;
    cout << m.add(1, 2) << endl;
    cout << m.add(1.5, 2.5) << endl;
}
```

#### Access Specifiers（存取權限）
控制可見範圍；`class` 預設 private，`struct` 預設 public

```cpp
class Example {
private:
    int secret = 10;
public:
    void show() { cout << secret; }
};

int main() {
    Example e;
    e.show(); // OK
    // e.secret; // 錯誤: private
}
```

### Constructor / Destructor（建構子 / 解構子）
建立與銷毀物件時自動執行初始化與清理，一個class裡面可以有很多種建構子

```cpp
class MyVector {
public:
    MyVector() : n(0), m(nullptr) {}
private:
    int n;
    int* m;
};

class MyVector2 {
public:
    int n;
    int* m;
};

int main() {
    MyVector v; // 有自動初始化
    MyVector2 v;  // 沒有自動初始化，n跟m會是未知值
}
```

### this 指標
指向當前物件，用於區分變數或鏈式操作

```cpp
class Counter {
private:
    int value;
public:
    Counter(int v) { this->value = v; }
    Counter& add(int x) { value += x; return *this; }
    void show() { cout << value << endl; }
};

int main() {
    Counter c(5);
    c.add(3).add(2).show(); // 鏈式呼叫
}
```

### Function Hiding（函式遮蔽）
父與子都有同名的函式（沒有 virtual）時，子類別的版本會蓋掉父類別的版本

```cpp
class Base {
public:
    void show() { cout << "Base" << endl; }
};

class Derived : public Base {
public:
    void show() { cout << "Derived" << endl; }
};

int main() {
    Derived d;
    d.show(); // 呼叫 Derived 版本
}
```

# C C++
## C C++宣告

| 資料型態               | 中文說明         | 範例值               | 記憶體大小（常見）   |
| ------------------ | ------------ | ----------------- | ----------- |
| **char**           | 單一字元         | 'A', 'b', '3'     | 1 byte      |
| **unsigned char**  | 不含負數的字元 / 整數 | 0~255             | 1 byte      |
| **short**          | 短整數（含負）      | -32768 ~ 32767    | 2 bytes     |
| **unsigned short** | 無號短整數        | 0 ~ 65535         | 2 bytes     |
| **int**            | **整數**       | -21 億 ~ 21 億      | 4 bytes     |
| **unsigned int**   | 無號整數         | 0 ~ 42 億          | 4 bytes     |
| **long**           | 長整數          | 視系統而定             | 4 或 8 bytes |
| **long long**      | 更大的整數        | -2⁶³ ~ 2⁶³-1      | 8 bytes     |
| **float**          | **小數（單精度）**  | 3.14              | 4 bytes     |
| **double**         | 小數（雙精度）      | 3.1415926         | 8 bytes     |
| **long double**    | 超高精度小數       | 視編譯器（10~16 bytes） | 10~16 bytes |
| **bool**（C++）      | 布林           | true/false        | 1 byte（實際）  |

| 型態         | 中文說明      | 範例                   |
| ---------- | --------- | -------------------- |
| **char[]** | 字元陣列 → 字串 | `char s[] = "ABC";`  |
|**int[]** |array|`int a[3] = {1,2};`|
| **char***  | 指向字串的指標   | `char *p = "Hello";` |
| **int***   | 指向整數的指標   | `int *p;`            |

（C 沒有 STL）
| 型態 | 說明 | 範例 |
| -- | -- | -- |
| **vector** | 動態陣列         | `vector<int> v;`        |
| **string**    | 字串類別         | `string name = "Jack";` |
| **map<K, V>** | key-value 結構 | `map<string, int> mp;`  |
| **set**    | 自動排序，不重複     | `set<int> s;` |

## C C++差異

| 項目    | C                                 | C++                                             |
| ----- | --------------------------------- | ----------------------------------------------- |
| 語言類型  | 結構化程式語言                           | 支援物件導向（OOP） + 結構化程式                             |
| 標準庫   | 標準 C 函式庫 `<stdio.h>` `<stdlib.h>` | 標準 C++ 庫 `<iostream>`, STL `<vector>` `<map>` 等 |
| 記憶體管理 | 手動（malloc/free）                   | 支援 new/delete，還可用智能指標（C++11）                    |
| 函式多載  | 不支援                               | 支援函式多載（同名不同參數）                                  |
| 運算子多載 | 不支援                               | 支援（可以自訂 +, -, << 等）                             |
| 結構    | `struct` 只存資料                     | `struct`/`class` 可存資料與函式（方法）                    |
| 引用    | 無                                 | 有引用 `int &a = b;`                               |
| 名稱空間  | 無                                 | `namespace`，避免命名衝突                              |

輸入輸出

| C                          | C++                              |
| -------------------------- | -------------------------------- |
| `printf("Hello %d\n", x);` | `cout << "Hello " << x << endl;` |
| `scanf("%d", &x);`         | `cin >> x;`                      |

記憶體分配

| C                                     | C++                 |
| ------------------------------------- | ------------------- |
| `int *p = (int*)malloc(sizeof(int));` | `int* p = new int;` |
| `free(p);`                            | `delete p;`         |

字串處理

| C                                                 | C++                             |
| ------------------------------------------------- | ------------------------------- |
| char 陣列 + 函式：`char str[100]; strcpy(str, "abc");` | `string s = "abc"; s += "def";` |
| 不支援直接比較字串                                         | `==` 可直接比較 `string`             |

容器

| C       | C++                                  |
| ------- | ------------------------------------ |
| 陣列或自訂結構 | STL：`vector`, `list`, `map`, `set` 等 |

```cpp
vector<int> v;
v.push_back(10);
cout << v[0];
```

函式差異

* **C**：同名函式只能一個（無多載）
* **C++**：支援多載

```cpp
int add(int a, int b) { return a+b; }
double add(double a, double b) { return a+b; } // 多載
```

結構/類別差異

C：
```c
struct Node {
    int data;
    struct Node* next;
};
```

C++：
```cpp
struct Node {
    int data;
    Node* next;
    Node(int val) : data(val), next(nullptr) {} // 建構子
};
```

* C++ 可以在 struct/class 裡放 **函式、建構子、解構子**
* C 只能存資料欄位

其他常用差異

| 功能   | C            | C++                                   |
| ---- | ------------ | ------------------------------------- |
| bool | 無（用 int 0/1） | 有 `bool`，true/false                   |
| enum | 基本 enum      | enum class（類型安全）                      |
| 預處理器 | `#define` 常用 | 可以用 `const`, `inline`, `constexpr` 替代 |
| 指標   | 完全依賴指標       | 可以用引用 & 智能指標，減少手動管理                   |

**總結**
* **C**：簡單、結構化，手動管理記憶體，多用函式、指標
* **C++**：C 的超集，支援 OOP、STL(標準模板函式庫)、引用、函式多載、物件管理，更高階抽象

## pointer 指標
### 語法
| 符號 | 內容/房間 | 說明                    |
| -- | ----- | --------------------- |
| x  | 5     | x 的value是 5             |
| &x | A房間   | &口，口是變數，取其位址，用 A 房間表示        |
| *p | 5 |*口，口是地址，讀其地址的變數value|
| p  | A房間 | p 是x 的位址，A 房間 |
| &p | B房間 | p真正的房間 |

```cpp
int a = 5;

// 此為簡寫
int *p = &a; // 宣告p變成指標變數，並指向a的地址

// 此為展開後
int *p;   // 宣告p變成指標變數
p = &a;   // 指向 a 的地址
```
```cpp
int x = 5;
int *p = &x;
*p = 10;  // 指定這個位子的value是10
/* 
x → 10
*p → 10
p → 還是 A 房間
*/

int y = 20;
p = &y; // 改變p這個變數指向的地址
/* 
p → y 的房間
*p → 20
x → 5 不變
*/
```
|![image](https://hackmd.io/_uploads/r15wf8ngbl.png)|![image](https://hackmd.io/_uploads/S1YkQU3xWx.png)|
|- | - |
- 地址賦值給指標
```cpp
struct Node {
    int data;
    Node* next;
    Node(int val) : data(val), next(nullptr) {} 
};

Node* top;
Node* newNode = new Node(val);
newNode->next = top;
top = newNode;  // 因為top跟newNode都是指標，直接改top指向的位子
```
### 變數、stack、heap
```c
int a = 10; // 建立在stack上
int *p = &a;  // p 指向 stack 上的 a
*p = 20;      // 修改 a 的值

int* p = (int*)malloc(sizeof(int)); // 建立在heap上
*p = 5; // 同p[0]是5  // 實際上並不知道heap上value是5的位子的identify是什麼
```
- int*p = malloc 在heap上建立任何東西 其實都看不到heap層的id
- 所以用指標會覺得不知道自己在指什麼，但實際上指到了
### 為什麼要用指標? call by address，func輸入指標(地址)改stack的value
- call by value，是讀`5`這個數字
- call by address，是讀`0x100`這個地址
- 想改main上stack的任何變數、指標，都要傳stack上的地址
- 指標 + malloc將記憶體分配到 heap 層：函式可以操作 heap 上的資料，任何函式外也可見
- Python 為何沒有指標？：因為 Python 使用 mutable（可變）型別，例如 `list`、`dict`、`set`，函式可以直接修改物件內容，而不需要指標概念。
```c
void func(int* c) {
    *c = 10; // 指定這個位子的value是10
}

int main() {
    int a = 5;
    func(&a);
    printf("%d", a); // 透過指標間接改值
}
```
|address|identifier|value|
|-|-|-|
|0x100|a|5|
|0x200|c|0x100|
|0x300|*c|10|
### 建立空指標
- 只要看到建立指標，就要知道在stack建立了一個變數
```c
int *a;
/*
stack
address | id | value |
0x1000  | a  | ???   |
*/

a = (int*)malloc(sizeof(int));
// 在 heap 配置一塊可存 int 的空間，並把位址存進 a
// 同int*a = (int*)malloc(sizeof(int));
/*
stack
address | id | value  |
0x1000  | a  | 0x3000 |

heap
address | id | value |
0x3000  | ???| ???   |
*/

*a = 5;   // 將 5 存進 heap 中 a 指向的位置

/*
stack
address | id | value  |
0x1000  | a  | 0x3000 |

heap
address | id | value |
0x3000  | ???|   5   |
*/
```
### func輸入指標的地址改stack的指標的value
- 要改stack上的變數或指標，func都要input其地址
- 看到func有輸入指標 `func(Node *head)` 此時`head`在func內就是地址，指向Node
-  `func(Node **head)` 此時`*head`在func內就是地址，指向Node*
```c
int *b = NULL;

func(&b); // 寫法1 void，用func更改指標
b = func2(b); // 寫法2 int*，用func回傳地址賦值給指標

// 想要改 stack 上的指標（b 指向哪）
// 一定要傳入指標的位址 → int ** 
// call by address 也適用於更改指標的value(地址)
void func(int **c) {
    *c = (int*)malloc(sizeof(int)); // 配置 heap，並改變外層指標 b (*c) 指向某個heap地址，該地址放int
    **c = 10;

    int *d;   // d 是 func stack 內的指標
    d = (int*)malloc(sizeof(int)); // heap 配置空間

    // c 跟 d 會在 func 結束後消失
    // 若不 return 或 free, d 指向的這塊 heap 會 memory leak
}

int* func2(int* e) {
    int f = (e == NULL) ? 10 : *e;
    int *g = malloc(sizeof(int));
    *g = f + 10;
    return g; // 回傳heap建立的地址
}
```
### python自帶指標功能
```python
# list範例
a = [1, 2, 3]
b = a         # b 指向同一個 list
b[0] = 10
print(a)      # [10, 2, 3]

# class範例
class Node:
    def __init__(self, val):
        self.val = val

a = Node(5)
b = a          # b 指向同一個 Node 物件
b.val = 10
print(a.val)   # 10
```

對應c++
```cpp
#include <iostream>
#include <vector>
using namespace std;

// 直接學python的寫法沒用
int main() {
    vector<int> a = {1, 2, 3};
    vector<int> b = a;   // 拷貝 a 的內容
    b[0] = 10;
    for(int v : a) cout << v << " ";  // 1 2 3
    return 0;
}

int main() {
    vector<int>* a = new vector<int>{1, 2, 3};
    vector<int>* b = a;    // b 指向同一個 vector
    (*b)[0] = 10;
    for(int v : *a) cout << v << " ";  // 10 2 3
    delete a;
    return 0;
}

class Node {
public:
    int val;
    Node(int v) : val(v) {}
};

// 直接學python的寫法沒用
int main() {
    Node a(5);
    Node b = a;   // 值拷貝
    b.val = 10;
    cout << a.val << endl; // 5
    return 0;
}

int main() {
    Node* a = new Node(5);
    Node* b = a;   // b 指向同一個 Node
    b->val = 10;   // 等效 (*b).val
    cout << a->val << endl; // 10
    delete a;
    return 0;
}
```
### 台大上課補充
- `*(&x)`，指標提取`&x`這個地址，所以`*(&x) equal x`
- `int* p`跟`int *p`是一樣的
- 宣告用的`int* p`跟取值用的`*p`是完全不一樣的
- 取值的`&x`跟reference的`int &x = a;`是完全不一樣的
- 宣告空的指標要用`int* p = nullptr;`
- 掃描array時可以知道a[0]的指標跟當下a[i]的指標，那要如何知道當下的i是多少? `int* a = a[0];` `int* p  = a[i]` `p-a equal i`
- call by value的時機：
    - 不想改變main宣告的變數
    - 函式只需要讀變數，不需要改它
- call by pointer的時機：
    - 想改變main宣告的變數但函式沒return
- 使用指標的時機：
    - Dynamic memory allocation
    - Dynamic arrays
    - Dynamic data structures
    - C strings
### `++*p`, `*p++`, `*++p`的不同
- 討論兩件事情：
    - 賦值
    - 事後p的指標指向哪裡
- ++放後面，事後再+，++放前面，賦值前先處理
```c
#include <stdio.h>

int main() {
    int arr1[] = {10, 20, 30};
    int arr2[] = {10, 20, 30};
    int arr3[] = {10, 20, 30};

    int *p1 = arr1;
    int *p2 = arr2;
    int *p3 = arr3;
    
    // ++*p  // ++(*p)
    int val1 = ++*p1;       // arr1[0] 原本 10 → 11
    printf("%d %d\n", val1, *p1);  // 11 11   ← *p1 和 val1 都是 11

    // *p++
    int val2 = *p2++;       // 先取 arr2[0] = 10，然後 p2 指向 arr2[1]
    /* 
    後置遞增縮寫
    int val2 = *p2;  // 先取值
    p2 = p2 + 1;     // 再指標遞增 
    */

    printf("%d %d\n", val2, *p2); // 10 20   ← val2 = 10，*p2 = 20

    // *++p  // *(++p)
    int val3 = *++p3;       // p3 先移到 arr3[1]，再取值 arr3[1] = 20
    printf("%d %d\n", val3, *p3); // 20 20   ← val3 = 20，*p3 = 20

    return 0;
}
```
### function pointer 函式指標
```c
int (*math)(int a, int b);
math = add;
```
```c
// (int*)(*f(int,int))(int)
int*(*f(int,int))(int){ 
    // 讀取f回傳的函數指標
    // 所以這邊要寫的是f的功能
    // f回傳的函數input是int，output是int*
};
```
```c
typedef int* (*G_FUNC)(int);
G_FUNC f(int a, int b);
```
```c
#include <stdio.h>

int* g1(int x) {
    int x = x + 100;
    return &x;
}

int* g2(int x) {
    int x = x * 10;
    return &x;
}

int *(*f(int a, int b))(int) {
    if (a + b > 10)
        return g1;    // 因為你前面定義了回傳int*，所以會回傳 g1 的函式指標
    else
        return g2;    // 回傳 g2 的函式指標
}

int main() {
    int *(*func_ptr)(int);   // 第一次呼叫 f，給兩個 int
    func_ptr = f(7, 5);   // 7+5=12 > 10 → 會回傳 g1
    int *p = func_ptr(123);  // 第二次呼叫 func_ptr ，給一個 int
    printf("Result = %d\n", *p);   // g1(123) = 123 + 100 = 223
    return 0;
}
```

### 群聯考古題1 What is the result?
```c
    void change(int *a, int &b, int c) {
            c = *a;
            b = 3;
            *a = 2;
            return;
    }
    void main() {
            int a = 1, b = 2, c = 3;
            change(&a, b, c);
            printf(“%d %d %d”, a, b, c);
            return;
    }
```
```
2 3 3
```
### 群聯考古題2 What is the result?
```c
int a[] = {1,2,3,4,5,6};
int *p = a;
*(p++) += 100; // postfix先做等號兩邊運算 再做括號內的運算 所以是p[0]+100 再位址+1到p[1]
*(++p) += 100; //prefix先做括號內的運算 再做等號兩邊運算 所以先位址+1到p[2]再取值+100
 
for(int i = 0; i<6 ; i++)
printf("%d ", a[i]);    

//補充
int a[] = {1,2,3,4,5,6};
int *p2 = a;
int *p3 = a;
int e = (*p2)++; //e = *p = 1, 再e+1 但沒有e = e+1 所以++沒用
int f = ++*p3; //f = *p2 + 1 = 2

cout << "e =" << e << endl;
cout << "f =" << f << endl;
```
```
a = {101, 2, 103, 4, 5, 6}
e = 1
f = 3
```

## array and pointer 陣列與指標
### 陣列a退化成地址
- 非常反直覺，宣告好陣列a後，大部分a單獨出現時會退化成地址`0x1000`
- `siezof(a)`, `int *a`, 這種時候陣列a不會退化
### 1D array main建立好array -> func(int *a)
```c
// main
int arr[5] = {1, 2, 3, 4, 5}; // 存入stack
int *p = arr;       // 合法 // 因為陣列退化成指標 a會變成存a的地址
int *p = &arr[0];  // 等價

int x = 10;
int *p = x;     // 不合法
int *p = &x;   // 正確

func(arr);  // 傳入 stack 陣列

int *aaa = malloc(sizeof(int) * 5); // 存入heap
aaa[0] = 1;
func(aaa);
free(aaa);

// func
void func(int *a) {
    a[0] = 99; // 改變 arr[0]
}
```
* main：定義 stack 陣列 `arr[5]`，內容初始化
* func input：`int* a`，退化成 pointer
* 操作結果：func 可以改內容，但不能 malloc 新記憶體給 arr
* 記憶體位置：全部在 stack
```c
int nums[3] = {1, 2, 3};

// 傳陣列，用索引操作
void sort(int arr[], int size) {  // 同 int *arr
    for (int i = 0; i < size; i++)
        arr[i] += 10;  // 編譯器幫你隱式轉成 *(arr + i)
}


// 傳指標，用指標運算
void sort(int *arr, int size) {
    for (int i = 0; i < size; i++)
        *(arr + i) += 10;  // 同*arr++ += 10;
}

// 用指標 + 指標移動
void sort(int *arr, int size) {
    int *ptr = arr;   
    /*
    同
    int *ptr;
    int ptr = &arr[0];
    用 ptr 不會修改原本的 arr
    */
    for (int i = 0; i < size; i++)
        *ptr++ += 10;        // 先解引用，再讓指標移到下一個元素
}
```
三種寫法功能完全等價，只是表達方式不同
| 寫法           | 內部本質            | 好處       | 何時常用                          |
| ------------ | --------------- | -------- | ----------------------------- |
| `arr[i]`     | 隱式 `*(arr + i)` | 易懂、直觀    | 一般陣列操作                        |
| `*(arr + i)` | 指標運算            | 明確顯示位址運算 | 教學、低階操作                       |
| `*ptr++`     | 指標迭代            | 適合走訪動態結構 | linked list、pointer traversal |

### 指標的指標 int**
```c
int* a; // a是指向int(整數)的指標

int** b; 
// b是指標的指標 pointer to pointer
// b是指向int*的指標
// 指向指向整數的指標的指標
// b的value地址 →地址 →整數
```
|address|identifier|value|
|-|-|-|
|0x100|c|5|
|0x200|a|0x100|
|0x300|b|0x200|

```c
int* change(int* aaa, int* bbb) {
    aaa[0] = 10;   // 等價於 *(aaa + 0)
    *bbb = 10;
    return aaa; 
}

int main() {
    int aaa[5] = {0};
    int bbb = 0;

    int* res = change(aaa, &bbb);

    printf("aaa[0] = %d\n", aaa[0]); // 10
    printf("bbb = %d\n", bbb);       // 10
    return 0;
}
```
- `int* change(int* aaa, int* bbb)`兩個都是 `int*`
    - aaa 指向陣列第一個元素
    - bbb 指向單一整數
- 在 C 裡函式不能直接回傳陣列，只能回傳指標
- res是指向陣列第一個元素的指標


### 1D array main建立指標 -> func(int **a) malloc建立array在Heap 並回傳給 caller
```c
// main
int* p = NULL;  // 只是定義指標，尚未分配記憶體
func(&p);       // 傳入 p 的地址

// func
void func(int **a) {
    *a = malloc(sizeof(int) * 5); // malloc 給 caller
    (*a)[0] = 42;
}
```
* main：定義 pointer，未指向有效記憶體
* func input：`int** a` → 可以 malloc 並修改 main 的 pointer
* 你建立了一個指標，你想在函式內修改這個指標(建立malloc)，就必須傳這個指標的地址，所以要傳入指標的指標進func
* 函式內才用`malloc`建立`array`
* 操作結果：main 的 `p` 會指向 heap 上的新 array
* 記憶體位置：array 在 heap，指標本身在 stack
### 2D array main建立好array在stack -> func(int a[][3])
```c
// main
int arr[2][3] = {{1,2,3},{4,5,6}}; // 在記憶體上是 1D 連續的，但在型態與語意上仍然是 2D array
func(arr);  // 傳入 stack 二維陣列

// func
void func(int a[][3]) { 
    // func(int (*a)[3]) 
    // 不能int **a，因為記憶體排序其實是1D  
    // 這裡的[3]是在說a每次移動3格
    a[0][0] = 99; // 改變 arr[0][0]
}
```
* main：定義 stack 二維陣列 `arr[2][3]`
* func input：`int a[][3]` 或 `int (*a)[3]`
* 操作結果：func 可以改內容，但不能 malloc 新 array 給 arr
* 記憶體位置：全部在 stack

### 2D array main建立好array在heap -> func(int **a)

```c
// main
int **arr = malloc(sizeof(int*) * 2);
for(int i = 0; i < 2; i++) arr[i] = malloc(sizeof(int) * 3);  // 已分配記憶體
func(arr);  // 傳入已 malloc 的 array

// func
void func(int **a) {
    a[0][0] = 99;  // 可以直接改內容
}
```
* main：malloc 外層指標和每一層子陣列
* func input：`int** a`
* 操作結果：func 可以直接改內容
* 記憶體位置：array 在 heap，指標本身在 stack

Stack
| Address | Identify  | Value                  |
| ------- | --------- | ---------------------- |
| 0x1000  | arr       | 0x5000  (指向 heap 外層陣列) |

Heap
| Address | Identify  | Value                  |
| ------- | --------- | ---------------------- |
| 0x5000  | arr[0]    | 0x6000  (指向第一列 int[3]) |
| 0x5008  | arr[1]    | 0x7000  (指向第二列 int[3]) |
| 0x6000  | arr[0][0] | ?                      |
| 0x6004  | arr[0][1] | ?                      |
| 0x6008  | arr[0][2] | ?                      |
| 0x7000  | arr[1][0] | ?                      |
| 0x7004  | arr[1][1] | ?                      |
| 0x7008  | arr[1][2] | ?                      |

### 指標陣列（陣列裡的元素是指標）
```c
int* a[3];         // 陣列裡的每個元素都是 int*
int** pa = a;      // 指向陣列裡的元素 → int** // a 退化成 &a[0]
int*** c = &pa;  // c 指向 pa

a[0] = malloc(sizeof(int) * 5);  // 每個元素又指向一個 int 陣列
a[0][0] = 10; // 等價pa[0][0] = 10
c[0][0][0]   // 最終等於 a[0][0] → 10
```
* `int* a[3]` → 陣列裡的每個元素都是 int*
* `int** pa` → 指向這個陣列裡的指標元素
* a指標陣列
* pa是pointer to pointer
* `pa[i][j] ≡ *(*(pa + i) + j)`
* 因為陣列a會退化成0x1000，a[0] → 0x2000（heap 開始地址）
* a[0][0] → *(a[0] + 0) → *(0x2000) → 值 = 10
* pa[0] → *(pa + 0) → *(0x1000)
* *(0x1000) → a[0] 的值 → 0x2000（heap 地址）

Stack

| Address | Identify | Value              |
| ------- | -------- | ------------------ |
| 0x1000  | a        | 0x2000 (a[0])      |
| 0x1008  |         | 0x0000 (a[1] 尚未指向) |
| 0x1010  |        | 0x0000 (a[2] 尚未指向) |
| 0x1018  | pa       | 0x1000 (指向 a[0])   |

Heap

| Address | Identify | Value |
| ------- | -------- | ----- |
| 0x2000  | a[0][0]  | 10    |
| 0x2004  | a[0][1]  | ?     |
| 0x2008  | a[0][2]  | ?     |
| 0x200C  | a[0][3]  | ?     |
| 0x2010  | a[0][4]  | ?     |

* 用法對應 LeetCode 的 2D array：
```c
int** result = malloc(sizeof(int*) * capacity);  // result[i] 是 int*（每個三元組）
result[i] = malloc(sizeof(int) * 3);            // malloc 真正的三元組
result[i][0] = nums[i];
```

### 2D array main建立指標 -> func(int ***a) malloc建立array在Heap 並回傳給 caller
```c
// main
int **arr = NULL;
func(&arr);  // 傳入 arr 的地址

// func
void func(int ***a) {
    *a = malloc(sizeof(int*) * 2);  // malloc 外層
    for(int i=0;i<2;i++)
        (*a)[i] = malloc(sizeof(int) * 3);  // malloc 每一列
    (*a)[0][0] = 42;
}
```
* main：只定義指標，未 malloc
* func input：`int*** a` → 可以 malloc 外層 pointer 給 caller
* 操作結果：main 的 `arr` 會指向 heap 上的 2D array
* 記憶體位置：外層和內層都在 heap

### 總整理
```c
int a;	// 單一變數
int *p;	// 指標
int a[5]; // array
int *a[5]; // array of pointer
int (*a)[5]; // pointer to array，input進func的形式
```
| Array 類型            | main 做什麼                | func input | pointer 層數 | 需 malloc 給 caller? |
| ------------------- | ----------------------- | ---------- | ---------- | ------------------ |
| Stack 1D            | arr[5] 初始化              | int* a     | 1          | ❌                  |
| Heap 1D             | int* p=NULL             | int** a    | 2          | ✅                  |
| Stack 2D            | arr[2][3] 初始化           | int a[][3] | 2D pointer | ❌                  |
| Heap 2D             | int** arr = malloc(...) | int** a    | 2          | ❌（已 malloc）        |
| Heap 2D + malloc 回傳 | int** arr=NULL          | int*** a   | 3          | ✅                  |

## string and pointer 字串與指標
### char *str → func(char *s)，指標（pointer to char）
```c
// main
char *str = "dog";
str[0] = 'D'; // 無法更改（UB）

// func
void func(char *s);

/*
Stack
str ──► 0x3000

RODATA
0x3000  d o g \0
*/
```
* `"dog"` 在 rodata（唯讀資料區）
* `str` 在 stack
* 本體是 指標
* 不可改內容（Undefined Behavior）

### char str[] → func(char *s)，char array（陣列）
```c
// main
char str[] = "dog";
str[0] = 'D'; // 合法
func(str);

// func
void func(char *s) {
    s[0] = 'D';
}

/*
Stack
str[0] = 'd'
str[1] = 'o'
str[2] = 'g'
str[3] = '\0'
*/
```
* 字串內容在 stack
* 本體是 陣列
* 傳入 func 時 退化成 char*
* 可以改內容
* 只要宣告時有 `[]`，本體一定是 array

### char *str = malloc(...) → func(char *s)，指標（指向 heap 上的 char array）
```c
// main
char *str = malloc(4);
strcpy(str, "dog");

/*
Stack
str ──► 0x5000

Heap
0x5000  d o g \0
*/
```
* `str` 在 stack
* 字串內容在 heap
* 本體仍然是 指標
* 可以改內容
* 需要 `free(str)`

### static char str[] / global char str[]，char array
```c
static char str[] = "dog";
// or
char str[] = "dog";  // global

/*
Data segment
d o g \0
*/
```
* 字串內容在 data segment
* 本體是 陣列
* 不在 stack、不在 heap
* 可以改內容

### char *str[] → func(char **s) 本體是：指標陣列（array of char*)
```c
// main
char *str[] = {"cat", "dog"};
func(str);

// func
void func(char **s);

/*
Stack
str[0] ──► 0x3000
str[1] ──► 0x3010

RODATA
0x3000  c a t \0
0x3010  d o g \0
*/
```
* `str` 本體在 stack
* 每個元素是 `char*`
* 指向的字串在 rodata
* 本體是 array
* 傳入 func 時退化成 `char** `
* 不可改字串值

### 總整理

| 宣告                   | 本體    | 字串在哪   |
| -------------------- | ----- | ------ |
| `char *s = "dog"`    | 指標    | rodata |
| `char s[] = "dog"`   | array | stack  |
| `char *s = malloc()` | 指標    | heap   |
| `static char s[]`    | array | data   |
| `char *s[] = {...}`  | 指標陣列  | rodata |

> 宣告看「[] 在哪」，使用看「退化後是什麼」

## reference 引用
```cpp
int b = 10;
int &ref = b; // 此時ref等同b這個變數  // 此寫法不是縮寫
```
- call by reference 是 call by pointer的捷徑
- call by call by pointer 是 call by reference的原理
- 因為call by pointer比較複雜，所以使用call by referece，以swap舉例
```cpp
// call by reference
int main()
{
    int a = 10, b = 20;
    cout << a << " " << b << n";
    cout << &a << n";
    swap(a, b);
    cout << a << " " << b << n";
}
void swap(int & x, int &y)
{
    cout << &x << n";
    int temp = x;
    x = y;
    y = temp;
}
```
## c malloc & c++ new
```cpp
// malloc: C 語言函式，不會呼叫建構子
int* arr1 = (int*)malloc(5 * sizeof(int));
free(arr1);

// new: C++ 運算子，會呼叫建構子
int* arr2 = new int[5];
delete[] arr2;

// 以上宣告的是array [0, 0, 0, 0, 0]
```
- malloc
    - 給左邊identifier的value一個地址
    - 那個地址在Heap上取得一段指定大小的連續記憶體
    - malloc 經常用來建立C陣列的array
    - 用malloc建立陣列的優點是可以在程式跑的過程中決定大小
    - 看不懂就列出`|address|indentifier|value|`
- Python：list 幾乎就是日常用的主要容器
- C：array 最常用，linked list 偶爾用
- C++：vector 幾乎取代了大部分需要 list 的情況，真正的 linked list (std::list) 很少用

### leetcode15 result 的用法
```c
int** result = (int**)malloc(sizeof(int*) * 5); 
// result = [[], [], [], [], [],]

result[*returnSize] = (int*)malloc(sizeof(int) * 3); 
// result = [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3],]
// result是5x3矩陣，5個row，3個column

result[*returnSize][0] = nums[i]; 
result[*returnSize][1] = nums[left]; 
result[*returnSize][2] = nums[right];
```
```c
int** result = (int**)malloc(sizeof(int*) * 5); 
// 地址分配在result這個identifier的value
```
Stack（指標本身）
| address | identifier | value |
| ------- | ---------- | ----- |
| 0x080   | result     | 0x100 |

Heap（5 個 int*）
| address | element   | value |
| ------- | --------- | ----- |
| 0x100   | result[0] | ?     |
| 0x108   | result[1] | ?     |
| 0x110   | result[2] | ?     |
| 0x118   | result[3] | ?     |
| 0x120   | result[4] | ?     |

```c
result[0] = (int*)malloc(sizeof(int) * 3);
// 地址分配在result[0]這個identifier的value

result[0][0] = 1;
result[0][1] = 2;
result[0][2] = 3;
```
| address | element   | value |
| ------- | --------- | ----- |
| 0x080   | result     | 0x100 |
| 0x100   | result[0] | 0x200     |
| 0x108   | result[1] | ?     |
| 0x110   | result[2] | ?     |
| 0x118   | result[3] | ?     |
| 0x120   | result[4] | ?     |
| 0x200   | result[0][0] | 1     |
| 0x204   | result[0][1] | 2     |
| 0x208   | result[0][2] | 3     |

- 最後因為是 int** threeSum，所以return result的value 0x100

## memory 記憶體
### 記憶體區域總覽
```
+-----------------------+
| Code Segment          | <- 程式碼
+-----------------------+
| RO Data / Const       | <- const 變數、字串
+-----------------------+
| Data Segment          | <- 全域 / static 變數
+-----------------------+
| Heap                  | <- new / malloc 動態分配，額外增加的空間，只要是指標就能使用
+-----------------------+
| Stack                 | <- func內變數、參數
+-----------------------+
```

| 區域                     | 存放對象             | 生命週期                     | 常用語法 / 函式                          |
| ----------------------- | ---------------- | ------------------------ | ---------------------------------- |
| **Stack（堆疊）**            | 函式內的局部變數、參數、回傳地址 | 隨函式呼叫/結束自動分配與釋放          | `int x = 5;`、`char arr[10];`       |
| **Heap（動態記憶體區）**            | 動態分配物件 / 陣列      | 直到 `delete` / `free` 才釋放 | `new` / `delete`、`malloc` / `free` |
| **Data Segment (靜態區)**      | 全域變數、static 變數   | 程式啟動到結束                  | `int g = 10;`、`static int s = 5;`  |
| **Code Segment (程式碼區)**              | 程式本身的機器碼         | 程式啟動到結束                  | 只讀，不可改寫程式碼                         |
| **常數區 (RO Data)**                    | `const` 變數、字串常數，不可更改  | 程式啟動到結束                  | `const int c = 5;`、`"Hello"`       |

### Stack 詳細

* 優點：分配快速、自動管理
* 缺點：大小有限，過大可能造成 stack overflow
* 用法：

```cpp
void func() {
    int x = 10;      // 存在 stack
    char buf[100];   // 存在 stack
}
```

### Heap 詳細

* 優點：大小彈性，可動態控制生命週期
* 缺點：分配慢，需要手動釋放，否則會記憶體洩漏
* 用法：

```cpp
// C++ 語法
int* p = new int(5);      // 分配單一 int
int* arr = new int[10];   // 分配陣列
delete p;                 // 釋放單一 int
delete[] arr;             // 釋放陣列

// C 語法
int* p2 = (int*) malloc(sizeof(int) * 10);
free(p2);
```

### Data Segment / 靜態區 / 全域 static 變數
```cpp
class Example {
public:
    static int staticVar;  // 宣告一個「靜態成員變數」
};

Example::staticVar = 300;  // 可直接透過類別名稱存取
Example a, b;
a.staticVar = 400;          // 也可透過物件名，但其實是同一個變數
cout << b.staticVar;        // 會輸出 400
```

```cpp
int g = 100;        // 全域變數 -> Data Segment
static int s = 50;  // static 變數 -> Data Segment

void main() {
    int x = 10;      // 存在 stack
    char buf[100];   // 存在 stack
}
```

* 全域變數、static 變數會在程式啟動時分配
* 程式結束自動釋放

### Code Segment（程式碼區）

```cpp
void func() {
    // 函式指令儲存於 code segment
}
```

* 儲存程式機器碼
* 通常不可修改

### 常數區（只讀資料）

```cpp
const int c = 10;      // 儲存在常數區
const char* str = "Hello";  // 字串常數 -> 常數區
```

* 儲存不可變的常數
* 防止程式修改

### 為什麼一定要用heap
```cpp
Stack:
enqueue() {
  Node newNode  --> 函式結束(只要return一次)就消失
}

Heap:
enqueue() {
  Node* newNode = new Node  --> 永遠存在
}
```

### 我如果都全域宣告，是否就能避免使用指標(heap)?
```c
int data = 10;   // 全域變數

void func() {
    data = 20;   // 直接改！
}

// 這裡就不需要用：
void func(int *p) {
    *p = 20;
}
```
在小型程式，很多人會為了簡單直接用全域變數取代指標傳遞

風險：
- 無法重複利用函式（失去模組化）：
假設
```c
void sort() {
    // sort global array
}

// 這只能排序你那個全域陣列，但如果你改寫成：
void sort(int *arr, int size) {
    // sort 任何傳進來的陣列
}
```
- 可讀性與維護性差：如果程式有 10 個函式都在改 `global_data`，誰改過、何時改的，很難追蹤
- 執行緒安全（Thread Safety）
多執行緒同時操作全域變數會發生衝突（race condition），使用區域變數或用指標傳遞資料能避免互相干擾

## typedef vs. typedef stuck vs. stuck
- `typedef`定義宣告名稱
```c
typedef unsigned int u32;

u32 a = 100;   // 等於 unsigned int a = 100;
```
```c
struct Point {
    int x;
    int y;
};

struct Point p1;  // 必須加 struct

typedef struct Point {
    int x;
    int y;
} Point;

Point p2;  // 不需要寫 struct
```
| 寫法                                     | 宣告變數方式           | 
| -------------------------------------- | ---------------- |
| 只用 `struct node`                       | `struct node a;` |
| 加上 `typedef struct node { ... } Node;` | `Node a;`        |

| 名稱                         | 說明                   |
| -------------------------- | -------------------- |
| `struct node`              | 原始結構體型別名稱            |
| `typedef struct node Node` | 幫這個型別取個簡短名字 `Node`   |
| `Node`                     | 就是 `struct node` 的別名 |

## 面試常見問題
### Swap Function 差別 (C 語言)
為什麼要呼叫指標swap才能work?
```cpp
#include <stdio.h>

// call by value -> 無法交換
void swap1(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

// call by pointer -> 可以交換
void swap2(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 5, y = 10;
    swap1(x, y);
    printf("After swap1: x=%d y=%d\n", x, y); // 不會變

    swap2(&x, &y);
    printf("After swap2: x=%d y=%d\n", x, y); // x=10 y=5
}
```
A：參考c記憶體區域，呼叫值僅在swap函數內生效，僅在stack層生效，return後兩個數值又回歸原本的值，要呼叫指標才能更改heap層的數值

### C: `i++` `++i` 差異，python沒有
```c
// 後置遞增
int i = 0;
value = i++; // value = 0, i = 1

int i = 0;
value = ++i; // value = 1, i = 1

// 沒賦予變數沒差
i++;
++i;
```

### 實做 C str所有函式
```c
#include <stdio.h>

size_t my_strlen(const char *str) {
    size_t len = 0;
    while (str[len] != '\0') {
        len++;
    }
    return len;
}

char* my_strcpy(char *dest, const char *src) {
    char *p = dest;
    while (*src != '\0') {
        *p++ = *src++;
    }
    *p = '\0';
    return dest;
}

int my_strcmp(const char *s1, const char *s2) {
    while (*s1 && (*s1 == *s2)) {
        s1++;
        s2++;
    }
    return *(unsigned char*)s1 - *(unsigned char*)s2;
}

char* my_strcat(char *dest, const char *src) {
    char *p = dest;
    while (*p) p++;          // 移到 dest 的結尾 '\0'
    while (*src) *p++ = *src++;
    *p = '\0';
    return dest;
}

int main() {
    char str1[50] = "Hello";
    char str2[] = ", world!";
    char str3[50];
    
    printf("=== Testing my_strlen ===\n");
    printf("Length of '%s' = %zu\n\n", str1, my_strlen(str1));

    printf("=== Testing my_strcpy ===\n");
    my_strcpy(str3, str1);
    printf("Copied string: '%s'\n\n", str3);

    printf("=== Testing my_strcmp ===\n");
    char a[] = "abc";
    char b[] = "abd";
    printf("Compare '%s' and '%s' = %d\n", a, b, my_strcmp(a, b)); // -1
    printf("Compare '%s' and '%s' = %d\n", a, a, my_strcmp(a, a)); // 0
    printf("Compare '%s' and '%s' = %d\n\n", b, a, my_strcmp(b, a)); // 1

    printf("=== Testing my_strcat ===\n");
    my_strcat(str1, str2);
    printf("Concatenated string: '%s'\n", str1);

    return 0;
}
```

### C手刻vector
```c
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int *data;
    int size;
    int capacity;
} Vector;

// 初始化
void init(Vector *v, int capacity) {
    v->data = (int*)malloc(sizeof(int) * capacity);
    v->size = 0;
    v->capacity = capacity;
}

// 釋放記憶體
void free_vector(Vector *v) {
    free(v->data);
    v->size = 0;
    v->capacity = 0;
}

// push_back
void push_back(Vector *v, int val) {
    if (v->size == v->capacity) {
        v->capacity *= 2;
        v->data = (int*)realloc(v->data, sizeof(int) * v->capacity);
    }
    v->data[v->size++] = val;
}

// erase idx
void erase(Vector *v, int idx) {
    if (idx < 0 || idx >= v->size) return;
    for (int i = idx; i < v->size - 1; i++)
        v->data[i] = v->data[i+1];
    v->size--;
}

// resize
void resize(Vector *v, int new_size) {
    if (new_size > v->capacity) {
        v->capacity = new_size;
        v->data = (int*)realloc(v->data, sizeof(int) * v->capacity);
    }
    v->size = new_size;
}

// 印出 vector
void print_vector(Vector *v) {
    printf("[");
    for (int i = 0; i < v->size; i++) {
        printf("%d", v->data[i]);
        if (i != v->size - 1) printf(", ");
    }
    printf("]\n");
}

int main() {
    Vector v;
    init(&v, 2);

    push_back(&v, 10);
    push_back(&v, 20);
    push_back(&v, 30);
    print_vector(&v);  // [10, 20, 30]

    erase(&v, 1);
    print_vector(&v);  // [10, 30]

    resize(&v, 5);
    print_vector(&v);  // [10, 30, 0, 0, 0]

    free_vector(&v);
    return 0;
}
```

# 韌體0x10
## 預處理器 (Preprocessor)：`#define`聲明
>用預處理指令 `#define` 聲明一個常數，用以表示一年中有多少秒 (忽略閏年問題)
```c
#define SECOND_PER_YEAR (365 * 24 * 60 * 60)UL
````

* `#define` 語法基本知識（不能以分號結束、括號的使用）
* 命名習慣：大寫 + 底線
* 預處理器會計算常數運算式
* 在 16-bit 系統上可能整數溢位，因此需要加 `L`
* 使用 `UL`（unsigned long）避免符號與大小問題

| 型態名稱    | 關鍵字            | 常見大小 (32/64-bit) | printf 格式化符號 |
| ------- | -------------- | ---------------- | ------------ |
| 字元      | char           | 1                | %c           |
| 無號字元    | unsigned char  | 1                | %u           |
| 短整數     | short          | 2                | %d           |
| 無號短整數   | unsigned short | 2                | %u           |
| 整數      | int            | 4                | %d           |
| 無號整數    | unsigned int   | 4                | %u           |
| 長整數     | long           | 4/8              | %ld          |
| 無號長整數   | unsigned long  | 4/8              | %lu          |
| 單精度浮點數  | float          | 4                | %f           |
| 倍精度浮點數  | double         | 8                | %f           |
| 長倍精度浮點數 | long double    | 12/16            | %Lf          |

> 整數常數預設為 `int`，浮點數常數預設為 `double`。
> 若要避免溢位或明確指定型態，需加上後綴字：

| 後綴    | 意義        |
| ----- | --------- |
| U/u   | unsigned  |
| L/l   | long      |
| LL/ll | long long |
| F/f   | float     |

範例：
```c
unsigned int a = 10U;
long b = 10L;
float c = 3.14F;
long double d = 2.06L;
unsigned long e = 25UL;
```

## 預處理器 (Preprocessor)：Macro 巨集 文字取代功能
>寫一個標準 `MIN` 巨集，輸入兩個參數並回傳較小的那個。
```c
#define MIN(X, Y) ((X) >= (Y) ? (X) : (Y))
```

* `#define` 用於巨集的基礎知識
* 三元運算子 `?:` 的使用
* 必須在巨集參數外加括號以防副作用

副作用範例：
```c
least = MIN(*p++, b);

// 會展開為：
// *p 可能被遞增一次或兩次
least = ((*p++) >= (b) ? (*p++) : (b));

// 解法：
int val = *p++;
least = MIN(val, b);
```

## 預處理器 (Preprocessor)：`#error`的作用
```c
#error message
```

在編譯時輸出錯誤訊息並中斷編譯
範例：
```c
#include <stdio.h>
//#define NUM 3

int main(void) {
    #ifndef NUM  // if not defined
        #error NOT define NUM
    #endif
    
    printf("NUM = %d", NUM);
    return 0;
}
```

## 無窮迴圈 (Infinite loops)
嵌入式系統常見的無窮迴圈寫法：
```c
while (1) {
    /* statement */
}

for (;;) {
    /* statement */
}
```

## 資料宣告 (Data declaration)

| 類型說明（中文）                                  | 類型說明（英文）                                                                                  | 宣告語法                 |
| ----------------------------------------- | ----------------------------------------------------------------------------------------- | -------------------- |
| 一個整數                                      | An integer                                                                                | `int a;`             |
| 一個指向整數的指標                                 | A pointer to an integer                                                                   | `int *a;`            |
| 一個指向指標的指標，它指向的指標是指向一個整數                   | A pointer to a pointer to an integer                                                      | `int **a;`           |
| 一個有 10 個整數的陣列                             | An array of 10 integers                                                                   | `int a[10];`         |
| 一個有 10 個指標的陣列，該指標是指向一個整數                  | An array of 10 pointers to integers                                                       | `int *a[10];`        |
| 一個指向有 10 個整數陣列的指標                         | A pointer to an array of 10 integers                                                      | `int (*a)[10];`      |
| 一個指向函式的指標，該函式有一個整數參數且回傳一個整數               | A pointer to a function that takes an integer as an argument and returns an integer       | `int (*a)(int);`     |
| 一個有 10 個指標的陣列，該指標指向一個函式，該函式有一個整數參數並回傳一個整數 | An array of ten pointers to functions that take an integer argument and return an integer | `int (*a[10])(int);` |

## static
`static` 有三種用途：
* 函式內的變數：函式結束後仍保留數值
* 模組內的全域變數：僅該檔案可存取
* 函式：僅限該檔案可呼叫

### `static` vs. `extern`
這是 **變數與函式作用域 (scope)** 的重要概念。

| 關鍵字        | 用途   | 範圍 / 壽命                | 使用場合          |
| ---------- | ---- | ---------------------- | ------------- |
| **static** | 靜態   | 只在定義的檔案或函式內可見（不能被外部使用） | 限制作用範圍、防止外部干擾 |
| **extern** | 外部宣告 | 告訴編譯器這個變數或函式在別的檔案定義    | 多檔案共用全域變數或函式  |

```c
// file1.c
static int count = 0;  // 只在 file1.c 有效

void add() {
    count++;
}

// file2.c
extern void add();     // OK，宣告函式
// printf("%d", count); // 無法使用 static 變數
```


```c
// file1.c
int value = 10;  // 定義

// file2.c
extern int value;  // 宣告
printf("%d", value);  // 可讀取
```
| 關鍵字    | 儲存位置  | 作用範圍 | 可否被外部使用 |
| ------ | ----- | ---- | ------- |
| static | 全域變數區 | 檔案內  | ❌       |
| extern | 全域變數區 | 跨檔案  | ✅       |

## const
| 宣告| 意義 |舉例 |
| --- | --- | --- |
| `const int a;`        | 整數常數               |
| `int const a;`        | 整數常數               |
| `const int *a = &x;`       | 指向整數常數的指標 (整數值不可改)，綁住`*`a對指標來說是value|```*a = 15; 不能改變 a 所指的內容，a = &y; 可以改變 a 指向哪裡``` |
| `int *const a;` =`int *a`+`const`      | 常數指標 (地址不可改)       |
| `const int *const a;` | 皆不可改               |

> 小訣竅：從右往左解釋

## volatile
`volatile` 告訴編譯器：
>「這個變數可能在程式看不見的地方被改變，不要優化讀寫。」
如果沒有 `volatile`，編譯器可能會把變數讀一次放在暫存器，後續運算都用暫存器的值，可能錯過外部變化。

常見用途：
1. 週邊裝置暫存器
2. ISR 可存取的變數
3. 多執行緒共享變數

進階問題：
| 問題                           | 答案              |
| ---------------------------- | --------------- |
| 可同時為 `const` 和 `volatile` 嗎？ | 可以。例如唯讀暫存器      |
| 指標可為 `volatile` 嗎？           | 可以，例如 ISR 修改指標  |
| 下列函式有何錯誤？                    | 語義錯誤，應先存區域變數再運算 |

```c
int square(volatile int *ptr) {
    int temp = *ptr;
    return temp * temp;
}
```
```c
#include <stdio.h>
#include <stdbool.h>

bool button_pressed = false;
volatile bool v_button_pressed = false;  // 用 volatile

int main() {
    // 模擬硬體中斷改變按鈕狀態
    v_button_pressed = true;   // 假設中斷改變這個值
    button_pressed = true;     // 假設中斷改變這個值

    // 沒用 volatile 的情況
    while (!button_pressed) {  // 編譯器可能認為 button_pressed 永遠是 false，優化成無窮迴圈
        // do nothing
    }

    // 用 volatile 的情況
    while (!v_button_pressed) { // 每次都重新讀取，能正確跳出迴圈
        // do nothing
    }

    printf("Button pressed!\n");
    return 0;
}
```
* `button_pressed` 可能被編譯器優化掉，讀一次就不再讀。
* `v_button_pressed` 因為 `volatile`，每次迴圈都會重新讀取記憶體。

## Interrupt Service Routine ISR
```c
__interrupt double compute_area(double radius)
{
    double area = PI * radius * radius;
    printf("\nArea=%f", area);
    return area;
}
```

錯誤原因：
- ISR 是硬體觸發的函式，像是按鈕按下、計時器溢位等事件
- ISR 不能有參數與回傳值
- 不建議使用浮點運算
- 不建議在 ISR 中使用 `printf`（可重入性問題）

正確 ISR 範例（C 語法簡化）
```c
#include <stdio.h>
#include <stdint.h>

volatile uint16_t timer_flag = 0;

void __interrupt timer_ISR(void) {
    timer_flag = 1;  // ISR 簡單操作，設定 flag
}

int main() {
    // 模擬主程式
    while (1) {
        if (timer_flag) {
            printf("Timer triggered!\n");
            timer_flag = 0;
        }
    }
    return 0;
}
```
* ISR 只做「簡單、快速」的操作，例如設定 flag
* 主程式讀 flag 去做複雜運算或輸出

### 中斷 Interrupt
中斷（Interrupt）＝ 一個「打斷CPU」的事件

- 鍵盤按下一個鍵 → 產生中斷 → CPU跳去執行「鍵盤處理程式」
- 定時器時間到 → 產生中斷 → CPU執行「定時器中斷處理程式」

8051 的中斷機制讓系統可以即時處理特定事件，而不必「一直輪詢 (polling)」去檢查事件是否發生

| 中斷名稱      | 含義         | 觸發方式            | 向量位址    |
| --------- | ---------- | --------------- | ------- |
| **IE0**   | 外部中斷 0     | 可設成電平觸發或邊緣觸發    | `0003H` |
| **TF0**   | 定時器 0 溢出中斷 | Timer0 overflow | `000BH` |
| **IE1**   | 外部中斷 1     | 可設成電平觸發或邊緣觸發    | `0013H` |
| **TF1**   | 定時器 1 溢出中斷 | Timer1 overflow | `001BH` |
| **RI/TI** | 串列通訊中斷     | 接收或傳送完成         | `0023H` |

## 位元操作 (Bit Operation)
- bitwise manipulation
    - 往右邊8bit = 除以2的8次方
    - 往左邊8bit = 乘以2的8次方
    - 因為位移比乘法快很多，可以切換到bitwise的操作
    - 把bit設為0，跟0做AND
    - 把bit設為1，跟1做OR
    - 微分做xor，有變化是1、沒變化是0

設定與清除 bit 3 (bit3 = 0000 1000 = 0x08)：
```c
a = a | 0x08;    // 設定a的bit3 = 1
a = a & (~0x08); // 清除a的bit3 = 0
```
更好的可移植寫法：
```c
#define BIT3 (0x1 << 3)

void set_bit3(void) { a |= BIT3; }
void clear_bit3(void) { a &= ~BIT3; }
```

> 需用指標轉型成 `int *` 才能存取指定位址

| 運算子 | 名稱 | 說明 | 範例 |
| - | - | - | - |
| `&` | AND（且）| 兩邊都為 1 才是 1 | `1100 & 1010 = 1000` | 
| `\|` | OR（或）| 只要有一邊是 1 即為 1| `1100 \| 1010 = 1110` |
| `^`  | XOR（互斥或） | 不同為 1，相同為 0 | `1100 ^ 1010 = 0110` |
| `~`  | NOT（反相）| 0→1、1→0 | `~0101 = 1010` |
| `<<` | 左移 | 乘以 2ⁿ  | `0001 << 2 = 0100`   |
| `>>` | 右移 | 除以 2ⁿ  | `1000 >> 3 = 0001`   |

## `unsigned`，求result
```c
void foo(void)
{
    unsigned int a = 6;
    int b = -20;
    (a + b > 6) ? puts(">6") : puts("<=6");
}
```

輸出：
```
>6
```
原因：`signed` + `unsigned` → 轉為 `unsigned`，導致 `b` 被轉為非常大的正數。

## `unsigned`
以下程式何者有錯？
```c
unsigned int zero = 0;
unsigned int compzero = 0xFFFF;
```

不同平台整數長度不同，在 32-bit 系統上此值為 `0x0000FFFF`
正確寫法：
```c
unsigned int compzero = ~0;
```

## 動態記憶體分配 (Dynamic Memory Allocation)
嵌入式系統中使用動態配置的問題：

* Heap 空間有限
* 碎片化 (fragmentation)
* 無法保證即時性
* 無法輕易釋放導致記憶體洩漏

## 存取固定記憶體位址
```c
int main() {
    int *ptr = (int *)0x67a9;
    *ptr = 0xaa55;
    return 0;
}
```

## 遞增運算子 Increment Operator
```c
int a = 5, b = 7, c;
c = a+++b;

// 等價於：
c = (a++) + b;
```

結果：
```
a = 6;
b = 7;
c = 12;
```
* "maximum munch" 原則：盡可能解析最長合法 token

## typedef
```c
#define dPS struct s *
typedef struct s * tPS;
```

**建議使用 typedef**

**原因：**

```c
dPS p1, p2; // 展開為 struct s *p1, p2; (p2 不是指標)
tPS p3, p4; // 皆為 struct s * 類型
```

`typedef` 更安全且語義清楚

## 8051
### 8051 是什麼？
8051是 Intel 在1980年推出的一款8位元微控制器（Microcontroller, MCU）。
它是一顆「小型電腦晶片」，內部整合了 CPU、記憶體、I/O 埠、計時器與中斷控制器等模組。
> 8051 = 一顆可以執行程式、控制外部設備的「迷你電腦」

### 8051 的主要組成架構
| 模組| 功能說明 |
| - | - |
| CPU（Central Processing Unit） | 控制與運算核心|
| ROM（程式記憶體）| 儲存使用者程式（通常 4KB）       |
| RAM（資料記憶體） | 儲存變數（128 Bytes）            |
| I/O Ports | 4 組（P0~P3），可連接 LED、按鍵、感測器等 |
| Timer/Counter | 2 組計時器（Timer0、Timer1）      |
| Serial Port | 串列通訊埠，可做 UART 通訊           |
| Interrupt System| 支援 5 個中斷源（外部、Timer、Serial） |
| Oscillator & Clock | 提供時脈訊號（通常是 12MHz）|

### 8051 與一般電腦的差別
| 項目   | 微控制器（8051）            | 一般電腦（PC）            |
| ---- | --------------------- | ------------------- |
| 構成   | 單晶片整合 CPU、記憶體、I/O     | CPU、RAM、硬碟分開        |
| 目的   | 控制特定裝置（嵌入式系統）         | 通用計算                |
| 執行環境 | 實時、無作業系統              | 有 OS（Windows/Linux） |
| 儲存容量 | 幾 KB ～ 幾十 KB          | 幾十 GB 起跳            |
| 範例   | 洗衣機控制板、微波爐、電風扇、車用 MCU | 筆電、伺服器              |

### 8051 的記憶體架構
8051 採用「**哈佛架構（Harvard Architecture）**」：
程式記憶體（ROM）與資料記憶體（RAM）是**分開**的。

```
        ┌───────────────┐
        │ ROM (程式區)  │ ← 儲存程式碼
        ├───────────────┤
        │ RAM (資料區)  │ ← 儲存變數、堆疊
        └───────────────┘
```

### 常見功能介紹（重點複習）

| 功能                         | 簡介              | 範例           |
| -------------------------- | --------------- | ------------ |
| **I/O 控制**                 | 可控制 LED、按鍵輸入    | `P1 = 0xFF;` |
| **Timer/Counter**          | 定時或計數外部事件       | 計算時間、週期性中斷   |
| **Interrupt（中斷）**          | 即時處理事件          | 按鍵觸發 ISR     |
| **UART 串列通訊**              | 與 PC 或其他 MCU 溝通 | 傳送資料         |
| **位元操作 (Bit-addressable)** | 直接操作單一位元        | `SETB P1.0`  |

### 常見面試 / 口試題目整理

| 類型        | 常見問題                   | 你可以怎麼回答                                           |
| --------- | ---------------------- | ------------------------------------------------- |
| **基本概念**  | 什麼是 8051？              | 一種 8-bit 微控制器，內含 CPU、RAM、ROM、I/O、Timer、UART、中斷系統。 |
| **架構理解**  | 8051 有幾個 I/O port？     | 4 個：P0、P1、P2、P3。                                  |
| **記憶體**   | RAM 與 ROM 的大小？         | 128 Bytes RAM、4KB ROM（標準版本）。                      |
| **中斷**    | 8051 有幾個中斷來源？          | 5 個中斷源（IE0、TF0、IE1、TF1、Serial）。                   |
| **Timer** | Timer0 和 Timer1 有什麼作用？ | 可作為計時器或事件計數器。                                     |
| **應用**    | 給一個 8051 實際應用例子？       | 電子時鐘、LED 閃爍、溫度感測控制器。                              |
| **組語題**   | MOV A, #55H 代表什麼？      | 將立即數 55H 傳入累加器 A。                                 |
| **中斷題**   | ISR 是什麼？               | Interrupt Service Routine，中斷服務程式。                 |

### 8051範例程式
```c
#include <reg51.h>

// 基礎延遲
void delay() {
    unsigned int i, j;
    for(i = 0; i < 1000; i++)
        for(j = 0; j < 120; j++);
}

// UART：傳送單一字元
void uart_send(char c) {
    SBUF = c;
    while(TI == 0);
    TI = 0;
}

// UART：傳送字串
void uart_send_string(char *s) {
    while(*s) {
        uart_send(*s);
        s++;
    }
}

// Timer0 中斷：LED 翻轉
void Timer0_ISR(void) interrupt 1 {
    P1_0 = ~P1_0;
}

// 外部中斷 INT0：亮 LED
void External_INT0(void) interrupt 0 {
    P1_0 = 0;
}

// LED 閃爍
void demo_led_blink() {
    while(1) {
        P1 = 0x00;
        delay();
        P1 = 0xFF;
        delay();
    }
}

// 點亮單一 LED（P1.0）
void demo_led_single() {
    P1 = 0xFF;
    P1_0 = 0;
    while(1);
}

// 按鍵控制 LED（P3.2）
void demo_button_led() {
    while(1) {
        if(P3_2 == 0)
            P1_0 = 0;
        else
            P1_0 = 1;
    }
}

// Timer0 週期中斷
void demo_timer0_interrupt() {
    TMOD = 0x01;
    TH0  = 0xFC;
    TL0  = 0x66;
    ET0  = 1;
    EA   = 1;
    TR0  = 1;
    while(1);
}

// UART 傳送字串
void demo_uart() {
    SCON = 0x50;
    TMOD = 0x20;
    TH1  = 0xFD;
    TR1  = 1;

    while(1) {
        uart_send_string("Hello\n");
        delay();
    }
}

// 外部中斷 INT0
void demo_ext_int0() {
    EA  = 1;
    EX0 = 1;
    IT0 = 1;
    while(1);
}

// 軟體 PWM（簡易）
void demo_pwm() {
    while(1) {
        P1_0 = 1;
        _nop_(); _nop_();
        P1_0 = 0;
        _nop_(); _nop_();
    }
}

void main() {
    // 根據需要啟用其中一個功能：

    // demo_led_blink();
    // demo_led_single();
    // demo_button_led();
    // demo_timer0_interrupt();
    // demo_uart();
    // demo_ext_int0();
    // demo_pwm();

    // 預設跑 LED 閃爍
    demo_led_blink();
}
```

# Python
## Python 常用的內建函式語法：
### `print` 
```python
i, j, k = 3, 4, 5
print("i")            #輸出i
print(i)             #輸出3

# print 一次印多個數值
print(f"i={i}, j={j}, k={k}") #輸出i=3, j=4, k=5
print("i=", i, "j=", j, "k=", k)
print("i=" + str(i) + ", j=" + str(j) + ", k=" + str(k))
```

### `def` (要加冒號)，傳值呼叫

( )內為函式內的變數，python雖然沒有括號，在函式內空格還是要對整齊，最後return的值，是函式最後的輸出
```python
def main(a, b): 
    #程式碼
return  0  #return為這個函式的輸出
```
Python定義任何函式都用def，C++定義函式要依據回傳值決定
![004](https://hackmd.io/_uploads/SkYW0BHsxx.png)
leetcode 1.twoSum

```python
class Solution(object):
    def twoSum(self, nums, target):
        for i in range(len(nums)):
            for j in range(i+1, len(nums)):
                if nums[i] + nums[j] == target:
                    return i, j

nums = [2, 7, 11, 15]
target = 9
print(Solution.twoSum(1, nums, target))
```
### `return` vs `print`
retrun是func輸出的值，要用print印出來

### Python 讀取 Module，讀取同個資料夾內檔案名叫 `tool.py` 程式的四種方法
```python
import tool #第一種呼叫module法
print(tool.sum_mul(1, 2, 3, 4)) #要加.

import tool as t #第二種呼叫module法，改掉呼叫module的名稱
print(t.sum_mul(1, 2, 3, 4)) #要+.

from tool import sum_mul #第三種呼叫module法，指定呼叫某個def
print(sum_mul(1, 2, 3, 4))

from tool import * #第四種呼叫module法，全部呼叫，若主程式內有與module相同名稱的程式會有bug
print(sum_mul(1, 2, 3, 4))
```

### `if __name__ == "__main__":`，防止被引用時誤跑程式
```python
def sum_mul(a, b, c, d):
    return (a+b+c)*d

if __name__ == "__main__":
    print("直接執行時才會列印，可以防止被引用時執行")

if __name__ == "tool":
    print("被引用時才會列印")

# __name__是一個python內部的變數，當程式直接執行時會變__main__，被引入時會變「檔案名稱」
# 使用if __name__ == "__main__":是為了防止被引入時執行內部的程式
```

#### 範例
```python
def main():
    print("hello")

if __name__ == "__main__": #防止被引用時直接執行
    main()
```

### `map` 大量宣告 `int`
```python
# map(函式, 可迭代物件) 是一種簡潔的「批次運算」方式
map(int, …)
map(float, …)

num1 = "123"
num2 = "456"
result = num1 + num2
print(result)  # 輸出 "123456"，而不是整數相加的結果

num1 = int(num1)  # 將字符轉換為整數
num2 = int(num2)  # 將字符轉換為整數
result = num1 + num2
print(result)  # 輸出整數相加的結果，即 579
```

#### 用map一次對一個變數要用list外包
```python
num1 = "123"
num2 = "456"
num1 = list(map(int, [num1]))  #因為用list，所以是列表，值存在num1[0]
num2 = list(map(int, [num2]))  # 將字符轉換為整數並放入列表
result = num1[0] + num2[0]  # 從列表中提取整數值並相加

print(result)  # 輸出整數相加的結果，即 579

num1, num1 = map(int, [num1, num1]) # 用map的多重賦值特性，達成一次對一個變數不用list
result = num1 + num2
print(result)  # 輸出整數相加的結果，即 579
```

### `stored` 
```python
sorted(iterable(遞迴物), key=函數) # 有點像.sort
print(sorted([5, 3, 9, 1])) # [1, 3, 5, 9]
```

### `lambda` 匿名函式
- `lambda func`匿名函式：一行內建的小函式，可以在 `sorted()`、`map()`、`filter()` 等地方使用，不用額外`def`
- `lambda` 參數1, 參數2, ... : 表達式、運算結果

![003](https://hackmd.io/_uploads/B14NABHjex.png)
```python
add = lambda x, y: x + y
print(add(3, 5))  #  8

data = [('apple', 5), ('banana', 2), ('cherry', 8)]
sorted_data = sorted(data, key=lambda x: x[1])  # 按數字大小排序
print(sorted_data)

nums = [1, 2, 3, 4]
squared = list(map(lambda x: x ** 2, nums))
print(squared)  #  [1, 4, 9, 16]

nums = [1, 2, 3, 4, 5, 6]
even_nums = list(filter(lambda x: x % 2 == 0, nums))
print(even_nums)  #  [2, 4, 6]

from functools import reduce
nums = [1, 2, 3, 4]
product = reduce(lambda x, y: x * y, nums)
print(product)  #  24 (1*2*3*4)

data = ['apple', 'banana', 'cherry']
sorted_data = sorted(data, key=lambda x: x[1])  
# 用每個字串的 第 2 個字元 來排序
# ['banana', 'cherry', 'apple']
```

### 輸入以空格相間的列表
```python
user_input = input("請輸入一些文字: ")  #等待用戶輸入一行以空格分隔的數字或單詞
words = user_input.split()  #.split是將字串轉成list，"hello world" →["hello", "world"]
print(words)
for word in words:
    print(word) # 打印分割後的單詞列表
data = [int(x) if x.isdigit() else x for x in words]
print(data)
```

### 輸入多個資料 `input().split()` + `map(int, …)` + `list`
```python
x, y = map(int, input("輸入兩個整數（以空格分隔）: ").split())
print(f"{x},{y}")

numbers = list(map(int, input("輸入多個整數（以空格分隔）: ").split()))  #比上面多一個list
print(numbers)

floats = list(map(float, input("輸入多個浮點數（以空格分隔）: ").split()))
print(floats)

words = input("輸入多個字串（以空格分隔）: ").split()
print(words)
```

### enumerate
使迴圈變比較好寫，第一個i表示編號，第二個j表示值
```python
data = ['a', 'b', 'c', 'd', 'e']

for index, obj in enumerate(data):
    print(f"Index: {index}, Value: {obj}")

strs = ["flower","flow","flight"]
for i, char in enumerate(strs[0]):  # 以第一個flower為基準
            for word in strs:  # 依序比對所有字元的i=1、i=2、i=3等
                # 超出字串範圍，或字串不同，直接結束返回結果
                if i >= len(word) or word[i] != char:
                    return ans
```

### List Comprehension（列表生成式）
```python
squares = [x**2 for x in range(10)]
```
>用一行簡潔的語法產生新 list，常取代 for 迴圈。
輸入 (Input)： `range(10)`
輸出 (Output)： `[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]`
可加條件判斷，例如 `[x for x in range(10) if x % 2 == 0]`
效率高、語法簡潔

* Generator / yield（生成器）
```python
def gen():
    for i in range(3):
        yield i

for x in gen():
    print(x)
```
>建立可逐步產生值的迭代器，節省記憶體
輸入 (Input)：** 無
輸出 (Output)：** 依序輸出 `0, 1, 2`
`yield` 暫停函式狀態，下次繼續執行，有點像建立好一個list
適合大資料流，例如逐行讀檔

### Decorator（裝飾器）
```python
def timer(func):
    def wrapper():
        print("Start")
        func()
        print("End")
    return wrapper

@timer
def hello():
    print("Hello World")

hello()
```
>在不修改原函式的情況下，額外包裝功能
可以用在記錄執行時間、登入檢查、快取控制
輸入 (Input)： 呼叫 `hello()`
輸出 (Output)：
```
Start
Hello World
End
```

### Context Manager（上下文管理器）
```python
with open('file.txt', 'r') as f:
    data = f.read()
```
>自動處理資源開啟與釋放（例如檔案）。
輸入 (Input)： `'file.txt'`
輸出 (Output)： 讀取到的檔案內容字串
不需手動 `close()`
即使出錯也會自動釋放資源

## 數學有關的語法：
### 整數的大於、等於、小於
- 整數中 `i+1 >9` 同 `i>=9`
- 整數中 `10>9` 同 `10-1>=9`

### 除法取整數 `//`，除法取餘數 `%` 
- 除法取整數 `t = 10//3`
- 除法取餘數 `t = 10%3`

### 奇偶判斷，`x % 2 == 0`（例：x 10783）
```python
if x % 2 == 1:  # 奇數
if x % 2 == 0:  # 偶數
```

### 找數列中最大值 `max(list)`
```python
num = [(1,2.5),(1.5,3.2),(1.3,4.0),(2.2,1.8)]
y, z = max(num, key=lambda x:x[0])
print(y,z)
a, b = max(num, key=lambda x:x[1])
print(a, b)
```

### 累加縮寫 `a += b`
`a += b` 同 `a = a + b`

### 印小數點（`format`、`round`、`f"{:.2f}"`）
印到小數點第三位`print(f"{age:.3f}%")`

### 輸入變數後指定變數
```python
t = int(input("請輸入一個數字: "))  
name = input("請輸入你的名字: ")  
print("你好," + name)
```
常用在輸入指定變數後決定迴圈數量
```python
t = int(input()) #　int表示把值變成可計算
for case in range(1, t + 1):
```

### 兩數值交換
```python
c = a    # 口  ← A
a = b    # A   ← B
b = c    # B   ← 口

# 簡寫為
a, b = b, a
```
```python
a, b = b, a % b
```
![005](https://hackmd.io/_uploads/H19GASBieg.png)

### 歐幾里得找最大公因數（`math.gcd`）
- 歐幾里德演算法參考https://hackmd.io/@donglinwu/HyOMwBhfY
- 每次都會有三個數字，a, b, a%b，選其中最小的兩個繼續做，新a,新b,新a%新b，直到某a%某b = 0 為止
- 如 a=120, b=1512
- round1, a = 120, b = 1512,a%b = 120，此時120與1512的最大公因數跟1512與120的最大公因數相同
- round2, a = 1512,b = 120 ,a%b = 72，此時120與1512的最大公因數跟120與72的最大公因數相同
- round3, a = 120, b = 72, a%b = 48，此時120與1512的最大公因數跟72與48的最大公因數相同
- round4, a = 72, b = 48, a%b = 24，此時120與1512的最大公因數跟48與24的最大公因數相同
- round5, a = 48, b = 24, a%b = 0，此時120與1512的最大公因數同(48 ,24)，最大公因數是24
```python
a = 120
b = 1512
def find_gcd(a, b):
    while b:
        a, b = b, a % b
        print(f"a = {a},b = {b}")
    print(a)
    return a

find_gcd(a, b)
```

## 匯入外部函式：
### `matplotlib.pyplot`
```python
import matplotlib.pyplot as plt
plt.plot(x, y) # 繪製折線圖（連續的線條）
plt.stem(x, y) # 繪製桿狀圖（垂直線條，底部連接 x 軸，上方有圓點）
plt.bar(range(0, 256), y) # 繪製條形圖（每個區間以矩形表示）

b.imshow(image, cmap='gray') # 加入圖片image，gray是顯示灰階圖，沒這行不會有圖片

plt.figure(figsize=(width, height)) # 設置 Matplotlib 圖形的尺寸大小
plt.xlim([0, 12]) # 設一個大概的x範圍
plt.ylim([-60, 140])

plt.title(label) # 設置 Matplotlib 圖形的標題
plt.legend(labels) # 添加 Matplotlib 圖例，用於標識不同的數據序列或圖形
plt.xlabel("年資") # 設定x軸名稱
plt.ylabel("月薪(千)") 
plt.savefig('照片名稱') # 放在show前面就會儲存照片
plt.show() # 顯示 Matplotlib 圖形，將之前設置的圖形顯示出來

plt.figure() # 畫一張大圖放好幾個子圖
plt.suptitle(標題)

# 加入第一個子圖
plt.subplot(1, 2, 1) # 這個子圖要放在哪裡，plt.subplot(總共的row, 總共的column, 位子)
plt.axis('off') # xy軸不要出現
plt.imshow(A, cmap="gray") # 加入圖片A，gray是顯示灰階圖，沒這行不會有圖片

# 加入第二個子圖
plt.subplot(1, 2, 2)
plt.axis('off')
plt.imshow(B, cmap="gray")

plt.savefig(f'HW4_{filename1} and {filename2}')
plt.show()

'''
plt.subplot(2, 2, 1) # 左上角的子圖
plt.subplot(2, 2, 2) # 右上角的子圖
plt.subplot(2, 2, 3) # 左下角的子圖
plt.subplot(2, 2, 4) # 右下角的子圖
'''

# 使用 fig.add_subplot() 函數來添加子圖
for i in range(4):
    fig = plt.figure(figsize=(12, 8))
    for j in range(7):
        output_image = together[i][j]
        if j == 0:
            fig.add_subplot(n, m, 2)
            plt.imshow(output_image, cmap='gray')
            plt.title("{}\nSNR = {}".format(together_title[i], SNR(img, output_image)))
        else:
            fig.add_subplot(n, m, j + 3)
            plt.imshow(output_image, cmap='gray')
            plt.title("{}  SNR = {:.6f}".format(title[j - 1], SNR(img, output_image)))
        plt.xticks([])
        plt.yticks([])
    plt.savefig(os.path.join(output_directory, f'HW8_image_{together_title[i]}.jpg'))
    plt.show()
```

---

### `numpy` 
```python
import numpy as np

# 陣列（array）：

# 矩陣的標準用法
A = np.mat([
    [1, 1, 1, 1],
    [2, 2, 2, 2],
    [3, 3, 3, 3]
])  

# 用陣列也可以代表矩陣  # 上面是3x2矩陣，下面是2x3矩陣
aaa1 = np.array([np.array([-0.707, 0.707]),
                    np.array([0.8,0.6]),
                    np.array([ 0.,-1.])])

aaa2 = np.array([[-0.707, 0.8, 0],
              [0.707, 0.6, -1]])

a_array = np.array() # 函式創建數組，例如 arr = np.array([1, 2, 3, 4, 5])
a_array = np.zeros_like(A) # 函式創建與A同大小，元素全為零的矩陣
a_array = np.zeros() # 函式創建元素全為零的數組，例如 zeros_arr = np.zeros((3, 3))，np.zeros((列, 行))
a_array = np.ones() # 函式創建元素全為一的數組，例如 ones_arr = np.ones((2, 4))
a = np.round(a_array, decimals=6) # 取小數點到第六位，數字會變比較漂亮

# 兩種矩陣乘法
c = a @ b
c = np.dot(a, b)

A = np.array([[-0.707, 0.8, 0], [0.707, 0.6, -1]] # row在台灣是列，在大陸、日本是行

a_array = np.split(A, A.shape[1], axis=1) # np.split(切割A, 切割多少份, 由哪裡切)，
# A.shape[1]是行數 = 3，A.shape[0]是列數 = 2，A.shape = (2, 3)
# axis = 0、1、2對應x、y、z，在此僅能用axis = 1由行切割

b_array = np.concatenate(a_array, axis=1) # 把分開的矩陣合在一起
max_idx = np.argmax(np.abs(w)) # np.abs(w)，找w的最大值，argmax找w的最大值在矩陣中的位子

Anew[:, max_idx] = b_array[max_idx][:, 0] # 參考7.5 #[:, 0]是[列,行]，冒號是選擇全部，所以[:, 0]是指定第0行
# 這邊b_array是由concatenate來的，由好幾列(口,口)疊在一起，只能用[max_idx][:, 0]的方式去找，
# 其中[max_idx]是取列，測其他數字都沒用
Anew[:, max_idx] = 某數列，某數列加入到Anew的行裡面
a_inv = np.linalg.pinv(a) # 取a的反矩陣	

# 數組屬性：
array.shape # 獲取數組的形狀，例如 (3, 3)
array.dtype # 獲取數組的數據類型，例如 int64
array.T # array的T轉換

# 數組索引和切片：
arr[index] # 獲取數組中指定索引位置的元素，例如 arr[0] 獲取第一個元素。
arr[start:end] # 進行切片操作，獲取指定範圍的元素，例如 arr[1:4] 獲取第二個到第四個元素。

# 數學函式：
np.sum() # 計算數組中元素的和，例如 total = np.sum(arr)。
np.mean() # 計算數組中元素的平均值，例如 avg = np.mean(arr)。
y = np.exp(x) # 計算e^x次方，例如x = np.arange(-5, 5, 0.1)，y = np.exp(x)
y = np.log(x) # 計算log(x)，x = np.arange(1, 10, 0.1)，y = np.log(x)
y = np.sin(x) # 計算sin(x)，x = np.arange(0, 2 * np.pi, 0.1)，y = np.sin(x)
np.fft.fft(x) # 計算fourier transform，time = np.array([0, 1, 2, 1, 0])，frequency = np.fft.fft(time)
np.fft.ifft(x) # 逆fourier transform，frequency = np.array([0, 1, 2, 1, 0])，time = np.fft.ifft(frequency)

# 矩陣運算：
np.dot() # 執行矩陣乘法，例如 result = np.dot(matrix1, matrix2)
np.transpose() # 獲取矩陣的轉置，例如 transposed_matrix = np.transpose(matrix)

```
---

### `OpenCV`
#### 112-1傅楸善CV HW只有hw3.5.8.有用到plt.savefig
```python
import cv2 as cv

img = cv.imread('lena.bmp') # 讀取跟.py檔同個資料夾名稱為lena.bmp的照片，並傳送到img這個位子
img = cv.resize(img, (1000, 600)) # 改變相片長與寬，比例可能會跑掉

cv.imwrite(image_eq) # 存照片到跟.py檔同個資料夾
cv.imshow('photo', img) # 輸出照片叫photo，從img內輸出；按enter可以關掉，plt.show不行
cv.imwrite('HW3_part(b)_divided_by_3.jpg', image2_new)

cv.waitKey(0) # 鍵盤訊號或等待框內時間後關閉，0表示無限時間，1000表示1秒，plt.show不用刻意+這個
```

---
### `OS`
```python
import os
output_directory = 'results'

os.makedirs(directory, exist_ok=True)  # 等效以下
if not os.path.exists(output_directory):
    os.makedirs(output_directory)

cv.imwrite(os.path.join(output_directory, 'equalized_image.jpg'), image_eq) # 一定要+ cv.waitKey(0)一張一張存
plt.savefig(os.path.join(output_directory, f'HW8_{together_title[i]}.jpg'))
plt.savefig(os.path.join(output_directory, 'HW7_image.jpg'))

# 等同以下
cv.imwrite('results/dif_gaussian.jpg', dif_gaussian) # 沒result資料夾，會自動建立，可以一次存很多張照片
plt.savefig('results/HW7_image.jpg') # 如果沒result資料夾，程式會卡住
```

## 資料處理相關的外部函式：
### 資料處理的流程
```python
input_file_name = 'P0001'
input_dir = f'./data/{input_file_name}'
output_dir = './ data_output'
output_csv_file = f'./{output_dir}/output.csv'
variable1 = 1
variable2 = 2
variable3 = 3

def function1():

def function2():
```

以下是我在撰寫 Python 時的習慣與原則：
* 盡可能不使用 `def` 函式定義
* 不使用 `def process():`
* 不使用 `if __name__ == "__main__"`
* 把input/output路徑變數放在程式最上方
* Jupyter Notebook (`.ipynb`) 很方便，但我仍偏好標準的 `.py` 

### 讀取資料夾內所有檔案
處理每張圖片
```python
input_folder = f"datasets/test" # 原始圖片路徑
for file_name in photo_files:
    file_path = os.path.join(input_folder, file_name)
    """
    檔案處理，如predict、解壓縮等，input是file_path
    """
```

處理所有檔案
```python
directory = "."
directory = os.path.abspath(directory) # 確保路徑為絕對路徑
os.makedirs(directory, exist_ok=True) # 確定有此資料夾
for file_name in os.listdir(directory): # 遍歷目錄下所有檔案
    file_path = os.path.join(directory, file_name)
    """
    檔案處理，如predict、解壓縮等，input是file_path
    """
```

### `pandas`（讀取 `csv`）
```python
### 智慧醫療程式設計 HW5-1的輸出圖片
import pandas as pd
data = pd.read_csv('./100.csv') #讀跟.py檔案同個資料夾內的excel
print(data.columns, data.shape) #data.columns是列的數量，data.shape是行的數量 #確認有讀到資料
import matplotlib.pyplot as plt
def ecg_peak(data):
    plt.figure(figsize=(13, 5)) #設定圖形大小
    plt.plot(data) #繪製折線圖
    plt.show() #顯示圖形
ecg_peak(data["'MLII'"][:1000])
ecg_peak(data["'MLII'"][11000:12000])
ecg_peak(data["'MLII'"][51000:55000])

### 讀excel跟網路上的csv
import pandas as pd
data = pd.read_csv("https://raw.githubusercontent.com/GrandmaCan/ML/main/Resgression/Salary_Data.csv")

### 410Lab讀mimi3的csv
df = pd.read_csv("./60_people.csv")
row = 1
gender = df.loc[row - 1, 'gender']  # 讀取第0 row的gender這個項目，第一行項目名稱不算row
age = df.loc[row - 1, 'age']
death = df.loc[row - 1, 'death']
loadPath = df.loc[row - 1, 'loadPath']

### 112-2數位訊號處理導論
import pandas as pd
data = pd.read_csv('stock_price_globe.csv')
data.head()
# 選擇最後 5 個日期的資料
last_5_data = data.loc[11390:11395] # loc就是row，把第二列當0，實際範圍[0:14651]

# 計算對數收益率
adj_close = last_5_data['Adj Close']
adj_close_shifted = adj_close.shift(1)  # 取得上一期的 adj_close

# 計算對數收益率
log_returns_Q1 = np.log(adj_close / adj_close_shifted)

#Q1 顯示最後 5 個日期的對數收益率
print("\nLog Returns of Last 5 Dates in Taiwan:")
print(log_returns_Q1[1:].values)  # 不印出索引為 11390 的結果
```

### `json`
### `openpyxl`

## 範例程式：
### CPE 程式範本

```python
# 輸入用到的變數
t = int(input())  #跑幾個迴圈 # 輸入一個整數
for case in range(1,t+1):  #跑1到t個迴圈
    data = list(map(int, input().split()))  # 輸入一個字串 # 1 2 3 4 5 # 讀取多個數字並轉換為整數列表
    string = input()  # 讀取單行字串
    x, y = map(int, input().split())  # 輸入兩個整數以空格隔開 # 5 10
    a, b, c = map(int, input().split())  # 輸入三個整數以空格隔開

int n;  // 讀取輸入的行數
cin >> n;  // 對應 t = int(input()) 
string s;
getline(cin, s); // 清除緩衝區的 '\n'，避免影響後續輸入  // 對應string = input()

# 列表lis  # list可以指定位子，如s[1][2]
s = []  # 初始化空列表list來存放輸入的每一行
while True:
    try:
        s.append(input())  # 逐行加入到s
    except:
        break

# 字串
number = ' '
number += '1'
number += '0'

# 數列，1D_array，可以指定位子，如number[2]
number = [0]*3
for i in range(len(number)):
    number[i] = i

# 2D 陣列  # 可以指定位子，如arr_2d[1][2]，python中list更靈活更常用
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])
arr_2d[0][0] = 10

# 常用的非輸入變數
count = 0  # 要計算某次數，放在迴圈外面
for i in range( ):
    count += 1

max_cols = max(max_cols, len(s[i]))  # 一直更新最大值

# 迴圈範例
for case2 in range(a): # for迴圈
    b+=1
while a>b: # while條件內迴圈
    c+=1
while True: # while設定條件結束迴圈
    a+=1
    if 5>=a>0: # if用法
        print("so small")
    elif a==6:
        print("mid")
    else:
        print("big")
    if a==10: # 條件必須用==
        print(data[1])
        print(f"hello,world{a},I like {b}")
        break
```

### `numpy` 實例
```python
### 程式1
import numpy as np

b_list = np.array([np.array([[-0.707],[ 0.707]]),
                   np.array([[0.8],[0.6]]),
                   np.array([[ 0.],[-1.]])])

Anew = np.array([[0., 0., 0.],
                 [0., 0., 0.]])

Anew[:, 1] = b_list[1][:, 0]

print(f"{b_list}\n{b_list[0][:, 0]}\n{Anew}")

### 程式2
import numpy as np

x = np.array([[1,2,3],
              [4,5,6]])# array盡量不和matrix混用,

#row列操作
a = x[0] #取第一列 [[1 2 3]]  row在台灣是列，在大陸日本是行
print(f'x[0] is {a}\n')

b = x[1] #取第二列 [[4 5 6]]
print(f'x[1] is {b}\n')

c = x[1,0:2] # 索引取值,取第二列,1元素 [[4 5]]
print(f'x[1,0:2] is {c}\n')

#column行操作
d = x[ :,0] #取第一行
print(f'x[ :,0] is\n {d}\n')
'''
[[1]
[4]]
'''

e = x[:,:2] #取前两行
print(f'x[ :,:2] is\n {e}\n')
'''
[[1 2]
[4 5]]
'''

f = x[:,-1]#取最后一行
print(f'x[ :,-1] is\n {f}\n')
'''
[[3]
[6]]
'''

g = x[:,1:3]#取第2-3行
print(f'x[ :,1:3] is\n {g}\n')
'''
[[2, 3],
[5, 6]]
'''

h = x[0:2,:]#取1-2列
print(f'x[0:2,:] is\n {h}\n')
'''
[[1, 2, 3],
[4, 5, 6]]
'''
```

## 程式環境：
### IDE、compiler、interpreter
#### IDE：集成開發環境（Integrated Development Environment）

* 功能強大的記事本，撰寫、排版、除錯與執行程式的完整工具
* 常見 IDE：
  * PyCharm
  * VSCode
  * Visual Studio

#### Compiler：編譯器
* 將原始碼編譯成可執行檔（例如 `.exe`）
* 適用語言：C、C++、C#、Java（編譯成 JVM bytecode）
* 常見 C/C++ 編譯器：
  * GCC
  * Clang
  * 安裝方式：可透過MinGW或CodeBlocks取得

#### Interpreter：解譯器
* 將程式逐行解釋執行
* 適用語言：Python、JavaScript、R 等。
* 常見解譯器：
  * Python 解譯器
  * Node.js（JavaScript 執行環境）

#### 系統環境變數 PATH 設定
* 不論是編譯器或解譯器，都必須將其路徑加入系統環境變數的PATH
* 目的：讓 IDE 或 Terminal 能在任何資料夾直接找到對應的執行檔（如 `gcc`, `python`）。

#### 常見路徑範例：
* C/C++ 編譯器路徑：
  ```txt
  C:\mingw64\bin
  C:\Program Files\CodeBlocks\MinGW\bin
  ```
* Python 解譯器路徑：
  ```txt
  C:\Users\User\AppData\Local\Programs\Python\Python311\
  ```

### Python interpreter 設定
#### pycharm創立新環境
##### 選項 1：New environment（建立新環境）
* 在專案資料夾內會自動創建一個 `venv` 子資料夾。
* 該資料夾即為虛擬環境，專案所需套件將安裝在此，不會影響其他專案。

##### 選項 2：Previously configured interpreter（使用現有的 Interpreter）
* 路徑範例：
  ```
  C:\Users\User\AppData\Local\Programs\Python\Python311
  ```
* 好處：
  * 之後新建的專案可以共用相同的 Interpreter。
  * 統一管理套件與環境設定，避免重複安裝。
  * 換電腦時，只需將該 Interpreter 資料夾整個複製到新電腦上即可繼續使用。

![006](https://hackmd.io/_uploads/HJZ8RBSixg.png =80%x)

#### 已經建立好project想改環境
* 使用 pip 安裝的套件，會依據所選 Interpreter 對應安裝到指定路徑。
* 專案建立後，也可以進入 `Settings > Project: 專案名稱 > Python Interpreter` 修改 Interpreter 設定。

![007](https://hackmd.io/_uploads/rJ6ICBSsxx.png)

### C++ vscode、vs2019 設定
#### Visual Studio 2019（VS2019）
* VS2019 在建立專案時，會在資料夾中自動建立 `.vs` 資料夾
* `.vs` 裡面包含設定檔（如 `.json`）來儲存 project 設定
* **可以透過 GUI 設定 include path 和 linker 選項**，不需手動編輯 `.json`
* 這些設定完成後，系統會自動產生對應的 `.json` 設定檔
* 已於2024/02/29在臺大完成設定測試

#### Visual Studio Code（VSCode）工作區概念
* VSCode使用工作區(Workspace)管理專案設定
* 建立工作區會產生 `.vscode/` 資料夾，內含下列重要檔案：

| 檔案名稱            | 說明                          |
| --------------- | --------------------------- |
| `settings.json` | VSCode 的基本環境設定（如字體大小、換行寬度等） |
| `launch.json`   | 設定除錯器的執行參數與目標檔案             |
| `tasks.json`    | 設定自動化任務，例如編譯程式、執行指令腳本       |

* 這些 `.json` 檔可透過 VSCode 介面設定，也可手動編輯，方便搬移設定。

#### 是否需要使用工作區？
* 如果你主要在 Terminal 執行程式，就不太需要設定 `.vscode` 裡的 `.json`
* 使用 Terminal 執行程式是最直接、簡單的方式
* 你也可以安裝套件（如Extension Pack、Code Runner）來執行程式：
  * 但這些套件執行時無法正確處理 `input()` 輸入類型的程式

![008](https://hackmd.io/_uploads/rJuPABBjxl.png)

#### 使用 Terminal 指令執行 C / C++ 程式
> 執行 C 程式
```bash
gcc name.c -o name; ./name.exe
```
> 執行 C++ 程式
```bash
g++ -o test test.cpp; ./test
```

### Verilog 環境
#### 方法一：使用 Intel Quartus Prime（含波形顯示）
詳細使用步驟與圖示請參考另一份 Word 文件。

#### 方法二：使用 VSCode 搭配 Icarus Verilog + GTKWave
* 使用VSCode作為文字編輯介面。
* 下載並安裝 [Icarus Verilog](http://bleyer.org/icarus/)（內含 `iverilog`、`vvp`、`GTKWave`）。

#### 專案檔案結構
將以下兩個檔案放在同一資料夾：
* `test.v`：主設計檔
* `test_tb.v`：測試檔（testbench）

> test\_tb.v 需額外加入以下程式碼以產生波形檔：
```verilog
initial begin
    $dumpfile("test_tb.vcd");     // 產生 vcd 波形檔
    $dumpvars(0, counter_tb);     // 設定 testbench 模組名稱
end
```

> 執行步驟（在 Terminal 中操作）
```bash
iverilog -o test.bar test.v test_tb.v   # 編譯兩個檔案成一個可執行檔
vvp test.bar                            # 執行模擬，產出 test_tb.vcd
gtkwave test_tb.vcd                     # 使用 GTKWave 開啟波形
```

# Reference
- [Hello Algo](https://www.hello-algo.com/zh-hant/)
- [GeeksforGeeks](https://www.geeksforgeeks.org/)
- [Leetcode](https://leetcode.com/)
- [Collegiate Programming Examination](https://cpe.mcu.edu.tw/)
- [HackerRank](https://www.hackerrank.com/)
- [韌體0x10](https://hackmd.io/@ChenZE/ByOoO0LEee)