Menu

Vòng lặp do while trong C: cú pháp, ví dụ và khi nào dùng

Vòng lặp chạy thân trước của C: do-while đảm bảo chạy một lần trước khi kiểm tra ra sao, vì sao nó kết thúc bằng dấu chấm phẩy, mẫu menu và nhập lại mà nó sinh ra để giải quyết, và nó khác vòng lặp while thường thế nào.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Vòng lặp luôn chạy một lần

Vòng lặp while kiểm tra trước khi làm, nên có thể chạy 0 lần. Thường thì điều đó đúng. Nhưng đôi khi nó lại sai hoàn toàn: bạn không thể biết có cần hỏi lại hay không cho đến khi đã hiện câu hỏi, và không thể đánh giá đầu vào của người dùng cho đến khi đã đọc được gì đó. do-while đưa phép kiểm tra xuống cuối, nên thân vòng lặp chạy trước và điều kiện chỉ quyết định có chạy thêm lần nữa hay không.

Điều kiện i < 5 sai ngay từ đầu. Vòng lặp while chạy 0 lần; do-while chạy đúng một lần. Đó là toàn bộ khác biệt giữa chúng.

Cú pháp và dấu chấm phẩy

do {
    // body - always runs at least once
} while (condition);

Thứ tự đọc đúng như thứ tự thực thi: làm (do) thân vòng lặp, trong khi (while) điều kiện vẫn đúng thì làm lại.

Dấu chấm phẩy sau dấu ngoặc đóng là bắt buộc. do ... while (cond); là một câu lệnh, và câu lệnh C kết thúc bằng dấu chấm phẩy. Bỏ quên nó thì trình biên dịch tiếp tục đọc, rồi báo lỗi cú pháp ở đâu đó phía dưới, vì thế lỗi thật thường cách dòng mà thông báo lỗi chỉ tới vài dòng.

Đây cũng là chỗ duy nhất trong C mà while (cond); có dấu chấm phẩy là đúng chứ không phải bug. Trong một vòng lặp while thường, cùng dấu câu đó tạo ra thân rỗng và thường là vòng lặp vô hạn; ở đây nó đóng lại một do.

Dấu ngoặc nhọn không bắt buộc khi thân chỉ có một câu lệnh, nhưng giống mọi cấu trúc điều khiển khác của C, bạn vẫn nên viết chúng.

Mẫu kiểm tra đầu vào

Đây là việc do-while được thiết kế để làm. Bạn phải đọc dữ liệu rồi mới biết nó có chấp nhận được không, nên lệnh đọc phải diễn ra trước phép kiểm tra:

Vòng lặp tiếp tục đọc cho đến khi có giá trị hợp lệ, và chính điều kiện loại bỏ giá trị sai cũng là điều kiện yêu cầu chạy thêm lần nữa. Nếu viết bằng while, lệnh đọc phải xuất hiện hai lần, một lần trước vòng lặp để chuẩn bị điều kiện, một lần ở cuối thân vòng lặp, và đó chính là sự trùng lặp mà do-while loại bỏ.

Với đầu vào thật, thân vòng lặp sẽ gọi scanf:

int age;
do {
    printf("Enter your age (1-120): ");
    if (scanf("%d", &age) != 1) {
        while (getchar() != '\n') { }   /* discard the bad line */
        age = -1;                        /* force another pass */
    }
} while (age < 1 || age > 120);

Để ý vòng lặp while bên trong dùng để bỏ phần còn lại của dòng. Nếu scanf không chuyển đổi được, đoạn văn bản gây lỗi vẫn nằm trong bộ đệm đầu vào và mọi lần đọc sau cũng thất bại vì nó, tạo ra một vòng lặp quay mãi và in câu hỏi không ngừng. Dọn bộ đệm là một phần của mẫu này.

Mẫu menu

Cách dùng kinh điển còn lại: hiện các lựa chọn, đọc một lựa chọn, thực hiện nó và lặp lại cho đến khi người dùng thoát. Menu phải xuất hiện trước khi có lựa chọn nào để kiểm tra.

break bên trong switch kết thúc switch, không phải vòng lặp, một điểm cần nói rõ vì cả hai dùng cùng một từ khóa. Ở đây vòng lặp kết thúc vì choice != 4 trở thành sai. Nếu bạn thật sự muốn thoát vòng lặp từ bên trong switch, hãy dùng return hoặc một biến cờ; chỉ break thì không làm được.

