← Lập trình C cơ bản

Bài 10 · Vận dụng · 22 phút· Cập nhật 11/06/2026

Vòng lặp: for, while, do-while

Biên soạn bởi Nguyễn Anh Tuấn

Viết while, for, do-while; theo dõi điều kiện, biến đếm, break/continue, vòng lặp vô tận và lỗi off-by-one.

while (điều_kiện) chạy đi chạy lại khối lệnh chừng nào điều kiện còn đúng - điều kiện vẫn là biểu thức đúng/sai quen thuộc từ bài Rẽ nhánh: if/else & switch. Mỗi vòng: kiểm tra điều kiện → nếu đúng thì chạy thân → quay lại kiểm tra. Phải có gì đó trong thân làm điều kiện tiến tới chỗ dừng, nếu không sẽ lặp vô tận.

while.c

#include <stdio.h>

int main() {
    int i = 1;
    while (i <= 5) {
        printf("%d ", i);
        i++;            // khong co dong nay -> lap vo tan
    }
    return 0;
}

Kết quả khi chạy

1 2 3 4 5
  • while kiểm tra điều kiện TRƯỚC mỗi vòng → thân có thể chạy 0 lần.
  • Phải cập nhật biến đếm (i++) để điều kiện có ngày thành sai.
  • Quên cập nhật ⇒ vòng lặp vô tận (chương trình treo).

Khi biết trước số lần lặp, for gọn hơn: nó gộp ba phần lên một dòng - khởi tạo; điều kiện; bước nhảy. Kéo thử các ô bên dưới để xem vòng chạy ra dãy nào, lặp bao nhiêu lần:

for (int i = 1; i <= 5; i += 1) {
    printf("%d ", i);
}
i = 12345
Số lần lặp
5
In ra màn hình
1 2 3 4 5

Đổi Tới giữa i <= 5i < 5 chính là lỗi “lệch một đơn vị” (off-by-one) hay gặp nhất.

for.c

#include <stdio.h>

int main() {
    for (int i = 1; i <= 5; i++) {
        printf("%d ", i);
    }
    return 0;
}

Kết quả khi chạy

1 2 3 4 5

for chạy theo thứ tự nào?

1. khởi tạo i = 1 (một lần duy nhất) → 2. kiểm tra i <= 5 → nếu đúng 3. chạy thân → 4. bước nhảy i++ → quay lại bước 2. Khi điều kiện sai thì thoát.

do … while chạy thân trước rồi mới kiểm tra điều kiện ở cuối - nên thân luôn chạy ít nhất một lần, kể cả khi điều kiện sai ngay từ đầu:

do-while.c

#include <stdio.h>

int main() {
    int i = 10;
    do {
        printf("%d\n", i);   // chay 1 lan du i da > 5
    } while (i <= 5);
    return 0;
}

Kết quả khi chạy

10
  • do-while kiểm tra điều kiện Ở CUỐI → thân chạy tối thiểu 1 lần.
  • Hợp khi cần làm trước rồi mới quyết định lặp lại (nhập lại khi sai, menu).
  • Nhớ dấu chấm phẩy sau while (…); ở cuối do-while.

break thoát hẳn khỏi vòng lặp ngay lập tức. continue bỏ qua phần còn lại của vòng hiện tại và nhảy sang vòng kế tiếp:

break-continue.c

for (int i = 1; i <= 10; i++) {
    if (i == 6) break;        // tới 6 thì thoát han
    if (i % 2 == 0) continue; // so chan -> bo qua, khong in
    printf("%d ", i);
}

Kết quả khi chạy

1 3 5
  • break: dừng sớm khi đã tìm thấy thứ cần (thoát cả vòng).
  • continue: bỏ qua một trường hợp nhưng VẪN chạy bước cập nhật rồi lặp tiếp.
  • i = 6 gặp break ⇒ không in 6; các số chẵn 2,4 bị continue bỏ qua.

Hai lỗi vòng lặp phổ biến nhất. Thứ nhất - vòng lặp vô tận do quên cập nhật biến đếm hoặc bước nhảy sai hướng:

vo-tan.c

int i = 1;
while (i <= 5) {
    printf("%d ", i);
    // QUEN i++  ->  i mai bang 1  ->  in "1 1 1 1 ..." mai mai
}

Kết quả khi chạy

1 1 1 1 1 …  (treo)

Lỗi thứ hai: lệch một đơn vị (off-by-one)

