Bài 5.5: Bài tập thực hành vòng lặp cơ bản trong C++

Chào mừng trở lại với series blog về lập trình C++! Sau khi đã làm quen với các khái niệm cơ bản như biến, kiểu dữ liệu và cấu trúc điều khiển rẽ nhánh (if-else, switch), chúng ta thường gặp phải một nhu cầu phổ biến trong lập trình: thực hiện đi thực hiện lại một đoạn mã nhiều lần.

Hãy tưởng tượng bạn cần in ra dòng chữ "Xin chào!" 10 lần. Liệu bạn có viết câu lệnh cout << "Xin chào!\n"; 10 lần không? Chắc chắn là không nếu con số đó lớn hơn, ví dụ 1000 lần! Đây chính là lúc vòng lặp (loops) trở thành người bạn đồng hành không thể thiếu của chúng ta.

Vòng lặp cho phép chúng ta lặp đi lặp lại một khối lệnh dựa trên một điều kiện nhất định. Trong C++, chúng ta có ba loại vòng lặp cơ bản:

  1. Vòng lặp for
  2. Vòng lặp while
  3. Vòng lặp do-while

Mỗi loại có cú pháp và cách hoạt động hơi khác nhau, phù hợp với từng kịch bản cụ thể. Hôm nay, chúng ta sẽ cùng nhau đi sâu vào từng loại, xem các ví dụ minh họa và thực hành để nắm vững chúng nhé!

1. Vòng lặp for

Vòng lặp for thường được sử dụng khi bạn đã biết trước số lần lặp hoặc khi bạn muốn lặp qua một dãy giá trị có quy luật. Cú pháp của nó khá rõ ràng và gom tất cả các yếu tố điều khiển vòng lặp vào một dòng duy nhất:

for (khởi tạo; điều kiện; cập nhật) {
    // Khối lệnh sẽ được thực hiện lặp đi lặp lại
}
  • khởi tạo: Được thực hiện một lần duy nhất ở đầu vòng lặp. Thường dùng để khởi tạo biến đếm.
  • điều kiện: Được kiểm tra trước mỗi lần lặp. Nếu điều kiện đúng (true), khối lệnh bên trong vòng lặp sẽ được thực thi. Nếu điều kiện sai (false), vòng lặp sẽ kết thúc.
  • cập nhật: Được thực hiện sau mỗi lần lặp. Thường dùng để tăng hoặc giảm biến đếm.

Hãy xem một ví dụ kinh điển: In ra các số từ 1 đến 5.

#include <iostream>

int main() {
    cout << "Cac so tu 1 den 5 voi vong lap for:\n";
    for (int i = 1; i <= 5; ++i) {
        cout << i << " ";
    }
    cout << "\n"; // In xuong dong ket thuc

    return 0;
}

Giải thích:

  • int i = 1;: Khởi tạo biến đếm i với giá trị ban đầu là 1.
  • i <= 5;: Điều kiện lặp. Vòng lặp sẽ tiếp tục chạy chừng nào i còn nhỏ hơn hoặc bằng 5.
  • ++i;: Cập nhật biến đếm. Sau mỗi lần lặp, i sẽ tăng lên 1.
  • Khối lệnh { cout << i << " "; } sẽ in giá trị hiện tại của i và một dấu cách.

Kết quả chạy đoạn code trên sẽ là: Cac so tu 1 den 5 voi vong lap for: 1 2 3 4 5

Bạn cũng có thể lặp ngược hoặc bỏ qua các phần trong cú pháp for (mặc dù không nên lạm dụng để tránh khó hiểu). Ví dụ lặp ngược từ 5 về 1:

#include <iostream>

int main() {
    cout << "Dem nguoc tu 5 ve 1 voi vong lap for:\n";
    for (int j = 5; j > 0; --j) { // Khoi tao j=5, dieu kien j > 0, cap nhat --j (giam j di 1)
        cout << j << " ";
    }
    cout << "\n";

    return 0;
}

