Lập trình C : Bài 6 – Vòng lặp for trong C

1. Ví dụ mở đầu

Việc in ra tên của bạn rất đơn giản phải không. Một chương trình viết rất đơn giản.

#include <stdio.h>

int main()
{
    printf("Nguyen Van Quan\n");
    return 0;
}

Ok. Vậy bây giờ tôi muốn bạn in ra 10 lần tên bạn?

#include <stdio.h>

int main()
{
    printf("Nguyen Van Quan\n");
    printf("Nguyen Van Quan\n");
    printf("Nguyen Van Quan\n");
    printf("Nguyen Van Quan\n");
    printf("Nguyen Van Quan\n");
    printf("Nguyen Van Quan\n");
    printf("Nguyen Van Quan\n");
    printf("Nguyen Van Quan\n");
    printf("Nguyen Van Quan\n");
    printf("Nguyen Van Quan\n");
    return 0;
}

Khá đơn giản, chỉ cần copy thành 10 dòng printf là xong. Nhưng nếu không phải 10, mà là 1000 hoặc nhiều hơn? Rõ ràng việc copy là không khả thi.

Trong thực tế, các phần mềm sẽ có những công việc phải lặp đi lặp lại nhiều lần giống như ví dụ trên. Hoặc ví dụ như phần mềm của bạn cần in một danh sách các nhân viên, mỗi nhân viên có thông tin (nội dung) khác nhau nhưng cấu trúc thì rất giống nhau. Hoặc đơn giản hơn là bạn lướt facebook và thấy các tin bài từ bạn bè của mình, các tin này không giống nhau về nội dung nhưng cấu trúc thì rất giống nhau.

Để thực hiện được những công việc cần lặp lại nhiều lần như thế, chúng ta sẽ sử dụng cấu trúc vòng lặp gồm for, while, do-while. Bài này chúng ta sẽ tìm hiểu về vòng lặp for.

Chúng ta sẽ sửa lại ví dụ in 10 lần tên bạn như sau:

#include <stdio.h>

int main()
{
    int i;
    for (i = 1; i <= 10; i++)
    {
        printf("Nguyen Van Quan\n");
    }
    return 0;
}

Như code trên, tôi đã sử dụng vòng lặp for để thực hiện công việc in ra tên của mình 10 lần, với 1000 lần cũng thật đơn giản khi tôi thay số 10 thành số 1000 (bạn có thể thử). Nhìn vào code bạn cũng có thể hình dung cơ bản về việc chúng ta làm.

2. Cấu trúc vòng for

Vòng lặp for

Cú pháp, lưu đồ và cách hoạt động của vòng lặp for

Nhìn vào hình trên ta thấy vòng for có một cú pháp và cách hoạt động khá rõ ràng và dễ hiểu. Tuy nhiên các bạn cần lưu ý:

  • Sau lệnh for không có chấm phẩy.
  • 3 biểu thức của vòng lặp for ngăn cách nhau bằng dấu chấm phẩy (;), các biểu thức có thể vắng mặt 1,2 hoặc cả 3 nhưng vẫn phải có dấy chấm phẩy này.
  • Biểu thức 1 bao giờ cũng chỉ được tính toán một lần khi gọi thực hiện for.
  • Biểu thức 2, 3 và thân for có thể thực hiện lặp lại nhiều lần.
  • Biểu thức 1, 2, 3 phải phân cách bằng dấu chấm phẩy ( ; ), các biểu thức có thể vắng mặt 1,2 hoặc cả 3 nhưng vẫn phải có dấy chấm phẩy này.
  • Nếu biểu thức 2 không có, vòng for được xem là luôn luôn đúng. Muốn thoát khỏi vòng lặp for phải dùng một trong lệnh break, goto hoặc return.
  • Với mỗi biểu thức có thể viết thành một dãy biểu thức con phân cách nhau bởi dấu phẩy. Khi đó các biểu thức con được xác định từ trái sang phải. Tính đúng sai của dãy biểu thức con trong biểu thức thứ 2 được xác định bởi biểu thức con cuối cùng.
  • Trong thân for (khối lệnh) có thể chứa một hoặc nhiều cấu trúc điều khiển khác, vòng lặp khác.
  • Khi gặp lệnh break, cấu trúc lặp sâu nhất sẽ thoát ra.
  • Trong thân for có thểdùng lệnh goto để thoát khỏi vòng lặp đến vị trí mong muốn.
  • Trong thân for có thể sử dụng return để trở về một hàm nào đó.
  • Trong thân for có thể sử dụng lệnh continue để chuyển đến đầu vòng lặp (bỏ qua các câu lệnh còn lại trong thân).

