#include <stdio.h>
// Hàm hoán đổi 2 con trỏ sử dụng con trỏ kép
void swap_pointers(int **p1, int **p2) {
// Hoán đổi địa chỉ mà p1 và p2 đang lưu
int *temp = *p1; // Lưu địa chỉ mà p1 đang trỏ
*p1 = *p2; // p1 trỏ sang nơi p2 đang trỏ
*p2 = temp; // p2 trỏ sang nơi p1 ban đầu trỏ
}
int main() {
int a, b;
scanf("%d %d", &a, &b);
int *p1 = &a; // p1 trỏ vào a
int *p2 = &b; // p2 trỏ vào b
swap_pointers(&p1, &p2); // Truyền địa chỉ của p1 và p2
printf("%d %d", *p1, *p2);
return 0;
}
/*
* ═══════════════════════════════════════════════════════════
* GIẢI THÍCH CHI TIẾT - SWAP TWO POINTERS
* ═══════════════════════════════════════════════════════════
*
* ĐIỂM QUAN TRỌNG:
* - Bài này KHÔNG hoán đổi giá trị a, b
* - Bài này hoán đổi ĐỊA CHỈ mà p1, p2 đang lưu
*
* ═══════════════════════════════════════════════════════════
* TRACE EXAMPLE 1: a = 10, b = 20
* ═══════════════════════════════════════════════════════════
*
* TRƯỚC KHI SWAP:
* ───────────────
* Memory Layout:
*
* ┌─────────┬──────────┐
* │ a │ 10 │ ← Tại địa chỉ 0x100
* └─────────┴──────────┘
*
* ┌─────────┬──────────┐
* │ b │ 20 │ ← Tại địa chỉ 0x150
* └─────────┴──────────┘
*
* ┌─────────┬──────────┐
* │ p1 │ 0x100 │ ← p1 trỏ vào a
* └─────────┴──────────┘
*
* ┌─────────┬──────────┐
* │ p2 │ 0x150 │ ← p2 trỏ vào b
* └─────────┴──────────┘
*
* Kiểm tra:
* *p1 = 10 (giá trị tại 0x100)
* *p2 = 20 (giá trị tại 0x150)
*
*
* TRONG HÀM swap_pointers(&p1, &p2):
* ───────────────────────────────────
*
* Tham số nhận được:
* **p1 = địa chỉ của p1 (ví dụ: 0x200)
* **p2 = địa chỉ của p2 (ví dụ: 0x250)
*
* Bước 1: int *temp = *p1;
* *p1 = 0x100 (địa chỉ mà p1 đang lưu)
* temp = 0x100
*
* Bước 2: *p1 = *p2;
* *p2 = 0x150 (địa chỉ mà p2 đang lưu)
* *p1 = 0x150
* → p1 BÂY GIỜ TRỎ VÀO b!
*
* Bước 3: *p2 = temp;
* temp = 0x100
* *p2 = 0x100
* → p2 BÂY GIỜ TRỎ VÀO a!
*
*
* SAU KHI SWAP:
* ─────────────
*
* ┌─────────┬──────────┐
* │ a │ 10 │ ← Vẫn tại 0x100 (KHÔNG ĐỔI)
* └─────────┴──────────┘
*
* ┌─────────┬──────────┐
* │ b │ 20 │ ← Vẫn tại 0x150 (KHÔNG ĐỔI)
* └─────────┴──────────┘
*
* ┌─────────┬──────────┐
* │ p1 │ 0x150 │ ← p1 BÂY GIỜ TRỎ VÀO b ✓
* └─────────┴──────────┘
*
* ┌─────────┬──────────┐
* │ p2 │ 0x100 │ ← p2 BÂY GIỜ TRỎ VÀO a ✓
* └─────────┴──────────┘
*
* Kiểm tra:
* *p1 = 20 (bây giờ p1 trỏ vào b)
* *p2 = 10 (bây giờ p2 trỏ vào a)
*
* Output: a points to 20, b points to 10 ✓
*
*
* ═══════════════════════════════════════════════════════════
* TRACE EXAMPLE 2: a = 5, b = 15
* ═══════════════════════════════════════════════════════════
*
* TRƯỚC: p1 → a(5), p2 → b(15)
*
* TRONG HÀM:
* temp = *p1 = địa chỉ của a
* *p1 = *p2 = địa chỉ của b → p1 trỏ vào b
* *p2 = temp = địa chỉ của a → p2 trỏ vào a
*
* SAU: p1 → b(15), p2 → a(5)
*
* Output: a points to 15, b points to 5 ✓
*
*
* ═══════════════════════════════════════════════════════════
* SO SÁNH: SWAP GIÁ TRỊ vs SWAP CON TRỎ
* ═══════════════════════════════════════════════════════════
*
* ┌──────────────────────┬─────────────────┬─────────────────┐
* │ │ Swap giá trị │ Swap con trỏ │
* ├──────────────────────┼─────────────────┼─────────────────┤
* │ Hàm │ swap(int*, int*)│ swap(**p1, **p2)│
* │ Thay đổi │ Giá trị a, b │ Địa chỉ p1, p2 │
* │ a, b sau khi swap │ THAY ĐỔI │ KHÔNG ĐỔI │
* │ p1, p2 sau khi swap │ KHÔNG ĐỔI │ THAY ĐỔI │
* └──────────────────────┴─────────────────┴─────────────────┘
*
* Ví dụ cụ thể với a=10, b=20:
*
* SWAP GIÁ TRỊ:
* Trước: a=10, b=20, p1→a, p2→b
* Sau: a=20, b=10, p1→a, p2→b
* *p1 = 20, *p2 = 10
*
* SWAP CON TRỎ (bài này):
* Trước: a=10, b=20, p1→a, p2→b
* Sau: a=10, b=20, p1→b, p2→a
* *p1 = 20, *p2 = 10
*
* ═══════════════════════════════════════════════════════════
* TẠI SAO CẦN CON TRỎ KÉP?
* ═══════════════════════════════════════════════════════════
*
* ❌ SAI: void swap_pointers(int *p1, int *p2)
*
* → Hàm chỉ nhận BẢN SAO của p1, p2
* → Thay đổi trong hàm KHÔNG ảnh hưởng p1, p2 gốc
* → Sau khi return, p1, p2 vẫn trỏ chỗ cũ!
*
* ✓ ĐÚNG: void swap_pointers(int **p1, int **p2)
*
* → Hàm nhận ĐỊA CHỈ của p1, p2
* → Có thể thay đổi CHÍNH p1, p2 gốc
* → Sau khi return, p1, p2 đã trỏ chỗ mới!
*
* ═══════════════════════════════════════════════════════════
* TÓM TẮT CÔNG THỨC:
* ═══════════════════════════════════════════════════════════
*
* Muốn thay đổi gì → Phải truyền địa chỉ của cái đó
*
* - Thay đổi giá trị int → truyền int*
* - Thay đổi con trỏ int* → truyền int**
* - Thay đổi con trỏ int** → truyền int*** (hiếm dùng)
*/
Input
10 20
Expected Output
20 10