Kết quả: Dem nguoc tu 5 ve 1 voi vong lap for: 5 4 3 2 1

Vòng lặp for rất linh hoạt và là lựa chọn hàng đầu khi bạn có một phạm vi lặp rõ ràng.

2. Vòng lặp while

Không giống như for, vòng lặp while được sử dụng khi bạn chưa biết trước số lần lặp cụ thể, mà chỉ biết rằng vòng lặp sẽ tiếp tục chạy chừng nào một điều kiện nào đó còn đúng. Cú pháp của nó đơn giản hơn:

while (điều kiện) {
    // Khối lệnh sẽ được thực hiện lặp đi lặp lại
    // Đảm bảo có sự thay đổi làm cho điều kiện cuối cùng sai
}
  • điều kiện: Được kiểm tra trước mỗi lần lặp. Nếu điều kiện đúng (true), khối lệnh bên trong sẽ được thực thi. Nếu sai (false), vòng lặp dừng lại.

Lưu ý quan trọng: Điều kiện của vòng lặp while cần phải có khả năng trở nên sai sau một số lần lặp. Nếu không, bạn sẽ rơi vào vòng lặp vô hạn (infinite loop), khiến chương trình bị treo! Bạn phải đảm bảo có một logic nào đó bên trong khối lệnh của while làm thay đổi các yếu tố ảnh hưởng đến điều kiện.

Ví dụ: In ra các số từ 1 đến 5 sử dụng while.

#include <iostream>

int main() {
    cout << "Cac so tu 1 den 5 voi vong lap while:\n";
    int count = 1; // Khoi tao bien dem truoc vong lap
    while (count <= 5) { // Kiem tra dieu kien
        cout << count << " ";
        count++; // Cap nhat bien dem ben trong vong lap
    }
    cout << "\n";

    return 0;
}

Giải thích:

  • Biến count được khởi tạo trước vòng lặp.
  • Điều kiện count <= 5 được kiểm tra. Ban đầu là 1 <= 5 (đúng).
  • Khối lệnh được thực thi: in 1 và tăng count lên 2.
  • Lặp lại: count <= 5 (2 <= 5, đúng). In 2, tăng count lên 3... cho đến khi count là 6.
  • Khi count là 6, điều kiện 6 <= 5 là sai, vòng lặp kết thúc.

Kết quả tương tự như vòng lặp for ở trên: Cac so tu 1 den 5 voi vong lap while: 1 2 3 4 5

Một trường hợp sử dụng phổ biến khác của while là xử lý đầu vào từ người dùng cho đến khi họ nhập một giá trị hợp lệ.

#include <iostream>
#include <limits> // Can thiet cho numeric_limits

int main() {
    int age;
    cout << "Moi nhap tuoi cua ban (phai la so duong): ";

    // Vong lap while de yeu cau nhap lai neu dau vao khong hop le
    while (!(cin >> age) || age <= 0) {
        cout << "Dau vao khong hop le. Hay nhap lai tuoi (phai la so duong): ";
        cin.clear(); // Xoa co loi cua cin
        // Bo qua phan con lai cua dong dau vao de tranh lap vo han neu nguoi dung nhap chuoi
        cin.ignore(numeric_limits<streamsize>::max(), '\n'); 
    }

    cout << "Tuoi hop le cua ban la: " << age << "\n";

    return 0;
}

