Menu

Vòng lặp for trong C#: cú pháp, đếm ngược, lặp lồng nhau

Cách vòng lặp for trong C# hoạt động: phần khởi tạo, điều kiện và bước lặp, đếm ngược và bước nhảy, nhiều biến lặp, duyệt mảng theo chỉ số, vòng lặp lồng nhau, for(;;), cùng các lỗi lệch một đơn vị và xóa phần tử khi đang lặ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 (loop) for lặp lại một khối lệnh khi điều kiện còn đúng, với phần chuẩn bị và bước lặp được viết ngay trong phần đầu vòng lặp. Đây là vòng lặp dùng khi bạn đếm: lặp một số lần cố định, hoặc đi qua mọi chỉ số của một mảng.

Đầu ra:

Lap 1 of 5
Lap 2 of 5
Lap 3 of 5
Lap 4 of 5
Lap 5 of 5

Ba phần chạy như thế nào

for (initializer; condition; iterator) thực thi theo một thứ tự cố định:

  1. Phần khởi tạo (int i = 1) chạy một lần, trước mọi thứ khác.
  2. Điều kiện (i <= 5) được kiểm tra. Nếu sai, vòng lặp kết thúc và thân vòng lặp không chạy thêm lần nào.
  3. Thân vòng lặp chạy.
  4. Bước lặp (i++) chạy, rồi quay lại bước 2.

Vì điều kiện được kiểm tra trước mỗi lần lặp, một vòng lặp for có thể chạy không lần nào: for (int i = 10; i < 5; i++) không bao giờ vào thân. Vòng lặp ở trên hoạt động giống vòng lặp while này:

int i = 1;
while (i <= 5)
{
    Console.WriteLine($"Lap {i} of 5");
    i++;
}

Hai dạng này khác nhau ở một chi tiết: continue trong thân for vẫn chạy bước lặp, còn trong phiên bản while này nó sẽ nhảy qua i++, nên vòng lặp kiểm tra lại cùng giá trị i và có thể quay mãi không dừng. Một biến khai báo trong phần khởi tạo chỉ tồn tại bên trong vòng lặp. Nếu cần giá trị cuối cùng của nó sau đó, hãy khai báo trước vòng lặp: int i; for (i = 0; ...; i++) { }.

Đếm ngược và bước nhảy

Bước lặp có thể là bất kỳ biểu thức nào. Giảm để đếm ngược, cộng nhiều hơn một để nhảy bước, hoặc nhân để tạo dãy cấp số nhân:

Đầu ra:

3... 2... 1... liftoff
 00 15 30 45
 1 10 100 1000

Hãy chắc rằng bước lặp đưa điều kiện dần về sai. for (int i = 0; i < 10; i--) đếm xa dần khỏi 10 và chỉ dừng khi i bị tràn số sau hai tỷ lần lặp.

Duyệt mảng theo chỉ số

Mảng có Length, list có Count, và chỉ số hợp lệ chạy từ 0 đến giá trị đó trừ một. Chỉ số cho bạn những thứ mà foreach không có: biết vị trí, truy cập phần tử kề bên và được ghi ngược vào mảng.

Đầu ra:

#1: 17.99
#2: 4.50
#3: 38.25
#4: 7.43
item 1 vs item 0: down
item 2 vs item 1: up
item 3 vs item 2: down

Vòng lặp cuối bắt đầu từ 1 vì nó so sánh mỗi phần tử với phần tử đứng trước. Trang về mảng trình bày cách tạo, sắp xếp và sao chép mảng.

Nhiều biến lặp

Phần khởi tạo có thể khai báo nhiều biến cùng kiểu, và bước lặp có thể cập nhật nhiều biến, phân tách bằng dấu phẩy. Cách dùng kinh điển là hai chỉ số tiến dần về phía nhau:

Đầu ra:

racecar is a palindrome: True
9, 1, 8, 3

Trong cùng một khai báo, các biến phải cùng kiểu: int left = 0, right = 10 hợp lệ, còn int i = 0, string s = "" thì không.

Vòng lặp lồng nhau

Một vòng lặp nằm trong vòng lặp khác sẽ chạy hết phạm vi của nó cho mỗi lần lặp của vòng ngoài. Bảng và lưới là trường hợp điển hình:

Đầu ra:

   1   2   3   4
   2   4   6   8
   3   6   9  12
   4   8  12  16

Thân vòng trong chạy 16 lần (4 × 4). Lồng nhau làm khối lượng công việc tăng rất nhanh: hai vòng lặp lồng nhau, mỗi vòng qua 10.000 phần tử, là 100 triệu lần lặp. Một break trong vòng trong chỉ thoát khỏi vòng trong; trang break và continue chỉ cách thoát khỏi cả hai.

Vòng lặp vô hạn: for(;;)

Cả ba phần của phần đầu vòng lặp đều không bắt buộc. Không có điều kiện, vòng lặp chạy cho đến khi có thứ gì đó bên trong thoát ra:

