Cho đến nay, câu lệnh lặp được sử dụng nhiều nhất trong C++ là câu lệnh for. Câu lệnh for (còn được gọi là vòng lặp for) rất lý tưởng khi chúng ta biết chính xác số lần chúng ta cần lặp lại, bởi vì nó cho phép chúng ta dễ dàng xác định, khởi tạo và thay đổi giá trị của các biến vòng lặp sau mỗi lần lặp.

Câu lệnh for trông khá đơn giản trong tưởng tượng:

for (init-statement; condition-expression; end-expression)
   statement

Cách dễ nhất để hiểu một vòng lặp for là chuyển đổi nó thành một vòng lặp while tương đương:

{ // note the block here
    init-statement;
    while (condition-expression)
    {
        statement;
        end-expression;
    }
} // variables defined inside the loop go out of scope here

Các biến được định nghĩa bên trong một vòng lặp for có một phạm vi đặc biệt gọi là phạm vi vòng lặp. Các biến có phạm vi vòng lặp chỉ tồn tại trong vòng lặp và không thể truy cập được bên ngoài nó.

1. Đánh giá câu lệnh for

Một câu lệnh cho được đánh giá làm 3 phần:

  1. Init-statement. Thông thường, câu lệnh khởi tạo(Init-statement) bao gồm các định nghĩa và khởi tạo biến. Câu lệnh này chỉ được đánh giá một lần, khi vòng lặp được thực thi lần đầu tiên.

2) Biểu thức điều kiện(condition-expression) được ước tính. Nếu điều này đánh giá là sai, vòng lặp chấm dứt ngay lập tức. Nếu điều này đánh giá là đúng, câu lệnh được thực thi.

3) Sau khi câu lệnh được thực thi, biểu thức kết thúc(end-expression) được ước tính. Thông thường, biểu thức này được sử dụng để tăng hoặc giảm các biến được khai báo trong câu lệnh khởi tạo(Init-statement). Sau khi biểu thức kết thúc được ước tính, vòng lặp trở lại bước 2.

Hãy cùng xem một mẫu vòng lặp và thảo luận về cách thức hoạt động của nó:

for (int count{ 0 }; count < 10; ++count)
    std::cout << count << ' ';

Đầu tiên, chúng ta khai báo một biến vòng lặp có tên là Count và gán cho nó giá trị 0.

Thứ hai, Count <10 được ước tính và vì Count là 0, 0 <10 đánh giá là đúng. Do đó, câu lệnh thực thi, in 0.

Thứ ba, Count ++ được ước tính, số này tăng lên 1. Sau đó, vòng lặp quay lại bước thứ hai.

Bây giờ, 1 <10 được ước tính là true, do đó vòng lặp lặp lại. Câu lệnh in 1 và số được tăng lên 2.
2 <10 đánh giá là đúng, câu lệnh in 2 và số đếm được tăng lên 3. Và cứ thế.

Cuối cùng, Count được tăng lên thành 10, 10<10 ước tính thành sai và thoát khỏi vòng lặp.

Do đó, chương trình này in kết quả là:

0 1 2 3 4 5 6 7 8 9

Đối với các vòng lặp có thể khó đọc đối với các lập trình viên mới – tuy nhiên, các lập trình viên có kinh nghiệm yêu thích chúng vì chúng là một cách rất nhỏ gọn để thực hiện các vòng lặp. Hãy chuyển đổi vòng lặp ở trên thành vòng lặp while tương đương:

{ // outer braces ensure loop scope
    int count{ 0 };
    while (count < 10)
    {
        std::cout << count << ' ';
        ++count;
    }
}

Hàm này trả về lũy thừa của giá trị.

Đây là một mức tăng đơn giản cho vòng lặp, với số vòng lặp đếm từ 0 đến (nhưng không bao gồm) số mũ.

Nếu số mũ là 0, vòng lặp for sẽ thực thi 0 lần và hàm sẽ trả về 1.
Nếu số mũ là 1, vòng lặp for sẽ thực thi 1 lần và hàm sẽ trả về 1 * value.
Nếu số mũ là 2, vòng lặp for sẽ thực thi 2 lần và hàm sẽ trả về 1 * value * value.

Mặc dù hầu hết các vòng lặp làm tăng biến vòng lặp lên 1, chúng ta cũng có thể giảm nó:

for (int count{ 9 }; count >= 0; --count)
    std::cout << count << ' ';

Điều này in ra kết quả:

9 8 7 6 5 4 3 2 1 0

Thay phiên, chúng ta có thể thay đổi giá trị của biến vòng lặp nhiều hơn 1 với mỗi lần lặp:

for (int count{ 9 }; count >= 0; count -= 2)
    std::cout << count << ' ';

Điều này sẽ in kết quả:

9 7 5 3 1

2. Off-by-one errors

Một trong những vấn đề lớn nhất mà các lập trình viên mới gặp phải đối với các vòng lặp (và các loại vòng lặp khác) là Off-by-one. Lỗi Off-by-one xảy ra khi vòng lặp lặp quá nhiều hoặc quá ít lần. Điều này thường xảy ra vì toán tử quan hệ sai được sử dụng trong biểu thức điều kiện (ví dụ:> thay vì> =). Các lỗi này có thể khó theo dõi vì trình biên dịch sẽ không phàn nàn về chúng – chương trình sẽ chạy tốt, nhưng nó sẽ tạo ra kết quả sai.