Giải thích:

  • !(cin >> age): Kiểm tra xem thao tác đọc age có thành công không. Nếu người dùng nhập chữ thay vì số, thao tác này sẽ thất bại và trả về false, khi đó !(false) sẽ là true, vòng lặp tiếp tục.
  • age <= 0: Kiểm tra xem tuổi có phải là số dương không. Nếu không, điều kiện này đúng, vòng lặp tiếp tục.
  • Toàn bộ điều kiện !(cin >> age) || age <= 0 sẽ đúng nếu hoặc việc đọc số thất bại hoặc số đọc được không phải là số dương.
  • cin.clear();: Đặt lại trạng thái lỗi của cin để có thể đọc tiếp.
  • cin.ignore(...);: Loại bỏ phần còn lại của dòng đầu vào hiện tại, bao gồm cả ký tự xuống dòng, ngăn chặn vòng lặp vô hạn nếu lỗi đọc là do ký tự không phải số.
  • Vòng lặp chỉ kết thúc khi người dùng nhập một số nguyên dương thành công.

Đây là một ví dụ hay cho thấy sức mạnh của while trong các tình huống điều kiện phức tạp hoặc phụ thuộc vào yếu tố bên ngoài (như đầu vào người dùng).

3. Vòng lặp do-while

Vòng lặp do-while rất giống với while, nhưng có một điểm khác biệt quan trọng: điều kiện của nó được kiểm tra sau khi khối lệnh được thực thi ít nhất một lần.

Cú pháp:

do {
    // Khối lệnh sẽ được thực hiện ít nhất một lần
    // và lặp đi lặp lại nếu điều kiện đúng
} while (điều kiện); // Lưu ý dấu chấm phẩy ở cuối
  • Khối lệnh bên trong do { ... } được thực thi trước.
  • Sau khi khối lệnh chạy xong, điều kiện trong while (...) mới được kiểm tra.
  • Nếu điều kiện đúng (true), quá trình lặp lại bắt đầu từ do.
  • Nếu điều kiện sai (false), vòng lặp kết thúc.

Điểm khác biệt cốt lõi là: vòng lặp do-while luôn thực thi khối lệnh của nó ít nhất một lần, bất kể điều kiện ban đầu đúng hay sai.

Ví dụ: Sử dụng do-while để in một thông báo và hỏi người dùng có muốn lặp lại không.

#include <iostream>

int main() {
    char choice;

    do {
        cout << "Ban co thay hoc C++ thu vi khong? (y/n): ";
        cin >> choice;
        choice = tolower(choice); // Chuyen ve chu thuong de so sanh de hon

    } while (choice != 'y' && choice != 'n'); // Lap lai neu nhap khong phai 'y' hoac 'n'

    if (choice == 'y') {
        cout << "Tuyet voi! Hay tiep tuc nhe!\n";
    } else {
        cout << "Hay co gang hon mot chut!\n";
    }

    return 0;
}

Giải thích:

  • Khối lệnh bên trong do { ... } sẽ chạy lần đầu tiên mà không cần kiểm tra điều kiện gì. Chương trình sẽ in câu hỏi và chờ người dùng nhập lựa chọn.
  • Sau khi người dùng nhập choice, điều kiện choice != 'y' && choice != 'n' được kiểm tra.
  • Nếu người dùng nhập bất cứ thứ gì khác 'y' hoặc 'n', điều kiện này sẽ đúng, và vòng lặp do sẽ chạy lại, yêu cầu nhập lại.
  • Chỉ khi người dùng nhập 'y' hoặc 'n' (sau khi chuyển về chữ thường), điều kiện mới sai và vòng lặp kết thúc.

Vòng lặp do-while phù hợp khi bạn cần thực hiện một hành động ít nhất một lần trước khi quyết định có lặp lại nó dựa trên kết quả của hành động đó hay không.

4. Điều khiển vòng lặp với breakcontinue

Đôi khi, bên trong một vòng lặp, chúng ta cần thay đổi luồng thực thi bình thường của nó. C++ cung cấp hai câu lệnh để làm điều này: breakcontinue.

break

Câu lệnh break được sử dụng để thoát ngay lập tức khỏi vòng lặp chứa nó (có thể là for, while hoặc do-while) mà không cần quan tâm đến điều kiện lặp. Việc thực thi chương trình sẽ tiếp tục ở câu lệnh ngay sau vòng lặp.