Lần chạy đầu được đảm bảo có thể là bug

Vì thân vòng lặp chạy trước mọi phép kiểm tra, do-while sẵn sàng xử lý cả dữ liệu không tồn tại:

/* BUG: prints a[0] even when n is 0 */
int i = 0;
do {
    printf("%d\n", a[i]);
    i++;
} while (i < n);

Với n == 0, đoạn này đọc a[0] trên một mảng rỗng, tức undefined behavior. Mọi vòng lặp duyệt qua một tập hợp có thể rỗng đều nên dùng while hoặc for, nơi phép kiểm tra đứng trước.

Quy tắc chung: chỉ dùng do-while khi việc chạy 0 lần là không thể do bản chất của bài toán, chứ không chỉ là hiếm gặp trong thực tế. Hỏi người dùng, tung xúc xắc cho đến khi ra số mong muốn, tạo và kiểm tra một ứng viên: những việc này thực sự không thể đánh giá trước lần chạy đầu tiên. Duyệt một danh sách thì không thể nói như vậy.

break và continue trong do-while

Cả hai đều dùng được, và continue có một điểm đáng biết: nó nhảy tới phép kiểm tra điều kiện, không phải lên đầu thân vòng lặp.

Lệnh i++ ở đầu thân vòng lặp chạy ở mọi lần lặp, kể cả những lần bị continue cắt ngang, nên vòng lặp vẫn tiến lên. Đặt lệnh cập nhật sau một continue thì vòng lặp sẽ treo, cùng một cái bẫy như vòng lặp while.

break thoát vòng lặp ngay lập tức và bỏ qua hoàn toàn điều kiện.

Chọn giữa ba loại vòng lặp

Ba vòng lặp của C mạnh như nhau; lựa chọn nằm ở chỗ vòng lặp nào thể hiện đúng ý định.

for        a counter, its limit, and its step belong together - "n times"
while      repeat until a condition changes, and maybe not at all - "until"
do-while   the same, but the first pass is guaranteed - "at least once"

Trong thực tế, do-while là loại hiếm gặp nhất trong ba loại, cách biệt rất xa. Phần lớn vòng lặp hoặc là đếm, hoặc phải xử lý trường hợp rỗng, và cả hai đều cần phép kiểm tra ở đầu. Hãy dùng do-while khi bạn thấy mình lặp lại một câu lệnh ngay trước vòng lặp while chỉ để chuẩn bị điều kiện: sự trùng lặp đó chính là tín hiệu.

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

Viết vòng lặp do-while trong C như thế nào?

do { body } while (condition);: thân vòng lặp đứng trước, phép kiểm tra đứng sau, và toàn bộ câu lệnh kết thúc bằng dấu chấm phẩy. Thân vòng lặp luôn chạy ít nhất một lần, sau đó lặp lại khi điều kiện còn khác 0.

while và do-while trong C khác nhau thế nào?

Khác ở vị trí phép kiểm tra. Vòng lặp while kiểm tra điều kiện trước lần chạy đầu tiên, nên có thể chạy 0 lần. do-while kiểm tra sau, nên luôn chạy ít nhất một lần. Chỉ chọn do-while khi bài toán thực sự cần lần chạy đầu tiên được đảm bảo đó.

Vì sao vòng lặp do-while cần dấu chấm phẩy ở cuối?

Vì do ... while (cond); là một câu lệnh duy nhất, và như mọi câu lệnh C khác, nó kết thúc bằng dấu chấm phẩy. Bỏ quên nó sẽ gây một lỗi cú pháp khó hiểu chỉ vào dòng phía sau, vì trình biên dịch tiếp tục đọc để tìm phần còn lại của câu lệnh.

Khi nào nên dùng vòng lặp do-while?

Khi thân vòng lặp phải chạy rồi bạn mới biết có cần lặp lại hay không: hiện menu trước khi đọc lựa chọn, hỏi lại cho đến khi đầu vào hợp lệ, hoặc tạo một giá trị rồi kiểm tra nó. Nếu điều kiện kiểm tra được ngay từ đầu, một vòng lặp while sẽ diễn đạt rõ ràng hơn.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu