Tác giả phạm hồng thái bài giảng ngôn ngữ LẬp trình c/C++



tải về 1.98 Mb.
trang14/55
Chuyển đổi dữ liệu07.07.2016
Kích1.98 Mb.
1   ...   10   11   12   13   14   15   16   17   ...   55

Câu lệnh nhảy goto

Ý nghĩa


Một dạng khác của rẽ nhánh là câu lệnh nhảy goto cho phép chương trình chuyển đến thực hiện một đoạn lệnh khác bắt đầu từ một điểm được đánh dấu bởi một nhãn trong chương trình. Nhãn là một tên gọi do NSD tự đặt theo các qui tắt đặt tên gọi. Lệnh goto thường được sử dụng để tạo vòng lặp. Tuy nhiên việc xuất hiện nhiều lệnh goto dẫn đến việc khó theo dõi trình tự thực hiện chương trình, vì vậy lệnh này thường được sử dụng rất hạn chế.

Cú pháp


Goto ;

Vị trí chương trình chuyển đến thực hiện là đoạn lệnh đứng sau nhãn và dấu hai chấm (:).


Ví dụ minh hoạ


: Nhân 2 số nguyên theo phương pháp Ấn độ.

Phương pháp Ấn độ cho phép nhân 2 số nguyên bằng cách chỉ dùng các phép toán nhân đôi, chia đôi và cộng. Các phép nhân đôi và chia đôi thực chất là phép toán dịch bit về bên trái (nhân) hoặc bên phải (chia) 1 bit. Đây là các phép toán cơ sở trong bộ xử lý, do vậy dùng phương pháp này sẽ làm cho việc nhân các số nguyên được thực hiện rất nhanh. Có thể tóm tắt phương pháp như sau: Giả sử cần nhân m với n. Kiểm tra m nếu lẻ thì cộng thêm n vào kq (đầu tiên kq được khởi tạo bằng 0), sau đó lấy m chia 2 và n nhân 2. Quay lại kiểm tra m và thực hiện như trên. Quá trình dừng khi không thể chia đôi m được nữa (m = 0), khi đó kq là kết quả cần tìm (tức kq = m*n). Để dễ hiểu phương pháp này chúng ta tiến hành tính trên ví dụ với các số m, n cụ thể. Giả sử m = 21 và n = 11. Các bước tiến hành được cho trong bảng dưới đây:



Bước

m (chia 2)

n (nhân 2)

kq (khởi tạo kq = 0)

1

21

11

m lẻ, cộng thêm 11 vào kq = 0 + 11 = 11

2

10

22

m chẵn, bỏ qua

3

5

44

m lẻ, cộng thêm 44 vào kq = 11 + 44 = 55

4

2

88

m chẵn, bỏ qua

5

1

176

m lẻ, cộng thêm 176 vào kq = 55 + 176 = 231

6

0




m = 0, dừng cho kết quả kq = 231

Sau đây là chương trình được viết với câu lệnh goto.

void main()

{

long m, n, kq = 0; // Các số cần nhân và kết quả kq



cout << “Nhập m và n: “ ; cin >> m >> n ;

lap: // đây là nhãn để chương trình quay lại

if (m%2) kq += n; // nếu m lẻ thì cộng thêm n vào kq

m = m >> 1; // dịch m sang phải 1 bit tức m = m / 2

n = n << 1; // dịch m sang trái 1 bit tức m = m * 2

if (m) goto lap; // quay lại nếu m ¹ 0

cout << “m nhân n =” << kq ;

}

CẤU TRÚC LẶP


