Bài 4.3: Bài tập thực hành rẽ nhánh if-else lồng nhau trong C++

Chào mừng trở lại với chuỗi bài học C++ của FullhouseDev! Ở các bài trước, chúng ta đã làm quen với cấu trúc rẽ nhánh ifif-else cơ bản, giúp chương trình của chúng ta đưa ra quyết định dựa trên một điều kiện đơn giản. Tuy nhiên, trong thế giới lập trình thực tế, các quyết định thường không chỉ dựa trên một điều kiện duy nhất. Thường thì, bạn cần kiểm tra một điều kiện, và chỉ khi điều kiện đó đúng (hoặc sai), bạn mới tiếp tục kiểm tra một điều kiện khác nữa. Đây chính là lúc cấu trúc rẽ nhánh if-else lồng nhau phát huy sức mạnh của nó.

Bài học này sẽ đưa bạn đi sâu hơn vào cách sử dụng các câu lệnh ifelse bên trong các khối if hoặc else khác. Hãy cùng khám phá làm thế nào để tạo ra logic chương trình mạnh mẽlinh hoạt hơn nhé!

Rẽ Nhánh if-else Lồng Nhau là Gì?

Đơn giản mà nói, rẽ nhánh if-else lồng nhau (Nested if-else) là việc đặt một câu lệnh if hoặc if-else (hoặc thậm chí là một cấu trúc if-else if-else) vào bên trong khối mã của một câu lệnh if hoặc else khác.

Hãy tưởng tượng bạn muốn kiểm tra hai điều kiện liên tiếp:

  1. Đầu tiên, kiểm tra xem một người có đủ tuổi để lái xe không (ví dụ: >= 18 tuổi).
  2. Nếu họ đủ tuổi, thì kiểm tra xem họ có bằng lái xe hợp lệ không.

Bạn không cần kiểm tra điều kiện có bằng lái nếu người đó chưa đủ tuổi. Đây chính là kịch bản lý tưởng cho if-else lồng nhau.

Cấu trúc chung:

if (dieu_kien_1) {
    // Mã được thực thi nếu dieu_kien_1 đúng
    // Bây giờ, kiểm tra dieu_kien_2 CHỈ KHI dieu_kien_1 đúng
    if (dieu_kien_2) {
        // Mã được thực thi nếu dieu_kien_1 đúng VÀ dieu_kien_2 đúng
    } else {
        // Mã được thực thi nếu dieu_kien_1 đúng NHƯNG dieu_kien_2 sai
    }
} else {
    // Mã được thực thi nếu dieu_kien_1 sai
    // Bạn cũng có thể lồng ghép ở đây
    if (dieu_kien_3) {
        // Mã được thực thi nếu dieu_kien_1 sai NHƯNG dieu_kien_3 đúng
    } else {
        // Mã được thực thi nếu dieu_kien_1 sai VÀ dieu_kien_3 cũng sai
    }
}

Lưu ý rằng việc thụt lề (indentation)cực kỳ quan trọng để giữ cho code lồng nhau dễ đọc và dễ hiểu. C++ không bắt buộc thụt lề về mặt cú pháp, nhưng nó là một quy tắc vàng trong lập trình chuyên nghiệp.

Khi Nào Sử Dụng if-else Lồng Nhau?

Bạn nên sử dụng cấu trúc lồng nhau khi logic của bạn yêu cầu kiểm tra một điều kiện phụ thuộc vào kết quả của một điều kiện khác. Các trường hợp phổ biến bao gồm:

  • Kiểm tra nhiều tiêu chí phải cùng đúng hoặc kết hợp theo một trình tự nhất định.
  • Xử lý các trường hợp đặc biệt bên trong các trường hợp chung.
  • Xây dựng các quy tắc phân loại phức tạp.

Mặc dù đôi khi bạn có thể sử dụng các toán tử logic như && (AND) hoặc || (OR) để kết hợp điều kiện (ví dụ: if (dieu_kien_1 && dieu_kien_2)), nhưng if-else lồng nhau cho phép bạn thực thi các khối mã riêng biệt dựa trên từng bước của quá trình kiểm tra điều kiện, hoặc khi các điều kiện phức tạp không thể dễ dàng kết hợp bằng && hoặc ||.

