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

break

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

  • Dùng break để thoát switch và thoát vòng lặp
  • Giải thích vì sao break chỉ thoát một tầng gần nhất
  • Thoát nhiều tầng bằng cờ hoặc bằng goto

break làm đúng một việc: thoát khỏi cấu trúc bao quanh nó gần nhất. Điều gây nhầm lẫn là nó chỉ thoát một tầng, nên trong vòng lặp lồng nhau, nó không làm điều mà nhiều người mong đợi.

#Hai vai trò của break

break dùng được ở đúng hai chỗ: trong switch và trong vòng lặp.

Trong switch: kết thúc một nhánh

switch (x) {
    case 1:
        printf("Một\n");
        break;              /* nếu thiếu, luồng rơi xuống case 2 */

    case 2:
        printf("Hai\n");
        break;
}

Trong vòng lặp: dừng sớm

/* Tìm phần tử, dừng ngay khi thấy */
long vi_tri = -1;

for (size_t i = 0; i < n; ++i) {
    if (a[i] == muc_tieu) {
        vi_tri = (long)i;
        break;              /* không cần duyệt tiếp */
    }
}

if (vi_tri >= 0) {
    printf("Tìm thấy tại %ld\n", vi_tri);
} else {
    printf("Không tìm thấy\n");
}

#Chỉ thoát một tầng

Đây là điểm quan trọng nhất của bài.

for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 3; ++j) {
        if (j == 1) {
            break;          /* chỉ thoát vòng j */
        }

        printf("%d,%d ", i, j);
    }
}

/* In ra: 0,0 1,0 2,0
   Vòng ngoài vẫn chạy đủ ba lần. */

#Thoát nhiều tầng

C không có break kèm nhãn như một số ngôn ngữ khác. Có ba cách thay thế.

Cách 1: dùng cờ

int xong = 0;

for (int i = 0; i < n && !xong; ++i) {
    for (int j = 0; j < m; ++j) {
        if (a[i][j] == muc_tieu) {
            xong = 1;
            break;
        }
    }
}

Cách này dễ hiểu nhưng phải kiểm tra cờ ở điều kiện của mọi vòng lặp bên ngoài, khá dài dòng khi lồng ba tầng trở lên.

Cách 2: dùng goto

for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
        if (a[i][j] == muc_tieu) {
            goto tim_thay;
        }
    }
}

printf("Không tìm thấy\n");
goto ket_thuc;

tim_thay:
printf("Tìm thấy\n");

ket_thuc: ;

Cách 3: tách thành hàm riêng

int tim(int a[][M], int n, int muc_tieu, int *hang, int *cot)
{
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < M; ++j) {
            if (a[i][j] == muc_tieu) {
                *hang = i;
                *cot  = j;

                return 1;      /* return thoát khỏi MỌI tầng vòng lặp */
            }
        }
    }

    return 0;
}

#Khi nào nên dùng

Duyệt hết vô ích
int tim_thay = 0;

for (size_t i = 0; i < n; ++i) {
    if (a[i] == x) {
        tim_thay = 1;
    }
}
/* Vẫn duyệt hết mảng dù đã tìm thấy ở phần tử đầu tiên. */
Dừng khi đã đủ
int tim_thay = 0;

for (size_t i = 0; i < n; ++i) {
    if (a[i] == x) {
        tim_thay = 1;
        break;
    }
}

Tự làm thử

  1. Viết chương trình tìm phần tử đầu tiên chia hết cho 7 trong một mảng, dùng break để dừng sớm. Đếm số lần lặp thực tế.
  2. Viết vòng lặp lồng hai tầng, dùng break ở vòng trong, quan sát vòng ngoài vẫn chạy tiếp.
  3. Tái hiện bẫy break trong switch nằm trong while, quan sát vòng lặp vô hạn, rồi sửa bằng cờ.
  4. Tìm một giá trị trong ma trận hai chiều bằng cả ba cách: dùng cờ, dùng goto, và tách thành hàm riêng. So sánh độ dễ đọc.
  5. Viết lại một vòng lặp có break thành vòng lặp có điều kiện dừng nằm trong phần điều kiện, so sánh hai cách.

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

  • break thoát khỏi switch hoặc vòng lặp bao quanh gần nhất.
  • Nó chỉ thoát một tầng, nên trong vòng lặp lồng nhau chỉ thoát vòng trong cùng.
  • break trong switch nằm trong vòng lặp chỉ thoát switch, không thoát vòng lặp.
  • Thoát nhiều tầng bằng cờ, bằng goto tiến về phía trước, hoặc tách thành hàm rồi return.
  • Tách thành hàm thường là cách tốt nhất vì return thoát khỏi mọi tầng.
  • Đừng rải quá nhiều break, nếu diễn đạt được điều kiện dừng ngay ở đầu vòng lặp thì tốt hơn.