# 📚 **Tổng Hợp Kiến Thức Buổi Học Lập Trình C Lesson 3**
Chào mừng các bạn đến với buổi học về các toán tử và cấu trúc điều khiển trong C. Hôm nay, chúng ta sẽ tìm hiểu các công cụ cốt lõi giúp chương trình của bạn trở nên linh hoạt và thông minh hơn.
## 🎯 **Nội dung chính**
1. **Toán tử và Biểu thức (Phần chọn lọc từ Buổi 3):**
* Toán tử So sánh (Quan hệ) và Toán tử Logic.
* Toán tử tăng giảm `++` và `--`.
* Chuyển đổi kiểu dữ liệu (Type Conversion) và Ép kiểu (Casting).
* Thứ tự ưu tiên của các toán tử.
2. **Cấu trúc điều khiển rẽ nhánh (Toàn bộ Buổi 5):**
* Lệnh `if` và `if-else`.
* Lệnh `if-else-if`.
* Lệnh `if` lồng nhau (Nested `if`).
* Lệnh `switch`.
---
## ⚙️ **Phần 1: Toán tử và Biểu thức**
Toán tử là các ký hiệu dùng để thực hiện các phép toán trên các biến và giá trị. Khi kết hợp toán tử và toán hạng (operands), chúng ta có một biểu thức.
## **1.1. Toán tử Tăng/Giảm (`++` và `--`)** ⚙️
Đây là các toán tử một ngôi (unary operators) dùng để tăng hoặc giảm giá trị của một biến đi 1 đơn vị.
* **`++` (Tăng):** Tăng giá trị biến lên 1.
* **`--` (Giảm):** Giảm giá trị biến đi 1.
Chúng có hai dạng:
* **Tiền tố (Prefix):** `++x` hoặc `--x`. Toán tử được thực hiện **trước**, sau đó giá trị mới của `x` được sử dụng trong biểu thức.
* **Hậu tố (Postfix):** `x++` hoặc `x--`. Giá trị **hiện tại** của `x` được sử dụng trong biểu thức, sau đó toán tử mới được thực hiện (biến được tăng/giảm).
```c
int x = 5, y;
// Ví dụ về tiền tố
y = ++x; // x tăng lên 6, sau đó gán giá trị của x cho y. Kết quả: x = 6, y = 6.
// Ví dụ về hậu tố
x = 5; // Reset x
y = x++; // Gán giá trị hiện tại của x (là 5) cho y, sau đó x tăng lên 6. Kết quả: x = 6, y = 5.
```
### **1.2. Toán tử So sánh và Toán tử Logic**
Đây là hai nhóm toán tử cực kỳ quan trọng, thường được sử dụng trong các cấu trúc điều khiển để đưa ra quyết định.
#### **🔍 Toán tử So sánh (Relational Operators)**
Dùng để kiểm tra mối quan hệ giữa hai giá trị. Kết quả của một biểu thức so sánh luôn là `1` (đúng - true) hoặc `0` (sai - false).
| Toán tử | Ý nghĩa | Ví dụ | Kết quả nếu x=5 |
| :------ | :----------------------- | :-------- | :--------------- |
| `==` | Bằng nhau | `x == 5` | `1` (đúng) |
| `!=` | Không bằng nhau | `x != 10` | `1` (đúng) |
| `>` | Lớn hơn | `x > 10` | `0` (sai) |
| `<` | Nhỏ hơn | `x < 10` | `1` (đúng) |
| `>=` | Lớn hơn hoặc bằng | `x >= 5` | `1` (đúng) |
| `<=` | Nhỏ hơn hoặc bằng | `x <= 4` | `0` (sai) |
*Bảng được tổng hợp từ thông tin tại *
#### **↔️ Toán tử Logic (Logical Operators)**
Dùng để kết hợp hoặc phủ định các biểu thức quan hệ.
| Toán tử | Tên | Ý nghĩa | Ví dụ |
| :------ | :----- | :----------------------------------------------- | :---------------------- |
| `&&` | AND | Trả về `true` (1) nếu **cả hai** biểu thức đều đúng. | `(x > 0) && (x < 10)` |
| `||` | OR | Trả về `true` (1) nếu **ít nhất một** biểu thức đúng. | `(y == 0) || (y > 5)` |
| `!` | NOT | Đảo ngược trạng thái của biểu thức (đúng thành sai, sai thành đúng). | `!(x == 10)` |
*Bảng được tổng hợp từ thông tin tại *
**Ví dụ:** Kiểm tra một số có nằm trong khoảng (10, 20) hay không.
if (a > 10 && a < 20) { //
// Làm gì đó nếu a lớn hơn 10 VÀ nhỏ hơn 20
}
## **1.3. Chuyển đổi kiểu và Ép kiểu (Type Conversion & Casting)** 🔄
### **Chuyển đổi kiểu tự động**
Khi một biểu thức chứa các toán hạng có kiểu dữ liệu khác nhau, C sẽ tự động chuyển đổi chúng về một kiểu chung trước khi tính toán để tránh mất dữ liệu.
**Quy tắc chung:**
* Các kiểu `char` và `short` được tự động chuyển thành `int`; `float` được chuyển thành `double`.
* Nếu một trong hai toán hạng là `double`, toán hạng còn lại sẽ được chuyển thành `double`.
* Nếu không, nếu một trong hai toán hạng là `long`, toán hạng còn lại sẽ được chuyển thành `long`.
* Nếu không, nếu một trong hai toán hạng là `unsigned`, toán hạng còn lại cũng được chuyển thành `unsigned`.
* Nếu không, các toán hạng phải là `int`.
### **Ép kiểu (Casting)**
Đôi khi bạn muốn **buộc** một biểu thức phải có một kiểu dữ liệu nhất định. Đây được gọi là ép kiểu.
**Cú pháp:**
`(kiểu_dữ_liệu) biểu_thức`
**Ví dụ:** Lấy phần nguyên của một số thực.
```c
float f = 3.14159; //
int x;
x = (int)f; // Ép kiểu f thành int trước khi gán cho x
// Kết quả: x sẽ có giá trị là 3. Phần thập phân bị cắt bỏ.
// 💡 Lưu ý: Giá trị của biến f không thay đổi.
```
## **1.4. ⚖️ Thứ tự ưu tiên của các Toán tử**
Thứ tự ưu tiên là quy tắc xác định thứ tự các toán tử được C đánh giá trong một biểu thức phức tạp. Toán tử có độ ưu tiên cao hơn sẽ được thực hiện trước.
💡 Bạn có thể dùng dấu ngoặc đơn `()` để thay đổi thứ tự ưu tiên mặc định, vì dấu ngoặc đơn có độ ưu tiên cao nhất và luôn được đánh giá trước tiên.
**Bảng thứ tự ưu tiên (từ cao đến thấp) cho các toán tử đã học:**
| Mức ưu tiên | Toán tử | Tên Nhóm | Kết hợp (Associativity) |
| :--- | :--- | :--- | :--- |
| 1 | `()` | Dấu ngoặc | Trái sang phải |
| 2 | `!`, `++`, `--`, `(type)` | Toán tử một ngôi | Phải sang trái |
| 3 | `*`, `/`, `%` | Số học (Nhân/chia) | Trái sang phải |
| 4 | `+`, `-` | Số học (Cộng/trừ) | Trái sang phải |
| 5 | `<`, `<=`, `>`, `>=` | So sánh | Trái sang phải |
| 6 | `==`, `!=` | So sánh (Bằng/không bằng) | Trái sang phải |
| 7 | `&&` | AND logic | Trái sang phải |
| 8 | `||` | OR logic | Trái sang phải |
| 9 | `=` | Gán | Phải sang trái |
## **🤔 Phần 2: Cấu trúc điều khiển rẽ nhánh**
Các câu lệnh điều kiện cho phép chúng ta thay đổi luồng thực thi của chương trình, giúp chương trình có thể "đưa ra quyết định" dựa trên các điều kiện đúng hoặc sai. C hỗ trợ hai loại câu lệnh lựa chọn chính là `if` và `switch`.
### **2.1. Lệnh `if`**
Lệnh `if` được dùng để thực thi một khối lệnh nếu một biểu thức điều kiện là đúng (khác 0).
**Cú pháp:**
```c
if (biểu_thức_điều_kiện) {
// các câu lệnh sẽ được thực thi nếu điều kiện đúng
}
```
### **2.2. Lệnh `if-else`**
Cung cấp một lựa chọn thay thế: một khối lệnh sẽ được thực thi khi điều kiện của `if` là sai (bằng 0).
**Cú pháp:**
```c
if (biểu_thức_điều_kiện) {
// Khối lệnh A: thực thi nếu điều kiện đúng
} else {
// Khối lệnh B: thực thi nếu điều kiện sai
}
```
### **2.3. Thang `if-else-if`**
Được sử dụng khi có nhiều hơn hai khả năng cần kiểm tra. Các điều kiện sẽ được kiểm tra tuần tự từ trên xuống dưới. Ngay khi một điều kiện đúng được tìm thấy, khối lệnh tương ứng sẽ được thực thi và toàn bộ cấu trúc sẽ kết thúc.
**Cú pháp:**
```c
if (dieu_kien_1) {
// Thực thi nếu điều kiện 1 đúng
} else if (dieu_kien_2) {
// Thực thi nếu điều kiện 1 sai VÀ điều kiện 2 đúng
} else if (dieu_kien_3) {
// Thực thi nếu cả 1, 2 đều sai VÀ điều kiện 3 đúng
} else {
// Thực thi nếu tất cả các điều kiện trên đều sai
}
```
### **2.4. Lệnh `if` lồng nhau (Nested `if`)**
Đây là một câu lệnh `if` được đặt bên trong một câu lệnh `if` hoặc `else` khác.
💡 **Quy tắc quan trọng:** Trong C, một lệnh `else` luôn thuộc về lệnh `if` gần nhất mà chưa được ghép cặp với `else` nào khác trong cùng một khối lệnh.
**Cú pháp:**
```c
if (dieu_kien_ngoai) {
// ...
if (dieu_kien_trong) {
// thực thi khi cả điều_kiện_ngoài và điều_kiện_trong đều đúng
} else { // else này là của if(dieu_kien_trong)
// thực thi khi điều_kiện_ngoài đúng và điều_kiện_trong sai
}
// ...
} else { // else này là của if(dieu_kien_ngoai)
// thực thi khi điều_kiện_ngoài sai
}
```
### **2.5. Lệnh `switch`**
Lệnh `switch` là một cấu trúc quyết định đa chiều, kiểm tra giá trị của một biểu thức với một danh sách các hằng số kiểu số nguyên hoặc ký tự. Nó thường là một giải pháp gọn gàng hơn cho một chuỗi `if-else-if` dài.
**Cú pháp:**
```c
switch (biểu_thức) {
case hang_so_1:
// các câu lệnh cho trường hợp 1
break; // Thoát khỏi switch
case hang_so_2:
// các câu lệnh cho trường hợp 2
break;
// ... nhiều case khác
default: // Tùy chọn
// các câu lệnh nếu không có case nào khớp
break;
}