Đầu ra:

Month 1: 70 left
Month 2: 40 left
Month 3: 10 left
Overdrawn in month 4: -20

for (;;) và while (true) được biên dịch thành cùng một thứ; hãy chọn cách mà codebase của bạn đang dùng.

Lỗi lệch một đơn vị

Lỗi for phổ biến nhất là điều kiện đi quá một bước:

Đầu ra:

Ada
Grace
Linus
IndexOutOfRangeException at index 3

Một mảng 3 phần tử có chỉ số 0, 1 và 2, nên i < names.Length là điều kiện đúng. Lỗi ngược lại là đếm lùi với i > 0, khiến chỉ số 0 không bao giờ được duyệt. Với List<T>, cùng lỗi đó sẽ ném ArgumentOutOfRangeException.

Xóa phần tử khi đang lặp

Xóa khỏi một List<T> trong vòng lặp tiến sẽ dịch mọi phần tử phía sau lùi một vị trí, nên vòng lặp bỏ qua phần tử ngay sau mỗi lần xóa:

Đầu ra:

forward:  5, 0, 3, 7
backward: 5, 3, 7

Vòng lặp tiến còn sót lại một số 0: sau khi xóa chỉ số 1, số 0 thứ hai dịch về chỉ số 1, nhưng i++ đã chuyển sang chỉ số 2. Lặp ngược tránh được lỗi này vì việc xóa chỉ dịch những phần tử bạn đã duyệt qua. Muốn một cách viết trên một dòng, stock.RemoveAll(x => x == 0) làm đúng việc đó. Vòng lặp foreach hoàn toàn không cho xóa; nó ném InvalidOperationException.

Biến đếm số thực

Tránh biến đếm kiểu double khi điều kiện so sánh bằng. 0.1 không có biểu diễn nhị phân chính xác, nên cộng nó mười lần không cho ra đúng 1.0:

for (double x = 0; x != 1.0; x += 0.1)   // never ends: x skips past 1.0
{
}

Thay vào đó, hãy đếm bằng số nguyên và tính giá trị từ nó: for (int i = 0; i <= 10; i++) { double x = i / 10.0; }.

for và foreach

Nhu cầuDùng
Đọc lần lượt mọi phần tửforeach
Cần chỉ số, hoặc phần tử kề bên (i - 1, i + 1)for
Gán vào một phần tử mảngfor
Nhảy 2 bước, đi ngượcfor
Xóa khỏi List khi đang lặpfor, lặp ngược
Collection không có indexer (HashSet, Dictionary, kết quả LINQ)foreach
Lặp một việc N lần, không có collectionfor

Với mảng, hai vòng lặp được biên dịch thành code gần như giống hệt nhau, nên hãy chọn theo độ dễ đọc, không phải tốc độ.

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

Cú pháp của vòng lặp for trong C# là gì?

for (initializer; condition; iterator) { body }, ví dụ for (int i = 0; i < 5; i++) { ... }. Phần khởi tạo chạy một lần, điều kiện được kiểm tra trước mỗi lần lặp, và bước lặp chạy sau mỗi lần lặp. Vòng lặp kết thúc ngay lần đầu tiên điều kiện sai.

Làm sao lặp ngược trong C#?

Bắt đầu từ chỉ số cuối cùng và giảm dần: for (int i = items.Length - 1; i >= 0; i--). Chú ý là >= 0 chứ không phải > 0, nếu không phần tử đầu tiên sẽ bị bỏ qua. Lặp ngược cũng là cách an toàn để xóa phần tử khỏi một List trong lúc đang lặp.

Khi nào nên dùng for thay cho foreach trong C#?

Dùng for khi bạn cần chỉ số (để so sánh các phần tử kề nhau, ghi ngược vào mảng hoặc nhảy nhiều hơn một bước), khi bạn đếm chứ không duyệt một collection, hoặc khi bạn xóa phần tử khỏi một list. Dùng foreach để đọc lần lượt mọi phần tử; nó ngắn hơn và không có chỉ số để viết sai.

Làm sao viết vòng lặp vô hạn trong C#?

for (;;) { ... } hoặc while (true) { ... }. Cả ba phần của phần đầu for đều không bắt buộc, và thiếu điều kiện thì được coi là đúng. Thoát khỏi vòng lặp bằng break hoặc return khi điều kiện dừng của bạn được thỏa mãn.

Vì sao vòng lặp for của tôi gặp IndexOutOfRangeException?

Điều kiện cho phép chỉ số chạm tới độ dài: i <= array.Length truy cập array[array.Length], vượt quá phần tử cuối một vị trí. Chỉ số hợp lệ chạy từ 0 đến Length - 1, nên điều kiện phải là i < array.Length (hoặc i < list.Count với List, khi đó lỗi ném ra là ArgumentOutOfRangeException).

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