Trong lập trình C, ngoài các câu lệnh điều kiện rẽ nhánh như if hay switch, các cấu trúc vòng lặp đóng vai trò cốt lõi trong việc xử lý các tác vụ lặp đi lặp lại. Việc sử dụng vòng lặp giúp tối ưu hóa mã nguồn, tránh việc sao chép dư thừa các đoạn code và quản lý luồng thực thi của chương trình hiệu quả hơn.
Vòng lặp While
Vòng lặp while thuộc dạng "kiểm tra trước thực hiện sau". Điều này có nghĩa là trình biên dịch sẽ kiểm tra điều kiện trước, nếu điều kiện đúng (true) thì khối lệnh bên trong mới được thực thi. Nếu điều kiện sai ngay từ đầu, khối lệnh sẽ không bao giờ được chạy.
Cấu trúc này thường được áp dụng khi số lần lặp không được xác định trước, phụ thuộc vào một trạng thái hoặc dữ liệu đầu vào từ người dùng.
#include <stdio.h>
int main() {
char confirm = 'y';
printf("Bat dau xu ly (y/n)? ");
scanf(" %c", &confirm);
// Xoa ky tu '\n' con lai trong bo nho dem sau lan nhap dau tien
while(getchar() != '\n');
while (confirm == 'y') {
printf("Dang thuc thi tien trinh...\n");
printf("Tiep tuc (y/n)? ");
scanf(" %c", &confirm);
// Doc ky tu newline de khong bi trong bo dem lan sau
while(getchar() != '\n');
}
printf("Ket thuc chuong trinh.\n");
return 0;
}
Lưu ý kỹ thuật: Khi sử dụng hàm scanf để đọc ký tự, ký tự xuống dòng \n từ lần nhập trước vẫn còn nằm trong bộ đệm (buffer). Lần gọi scanf tiếp theo sẽ tự động lấy ký tự này thay vì chờ người dùng nhập mới. Để khắc phục, cần dùng getchar() để làm sạch bộ đệm.
Vòng lặp Do-While
Khác với while, vòng lặp do-while đảm bảo khối lệnh được thực hiện ít nhất một lần trước khi kiểm tra điều kiện. Cấu trúc này phù hợp với các kịch bản cần khởi tạo hoặc hiển thị menu trước khi hỏi người dùng có muốn tiếp tục hay không.
#include <stdio.h>
int main() {
int choice = 0;
do {
printf("\n--- Menu Chinh ---\n");
printf("1. Chuc nang A\n");
printf("2. Thoat\n");
printf("Nhap lua chon: ");
scanf("%d", &choice);
if (choice == 1) {
printf("Da chon chuc nang A.\n");
}
} while (choice != 2);
printf("Tam biet!\n");
return 0;
}
Vòng lặp For
Vòng lặp for là lựa chọn tối ưu nhất khi số lần lặp được biết trước. Cấu trúc của nó gộp ba thành phần quan trọng: khởi tạo, điều kiện lặp, và bước tăng/giảm biến đếm vào cùng một dòng, giúp mã nguồn gọn gàng hơn.
#include <stdio.h>
int main() {
int total = 0;
// Tinh tong cac so chan tu 1 den 20
for (int n = 1; n <= 20; n++) {
if (n % 2 == 0) {
total += n;
}
}
printf("Tong cac so chan tu 1 den 20 la: %d\n", total);
return 0;
}
Quy tắc thực thi: Biến khởi tạo chỉ chạy một lần duy nhất. Sau mỗi lần lặp, biểu thức cập nhật biến sẽ được thực hiện và điều kiện được kiểm tra lại. Nếu bỏ qua điều kiện, vòng lặp sẽ trở thành vô tận.
Các câu lệnh điều khiển vòng lặp
Trong quá trình lặp, đôi khi chúng ta cần can thiệp vào luồng bình thường của vòng lặp thông qua các từ khóa sau:
1. Continue
Lệnh continue sẽ bỏ qua các đoạn code còn lại của lần lặp hiện tại và nhảy ngay sang lần lặp tiếp theo.
// In ra cac so tu 1 den 10, tru so 5
for (int i = 1; i <= 10; i++) {
if (i == 5) {
continue; // Bo qua viec in so 5
}
printf("%d ", i);
}
2. Break
Lệnh break dùng để thoát hoàn toàn ra khỏi vòng lặp (hoặc cấu trúc switch) ngay lập tức, bất kể điều kiện lặp có còn đúng hay không.
// Tim kiem so am trong day so
int arr[] = {2, 4, -1, 8, 10};
for (int i = 0; i < 5; i++) {
if (arr[i] < 0) {
printf("Tim thay so am tai vi tri %d\n", i);
break; // Dung tim kiem
}
}
3. Return
Trong hàm main hoặc bất kỳ hàm nào, lệnh return sẽ kết thúc hàm đó ngay lập tức và trả về giá trị (nếu có). Nếu nằm trong vòng lặp, nó sẽ chấm dứt cả vòng lặp và hàm chứa nó.
for (int i = 0; i < 10; i++) {
if (i > 5) {
return 1; // Ket thuc toan bo chuong trinh voi ma 1
}
printf("Dang xu ly: %d\n", i);
}
4. Goto
Lệnh goto cho phép nhảy vô điều kiện đến một nhãn (label) được định nghĩa trong cùng một hàm. Tuy nhiên, việc sử dụng goto thường được khuyến khích hạn chế vì nó làm rối loạn cấu trúc luồng của chương trình.
int counter = 0;
start_label:
printf("Counter: %d\n", counter);
counter++;
if (counter < 3) {
goto start_label; // Nhap lai vong lap
}