Thủ tục, hàm và lập trình có cấu trúc
Đã giới thiệu| English | Ý nghĩa |
|---|---|
| subroutines/ˈsʌbruːtiːnz/ | hàm con |
| function/ˈfʌŋkʃn/ | Hàm |
| procedure/prəˈsiːdʒə/ | Thủ tục |
| structured programming/ˈstrʌktʃəd ˈprəʊɡræmɪŋ/ | lập trình có cấu trúc |
| decomposition/ˌdiːkɒmpəˈzɪʃn/ | Phân rã |
| parameters/pəˈræmɪtəz/ | tham số |
| arguments/ˈɑːɡjuːmənts/ | thực tham |
| signature/ˈsɪɡnɪtʃə/ | ký hiệu hàm |
| pass by value/pæs baɪ ˈvæljuː/ | truyền theo giá trị |
| pass by reference/pæs baɪ ˈrefrəns/ | truyền theo tham chiếu |
| global variable/ˈɡləʊbl ˈveərɪəbl/ | biến toàn cục |
| local variable/ˈləʊkl ˈveərɪəbl/ | biến cục bộ |
| scope/skəʊp/ | phạm vi |
THƯ VIỆN routine mà ai cũng có thể sử dụng
- Đến năm 1951, nhóm EDSAC tại Cambridge đã lưu trữ thư viện các hàm con trên băng từ Punch: căn bậc hai, in ấn, logarit. Bất kỳ chương trình nào cũng có thể đọc một vào và gọi nó.
- Phần khó khăn nhất là tìm đường quay lại. Mẹo của David Wheeler, "v躍跳转 Wheeler", đã lưu địa chỉ quay lại để một hàm con có thể trở về đúng nơi nó đã được gọi từ đó.
- Mọi cuộc gọi hàm bạn viết ngày nay đều làm điều tương tự, và thư viện ngôn ngữ nào cũng bắt nguồn từ chiếc băng từ đó.
- Bài học này nói về Procedures và Functions: cách định nghĩa chúng, cách truyền giá trị vào và ra, và cách viết chúng sao cho đạt điểm Paper 2.
Procedures và functions
- Lập trình có cấu trúc xây dựng chương trình từ các hàm con nhỏ có tên riêng, mỗi hàm thực hiện một nhiệm vụ.
- Một thủ tục là một khối có tên thực hiện hành động và không trả về giá trị:
PROCEDURE Greet(Name : STRING) … ENDPROCEDURE, được gọi bằngCALL Greet("Ada"). - Một hàm trả về một giá trị trở thành một phần của biểu thức:
FUNCTION Square(X : INTEGER) RETURNS INTEGER … RETURN X * X … ENDFUNCTION, sử dụng nhưResult ← Square(5) + 1.