Hãy cùng đi qua các ví dụ cụ thể để thấy rõ hơn sức mạnh của cấu trúc này.

Các Ví Dụ Minh Họa

Để đơn giản hóa, chúng ta sẽ sử dụng using namespace std; trong các ví dụ code ngắn gọn này.

Ví Dụ 1: Kiểm Tra Tuổi và Điều Kiện Phụ

Yêu cầu: Nhập tuổi của học sinh. Nếu học sinh từ 16 tuổi trở lên, kiểm tra xem điểm trung bình của họ có đạt 7.0 không để xem xét cấp học bổng.

#include <iostream>

int main() {
    using namespace std; // Sử dụng namespace std

    int tuoi;
    double diemTrungBinh;

    cout << "Nhap tuoi cua hoc sinh: ";
    cin >> tuoi;

    // Dieu kien 1: Kiem tra tuoi
    if (tuoi >= 16) {
        cout << "Hoc sinh du tuoi xem xet hoc bong.\n";

        cout << "Nhap diem trung binh: ";
        cin >> diemTrungBinh;

        // Dieu kien 2 (long ben trong dieu kien 1): Kiem tra diem
        if (diemTrungBinh >= 7.0) {
            cout << "Hoc sinh DAP UNG du dieu kien hoc bong!\n";
        } else {
            cout << "Hoc sinh du tuoi nhung KHONG DU diem trung binh.\n";
        }
    } else {
        cout << "Hoc sinh CHUA du tuoi xem xet hoc bong.\n";
    }

    return 0;
}

Giải thích:

  • Chương trình đầu tiên kiểm tra if (tuoi >= 16).
  • Nếu điều kiện này đúng, nó sẽ in ra thông báo và tiếp tục vào khối mã bên trong if.
  • Bên trong khối if đầu tiên, nó sẽ hỏi điểm trung bình và thực hiện một câu lệnh if-else lồng nhau khác để kiểm tra diemTrungBinh >= 7.0.
  • Kết quả cuối cùng phụ thuộc vào việc cả hai điều kiện có đúng hay không (cho trường hợp đủ tuổi) hoặc chỉ cần điều kiện tuổi sai là đủ để kết luận.
Ví Dụ 2: Phân Loại Điểm Số Chi Tiết

Yêu cầu: Nhập điểm thi (từ 0 đến 100). Phân loại chung (Đạt/Trượt - ví dụ >= 50 là Đạt) và nếu Đạt, phân loại chi tiết hơn (Giỏi >= 80, Khá >= 65, Trung bình >= 50).

#include <iostream>

int main() {
    using namespace std;

    int diemThi;

    cout << "Nhap diem thi (0-100): ";
    cin >> diemThi;

    // Kiem tra diem co hop le trong pham vi 0-100 khong
    if (diemThi >= 0 && diemThi <= 100) {
        // Dieu kien 1: Kiem tra Dau hay Truot
        if (diemThi >= 50) {
            cout << "Ket qua: DAT\n";

            // Dieu kien 2 (long): Kiem tra xep loai chi tiet neu DAT
            if (diemThi >= 80) {
                cout << "Xep loai: GIOI\n";
            } else if (diemThi >= 65) {
                cout << "Xep loai: KHA\n";
            } else { // Diem >= 50 nhung < 65
                cout << "Xep loai: Trung binh\n";
            }
        } else { // Diem < 50
            cout << "Ket qua: TRUOT\n";
        }
    } else {
        cout << "Diem nhap vao KHONG hop le!\n";
    }

    return 0;
}

Giải thích:

  • Đầu tiên, chúng ta có một if bên ngoài kiểm tra tính hợp lệ của điểm (diemThi >= 0 && diemThi <= 100). Đây là một lớp kiểm tra ban đầu tốt.
  • Bên trong khối if hợp lệ, chúng ta kiểm tra điều kiện "Đạt" (diemThi >= 50).
  • Nếu điểm Đạt, chúng ta đi vào khối if thứ hai này và tiếp tục thực hiện một cấu trúc if-else if-else lồng nhau để xác định xếp loại chi tiết (Giỏi, Khá, Trung bình).
  • Nếu điểm không Đạt (khi diemThi < 50), chương trình sẽ thực hiện khối else tương ứng với if (diemThi >= 50) và in ra "TRUOT".