Một trong những cấu trúc quan trọng của lập trình cấu trúc là các câu lệnh cho phép lặp nhiều lần một đoạn lệnh nào đó của chương trình. Chẳng hạn trong ví dụ về bài toán nhân theo phương pháp Ấn độ, để lặp lại một đoạn lệnh chúng ta đã sử dụng câu lệnh goto. Tuy nhiên như đã lưu ý việc dùng nhiều câu lệnh này làm chương trình rất khó đọc. Do vậy cần có những câu lệnh khác trực quan hơn và thực hiện các phép lặp một cách trực tiếp. C++ cung cấp cho chúng ta 3 lệnh lặp như vậy. Về thực chất 3 lệnh này là tương đương (cũng như có thể dùng goto thay cho cả 3 lệnh lặp này), tuy nhiên để chương trình viết được sáng sủa, rõ ràng, C++ đã cung cấp nhiều phương án cho NSD lựa chọn câu lệnh khi viết chương trình phù hợp với tính chất lặp. Mỗi bài toán lặp có một đặc trưng riêng, ví dụ lặp cho đến khi đã đủ số lần định trước thì dừng hoặc lặp cho đến khi một điều kiện nào đó không còn thoả mãn nữa thì dừng … việc sử dụng câu lệnh lặp phù hợp sẽ làm cho chương trình dễ đọc và dễ bảo trì hơn. Đây là ý nghĩa chung của các câu lệnh lặp, do vậy trong các trình bày về câu lệnh tiếp theo sau đây chúng ta sẽ không cần phải trình bày lại ý nghĩa của chúng.

Lệnh lặp for

Cú pháp


for (dãy biểu thức 1 ; điều kiện lặp ; dãy biểu thức 2) { khối lệnh lặp; }

Các biểu thức trong các dãy biểu thức 1, 2 cách nhau bởi dấu phảy (,). Có thể có nhiều biểu thức trong các dãy này hoặc dãy biểu thức cũng có thể trống.

Điều kiện lặp: là biểu thức lôgic (có giá trị đúng, sai).

Các dãy biểu thức và/hoặc điều kiện có thể trống tuy nhiên vẫn giữ lại các dấu chấm phảy (;) để ngăn cách các thành phần với nhau.


Cách thực hiện


Khi gặp câu lệnh for trình tự thực hiện của chương trình như sau:

Thực hiện dãy biểu thức 1 (thông thường là các lệnh khởi tạo cho một số biến),

Kiểm tra điều kiện lặp, nếu đúng thì thực hiện khối lệnh lặp ® thực hiện dãy biểu thức 2 ® quay lai kiểm tra điều kiện lặp và lặp lại quá trình trên cho đến bước nào đó việc kiểm tra điều kiện lặp cho kết quả sai thì dừng.

Tóm lại, biểu thức 1 sẽ được thực hiện 1 lần duy nhất ngay từ đầu quá trình lặp sau đó thực hiện các câu lệnh lặp và dãy biểu thức 2 cho đến khi nào không còn thoả điều kiện lặp nữa thì dừng.


Ví dụ minh hoạ


: Nhân 2 số nguyên theo phương pháp Ấn độ

void main()

{

long m, n, kq; // Các số cần nhân và kết quả kq



cout << “Nhập m và n: “ ; cin >> m >> n ;

for (kq = 0 ; m ; m >>= 1, n <<= 1) if (m%2) kq += n ;

cout << “m nhân n =” << kq ;

}

So sánh ví dụ này với ví dụ dùng goto ta thấy chương trình được viết rất gọn. Để bạn đọc dễ hiểu câu lệnh for, một lần nữa chúng ta nhắc lại cách hoạt động của nó thông qua ví dụ này, trong đó các thành phần được viết trong cú pháp là như sau:



Dãy biểu thức 1: kq = 0,

Điều kiện lặp: m. Ở đây điều kiện là đúng nếu m ¹ 0 và sai nếu m = 0.

Dãy biểu thức 2: m >>= 1 và n <<= 1. 2 biểu thức này có nghĩa m = m >> 1 (tương đương với m = m / 2) và n = n << 1 (tương đương với n = n * 2).