break rất hữu ích khi bạn tìm thấy điều mình cần và không muốn tiếp tục lặp nữa.

Ví dụ: Tìm số đầu tiên chia hết cho 7 trong dãy từ 1 đến 100.

#include <iostream>

int main() {
    cout << "Tim so chia het cho 7 dau tien tu 1 den 100:\n";
    int found_number = -1; // Bien luu ket qua, -1 la khong tim thay

    for (int i = 1; i <= 100; ++i) {
        if (i % 7 == 0) { // Kiem tra xem i co chia het cho 7 khong
            found_number = i; // Neu co, luu lai so do
            break; // Thoat khoi vong lap ngay lap tuc
        }
    }

    if (found_number != -1) {
        cout << "So dau tien chia het cho 7 la: " << found_number << "\n";
    } else {
        cout << "Khong tim thay so nao chia het cho 7 trong day!\n"; // Truong hop nay khong xay ra voi day 1-100
    }

    return 0;
}

Giải thích:

  • Vòng lặp for bắt đầu từ 1 và chạy đến 100.
  • Bên trong vòng lặp, câu lệnh if (i % 7 == 0) kiểm tra tính chia hết.
  • Khi i bằng 7, điều kiện if đúng. found_number được gán giá trị 7.
  • Câu lệnh break; được thực thi. Vòng lặp for dừng lại ngay lập tức, không kiểm tra các số tiếp theo (8, 9, ... 100).
  • Chương trình nhảy ra khỏi vòng lặp và in kết quả.
continue

Câu lệnh continue được sử dụng để bỏ qua phần còn lại của lần lặp hiện tại và chuyển sang lần lặp tiếp theo (kiểm tra điều kiện lặp và thực hiện phần cập nhật đối với for).

continue hữu ích khi bạn muốn bỏ qua việc xử lý cho một trường hợp cụ thể trong lần lặp đó, nhưng vẫn muốn tiếp tục với các lần lặp tiếp theo của vòng lặp.

Ví dụ: In ra các số lẻ từ 1 đến 10.

#include <iostream>

int main() {
    cout << "Cac so le tu 1 den 10:\n";

    for (int i = 1; i <= 10; ++i) {
        if (i % 2 == 0) { // Kiem tra xem i co phai so chan khong
            continue; // Neu la so chan, bo qua phan con lai cua lan lap nay
        }
        // Dong code nay chi duoc thuc thi neu i la so le
        cout << i << " "; 
    }
    cout << "\n";

    return 0;
}

Giải thích:

  • Vòng lặp for duyệt qua các số từ 1 đến 10.
  • Khi i là 1, i % 2 == 0 là sai. Chương trình bỏ qua if và in 1.
  • Khi i là 2, i % 2 == 0 là đúng. Câu lệnh continue; được thực thi.
  • continue làm cho chương trình bỏ qua câu lệnh cout << i << " "; cho lần lặp khi i=2.
  • Vòng lặp chuyển sang lần lặp tiếp theo với i tăng lên 3.
  • Quá trình này tiếp diễn. continue sẽ bỏ qua việc in các số 2, 4, 6, 8, 10.

Kết quả: Cac so le tu 1 den 10: 1 3 5 7 9

Tóm tắt

Bạn đã thấy sức mạnh của các loại vòng lặp cơ bản trong C++:

  • for: Lý tưởng cho số lần lặp xác định hoặc duyệt qua một dãy.
  • while: Phù hợp khi số lần lặp không rõ ràng, chỉ dựa vào một điều kiện tiếp tục. Cẩn thận với vòng lặp vô hạn!
  • do-while: Đảm bảo khối lệnh chạy ít nhất một lần trước khi kiểm tra điều kiện lặp.

Cùng với đó, break giúp bạn thoát khẩn cấp khỏi vòng lặp, còn continue cho phép bạn bỏ qua lần lặp hiện tại để sang lần tiếp theo.

Comments

There are no comments at the moment.