Ví Dụ 3: Lồng Ghép trong Khối else

Yêu cầu: Nhập giới tính ('N'/'n' cho Nữ, 'M'/'m' cho Nam) và tuổi. Nếu không phải Nữ, kiểm tra xem có phải Nam không. Nếu là Nam, kiểm tra tuổi để xem có đủ điều kiện tham gia câu lạc bộ bóng đá (Nam và >= 18 tuổi). Nếu không phải Nam, coi là giới tính khác.

#include <iostream>
#include <string> // Can cho string

int main() {
    using namespace std;

    char gioiTinh;
    int tuoi;

    cout << "Nhap gioi tinh (N/M): ";
    cin >> gioiTinh;

    // Dieu kien 1: Kiem tra co phai Nu khong
    if (gioiTinh == 'N' || gioiTinh == 'n') {
        cout << "Gioi tinh: Nu.\n";
    } else {
        // Neu khong phai Nu, KIEM TRA TIEP xem co phai Nam khong (long trong else)
        if (gioiTinh == 'M' || gioiTinh == 'm') {
            cout << "Gioi tinh: Nam.\n";

            cout << "Nhap tuoi: ";
            cin >> tuoi;

            // Dieu kien 2 (long ben trong if la Nam): Kiem tra tuoi
            if (tuoi >= 18) {
                cout << "Du dieu kien tham gia cau lac bo bong da (Nam, >=18).\n";
            } else {
                cout << "La Nam nhung chua du tuoi tham gia cau lac bo bong da.\n";
            }
        } else {
            // Neu khong phai Nu va cung khong phai Nam
            cout << "Gioi tinh: Khac.\n";
        }
    }

    return 0;
}

Giải thích:

  • Đầu tiên kiểm tra giới tính có phải là Nữ hay không.
  • Nếu không phải Nữ (điều kiện if (gioiTinh == 'N' || gioiTinh == 'n') sai), chương trình nhảy vào khối else.
  • Bên trong khối else này, chúng ta lại có một cấu trúc if-else mới để kiểm tra xem giới tính có phải là Nam không.
  • Nếu là Nam (điều kiện if (gioiTinh == 'M' || gioiTinh == 'm') đúng bên trong khối else), chương trình tiếp tục vào khối mã của if đó, hỏi tuổi, và thực hiện một câu lệnh if-else lồng thêm một cấp nữa để kiểm tra tuổi.
  • Nếu không phải Nữ cũng không phải Nam, chương trình thực hiện khối else cuối cùng (tương ứng với if (gioiTinh == 'M' || gioiTinh == 'm')) và in ra "Gioi tinh: Khac".

Ví dụ này cho thấy bạn hoàn toàn có thể lồng if-else không chỉ trong khối if mà còn trong khối else nữa, tùy thuộc vào logic bạn muốn xây dựng.

Ví Dụ 4: Đặt Vé Rạp Chiếu Phim (Đơn Giản)

Yêu cầu: Giá vé xem phim phụ thuộc vào loại vé (thường/VIP) và thời điểm xem (buổi sáng/buổi tối).

#include <iostream>
#include <string>