Thủ tục làm điều gì đó; hàm trả về một giá trị
Ngăn gọi (call stack): đẩy vào khi gọi, rút ra khi trả về
Gọi một thủ tục sẽ đẩy một khung mới lên trên; trả về sẽ xóa nó đi và gửi lại một giá trị cho người gọi. Khung đang thực thi luôn là khung nằm ở vị trí trên cùng.
Sự khác biệt chính giữa một thủ tục và một hàm là hàm:
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Hàm trả về một giá trị (được dùng trong biểu thức); thủ tục thực hiện một hành động và không trả về gì cả.
Một hàm Square(x) trả về x * x. Gọi hàm Square(5) sẽ trả về kết quả gì?
Độ khó 2/5 · 140 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
5 × 5 = 25 — giá trị mà hàm gửi lại cho người gọi (khung bị xóa khỏi ngăn xếp cuộc gọi).
Khi nào áp dụng cho từng loại
- Một thủ tục khi cùng một nhóm bước cần thiết ở nhiều nơi: kiểm tra đầu vào, hiển thị menu, hoán đổi hai giá trị. Các bước được viết một lần và gọi theo tên.
- Một hàm khi cần tính toán một giá trị đơn lẻ rồi dùng trong biểu thức: tổng, kết quả
TRUE/FALSE, số lớn hơn trong hai số. Giá trị trả về thay thế lời gọi. - Sử dụng thủ tục con khi logic xuất hiện ở hơn một nơi, khi một khối có mục đích rõ ràng, khi chương trình đủ phức tạp để cần phân rã, hoặc khi bạn muốn kiểm tra riêng một phần.
Lý do tốt để viết một thủ tục là vì:
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Thủ tục loại bỏ sự trùng lặp, mang lại mục đích có tên và có thể được kiểm tra độc lập.
Tham số, đối số và giao diện
- Tham số là các biến mà thủ tục con khai báo để nhận giá trị; các giá trị người gọi cung cấp là đối số.
- Header (đầu dòng) là dòng đầu tiên:
PROCEDURE Name(Param : TYPE)hoặcFUNCTION Name(Param : TYPE) RETURNS TYPE. Giao diện, hay ký hiệu, là tên, các tham số theo thứ tự kèm kiểu dữ liệu, và kiểu trả về: tất cả những gì người gọi cần biết. - Giá trị trả về là thứ mà hàm truyền lại với
RETURN.
Khớp mỗi thuật ngữ với ý nghĩa của nó.
Độ khó 2/5 · 140 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Hàm so với thủ tục = trả về giá trị hay không; truyền theo giá trị so với theo tham chiếu = bản sao hay dữ liệu gốc.
Ví dụ minh họa: mô tả từng thuật ngữ trong header
FUNCTION Pass2(Count : INTEGER) RETURNS BOOLEAN.FUNCTION: một thủ tục con trả về giá trị.Pass2: định danh dùng để gọi nó.Count: tham số, định danh nhận đối số được truyền vào.INTEGER: kiểu dữ liệu của tham số đó.RETURNS BOOLEAN: kiểu dữ liệu của giá trị hàm trả về. Năm phần, mỗi phần một điểm.
Trong FUNCTION Pass2(Count : INTEGER) RETURNS BOOLEAN, danh xưng Count là ____.
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Tham số nhận đối số mà người gọi truyền vào và được sử dụng bên trong hàm giống như một biến cục bộ.
Truyền theo giá trị và truyền theo tham chiếu
- Truyền theo giá trị: routine nhận một bản sao, nên thay đổi bên trong không ảnh hưởng đến người gọi. Dùng cho đầu vào mà routine chỉ đọc.
- Truyền theo tham chiếu: routine nhận tham chiếu đến biến của người gọi, nên thay đổi có ảnh hưởng đến người gọi. Dùng khi routine cần cập nhật đối số, như trong
Swap. - Cambridge ghi chế độ trong header,
BYVALhoặcBYREF, trước mỗi tham số. Nếu không ghi gì,BYVALđược mặc định.

Một bản sao, hoặc liên kết đến biến của người gọi
Ví dụ minh họa: đầu ra là gì?
PROCEDURE Adjust(BYREF X : INTEGER, BYVAL Y : INTEGER)
X <- X + Y
Y <- Y * 2
ENDPROCEDURE
A <- 5
B <- 3
CALL Adjust(A, B)
OUTPUT A, B
Xlà tham chiếu đếnA, nênAtrở thành 8.Ylà bản sao củaB, nên nhân đôiYvẫn giữBở mức 3.- Đầu ra là
8, 3. Nếu header ghiBYVAL X,Avẫn sẽ là 5.
Trong ví dụ đã giải, giá trị của A sau khi gọi CALL Adjust(A, B) là gì?
Độ khó 2/5 · 140 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
X được truyền BYREF, nên X ← X + Y cộng thêm 3 vào A của người gọi: 5 + 3 = 8. B vẫn giữ nguyên là 3 vì Y chỉ là bản sao.
Biến cục bộ và biến toàn cục
- Một biến cục bộ được khai báo bên trong thủ tục con và chỉ tồn tại trong khi chạy; một biến toàn cục được khai báo bên ngoài và khả kiến ở mọi nơi. Vùng mà tên khả kiến là phạm vi của nó.
- Ưu tiên biến cục bộ: cùng một định danh có thể tái sử dụng ở nơi khác mà không gây xung đột, giá trị không thể bị thay đổi ngẫu nhiên bởi các phần khác của chương trình, bộ nhớ được giải phóng khi quay lại, và thủ tục con độc lập.
- Biến cục bộ được tạo mới mỗi lần gọi, nên không mang giá trị giữa các lần gọi. Một routine xây dựng chuỗi qua nhiều lần gọi cần chuỗi đó là toàn cục, hoặc truyền
BYREF.

