Menu

Vòng lặp while và do while trong C#: cú pháp, đọc input, lỗi

Cách vòng lặp while và do-while hoạt động trong C#: điều kiện được kiểm tra trước hay sau thân vòng lặp, đọc input đến khi gặp từ dừng hoặc hết input, while (true) với break, và những lỗi vòng lặp vô hạn hay gặp.

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 while lặp lại thân của nó chừng nào điều kiện vẫn còn đúng. Dùng nó khi bạn không biết trước cần bao nhiêu lần lặp: tiếp tục cho đến khi số dư đạt mục tiêu, hàng đợi trống hoặc hết input.

Đầu ra:

Year 1: 1070.00
Year 2: 1144.90
Year 3: 1225.04
Year 4: 1310.80
Year 5: 1402.55
Year 6: 1500.73
Goal reached after 6 years

Điều kiện được kiểm tra trước mỗi lần lặp, kể cả lần đầu tiên. Nếu savings đã đạt mục tiêu từ đầu, thân vòng lặp sẽ không chạy lần nào và chương trình in ra "after 0 years". Vòng lặp dựa vào việc thân thay đổi thứ mà điều kiện đọc; ở đây savings tăng lên mỗi năm cho đến khi savings < goal trở thành false.

do while: chạy ít nhất một lần

Vòng lặp do while chuyển phép kiểm tra xuống cuối, nên thân luôn chạy ít nhất một lần:

Đầu ra:

Attempt 1: got 7
Attempt 2: got 4
Attempt 3: got 1
Done after 3 attempts

Giá trị đầu tiên của code chỉ có sau khi thân đã chạy một lần, đúng là lúc nên dùng do while. Có hai chi tiết cú pháp hay làm người ta vấp:

  • Dấu chấm phẩy sau while (code != 1) là bắt buộc. Thiếu nó là lỗi biên dịch.
  • Các biến dùng trong điều kiện phải được khai báo trước do. Biến khai báo bên trong cặp ngoặc nhọn đã ra khỏi phạm vi khi điều kiện chạy, nên do { int code = ...; } while (code != 1); không biên dịch được.

Cùng vòng lặp đó viết bằng while sẽ cần hoặc gọi lặp lại một lần trước vòng lặp, hoặc một giá trị khởi đầu giả để ép lần chạy đầu tiên. do while diễn đạt thẳng ý "thử, rồi quyết định có thử lại không".

Đọc input đến khi gặp từ dừng

Đọc từng dòng cho đến một từ dừng (sentinel) hoặc đến khi hết input là ví dụ kinh điển của vòng lặp while. Console.ReadLine() trả về null khi không còn input, nên hãy kiểm tra cả hai:

Đầu ra:

skipping "abc": not a number
3 amounts, total 49.50

(line = Console.ReadLine()) != null gán dòng tiếp theo và kiểm tra nó trong cùng một biểu thức; cặp ngoặc quanh phép gán là bắt buộc vì != có độ ưu tiên cao hơn =. Vòng lặp dừng ở done, nên số 99 phía sau không bao giờ được đọc. decimal.TryParse từ chối abc mà không ném ngoại lệ, và continue nhảy sang dòng kế tiếp. Nếu thiếu phép kiểm tra null, khi hết input chương trình sẽ truyền null vào TryParse mãi mãi, vì ReadLine cứ tiếp tục trả về null.

do while hợp với mẫu hỏi rồi kiểm tra, khi câu hỏi phải xuất hiện ít nhất một lần:

Đầu ra:

Enter your age:
"-4" is not a valid age
Enter your age:
"fifteen" is not a valid age
Enter your age:
Age accepted: 15

Câu hỏi nằm trong vòng lặp nên được hỏi lại sau mỗi câu trả lời bị từ chối, và age được khai báo trước do để code sau vòng lặp dùng được. Khi có người dùng gõ phím, mỗi câu trả lời hiện trên console ngay sau câu hỏi; khi input được chuyển hướng như ở đây, chỉ có đầu ra của chính chương trình được hiển thị.

while (true) với break

Đôi khi điểm thoát tự nhiên nằm giữa thân vòng lặp, sau một phần việc và trước phần còn lại. Hãy viết vòng lặp là while (true) và thoát ra bằng break:

Đầu ra:

processing: resize photo
processing: send email
stop signal received
1 job(s) left in the queue