int main() {
    using namespace std;

    string loaiVe;
    string thoiGian;
    double giaVe = 0.0;
    bool inputHopLe = true; // Bien kiem tra dau vao co hop le khong

    cout << "Chon loai ve (Thuong/VIP): ";
    cin >> loaiVe;

    cout << "Chon thoi gian (Sang/Toi): ";
    cin >> thoiGian;

    // Chuyen doi chuoi nhap vao sang dang dong nhat de so sanh
    for(char &c : loaiVe) c = tolower(c);
    for(char &c : thoiGian) c = tolower(c);

    // Dieu kien 1: Kiem tra loai ve
    if (loaiVe == "thuong") {
        // Long Dieu kien 2: Kiem tra thoi gian neu la ve Thuong
        if (thoiGian == "sang") {
            giaVe = 80000.0;
        } else if (thoiGian == "toi") {
            giaVe = 100000.0;
        } else {
            cout << "Thoi gian khong hop le!\n";
            inputHopLe = false;
        }
    } else if (loaiVe == "vip") {
        // Long Dieu kien 2: Kiem tra thoi gian neu la ve VIP
        if (thoiGian == "sang") {
            giaVe = 120000.0;
        } else if (thoiGian == "toi") {
            giaVe = 150000.0;
        } else {
            cout << "Thoi gian khong hop le!\n";
            inputHopLe = false;
        }
    } else {
        cout << "Loai ve khong hop le!\n";
        inputHopLe = false;
    }

    // Chi in gia ve neu dau vao hop le
    if (inputHopLe) {
        cout << "Gia ve cua ban la: " << giaVe << " VND\n";
    }

    return 0;
}

Giải thích:

  • Chương trình đầu tiên kiểm tra loaiVe là "thuong" hay "vip" (hoặc không hợp lệ). Đây là tầng if-else if-else đầu tiên.
  • Bên trong mỗi nhánh của tầng đầu tiên (khi loaiVe là "thuong" hoặc "vip"), chúng ta lại có một cấu trúc if-else if-else lồng nhau để kiểm tra thoiGian là "sang" hay "toi".
  • Giá vé cuối cùng được xác định dựa trên sự kết hợp của cả hai điều kiện: loại vé thời gian.
  • Chúng ta cũng thêm biến inputHopLe để xử lý trường hợp người dùng nhập sai loại vé hoặc thời gian ở bất kỳ cấp độ nào.

Ví dụ này minh họa cách lồng ghép có thể xử lý các ma trận điều kiện (ví dụ: một bảng giá 2x2 hoặc lớn hơn).

Lưu Ý Quan Trọng: Tính Dễ Đọc và Phức Tạp

Mặc dù if-else lồng nhau rất mạnh mẽ, nhưng nó cũng có một nhược điểm: khi bạn lồng quá sâu (ví dụ: if bên trong if bên trong if...), code của bạn sẽ trở nên rất khó đọc, khó hiểukhó gỡ lỗi (debug).

  • Luôn luôn sử dụng thụt lề (indentation) nhất quán. Điều này giúp bạn dễ dàng nhìn thấy khối lệnh nào thuộc về điều kiện nào.
  • Tránh lồng ghép quá 3-4 cấp độ. Nếu logic của bạn yêu cầu lồng ghép sâu hơn, hãy xem xét các cách tiếp cận khác như:
    • Kết hợp điều kiện đơn giản bằng toán tử logic &&||.
    • Sử dụng các hàm riêng biệt để kiểm tra từng phần logic.
    • Cấu trúc lại logic tổng thể.
  • Thêm chú thích (comments) cho các khối lồng ghép phức tạp để giải thích mục đích của chúng.

Bài Tập Thực Hành

Hãy thử áp dụng kiến thức đã học bằng cách giải bài tập nhỏ sau:

Viết chương trình C++:

  1. Nhập vào ba số nguyên bất kỳ từ người dùng.
  2. Đầu tiên, kiểm tra xem số thứ nhất có phải là số dương (> 0) hay không.
  3. Nếu số thứ nhất là số dương, tiếp tục kiểm tra xem số thứ hai có lớn hơn số thứ ba hay không.
  4. In ra các thông báo phù hợp cho tất cả các trường hợp có thể xảy ra (ví dụ: "So thu nhat la so duong", "So thu hai lon hon so thu ba", "So thu nhat khong phai so duong", "So thu hai khong lon hon so thu ba", v.v.).

Gợi ý: Bạn sẽ cần một câu lệnh if bên ngoài kiểm tra số thứ nhất. Bên trong khối if đó, bạn sẽ cần một câu lệnh if-else khác để so sánh số thứ hai và số thứ ba. Đừng quên khối else cho if đầu tiên để xử lý trường hợp số thứ nhất không dương.

Comments

There are no comments at the moment.