Biến toàn cục khả kiến ở mọi nơi; biến cục bộ chỉ sống bên trong thủ tục con của nó
Biến cục bộ chỉ tồn tại bên trong thủ tục nơi nó được khai báo, trong khi biến toàn cục có thể truy cập được ở mọi nơi trong chương trình.
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Giữ các biến ở mức cục bộ giúp thu hẹp phạm vi, tránh xung đột tên và làm cho thủ tục có thể tự kiểm tra — tốt nhất nên tránh dùng biến toàn cục.
Những lợi ích nào sau đây khi sử dụng biến cục bộ? Chọn tất cả các đáp án đúng.
Độ khó 2/5 · 140 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Biến cục bộ được tạo mới mỗi lần gọi, nên không thể giữ giá trị giữa các lần gọi. Đó chính là chức năng mà biến toàn cục hoặc tham số BYREF đảm nhận thay thế.
Chuyển thủ tục thành hàm
- Đổi
PROCEDUREthànhFUNCTIONvà thêmRETURNS <type>vào header. - Thay thế
OUTPUT, hoặcBYREFtham số mang kết quả ra, bằng câu lệnhRETURN. - Đổi mọi lời gọi để giá trị trả về được sử dụng:
Result ← Unpack(Text)thay vìCALL Unpack(Text, Result).
Để chuyển đổi một thủ tục thành hàm, bạn thay đổi tiêu đề thành FUNCTION với RETURNS, thay OUTPUT bằng RETURN, và sửa các lời gọi để sử dụng giá trị được trả về.
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Ba thay đổi, ba điểm: tiêu đề, câu lệnh RETURN, và các lời gọi.
Ví dụ minh họa: viết module cho Paper 2
- Mảng toàn cục
Score : ARRAY[1:50] OF INTEGERlưu điểm thi. Viết hàmCountAbove(Limit : INTEGER)trả về số lượng điểm lớn hơnLimit.
FUNCTION CountAbove(BYVAL Limit : INTEGER) RETURNS INTEGER
DECLARE Index, Count : INTEGER
Count <- 0
FOR Index <- 1 TO 50
IF Score[Index] > Limit THEN
Count <- Count + 1
ENDIF
NEXT Index
RETURN Count
ENDFUNCTION
- Bộ chấm điểm trao điểm cho từng đặc điểm: header với tham số và kiểu trả về, khai báo cục bộ, bộ đếm khởi tạo trước vòng lặp, vòng lặp qua mọi phần tử, điều kiện với phép so sánh đúng, cập nhật bên trong, đóng các cấu trúc, và một
RETURNsau vòng lặp. - Module chưa hoàn thành vẫn thu điểm cho từng phần đúng, nên hãy viết hết chúng.

Mỗi phần của câu trả lời module mang điểm riêng
Sắp xếp các phần của câu trả lời mô-đun Paper 2 theo thứ tự chúng được viết.
Độ khó 3/5 · 200 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Tiêu đề, khai báo, vòng lặp, điều kiện, cập nhật, trả về. Mỗi phần là một điểm, ngay cả khi một phần khác bị sai.
Điểm số dễ mất
- Một routine cần thay đổi biến của người gọi cần
BYREFtrong header; nếu không có thìBYVALđược mặc định và sự thay đổi bị mất. - Hàm có một
RETURN, sau vòng lặp, vàENDFUNCTION. MộtRETURNbên trong vòng lặp kết thúc nó ngay phần tử đầu tiên. DECLAREmọi biến cục bộ, và khởi tạo bộ đếm hoặc tổng bằng 0 trước vòng lặp.- "Pseudocode hiệu quả" nghĩa là di chuyển công việc không thay đổi ra khỏi vòng lặp, dừng tìm kiếm tại matches đầu tiên, và không lặp lại lời gọi mà kết quả có thể được lưu trữ.
Để làm cho vòng lặp hiệu quả hơn, một giá trị không thay đổi theo bộ đếm vòng lặp nên:
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Di chuyển một bất biến vòng lặp ra ngoài giúp tránh tính toán lại cùng một giá trị ở mỗi lần lặp.
Bạn đã nắm vững
- một thủ tục thực hiện hành động và bị
CALL; một hàm trả về giá trị được sử dụng trong biểu thức - header đặt tên routine, tham số với kiểu và kiểu trả về; đối số là các giá trị được truyền vào
- BYVAL truyền bản sao (mặc định); BYREF cho phép routine thay đổi biến của người gọi
- ưu tiên biến cục bộ; biến cục bộ được tạo mới mỗi lần gọi, biến toàn cục giữ nguyên giá trị
- Mô-đun Bài thi 2: tiêu đề, khai báo, khởi tạo, vòng lặp, điều kiện, cập nhật, cấu trúc đóng, một
RETURN