Trần Lê Hùng Phi – Cấu trúc lặp

    • Ngay khi tổng Ti lớn hơn n thì dừng việc tính toán. Hay nói cách khác, khi Ti còn nhỏ hơn hoặc bằng n thì còn thực hiện việc tính toán.

Như vậy giải pháp của chúng ta có thể là: Trong khi tổng nhỏ hơn hoặc bằng n thì tăng i và tính tổng mới. Dưới đây là một trong những cách giải của bài toán trên:

#include <iostream>;

using namespace std;

int main(){

int n;

cout << “Nhap so tu nhien n: “;

cin >> n;

int kq = 0, i = 0;

while (kq <= n){

++i;

kq += i;

}

cout << kq;

return 0;

}

Chương trình trên bám rất sát với với giải pháp mà thầy đưa ra. Song, vẫn còn nhiều cách làm khác, các em hãy thỏa sức thử nghiệm nhé.

Vòng lặp do…while

Cú pháp của vòng lặp do…while như sau:

do{

<(các) câu lệnh>;

} while (<điều kiện>);

Các em có thể thấy khác với vòng lặp for hay vòng lặp while, cú pháp của vòng lặp do…while có phần <điều kiện> nằm ở dưới cùng. Điều này gây ra sự khác biệt về cách thực hoạt động giữa vòng lặp do…while và vòng lặp while, dù cho các thành phần <(các) câu lệnh> và <điều kiện> giống nhau.

Vòng lặp do…while hoạt động như sau: Thực hiện <(các) câu lệnh>, sau đó kiểm tra <điều kiện>. Nếu <điều kiện> đúng, quay lại bước đầu; ngược lại, vòng lặp do…while sẽ kết thúc và câu lệnh tiếp theo vòng lặp do…while sẽ được thực hiện.

Như vậy, dù cho <điều kiện> đúng hay sai, <(các) câu lệnh> trong vòng lặp do…while cũng thực hiện được ít nhất một lần.

Ví dụ:

Nhập số tự nhiên n (100 ≤ n < 1000). In ra màn hình số tự nhiên n.

Nếu giá trị nhập vào không thỏa điều kiện đề bài thì buộc người dùng nhập lại.

Ví dụ trên là là một bài toán lặp với số lần không biết trước đơn giản. Vấn đề ở đây là ta cần phải kiểm tra xem n có phải là số tự nhiên thuộc nửa khoảng [100; 1000) hay không. Nếu đúng thì in ra màn hình giá trị của n; ngược lại; nhập lại giá trị cho n.

Nhận xét:

    • Việc nhập giá trị cho n sẽ được thực hiện ít nhất một lần để kiểm tra giá trị. Vậy đây là một trong các tình huống có thể dùng vòng lặp do…while.

    • Điều kiện để dừng vòng lặp là: n là số tự nhiên thuộc nửa khoảng [100; 1000). Nói cách khác, điều kiện để vòng lặp được thực hiện là n < 100 hoặc n >= 1000.

Dưới đây là môt trong những cách giải quyết vấn đề với vòng lặp do…while.

#include <iostream>;

using namespace std;

int main(){

int n;

do {

cout << “Nhap so tu nhien n (100 <= n < 1000): “;

cin >> n;

//Phần thông báo

if (n < 0) cout << “n khong phai so tu nhien” << endl;

else {

if ((n < 100)||(n>=1000))

cout << “n khong thoa dieu kien” << endl;

else cout << “n thoa dieu kien” << endl;

}

//Kết thúc phần thông báo

} while ((n < 100)||(n >= 1000));

cout << n;

return 0;

}

Các em có thể thấy chương trình trên có một phần câu lệnh if…else với mục đích kiểm tra giá trị của biến n và gửi thông báo tương ứng, thầy gọi đó là phần thông báo. Nếu chỉ có các em sử dụng chương trình thì phần này có thể không cần thiết; nhưng trong trường hợp có nhiều người dùng chương trình, các em cần có những phần thông báo để được ra các chỉ dẫn đúng cho người dùng.

Và đừng quên dấu chấm phẩy (;) sau phần while (<điều kiện>) nhé.

Các vòng lặp lồng nhau

Một vòng lặp có thể được lồng trong một vòng lặp khác. Trong ngôn ngữ lập trình C++, ta có thể lồng vào nhau tối đa 256 cấp độ. Có thể một số bạn thắc mắc về “cấp độ”, thầy sẽ đưa ra ví dụ sau khi giới thiệu về cú pháp của các vòng lặp lồng nhau.

Cú pháp của vòng lặp for lồng nhau:

for (<khởi tạo 1>; <điều kiện 1>; <thay đổi 1>){

for (<khởi tạo 2>; <điều kiện 2>; <thay đổi 2>){

<(các) câu lệnh 2)>;

}

<(các) câu lệnh 1>; //Các em có thể thêm các câu lệnh hoặc không

}

Cú pháp của vòng lặp while lồng nhau:

while (<điều kiện 1>){

while (<điều kiện 2>){

<(các) câu lệnh 2>;

}

<(các) câu lệnh 1>; //Các em có thể thêm các câu lệnh hoặc không

}

Cú pháp của vòng lặp do…while lồng nhau:

do {

<(các) câu lệnh 1>; //Các em có thể thêm các câu lệnh hoặc không

do {

<(các) câu lệnh 2>;

} while (<điều kiện 2>);

} while (<điều kiện 1>);

Cấp độ của vòng lặp được xác định như sau:

//Cấp độ 1

while (<điều kiện>){

//Cấp độ 2

while (<điều kiện>){

//Cấp độ 3

while (<điều kiện>{

<(các) câu lệnh>;

}

<(các) cậu lệnh>;

}

//Cấp độ 2

while (<điều kiện>){

<(các) câu lệnh>;

}

<(các) câu lệnh>;

}

Ở trên là ví dụ với vòng lặp while, vòng lặp for hay vòng lặp do…while tương tự.

Ví dụ:

In ra các số nguyên tố trong khoảng từ 2 đến 100.

Số nguyên tố là các số tự nhiên có hai ước số dương phân biệt là 1 và chính nó.

Chúng ta hãy cùng nhìn qua và phân tích đề bài một chút:

    • “In ra các số nguyên tố trong khoảng từ 2 đến 100”, đọc vào là có thể thấy ngay ta cần một vòng lặp thực hiện việc “in ra các số nguyên tố” và sẽ được thực hiện tuần tự từ 2 đến 100. Điều này có nghĩa là ta đã biết trước được số lần lặp (hay điểm bắt đầu và điểm kết thúc là các số xác định). Trong trường hợp này, dùng vòng lặp for được khuyến khích.

    • Vấn đề thứ đầu tiên đó là việc “in ra các số nguyên tố” gồm những công đoạn nào? Ta phải “kiểm tra xem một số có phải là số nguyên tố hay không”, nếu đúng thì in số đó ra. Trước khi đào sâu thêm, ta có thể nhận ra ở đây có dùng cấu trúc rẽ nhánh: Nếu (là_số_nguyên_tố) {in_ra_màn_hình};

    • Vấn đề thứ hai là việc “kiểm tra xem một số có phải là số nguyên tố hay không”. Ta sẽ đi từ định nghĩa số nguyên tố, như vậy ta phải kiểm tra số ước của số đó. Và vấn đề trở thành bài toán đếm số ước mà ta đã giải ở trên.

Dưới đây là bài giải cho ví dụ trên, thầy cũng đã cải tiến “một chút” về vấn đề “đếm số ước số”.

#include <iostream>

#include <math.h>

using namespace std;

int main(){

int i, j, dem;

for (i = 2; i <= 100; ++i){

dem = 0;

for (j = 2; j <= sqrt(i); ++j){

if (!(i%j)) ++dem;

}

if (!dem) cout << i << ” la so nguyen to” << endl;

}

return 0;

}

Các lệnh điều khiển vòng lặp

Các lệnh điều khiển vòng lặp làm cho chương trình thực hiện khác với trình tự thông thường của nó. Ví dụ, như các em đã biết, vòng lặp while có trình tự thực hiện là: kiểm tra điều kiện; nếu điều kiện đúng, thực hiện các câu lệnh; ngược lại, kết thúc vòng lặp. Trong các lệnh điều khiển vòng lặp, có lệnh có thể kết thúc vòng lặp while ngay, và cũng có lệnh có thể bỏ qua bước kiểm tra điều kiện.

Câu lệnh break

Các em đã gặp câu lệnh này ở bài trước, đối với câu lệnh switch, câu lệnh break có tác dụng là:

    • “Khi gặp lệnh break, câu lệnh switch kết thúc và chương trình thực hiện câu lệnh tiếp theo, sau câu lệnh switch.” – Trích bài 7.

Bên cạnh đó, đối với câu trúc lặp, câu lệnh break có tác dụng là:

  • Khi gặp câu lệnh break trong vòng lặp, vòng lặp kết thúc ngay lập tức, chương trình tiếp tục thực hiện các câu lệnh phía sau cấu trúc lặp.

Nếu em đang sử dụng các vòng lặp lồng nhau, câu lệnh break sẽ ngừng cấu trúc lặp chứa nó và chương trình tiếp tục thực hiện các câu lệnh phía sau cấu trúc lặp đó. Thầy lấy ví dụ:

for (int i = 1; i <= 3; ++i){

for (int j = 1; j <= 3; ++j)

cout << i << ” ” << j << endl;

break;

}

Giả sử phần khai báo và phần thân chương trình đều được viết đúng, với phần vòng lặp loop lồng nhau ở trên, các em nghĩ chương trình sẽ xuất ra màn hình thế nào? Kết quả là:

1 1

1 2

1 3

Như các em thấy ở kết quả, khi vòng lặp với biến j thực hiện xong và kết thúc, chương trình gặp câu lệnh break và kết thúc vòng lặp với biến i. Sau đây là một ví dụ khác:

for (int i = 1; i <= 3; ++i){

for (int j = 1; j <= 3; ++j){

cout << i << ” ” << j << endl;

break;

}

}

Lúc này sẽ có một kết quả khác, các em hãy thử tìm hiểu và lí giải nhé.

Qua các ví dụ trên, chắc hẳn có em đã biết cú pháp của câu lệnh break trong ngôn ngữ lập trình C++, cú pháp đó là:

break;

Câu lệnh continue

Nếu câu lệnh break buộc cấu trúc lặp dừng hoàn toàn, thì câu lệnh continue bỏ qua các câu lệnh phía sau nó trong một vòng lặp và buộc vòng lặp tiếp theo thực hiện.

Đối với vòng lặp for, khi gặp câu lệnh continue lập tức thực hiện bước <thay đổi>, rồi đến bước <điều kiện>. Đối với vòng lặp while và do…while, câu lệnh continue lập tức thực hiện bước <điều kiện>.

Cú pháp của câu lệnh continue trong ngôn ngữ lập trình C++ là:

continue;

Sau đây thầy sẽ cho ví dụ là một chương trình in ra các số nguyên từ 1 đến 10, nhưng bỏ qua số 5. Như ở trên, ở đây thầy cũng sẽ giả sử rằng phần khai báo và phần thân đều đã viết đúng và chỉ viết ra phần chính của chương trình, các em phải tự bổ sung thành 1 chương trình hoàn chỉnh.

//Khai báo biến cục bộ

int i = 0;

//Thực hiện vòng lặp

do{

++i;

//Bỏ qua vòng lặp hiện tại

if (i == 5) continue;

cout << i << ” “;

} while (i < 10);

Ở chương trình trên, trong phần Thực hiện vòng lặp, nếu i có giá trị là 5, chương trình sẽ gặp lệnh continue, lúc này câu lệnh

cout << i << endl;

sẽ bị bỏ qua, và xét điều kiện

i < 10

Do điều kiện vẫn đúng, nên vòng lặp thực hiện tiếp, câu lệnh

++i;

tăng giá trị của i lên 6 nên chương trình không rẽ vào nhánh của câu lệnh if, cứ thế đến khi i có giá trị là 10 thì vòng lặp kết thúc. Và chúng ta có kết quả là:

1 2 3 4 6 7 8 9 10

Câu lệnh goto

Câu lệnh goto cho phép chương trình nhảy đến câu lệnh được dán nhãn ở cùng một hàm. Khái niệm về hàm các em sẽ được biết ở bài sau.

Câu lệnh goto có cú pháp như sau:

goto <tên nhãn>;

<tên nhãn>: <câu lệnh>;

<tên nhãn> là một định danh cho <câu lệnh>. Câu lệnh được dán nhãn là câu lệnh đứng sau một định danh và dấu hai chấm (:).

Câu lệnh goto thường không được khuyến khích sử dụng. Nguyên nhân là do nó sẽ gây khó khăn cho việc theo dõi luồng điều khiển của chương trình, gây khó khăn cho việc hiểu và chỉnh sửa. Vì thế, các chương trình dùng goto thường được viết lại để không cần dùng goto nữa.

Thầy sẽ lấy ví dụ với chương trình ở phần Câu lệnh continue.

//Khai báo biến cục bộ

int i = 0;

//Thực hiện vòng lặp

do{

increment: ++i;

//Quay lại bước tăng giá trị của i

if (i == 5) goto increment;

cout << i << ” “;

} while (i < 10);

Các em có thể thấy câu lệnh

++i;

đã được dán nhãn increment.

Và khi biến i có giá trị là 5, chương trình gặp câu lệnh if sẽ rẽ vào nhánh lệnh

goto increment;

và quay lại thực hiện câu lệnh được dán nhãn increment, lúc này giá trị của biến i là 6. Sau đó vòng lặp được tiếp tục đến khi <điều kiện> sai và cho kết quả là:

1 2 3 4 6 7 8 9 10

Một trong những trường hợp tốt để dùng goto là khi các em đang làm việc với một cấu trúc lặp lồng nhau có nhiều cấp độ và muốn thoát ngay tại một cấp độ nào đó. Ví dụ trường hợp phần chương trình có dạng như sau:

for (…) {

for (…) {

while (…) {

if (…) goto stop;

}

}

}

stop: cout << “Chuong trinh gap loi” << endl;

Với trường hợp trên, các em không nên dùng break, vì break chỉ dừng chứa vòng lặp chứa nó, có nghĩa là các em phải viết nhiều lệnh break khiến chương trình rất khó kiểm soát và chỉnh sửa. Trong khi đó, với câu lệnh goto trên, chương trình lập tức “nhảy” đến nhãn stop nằm ngoài vòng lặp.

Người viết: Thái Dương Bảo Duy