Quay trở lại code của ví dụ trên:

#include <stdio.h>

int main()
{
    int i;
    for (i = 1; i <= 10; i++)
    {
        printf("Nguyen Van Quan\n");
    }
    return 0;
}

Quá trình hoạt động như sau:

  • Bước 1: Chạy biểu thức 1 tức là gán i = 1.
  • Bước 2: Chạy biểu thức 2 tức là kiểm tra i <= 10 không. Do i = 1 nên cái này đúng => Chạy khối lệnh tức là in ra tên.
  • Bước 3: Chạy biểu thức 3 tức là tăng i lên 1 đơn vị. Giờ thì i = 2.
  • Bước 4: Quay lại biểu thức 2. Kiểm tra i < 10 không. Do i = 2 nên vẫn đúng => Chạy khối lệnh, tức là in ra tên.
  • Bước 5: Chạy biểu thức 3 tức tăng i lên 1. Giờ i = 3.
  • Bước 6. Quay lại biểu thức 2,…
  • Bước….
  • Bước x: Chạy biểu thức 3, tăng i lên 1. Giờ i = 10.
  • Bước x+1: Quay lại biểu thức 2 tức kiểm tra i <= 10. Vẫn đúng => Chạy khối lệnh in ra tên.
  • Bước x+2: Chạy biểu thức 3, tăng i lên 1. Giờ i = 11.
  • Bước x+3: Quay lại biểu thức 2, kiểm tra i <=10. Giờ thì sai vì i đang là 11 => Thoát khỏi vòng for. Thực hiện lệnh tiếp theo ngang hàng vòng for (lệnh return 0 bên dưới).

Ok. Giờ các bạn đã cơ bản hiểu về vòng lặp for. Tiếp tục làm vài ví dụ nữa.

Ví dụ 1:

Viết chương trình in ra 15 lần tên của bạn, kèm theo thứ tự như sau:

  1. Nguyen Van Quan
  2. Nguyen Van Quan
  3. Nguyen Van Quan
  4. ….

Hum… làm sao lấy được các số tăng dần? Các bạn có nhìn vào quá trình chạy các bước của vòng for? Chúng ta có 1 biến i cứ tăng dần… Vậy chúng ta sẽ lợi dụng nó.

#include <stdio.h>

int main()
{
    int i;
    for (i = 1; i <= 10; i++)
    {
        printf("%d.Nguyen Van Quan\n", i);
    }
    return 0;
}

Ví dụ 2:

Hãy in ra các số dương chẵn từ 1 đến 20 trên cùng 1 dòng, cách nhau bởi dấu cách.

Chỉ cần cho i chạy từ 1 đến 20 và chúng ta sẽ kiểm tra số nào chẵn thì in ra. Để kiểm tra số chẵn, chúng ta nhớ lại phép chia lấy dư. Nếu i chia 2 dư 0 thì là số chẵn.

#include <stdio.h>

int main()
{
    int i;
    for (i = 1; i <= 20; i++)
    {
        if( i % 2 == 0) 
        {
            printf("%d ", i);
        }
    }
    return 0;
}

Ok. Tuy nhiên tôi muốn bạn suy nghĩ thêm chút trước khi nhìn xuống gợi ý và code. Làm sao không dùng if kiểm tra số chẵn mà vẫn làm được bài này?

Hãy nhớ các biểu thức trong for không phải là cố định, chúng ta có thể thay đổi nó. Và hãy thay đổi cách tăng i. Chúng ta cho i bắt đầu từ 2 và mỗi lần tăng thì tăng lên 2 đơn vị.

#include <stdio.h>

int main()
{
    int i;
    for (i = 2; i <= 20; i = i + 2)
    {
        printf("%d ", i);
    }
    return 0;
}

Rõ ràng code này ngon hơn code của lần trước đó. Ở trên chúng ta tăng i lên 2 đơn vị bằng lệnh i = i + 2.
Đây là phép gán i + 2 cho i, chứ không phải lệnh so sánh i và i + 2.

Ví dụ 3:

Tính tổng các số nguyên chẵn từ 1 đến 20.