for (i = 1; i <= 5; i++) chạy 5 lần (1→5). Đổi thành i < 5 chỉ còn 4 lần (1→4). Bắt đầu từ 0 hay 1, dùng < hay <= - sai một bậc là thừa/thiếu đúng một vòng. Hãy thử ngay trên công cụ ở Bước 2.

Bài tiếp theo

Rẽ nhánh + vòng lặp là đủ điều khiển luồng chạy. Bài kế, Hàm, dạy cách gói các đoạn lệnh thành khối có tên để gọi lại ở nhiều nơi.

Câu hỏi thường gặp

Dùng for khi biết TRƯỚC số lần lặp (đếm từ 1 tới N). Dùng while khi lặp tới khi một điều kiện đổi mà chưa biết bao nhiêu lần (đọc tới khi hết dữ liệu). Thực ra hai cái tương đương - for chỉ gói gọn khởi tạo, điều kiện và bước nhảy lên một dòng.

while kiểm tra điều kiện TRƯỚC, nên thân có thể chạy 0 lần. do-while chạy thân TRƯỚC rồi mới kiểm tra, nên thân luôn chạy ÍT NHẤT 1 lần. Hợp khi cần hỏi người dùng ít nhất một lần (menu, nhập lại khi sai).

Là vòng mà điều kiện không bao giờ thành sai → chạy mãi. Nguyên nhân thường gặp: quên cập nhật biến đếm (thiếu i++), hoặc bước nhảy sai hướng (đếm lên nhưng điều kiện là i >= 0). Luôn kiểm tra: mỗi vòng có làm điều kiện tiến gần tới chỗ DỪNG không?

Là chạy thừa hoặc thiếu một lần do nhầm i <= n với i < n, hoặc bắt đầu từ 0 hay 1. Ví dụ in 1..5: for (i=1; i<=5; i++) chạy 5 lần; đổi thành i<5 chỉ còn 4 lần. Đây là lỗi kinh điển - hãy thử với công cụ ở Bước 2.

break THOÁT hẳn khỏi vòng lặp (bỏ luôn các vòng còn lại). continue chỉ BỎ QUA phần còn lại của vòng HIỆN TẠI rồi nhảy sang vòng kế tiếp (vẫn chạy bước cập nhật). break để dừng sớm khi tìm thấy; continue để bỏ qua trường hợp không quan tâm.

Có (nested loop) - vòng trong chạy trọn vẹn cho MỖI lần của vòng ngoài. Bảng cửu chương, ma trận đều cần lồng. Số lần chạy thân là tích: vòng ngoài m lần × vòng trong n lần = m×n lần.

Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.

Tick những điều em tự tin làm được sau khi học bài này. 0/6

Trả lời vài câu để chắc rằng em đã nắm bài.

Câu 1/3 Điểm: 0

Khác biệt cốt lõi giữa whiledo-while là gì?

  1. 1

    Đếm 1 tới 10

    Viết vòng for in các số từ 1 đến 10, mỗi số một dòng.

    Hoàn thành khi: for (int i = 1; i <= 10; i++) printf("%d\n", i);

  2. 2

    Tổng 1 tới 100

    Dùng vòng lặp cộng dồn 1 + 2 + … + 100. Kết quả bằng bao nhiêu?

    Hoàn thành khi: 5050. Tích luỹ: int tong = 0; for (i=1; i<=100; i++) tong += i;

  3. 3

    Off-by-one

    Dùng công cụ Bước 2: đặt Bắt đầu = 1, Bước = 1. Đổi Tới từ 5 thành 4 thì in ra gì? Còn i < 5 (đổi <= thành <) thì sao?

    Hoàn thành khi: Tới = 5 in “1 2 3 4 5” (5 lần); đổi đích/điều kiện đi một bậc là mất/thêm đúng một lần.

  4. 4

    Đếm ngược

    In từ 10 xuống 1 trên một dòng. Vòng for cần bước nhảy bao nhiêu?

    Hoàn thành khi: for (int i = 10; i >= 1; i--) - bước -1. In: 10 9 8 … 1.

  5. 5

    Bảng cửu chương 5

    Dùng vòng lặp in bảng cửu chương của 5: 5 x 1 = 5 … 5 x 10 = 50.

    Hoàn thành khi: for (i=1; i<=10; i++) printf("5 x %d = %d\n", i, 5*i);

  6. 6

    Bỏ qua số chẵn

    In các số lẻ từ 1 đến 9 bằng cách dùng continue để bỏ qua số chẵn.

    Hoàn thành khi: for (i=1; i<=9; i++) { if (i % 2 == 0) continue; printf("%d ", i); } → 1 3 5 7 9.