Chương 3: Cấu trúc ñiều khiển
Giảng viên: Ph.D Nguyễn Văn Hòa Khoa KT-CN-MT – ðH An Giang
1
Giới thiệu
ñiều khiển
(cid:1) Dữ liệu và tác vụ là 2 yếu tố cơ bản của CT (cid:1) Mỗi sự kết hợp của chúng gắn liền với cấu trúc
ñịnh thứ tự thực hiện chương trình (cid:1) Xét về cấu trúc thì có 3 loại ñiều khiển
(cid:2) ðiều khiển trong biểu thức (cid:2) ðiều khiển giữa các lệnh (phát biểu): như cấu trúc ñiều
kiện hay cấu trúc lặp
(cid:2) ðiều khiển trong chương trình con: gọi trả về hay ñệ
qui
2
(cid:1) Cấu trúc ñiều khiển là tập hợp các qui tắc xác
Giới thiệu (tt)
VD qui tắc ưu tiên của các toán tử
(cid:2) ðiều khiển tường minh: ñược xác ñịnh bởi programmer
(cid:1) Xét về thiết kế ngôn ngữ thì có 2 loại ñiều khiển (cid:2) ðiều khiển ngầm: ñược thiết kế trong ngôn ngữ LT,
(cid:2) ðiều khiển tuần tự (cid:2) ðiều khiển cạnh tranh (concurrency) : 2 hoặc nhiều hơn ñoạn chương trình ñược thực thi song song
(cid:1) Hai cấu trúc ñiều khiển
(cid:2) Dễ viết (cid:2) Dễ ñọc
3
(cid:1) Cấu trúc ñiều khiển tốt
Nội dung chính của chương
4
(cid:1) ðiều khiển trong biểu thức (cid:1) Lệnh lựa chọn hay ñiều kiện (cid:1) Lệnh lặp (cid:1) Rẽ nhánh không ñiều kiện (cid:1) Luồng ñiều khiển không tuần tự
ðiều khiển trong biểu thức
chất hàm (functional composition) (cid:2) Tác vụ hay phép toán (cid:2) Các ñối số hay toán hạng
(cid:1) Cơ chế ñiều khiển trong biểu thức là sự chồng
*
-
+
(cid:1) Toán hạng: hằng, các kết quả của các phép tham khảo dữ liệu (biến) hoặc kết quả của các phép toán khác
A
B C
A
(A+B)*(C-A)
5
(cid:1) Cơ chế chồng ñược biểu diễn bởi một cấu trúc cây
ðiều khiển trong biểu thức (tt)
(cid:2) Hiệu ứng lề
(cid:1) Thứ tự ưu tiên của các toán tử (cid:1) Các toán tử cùng ñộ ưu tiên (cid:1) Thứ tự các toán hạng
6
(cid:1) Tính ña năng của toán tử
Thứ tự ưu tiên các toán tử
thứ tự thực hiện các toán tử
(cid:1) Kết quả của biểu thức 3 + 5 * 2 ?? → phụ thuộc
(cid:1) Thứ tự thực hiện các toán tử trong NNLT
FORTRAN 95
C Ada **, abs ** postfix ++,-- *, / prefix ++, *, /, mod
-âm, +dương rem -âm, +dương *, /, % -âm, +dương +,-
+,-
+,-
7
Các toán tử cùng ưu tiên (associativity)
qui luật ñể xác ñịnh thứ tự thực hiện
(cid:1) Các phép toán có cùng ưu tiên, + và -, cần có 1
(cid:2) Từ trái sang phải (cid:2) Trừ Fortran (từ phải sang trái)
(cid:1) VD a-b+c-d (cid:1) Các NNLT qui ñịnh thứ tự thực hiện
tử bị mất ñi và thực hiện theo dấu ngoặc
8
(cid:1) Ada bắt buộc phải có dấu ngoặc ((a-b)+c)-d (cid:1) Nếu có ngấu ngoặc thì thứ tự ưu tiên của các toán
Biểu thức ñiều kiện
if (count == 0) average = 0;
else
average = sum /count;
9
(cid:1) Toán tử «?» là toán tử tam phân (ternary) (cid:1) Biểu thức ñiều kiện chỉ có trong ngôn ngữ C (cid:1) VD average = (count == 0)? 0 : sum / count (cid:1) Có thể dùng câu lệnh if-then-else thay thế
Biểu thức quan hệ
hạng có nhiều kiểu khác nhau
(cid:1) Biểu thức quan hệ: 1 toán tử quan hệ và 2 toán
(cid:1) Trị của biểu thức quan hệ: ñúng hoặc sai (cid:1) VD toán tử quan hệ
FORTRAN 95
C Ada = /= > < >= <=
Bằng .EQ. = = = = Không Bằng .NE. <> != Lớn hơn .GT. > > Nhỏ hơn .LT. < < Lớn hơn or bằng .GN. >= >= Nhỏ hơn or bằng .LN. <= <=
10
Biểu thức logic
kiểu logic
(cid:1) Biểu thức logic: 1 toán tử logic và 2 toán hạng có
C Ada FORTRAN 77 FORTRAN 90 .AND. and && and .OR. or || or .NOT. not ! not xor
11
(cid:1) Trị của biểu thức logic: ñúng hoặc sai (cid:1) VD các toán tử logic
Thứ tự thực hiện các toán tử : C
12
(cid:1) Hậu tố (++, --) (cid:1) Tiền tố (++, --, !) âm dương (+, -) (cid:1) *, /, % (cid:1) +, - (cid:1) <,>,<=,>= (cid:1) ==, != (cid:1) && (cid:1) ||
Hiệu ứng lề
bộ hoặc có truyền quy chiếu
int a= 5; int fun1(){a = 17; return 3;} void fun2(){a = a + fun1();} void main(){
fun2();
}
(cid:1) Kết quả của a là 8 hay 20
13
(cid:1) Hiệu ứng lề là 1 phép toán trả về kết quả ẩn (cid:1) Hàm hiệu ứng lề là hàm thay ñổi biến không cục
Hiệu ứng lề
(cid:2) NNLT không cho phép hàm tham chiếu các biến không
cục bộ và truyền quy chiếu (cid:1) Ưu ñiểm : dễ thực hiện (cid:1) Khuyết ñiểm : không linh hoạt
(cid:2) NNLT phải qui ñịnh thứ tự ưu tiên của các toán hạng (cid:1) Khuyết ñiểm : giảm khả năng tối ưu code của trình biên dịch
(cid:2) Ngôn ngữ C trả về giá trị của a là 20
14
(cid:1) Giải pháp ñể giải quyết hiệu ứng lề
Cú pháp của biểu thức
(cid:2) Phổ biến và tự nhiên nhất: kí hiệu phép toán ñược viết
giữa 2 toán hạng
(cid:2) VD (A + B) * (C - A) (cid:1) Dạng tiền tố (prefix)
(cid:2) Kí hiệu phép toán ñược viết trước các toán hạng (cid:2) VD * (+ (A B)) – (C A))
(cid:1) Dạng trung tố (infex)
(cid:2) Kí hiệu phép toán ñược viết sau các toán hạng (cid:2) VD ((A B) +) (C A) -)*
15
(cid:1) Dạng hậu tố (posfix)
Toán tử ña năng hóa (overloaded)
tử ña năng hóa
(cid:1) Một toán tử có thực hiện nhiều phép toán → toán
(cid:2) int x, y, z ; (cid:2) x = &y // trả về ñịa chỉ ô nhớ của y cho x (cid:2) x = y&z // trả về giá trị của phép toán And trên y,z
(cid:1) Phép toán + với kiểu số nguyên và kiểu số thực (cid:1) Phép toán &: lấy ñịa chỉ và phép toán And (bit)
(cid:2) Trả về trị của ô nhớ mà pointer trỏ ñến hoặc phép toán
nhân
16
(cid:1) Phép toán *
Lệnh ñiều khiển
(cid:2) Lệnh tuần tự
(cid:1) Lệnh gán, lệnh gọi chương trình con (cid:1) Lệnh xuất / nhập
(cid:2) Lệnh lựa chọn hay ñiều kiện (cid:2) Lệnh lặp
(cid:1) Ba loại cấu trúc ñiều khiển cơ bản
17
(cid:1) Lệnh rẽ nhánh không ñiều kiện
Lệnh lựa chọn hay ñiều kiện
của hai hoặc ña nhánh ñể thực hiện
(cid:1) Lệnh ñiều kiện là một lệnh biểu thị sự lựa chọn
(cid:2) Chỉ có 2 lựa chọn (lệnh IF) (cid:2) Nhiều lựa chọn (lệnh CASE)
18
(cid:1) Chia làm 2 loại
Lệnh lựa chọn : 2 lựa chọn
if control_expression then clause else clause
(cid:1) Dạng phổ biến :
(cid:2) Dạng và kiểu của biểu thức lựa chọn như thế nào : quan
hệ, toán và logic?
(cid:2) Các câu lệnh gì sau then và sau else? (cid:2) Lệnh lựa chọn có lòng nhau hay không?
19
(cid:1) Các yếu tố trong lệnh 2 lựa chọn
Biểu thức lựa chọn (2 lựa chọn)
if (boolean_expr) then stmt else stmt
(cid:1) ALGOL 60 : chỉ dùng biểu thức logic
(cid:2) VD if(5-3) printf(«A») else printf(«B»); (cid:2) C/C++/Java: if (expr) stmt else stmt
(cid:1) C (89 trở về trước) : chỉ dùng biểu thức logic (cid:1) C (99) và C++ : biểu thức toán và logic
logic
20
(cid:1) Ada, Java và C# chỉ cho phép dùng biểu thức
Sự lựa chọn lòng nhau
if (count == 0) result = 0;
else result = 1;
(cid:2) Lệnh if nào sẽ ñi cùng với lệnh else? (cid:2) NN Java qui ñịnh lệnh if và lệnh else gần nhau nhất
sẽ ñi cùng nhau
(cid:1) Thí dụ trong Java if (sum == 0)
21
(cid:1) C, C++, C# yêu cầu dùng {} ñể phân ñịnh (cid:1) Perl yêu cầu câu lệnh ghép (if else ñầy ñủ)
Sự lựa chọn lòng nhau
(cid:1) C, C++, C#
if (sum == 0){
if (count == 0) result = 0;
(cid:1) Ada
}else result = 1;
if (sum == 0) then if (sum == 0) then
if (count == 0)then if (count == 0)then
result = 0; result = 0;
else end if
result = 1; else
end if result = 1;
22
end if end if
Lệnh lựa chọn ña nhánh
nhánh lệnh ñể thực hiện
(cid:1) Cho phép lựa chọn 1 nhánh trong số nhiều
nó thực hiện lệnh gì?
23
(cid:1) Các yếu tố trong lệnh lựa chọn ña nhánh (cid:2) Kiểu và dạng của biểu thức ñiều khiển là gì? (cid:2) Công việc của từng nhánh lệnh là gì? (cid:2) Có nhánh lệnh không thỏa ñiều kiện không? Nếu có
Mô hình switch-case
switch (expr){
case const_expr_1 : stmt_1; … case const_expr_n : stmt_n; [default: stmt_n+1;]
}
(cid:1) Switch-case trong C, C++, Java
(cid:2) Biểu thức ñiều khiển phải là kiểu nguyên (cid:2) Câu lệnh ñược chọn có thể 1 câu lệnh ñơn hoặc lệnh hợp
thành
(cid:2) Default : ñược chọn nếu không có giá trị nào thỏa expr
24
Mô hình switch-case
(cid:1) Switch-case trong Ada case expression is
when choice list => stmt_sequence; … when choice list => stmt_sequence; when others => stmt_sequence;]
end case;
trường hợp ñược chọn
25
(cid:1) Dễ ñọc hơn switch-case của C (cid:1) C# chỉ cho phép thực hiện 1 lệnh ñơn trong
Chọn ña nhánh với lệnh if
chọn 2 nhánh với else-if if (expr == const_expr_1 ) stmt_1; else if (expr == const_expr_2) stmt_2 … Else if (expr == const_expr_n) stmt_n; else stmt_n+1; (cid:2) Phải kết với hợp với lệnh nhảy (goto) (cid:2) Code rất nghèo nàng
26
(cid:1) Lệnh chọn ña nhánh có thể chuyển thành lệnh
Lệnh lặp
lệnh hợp thành
(cid:1) Lệnh lặp là ñể thực hiện một số lần lệnh ñơn hay
(cid:2) Làm thể nào ñể kiểm soát lặp? (cid:2) Kiểm soát lặp xuất hiện ở ñâu trong vòng lặp?
27
(cid:1) Các yếu tố trong lệnh lặp
Lệnh lặp với bộ ñếm
(cid:1) Lệnh có 1 biến ñếm, giá trị của biến này từ giá trị bắt ñầu (initial) ñến giá trị kết thúc (terminal) và giá trị của bước nhảy (stepsize)
(cid:2) Biến lặp có kiểu gì và phạm vi nào? (cid:2) Giá trị của biến lặp khi vòng lặp kết thúc là bao nhiêu? (cid:2) Giá trị của biến lặp có ñược thay ñổi trong thân vòng lặp không? Nếu có thì có ảnh hưởng ñến vòng lặp không?
28
(cid:1) Các yếu tố trong lệnh lặp :
VD - lệnh lặp với bộ ñếm
(cid:2) do bien_lap = trị_bat_dau, trị_ket_thuc [, buoc_nhay] (cid:2) Trị của bước nhảy là bất kỳ (trừ 0), mặc ñịnh 1 (cid:2) trị_bat_dau, trị_ket_thuc có thể là biểu thức (cid:2) Kiểu của biến lặp phải là kiểu số nguyên (cid:2) Biến lặp không ñược thay ñổi trong thân vòng lặp
(cid:1) Cú pháp của Fortran 90
(cid:2) do bien_lap = trị_bat_dau, trị_ket_thuc [, buoc_nhay]
(cid:1) Fortran 95
… end do
29
VD - lệnh lặp với bộ ñếm (tt)
(cid:1) Cú pháp lệnh for của Pascal
for bien_lap := bat_dau (to|downto)
ket_thuc do …
(cid:2) bien_lap có kiểu số nguyên (cid:2) Sau khi kết thúc vòng lặp, giá trị của bien_lap là không
xác ñịnh
(cid:2) Giá trị của bien_lap không thể thay ñổi trong thân vòng
lập;
(cid:2) bat_dau, ket_thuc có thể là biểu thức, nhưng các tham số có thể thay ñổi trong vòng lặp và không ảnh hưởng ñến vòng lặp
30
VD - lệnh lặp với bộ ñếm (tt)
(cid:2) for bien_lap in [reverse] day_roi_rac loop
(cid:1) Cú pháp lệnh for trong Ada
… end loop
(cid:2) day_roi_rac : miền con số nguyên, 1..10, hoặc kiểu
liệt kê monday..friday
(cid:2) Phạm vi của biến có bao gồm vòng lặp (cid:2) Giá trị của biến lặp là không xác ñinh sau khi vòng lặp
kết thúc
31
VD - lệnh lặp với bộ ñếm (tt)
(cid:1) Cú pháp của for trong C
for ([expr_1] ; [expr_2] ; [expr_3])
statement
(cid:2) Mọi thứ có thể thay ñổi trong thân vòng lặp (cid:2) Biểu thức expr_1 ñược ñịnh lượng 1 lần (trước khi thực hiện vòng lặp), expr_2 và expr_3 ñược ñịnh lượng ở mọi lần lặp
(cid:2) C++ : cho phép khai báo kiểu trong expr_1
(cid:1) For(int count =0; count 32 (cid:1) C++ vs C (cid:2) Kiểm tra ñiều kiện trước hay sau
(cid:2) Có phải lệnh lặp có ñiều kiện là trường hợp ñặc biệt của lệnh lặp với bộ ñếm (cid:1) Lệnh lặp chỉ ñược thực hiện khi ñiều kiện ñúng
(cid:1) Các yếu tố trong lệnh lặp có ñiều kiện (cid:2) While (ctrl_expr) do loop body loop body while (ctrl_expr) 33 (cid:1) Cú pháp và sau : while-do và repeat-until
(cid:1) C và C++ dùng cả (while-do and do-while);
kiểm tra trước là lặp nếu ñiều kiện ñúng nhưng
kiểm tra ñiều kiện sau là lặp ñến khi ñiều kiện sai
(cid:1) Cũng giống như C, nhưng biểu thức ñiều kiện của Java có kiểu boolean
(cid:1) Ada chỉ có lặp kiểm tra trước 34 (cid:1) Pascal phân chia rõ ràng kiểm tra ñiều kiện trước (cid:1) Lệnh rẽ nhánh không ñiều kiền ñược ñưa ra 1960s
(cid:1) Cho phép thay ñổi thứ tự thực hiện chương trình
(cid:1) Cơ chế phổ biến nhất là lệnh: goto case (cid:1) Một số NNLT không hỗ trợ lệnh goto
(cid:1) C# cung cấp lệnh goto, có thể dùng trong switch- bảo trì 35 (cid:1) Lệnh goto làm cho CT trở nên khó ñọc và khó Luồng ñiều khiển không từng tự
(Nonlocal control flow) (cid:1) Cho phép thoát khỏi luồng ñiều khiển thông thường
(cid:1) Ứng dụng (cid:2) Thoát sớm trong các cấu trúc lặp
(cid:2) Trả về (return) sớm trong các hàm
(cid:2) Bắt các ngoại lệ (cid:1) VD (cid:2) Continue & break
(cid:2) Return
(cid:2) Try/catch 36 chuyển ñến vòng lặp tiếp theo (cid:1) Lệnh continue sẽ kết thúc vòng lặp hiện hành và của vòng lặp sẽ ñược bỏ qua (cid:1) Khi gặp lệnh này, các câu lệnh còn lại trong thân 37 (cid:1) VD (cid:1) Lệnh break ñể thoát khỏi các cấu trúc lặp hoặc switch 38 39 Lệnh continue và break (Java) block1:
while (XXX) { ...
while (XXX) { ...
if (XXX) break block1; } }
loop1:
while (XXX) { ...
while (XXX) { ...
if (XXX) continue loop1; } 40 } (cid:1) Cú pháp
try{ // ñoạn mã có khả năng gây ra ngoại lệ }
catch(Exception e1){ // Nếu các lệnh trong khối ‘try’ tạo ra ngoại lệ có loại e1 }
…
catch(Exception eN){ … }
Finally { // khối lệnh nay luôn ñược thực hiện cho dù ngoại lệ có xảy ra hay
không } 41 try { x = f(x,y); }
catch (ArithmeticException) { System.out.println(”An arithmetic error occurred!”); System.exit(0); }
(cid:2) Nếu hàm f(x,y) không có lỗi, tiến trình vẫn tiếp tục
(cid:2) Nếu hàm f(x,y) lỗi, ArithmeticException ñược chuyển tới JVM 42 (cid:1) VDLệnh lặp có ñiều kiện
Lệnh lặp có ñiều kiện (tt)
Rẽ nhánh không ñiều kiện
Lệnh continue & break
Lệnh continue & break (tt)
Lệnh return
Try/catch
Try/catch