Khối lệnh lặp: chỉ có một lệnh duy nhất if (m%2) kq += n ; (nếu phần dư của m chia 2 là khác 0, tức m lẻ thì cộng thêm n vào kq).

Cách thực hiện của chương trình như sau:

Đầu tiên thực hiện biểu thức 1 tức gán kq = 0. Chú ý rằng nếu kq đã được khởi tạo trước bằng 0 trong khi khai báo (giống như trong ví dụ 6) thì thành phần biểu thức 1 ở đây có thể để trống (nhưng vẫn giữ lại dấu ; để phân biệt với các thành phần khác).

Kiểm tra điều kiện: giả sử m ¹ 0 (tức điều kiện đúng) for sẽ thực hiện lệnh lặp tức kiểm tra nếu m lẻ thì cộng thêm n vào cho kq.

Quay lại thực hiện các biểu thức 2 tức chia đôi m và nhân đôi n và vòng lặp được tiếp tục lại bắt đầu bằng việc kiểm tra m …

Đến một bước lặp nào đó m sẽ bằng 0 (vì bị chia đôi liên tiếp), điều kiện không thoả, vòng lặp dừng và cho ta kết quả là kq.

: Tính tổng của dãy các số từ 1 đến 100.

Chương trình dùng một biến đếm i được khởi tạo từ 1, và một biến kq để chứa tổng. Mỗi bước lặp chương trình cộng i vào kq và sau đó tăng i lên 1 đơn vị. Chương trình còn lặp khi nào i còn chưa vượt qua 100. Khi i lớn hơn 100 chương trình dừng. Sau đây là văn bản chương trình.

void main()

{

int i, kq = 0;



for (i = 1 ; i <= 100 ; i ++) kq += i ;

cout << "Tổng = " << kq;

}

: In ra màn hình dãy số lẻ bé hơn một số n nào đó được nhập vào từ bàn phím.



Chương trình dùng một biến đếm i được khởi tạo từ 1, mỗi bước lặp chương trình sẽ in i sau đó tăng i lên 2 đơn vị. Chương trình còn lặp khi nào i còn chưa vượt qua n. Khi i lớn hơn n chương trình dừng. Sau đây là văn bản chương trình.

void main()

{

int n, i ;



cout << "Hãy nhập n = " ; cin >> n ;

for (i = 1 ; i < n ; i += 2) cout << i << '\n' ;

}

Đặc điểm


Thông qua phần giải thích cách hoạt động của câu lệnh for trong ví dụ 7 có thể thấy các thành phần của for có thể để trống, tuy nhiên các dấu chấm phẩy vẫn giữ lại để ngăn cách các thành phần với nhau. Ví dụ câu lệnh for (kq = 0 ; m ; m >>= 1, n <<= 1) if (m%2) kq += n ; trong ví dụ 7 có thể được viết lại như sau:

kq = 0;


for ( ; m ; ) { if (m%2) kq += n; m >>= 1; n <<= 1; }

Tương tự, câu lệnh for (i = 1 ; i <= 100 ; i ++) kq += i ; trong ví dụ 8 cũng có thể được viết lại như sau:

i = 1;

for ( ; i <= 100 ; ) kq += i ++ ;



(câu lệnh kq += i++; được thực hiện theo 2 bước: cộng i vào kq và tăng i (tăng sau)).

Trong trường hợp điều kiện trong for cũng để trống chương trình sẽ ngầm định là điều kiện luôn luôn đúng, tức vòng lặp sẽ lặp vô hạn lần (!). Trong trường hợp này để dừng vòng lặp trong khối lệnh cần có câu lệnh kiểm tra dừng và câu lệnh break.

Ví dụ câu lệnh for (i = 1 ; i <= 100 ; i ++) kq += i ; được viết lại như sau:

i = 1;


for ( ; ; )

{

kq += i++;



if (i > 100) break;

}