Khi viết các vòng lặp, hãy nhớ rằng vòng lặp sẽ thực thi miễn là biểu thức điều kiện là đúng. Nói chung, nên kiểm tra các vòng lặp của bạn bằng các giá trị đã biết để đảm bảo rằng chúng hoạt động như mong đợi. Một cách tốt để làm điều này là kiểm tra vòng lặp của bạn với các đầu vào đã biết khiến nó lặp lại 0, 1 và 2 lần. Nếu nó hoạt động cho những cái đó, nó có thể sẽ hoạt động cho bất kỳ số lần lặp.

3. Bỏ qua biểu thức trong vòng lặp

Có thể viết cho các vòng lặp bỏ qua bất kỳ hoặc tất cả các biểu thức. Ví dụ: trong ví dụ sau, chúng ta sẽ bỏ qua câu lệnh khởi tạo và biểu thức kết thúc:

int count=0;
for ( ; count < 10; )
{
    std::cout << count << ' ';
    ++count;
}

Vòng lặp for này tạo ra kết quả:

0 1 2 3 4 5 6 7 8 9

Thay vì có vòng lặp for thực hiện khởi tạo và tăng dần. Chúng ta có thể thực hiện hoàn toàn cho mục đích học thuật trong ví dụ này, nhưng có những trường hợp không khai báo biến vòng lặp (vì bạn đã có một biến) hoặc không tăng nó (vì bạn đang tăng nó theo cách khác) là mong muốn.

Mặc dù bạn không thấy nó rất thường xuyên, điều đáng chú ý là ví dụ sau đây tạo ra một vòng lặp vô hạn:

for (;;)
    statement;

Ví dụ trên tương đương với:

while (true)
    statement;

Điều này có thể hơi bất ngờ, vì bạn có thể mong đợi một biểu thức điều kiện bị bỏ qua được coi là “sai”. Tuy nhiên, tiêu chuẩn C ++ rõ ràng (và không nhất quán) định nghĩa rằng một biểu thức điều kiện bị bỏ qua trong một vòng lặp for phải được coi là “đúng”.

Chúng tôi khuyên bạn nên tránh hoàn toàn hình thức vòng lặp for này và sử dụng while (true).

4. Nhiều khái báo khởi tạo trong vòng lặp

Mặc dù đối với các vòng lặp thường lặp lại chỉ qua một biến, đôi khi đối với các vòng lặp cần phải làm việc với nhiều biến. Khi điều này xảy ra, lập trình viên có thể sử dụng toán tử dấu phẩy để phân cách nhiểu biến (trong câu lệnh khởi tạo) hoặc thay đổi (trong câu lệnh kết thúc) giá trị của nhiều biến:

 int iii{};
    int jjj{};
    for (iii = 0, jjj = 9; iii < 10; ++iii, --jjj)
        std::cout << iii << ' ' << jjj << '\n';

Vòng lặp này gán giá trị cho hai biến được khai báo trước đó: iii thành 0 và jjj thành 9. Nó lặp lại iii trong phạm vi 0 đến 9 và mỗi lần lặp iii được tăng lên và jjj bị giảm.

Chương trình này tạo ra kết quả:

0 9
1 8
2 7
3 6
4 5
5 4
6 3
7 2
8 1
9 0

Lưu ý: Thông thường hơn, chúng ta sẽ viết vòng lặp ở trên là:

 for (int iii{ 0 }, jjj{ 9 }; iii < 10; ++iii, --jjj)
        std::cout << iii << ' ' << jjj << '\n';

5. Lồng các vòng lặp

Giống như các loại vòng lặp khác, đối với các vòng lặp for có thể được lồng bên trong các vòng lặp khác. Trong ví dụ sau, chúng ta lồng một vòng lặp for vào vòng lặp khác:

#include <iostream>
 
int main()
{
	for (char c{ 'a' }; c <= 'e'; ++c) // outer loop on letters
	{
		std::cout << c; // print our letter first
		
		for (int i{ 0 }; i < 3; ++i) // inner loop on all numbers
			std::cout << i;
 
		std::cout << '\n';
	}
 
	return 0;
}

Đối với mỗi lần lặp của vòng lặp bên ngoài, vòng lặp bên trong sẽ chạy toàn bộ. Do đó, đầu ra là:

a012
b012
c012
d012
e012

Dưới đây là một số chi tiết về những gì đang xảy ra ở đây. Vòng lặp bên ngoài chạy trước và char c được khởi tạo thành ‘a’. Sau đó, c <= ‘e’ được ước tính, điều này là đúng, do đó phần thân vòng lặp thực thi. Vì c được đặt thành ‘a’, lần đầu tiên này in ‘a’. Tiếp theo vòng lặp bên trong thực thi hoàn toàn (in ‘0’, ‘1’ và ‘2’). Sau đó, một dòng mới được in. Bây giờ thân vòng ngoài đã kết thúc, do đó vòng lặp ngoài trở về đỉnh, c được tăng lên ‘b’ và điều kiện vòng lặp được đánh giá lại. Vì điều kiện vòng lặp vẫn đúng nên lần lặp tiếp theo của vòng lặp bên ngoài bắt đầu. Bản in này (“b012 \ n”). Và như thế.

Bài tập C++ về Vòng lặp

6. Phần kết luận

Đối với các câu lệnh là vòng lặp được sử dụng phổ biến nhất trong ngôn ngữ C ++. Mặc dù cú pháp của nó thường hơi khó hiểu với các lập trình viên mới, bạn sẽ thấy các vòng lặp thường xuyên đến mức bạn sẽ hiểu chúng ngay lập tức!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!