Bỏ qua điều hướng, tới nội dung chính
Học C
Bài 6.115 phút đọc

while

Sau bài này bạn sẽ làm được

  • Viết vòng lặp while đúng với đủ ba thành phần
  • Giải thích vì sao while có thể chạy không lần nào
  • Nhận diện ba nguyên nhân khiến vòng lặp chạy vô hạn
  • Biết khi nào chọn while thay vì for

Vòng lặp là thứ biến máy tính từ một cỗ máy tính toán thành một cỗ máy làm việc. Trước Phần 2, chương trình của bạn chạy từ trên xuống đúng một lượt. Từ giờ nó lặp lại một đoạn công việc bao nhiêu lần cũng được, và đó là lúc bạn giải được những bài toán thật.

#Cú pháp

while (dieu_kien) {
    /* thân vòng lặp */
}

Máy kiểm tra điều kiện. Nếu đúng thì chạy thân, xong lại quay về kiểm tra điều kiện. Nếu sai thì thoát ra. Vòng lặp này kiểm tra trước, chạy sau.

dem.c
#include <stdio.h>

int main(void)
{
    int i = 1;                    /* 1. khởi tạo */

    while (i <= 5) {              /* 2. điều kiện */
        printf("%d ", i);
        i++;                      /* 3. cập nhật */
    }

    printf("\n");

    return 0;
}
terminal
gcc -std=c17 -Wall -Wextra dem.c -o dem && ./dem
1 2 3 4 5
Ô điều kiện nằm trước thân. Đó là toàn bộ khác biệt giữa while và do while ở bài sau.

#Ba thành phần bắt buộc

Mọi vòng lặp đếm đều cần đủ ba thứ. Thiếu bất kỳ cái nào cũng dẫn tới lỗi, và với while thì ba thứ đó nằm ở ba chỗ khác nhau nên rất dễ quên.

Thành phầnNằm ở đâuThiếu thì sao
Khởi tạoTrước vòng lặpBiến chứa rác, điều kiện cho kết quả ngẫu nhiên
Điều kiệnTrong ngoặc của whileLỗi cú pháp, hoặc vòng lặp vô hạn nếu viết số khác 0
Cập nhậtTrong thân, thường ở cuốiVòng lặp chạy vô hạn vì điều kiện không bao giờ đổi

Chạy tay từng lượt

Cách chắc chắn nhất để hiểu một vòng lặp là lập bảng và điền tay. Hãy làm điều này với mọi vòng lặp mà bạn chưa chắc.

Lượti trướci <= 5In rai sau
11đúng12
22đúng23
33đúng34
44đúng45
55đúng56
66saithoát6

#Có thể chạy không lần nào

Vì điều kiện được kiểm tra trước, nếu nó sai ngay từ đầu thì thân vòng lặp không chạy lần nào cả. Đây thường là điều bạn muốn.

int i = 100;

while (i < 10) {
    printf("dòng này không bao giờ in\n");
    i++;
}

#Ba nguyên nhân chạy vô hạn

Vòng lặp vô hạn ngoài ý muốn là lỗi phổ biến nhất khi mới học vòng lặp. Nó gần như luôn thuộc một trong ba nhóm sau.

Nguyên nhân 1: quên cập nhật

Không nên
int i = 0;

while (i < 10) {
    printf("%d ", i);
    /* quên i++ */
}
/* i mãi bằng 0 nên điều kiện mãi đúng. */
Nên
int i = 0;

while (i < 10) {
    printf("%d ", i);
    i++;
}

Nguyên nhân 2: điều kiện không bao giờ đạt tới

int i = 0;

while (i != 10) {
    i += 3;      /* i nhận 0, 3, 6, 9, 12, 15 ... không bao giờ bằng đúng 10 */
}

Nguyên nhân 3: so sánh số thực bằng dấu bằng kép

double f = 0.0;

while (f != 1.0) {
    f += 0.1;    /* f không bao giờ bằng đúng 1.0 */
}

Bài 2.3 đã giải thích: 0.1 không biểu diễn chính xác được ở hệ nhị phân, nên cộng mười lần cho ra một số rất gần 1 nhưng không bằng 1. Cách sửa là đếm bằng số nguyên.

for (int i = 0; i < 10; ++i) {
    double f = i * 0.1;   /* tính lại từ số nguyên mỗi lượt */
    /* ... */
}

#Khi nào chọn while

Quy tắc chọn
Dùng while khi không biết trước số lần lặp. Dùng for khi có biến đếm rõ ràng và biết trước số lần.

Bốn tình huống kinh điển của while:

/* 1. Đọc tới khi hết dữ liệu vào */
int c;

while ((c = getchar()) != EOF) {
    putchar(c);
}

/* 2. Đọc từng dòng của file */
char dong[256];

while (fgets(dong, sizeof dong, f) != NULL) {
    xu_ly(dong);
}

/* 3. Lặp tới khi đạt điều kiện toán học */
while (b != 0) {                 /* thuật toán Euclid tìm ước chung lớn nhất */
    int t = b;

    b = a % b;
    a = t;
}

/* 4. Duyệt cấu trúc dữ liệu chưa biết độ dài, học ở Chương 21 */
while (p != NULL) {
    printf("%d ", p->data);
    p = p->next;
}

Tự làm thử

  1. Tính tổng các số từ 1 tới n bằng while, so sánh kết quả với công thức n(n+1)/2.
  2. Nhập một số nguyên dương, đếm số chữ số của nó bằng cách chia liên tiếp cho 10.
  3. Cài thuật toán Euclid tìm ước chung lớn nhất, đếm xem nó chạy bao nhiêu lượt với cặp số 1071 và 462.
  4. Đọc từng ký tự từ bàn phím tới khi hết dữ liệu, đếm số ký tự, số từ và số dòng.
  5. Tái hiện đủ ba nguyên nhân vòng lặp vô hạn, mỗi cái một chương trình riêng, rồi sửa từng cái.
  6. Viết vòng lặp tìm số Fibonacci đầu tiên lớn hơn một triệu.

Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.

Tóm tắt

  • while kiểm tra điều kiện trước rồi mới chạy thân, nên có thể chạy không lần nào.
  • Ba thành phần bắt buộc là khởi tạo, điều kiện và cập nhật, nằm ở ba chỗ khác nhau.
  • Ba nguyên nhân chạy vô hạn: quên cập nhật, điều kiện không bao giờ đạt tới, và so sánh số thực bằng !=.
  • Ưu tiên so sánh khoảng bằng < thay vì so sánh bằng, để vòng lặp vẫn dừng khi biến chạy nhảy qua giá trị đích.
  • Dùng while khi không biết trước số lần lặp, dùng for khi có biến đếm rõ ràng.