Tóm lại, việc sử dụng dạng viết nào của for phụ thuộc vào thói quen của NSD, tuy nhiên việc viết đầy đủ các thành phần của for làm cho việc đọc chương trình trở nên dễ dàng hơn.


Lệnh for lồng nhau


Trong dãy lệnh lặp có thể chứa cả lệnh for, tức các lệnh for cũng được phép lồng nhau như các câu lệnh có cấu trúc khác.

: Bài toán cổ: vừa gà vừa chó bó lại cho tròn đếm đủ 100 chân. Hỏi có mấy gà và mấy con chó, biết tổng số con là 36.

Để giải bài toán này ta gọi g là số gà và c là số chó. Theo điều kiện bài toán ta thấy g có thể đi từ 0 (không có con nào) và đến tối đa là 50 (vì chỉ có 100 chân), tương tự c có thể đi từ 0 đến 25. Như vậy ta có thể cho g chạy từ 0 đến 50 và với mỗi giá trị cụ thể của g lại cho c chạy từ 0 đến 25, lần lượt với mỗi cặp (g, c) cụ thể đó ta kiểm tra 2 điều kiện: g + c == 36 ? (số con) và 2g + 4c == 100 ? (số chân). Nếu cả 2 điều kiện đều thoả thì cặp (g, c) cụ thể đó chính là nghiệm cần tìm. Từ đó ta có chương trình với 2 vòng for lồng nhau, một vòng for cho g và một vòng cho c.

void main()

{

int g, c ;



for (g = 0 ; g <= 50 ; g++)

for (c = 0 ; c <= 25 ; c++)

if (g+c == 36 && 2*g+4*c == 100) cout << "gà=" << g << ", chó=" << c ;

}

Chương trình trên có thể được giải thích một cách ngắn gọn như sau: Đầu tiên cho g = 0, thực hiện lệnh for bên trong tức lần lượt cho c = 0, 1, …, 25, với c=0 và g=0 kiểm tra điều kiện, nếu thoả thì in kết quả nếu không thì bỏ qua, quay lại tăng c, cho đến khi nào c>25 thì kết thúc vòng lặp trong quay về vòng lặp ngoài tăng g lên 1, lại thực hiện vòng lặp trong với g=1 này (tức lại cho c chạy từ 0 đến 25). Khi g của vòng lặp ngoài vượt quá 50 thì dừng. Từ đó ta thấy số vòng lặp của chương trình là 50 x 25 = 1000 lần lặp.



Chú ý: Có thể giảm bớt số lần lặp bằng nhận xét số gà không thể vượt quá 36 (vì tổng số con là 36). Một vài nhận xét khác cũng có thể làm giảm số vòng lặp, tiết kiệm thời gian chạy của chương trình. Bạn đọc tự nghĩ thêm các phương án giải khác để giảm số vòng lặp đến ít nhất.

: Tìm tất cả các phương án để có 100đ từ các tờ giấy bạc loại 10đ, 20đ và 50đ.

main()

{

int t10, t20, t50; // số tờ 10đ, 20đ, 50đ



sopa = 0; // số phương án

for (t10 = 0 ; t10 <= 10 ; t10++)

for (t20 = 0 ; t20 <= 5 ; t20++)

for (t50 = 0 ; t50 <= 2 ; t50++)

if (t10*10 + t20*20 + t50*50 == 100) // nếu thoả thì

{

sopa++; // tăng số phương án



if (t10) cout << t10 << "tờ 10đ “ ; // in số tờ 10đ nếu ¹ 0

if (t20) cout << "+" << t20 << "tờ 20đ “ ; // thêm số tờ 20đ nếu¹0

if (t50) cout << "+" << t50 << "tờ 50đ “ ; // thêm số tờ 50đ nếu¹0

cout << '\n' ; // xuống dòng

}

cout << “Tong so phuong an = ” << sopa ;



}

1   ...   10   11   12   13   14   15   16   17   ...   55


Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2016
được sử dụng cho việc quản lý

    Quê hương