Dequeue lấy công việc tiếp theo ra khỏi đầu hàng đợi, và vòng lặp thoát ngay khi gặp dấu hiệu dừng, nên công việc cuối cùng vẫn nằm trong hàng đợi. while (true) không phải dấu hiệu code tệ khi điểm thoát rõ ràng và nằm gần đầu thân vòng lặp. Nó trở thành vấn đề khi có nhiều break rải rác trong một thân dài; lúc đó một điều kiện bool có tên rõ ràng hoặc một phương thức với return sẽ dễ theo dõi hơn. Trang break và continue có nói về cách thoát khỏi vòng lặp lồng nhau.

Vòng lặp không bao giờ dừng

Một vòng lặp vô hạn ngoài ý muốn thường có một trong ba nguyên nhân.

Thân vòng lặp không bao giờ thay đổi điều kiện. Biến đếm không bao giờ được tăng, hoặc tăng nhầm biến:

int i = 0;
while (i < 5)
{
    Console.WriteLine(i);   // i++ forgotten: prints 0 forever
}

Dấu chấm phẩy sau điều kiện. Dấu chấm phẩy chính là toàn bộ thân của vòng lặp, còn khối lệnh bên dưới chỉ chạy sau vòng lặp (mà vòng lặp không bao giờ kết thúc):

while (retries < 3);        // warning CS0642: Possible mistaken empty statement
{
    retries++;
}

Điều kiện nhảy qua mục tiêu. Kiểm tra bằng != khi biến thay đổi theo bước có thể nhảy qua giá trị dừng. while (x != 10) x += 3; đi qua 0, 3, 6, 9, 12 và vượt luôn qua 10 (nó chỉ tình cờ chạm 10 sau khi int tràn số và quay vòng, hàng tỷ bước sau đó). Hãy kiểm tra bằng < hoặc > thay cho != mỗi khi bước nhảy khác 1. Điều này cũng đúng với giá trị double, vốn hiếm khi trúng chính xác mục tiêu: while (x != 1.0) x += 0.1; không bao giờ dừng.

Chọn giữa while, do while và for

Tình huốngVòng lặp
Biết trước số lần lặp, hoặc cần chỉ sốfor
Duyệt mọi phần tử của một collectionforeach
Lặp chừng nào điều kiện còn đúng, có thể không lần nàowhile
Thân phải chạy một lần trước khi điều kiện có nghĩado while
Điều kiện thoát nằm giữa thân vòng lặpwhile (true) với break

Mọi vòng lặp for đều có thể viết lại thành while và ngược lại; lựa chọn nằm ở chỗ cách nào đặt logic của vòng lặp ở nơi người đọc mong đợi. Khi có đủ biến đếm, phép kiểm tra và bước nhảy, for giữ chúng trên một dòng. Khi vòng lặp được điều khiển bởi trạng thái thay đổi bên trong thân, while thể hiện đúng điều đó.

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

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

Vòng lặp while kiểm tra điều kiện trước mỗi lần lặp, nên thân vòng lặp có thể không chạy lần nào. Vòng lặp do { } while (condition); kiểm tra sau mỗi lần lặp, nên thân luôn chạy ít nhất một lần. Dùng do while khi lần chạy đầu tiên tạo ra giá trị mà điều kiện cần kiểm tra, chẳng hạn đọc input rồi mới kiểm tra hợp lệ.

Cú pháp vòng lặp do while trong C# là gì?

do { body } while (condition);. Chú ý dấu chấm phẩy sau dấu ngoặc đóng: nó là bắt buộc, thiếu nó là lỗi biên dịch. Điều kiện có thể dùng các biến được gán trong thân, nhưng chúng phải được khai báo trước do, vì cặp ngoặc nhọn của thân là một phạm vi riêng.

Viết while (true) trong C# thế nào?

while (true) { ... } lặp mãi cho đến khi có gì đó bên trong thoát ra bằng break, return hoặc một ngoại lệ. Đây là cách viết tự nhiên khi điều kiện thoát nằm ở giữa thân vòng lặp, chẳng hạn đọc một dòng và dừng khi dòng đó rỗng.

Làm sao đọc input đến khi người dùng gõ một từ hoặc hết input trong C#?

Lặp trên Console.ReadLine(), hàm này trả về null khi hết input: string line; while ((line = Console.ReadLine()) != null && line != "done") { ... }. Phép gán bên trong điều kiện vừa đọc dòng tiếp theo vừa kiểm tra nó trong một bước.

Vì sao vòng lặp while trong C# của tôi không bao giờ dừng?

Thường là do thân vòng lặp không bao giờ thay đổi thứ mà điều kiện kiểm tra (quên i++), hoặc có dấu chấm phẩy ngay sau điều kiện: while (count < 10); là vòng lặp có thân rỗng và quay mãi không dừng. Trình biên dịch cảnh báo trường hợp thứ hai bằng CS0642, Possible mistaken empty statement.

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