#include <stdio.h>

int main()
{
    int i;
    int s = 0;
    for (i = 2; i <= 20; i = i + 2)
    {
        s = s + i;
    }

    printf("S = %d\n", s);

    return 0;
}

Chú ý trong code trên, chúng ta khai báo 1 biến s (viết tắt của sum) để lưu lại tổng. Mỗi lần i tăng lên thì chúng ta cộng dồn vào s bằng lệnh s = s + i.

Ví dụ 4:

Tính tổng các số lẻ từ 1 đến 20 nhưng đến khi nào tổng vượt quá 15 thì dừng lại.

Ở đây chúng ta sẽ cộng tổng các số lẻ, giống như các số chẵn thôi, tuy nhiên khi mà tổng lớn hơn 15 rồi thì chúng ta sẽ dừng lại, không cộng nữa.

#include <stdio.h>

int main()
{
    int i;
    int s = 0;
    for (i = 1; i <= 20; i = i + 2)
    {
        if(s <= 15)
        {
            s = s + i;
        }
    }

    printf("S = %d\n", s);

    return 0;
}

Đơn giản chỉ việc kiểm tra khi nào s vẫn nhỏ hơn hoặc bằng 15 thì ta cộng vào. Chúng ta sẽ có s = 1 + 3 + 5 + 7 = 16.

Tuy nhiên nếu bạn để ý, khi s > 15, chúng ta không cộng vào s nhưng vòng lặp for vẫn chạy cho đến khi i > 20. Tức là sẽ chạy tiếp các lần lặp i = 9, 11, 13, 15, 17, 19. Do vậy nó làm lãng phí, thừa thãi và làm chương trình chạy lâu hơn. Vì vậy chúng ta nên ngắt vòng lặp tại thời điểm thực hiện xong lệnh khi i = 7. Để thực hiện việc này có thể dùng break, hoặc goto, nhưng khuyên các bạn nên dùng break vì đơn giản và an toàn.

#include <stdio.h>

int main()
{
    int i;
    int s = 0;
    for (i = 1; i <= 20; i = i + 2)
    {
        if(s <= 15)
        {
            s = s + i;
        } else 
        {
            break;
        }
    }

    printf("S = %d\n", s);

    return 0;
}

Ví dụ 5

Nhập vào n số nguyên, tính tổng các số chẵn đã nhập.

#include <stdio.h>

int main()
{
    int i, n, x;
    int s = 0;

    printf("Enter n = ");
    scanf("%d", &n);

    for (i = 1; i <= n; i++)
    {
        printf("Enter number %d : ", i);
        scanf("%d", &x);

        if(x % 2 != 0) continue;

        s = s + x;
    }

    printf("S = %d\n", s);

    return 0;
}

Ở ví dụ này, tôi hướng dẫn các bạn cách dùng lệnh continue. Lệnh này không thoát khỏi vòn lặp nhưng lại có tác dụng là quay trở về biểu thức 3 mà không làm các lệnh đằng sau nó. Ở đây nếu x nhập vào không chẵn thì bỏ qua lệnh cộng dồn s mà chạy đến lệnh tăng i ngay.

Bài tập:

  1. Viết chương trình nhập vào số n và in ra các ước của số n đó.
  2. Viết chương trình kiểm tra 1 số có là số nguyên tố không? Số nguyên tố là số nguyên dương có duy nhất 2 ước là 1 và chính nó. Ví dụ số 2, 3, 5, …
  3. Viết chương trình kiểm tra 1 số có là số hoàn hảo không? Số hoàn hảo là số nguyên dương có tổng các ước bằng 2 lần nó. VD số 6 có các ước 1, 2, 3, 6 và tổng 1 + 2 + 3 + 6 = 12 (bằng 2 lần 6).
  4. Viết chương trình tính S = 1 + 1/2 + 1/3 + … + 1/N
  5. Viết chương trình tính tổng bình phương các số lẻ từ 1 đến n.
  6. Viết chương trình tính n! biết n! = 1.2.3.4…n
  7. Viết chương trình tính số thứ n của dãy fibonaci biết dãy f(n) = f(n-1) + f(n-2), n > 2 và f(1) = 1, f(2) = 1.
  8. Viết chương trình nhập vào chiều dài, chiều rộng của hình chữ nhật. Vẽ hình chữ nhật dấu sao (*) có kích thước đã nhập.