Bài giảng Hệ thống máy tính và ngôn ngữ C - Chương 9: Hàm
9.1 Khái niệm hàm
9.2 Khai báo hàm
9.3 Đối số của hàm - đối số là tham trị
9.4 Kết quả trả về của hàm - lệnh RETURN
9.5 PROTOTYPE của một hàm
9.6 Hàm đệ quy
Bài tập cuối chương
.2 Quá trình hiện thực • Thực hiện hàm được gọi Đoạn code hồn thành việc này cho hàm Volta() như sau: ADD R6, R6, #-1 ; dành khơng gian cho trị trả về ADD R6, R6, #-1 STR R7, R6, #0 ; đẩy R7 (địa chỉ trở về) vơ stack ADD R6, R6, #-1 ; đẩy liên kết động vơ stack (con trỏ khung của hàm gọi) STR R5, R6, #0 ; đẩy R5 vơ stack ADD R5, R6, #-1 ; đặt con trỏ khung mới ADD R6, R6, #-2 ; định vị khơng gian cho các biến cục bộ 9.7 HIỆN THỰC HÀM TRONG C CHƯƠNG 9 HÀM 9.7.2 Quá trình hiện thực • Thực hiện hàm được gọi 9.7 HIỆN THỰC HÀM TRONG C CHƯƠNG 9 HÀM 9.7.2 Quá trình hiện thực • Kết thúc hàm được gọi Một khi hàm được gọi hồn thành cơng việc của nĩ, nĩ phải làm thêm một số tác vụ nữa trước khi trả điều khiển về cho hàm gọi. Đầu tiên, ta cần cĩ cơ chế để một hàm trả về trị một cách thích hợp cho nơi gọi. Thứ hai, hàm được gọi phải lấy ra khỏi stack mẫu tin kích hoạt của nĩ. 9.7 HIỆN THỰC HÀM TRONG C CHƯƠNG 9 HÀM 9.7.2 Quá trình hiện thực • Kết thúc hàm được gọi Như vậy, ta cĩ các việc như sau: 1) Nếu cĩ một trị trả về, nĩ cần phải được ghi vơ đầu vào trị trả về của mẫu tin kích hoạt. 2) Các biến cục bộ phải được lấy ra khỏi stack. 3) Liên kết động cần được phục hồi. 4) Địa chỉ trả về phải được phục hồi. 5) Lệnh RET trả điều khiển về cho hàm gọi. 9.7 HIỆN THỰC HÀM TRONG C CHƯƠNG 9 HÀM 9.7.2 Quá trình hiện thực • Kết thúc hàm được gọi Hàm Volta() khi lệnh return k; được thi hành như sau: LDR R0,R5,#0 ; nạp biến cục bộ k STR R0,R5,#3 ; lưu nĩ vơ đầu vào trị trả về ADD R6,R5,#1 ; pop các biến cục bộ LDR R5,R6,#0 ; pop liên kết động, con trỏ khung -> R5 ADD R6,R6,#1 ; R6 chỉ tới ơ địa chỉ trả về LDR R7,R6,#0 ; lưu địa chỉ trả về cho R7 ADD R6,R6,#1 ; R6 chỉ tới ơ trị trả về RET ; trả điều khiển về cho nơi gọi 9.7 HIỆN THỰC HÀM TRONG C CHƯƠNG 9 HÀM 9.7.2 Quá trình hiện thực • Trở về hàm gọi Sau khi hàm được gọi thực thi lệnh RET, điều khiển được trả ngược về cho hàm gọi. Trong một số trường hợp, khơng cĩ trị trả về (tức hàm được gọi được khai báo với kiểu void) và, trong một số trường hợp khác, hàm gọi bỏ qua các trị trả về (như khi ta gọi getch();). Đặc biệt, cĩ hai thao tác phải được thi hành: 1) Trị trả về (nếu cĩ) được lấy ra khỏi stack. 2) Các đối số cần được lấy ra khỏi stack. 9.7 HIỆN THỰC HÀM TRONG C CHƯƠNG 9 HÀM 9.7.2 Quá trình hiện thực • Trở về hàm gọi Đoạn code LC-3 sau lệnh JSR sẽ như sau: JSR Volta LDR R0, R6, #0 ; nạp trị trả về ở đỉnh stack STR R0, R5, #0 ; w = Volta(w, 20); ADD R6, R6, #1 ; pop trị trả về ADD R6, R6, #2 ; pop các đối số 9.7 HIỆN THỰC HÀM TRONG C CHƯƠNG 9 HÀM 9.7.2 Quá trình hiện thực • Sao lưu ở nơi gọi và sao lưu ở nơi được gọi Trong khi thực thi một hàm, R0 tới R3 cĩ thể chứa các giá trị tạm thời, là một phần của các thao tác tính tốn đang chạy. Thanh ghi từ R4 tới R7 được dành cho các mục đích khác: thanh ghi R4 là con trỏ chỉ tới vùng dữ liệu tồn cục, R5 là con trỏ khung, R6 là con trỏ stack, và R7 được dùng để giữ địa chỉ trở về. Nếu chúng ta gọi một hàm, dựa theo quy ước gọi hàm chúng ta đã mơ tả thanh ghi R4 tới R7 khơng thay đổi hay thay đổi theo các cách đã được xác định trước. 9.7 HIỆN THỰC HÀM TRONG C CHƯƠNG 9 HÀM 9.7.2 Quá trình hiện thực • Sao lưu ở nơi gọi và sao lưu ở nơi được gọi Nhưng cái gì xảy ra cho các thanh ghi R0, R1, R2, và R3? Tổng quát mà nĩi, chúng ta muốn chắc chắn rằng hàm được gọi sẽ khơng chép đè chúng. Để làm được điều này, các quy ước gọi hàm cụ thể theo một trong hai phương cách: (1) Nơi gọi sẽ sao lưu các thanh ghi bằng cách đẩy chúng vơ mẫu tin kích hoạt của nĩ. Đây được gọi là sao lưu nơi gọi (caller save). Khi điều khiển được trả về cho nơi gọi, nơi gọi sẽ khơi phục lại các thanh ghi này bằng việc lấy chúng ra khỏi stack. 9.7 HIỆN THỰC HÀM TRONG C CHƯƠNG 9 HÀM 9.7.2 Quá trình hiện thực • Sao lưu ở nơi gọi và sao lưu ở nơi được gọi (2) Hàm được gọi cĩ thể sao lưu các thanh ghi này bằng cách thêm vơ bốn vùng tin trong vùng thơng tin trạng thái của mẫu tin của nĩ. Đây chính là sao lưu nơi được gọi (callee save). Khi nơi được gọi được khởi tạo, nĩ sẽ sao lưu R0 tới R3 và R5 và R7 vơ vùng thong tin trạng thái và khơi phục các thanh ghi này lại trước khi trở về nơi gọi. 9.7 HIỆN THỰC HÀM TRONG C CHƯƠNG 9 HÀM 9.7.3 Tĩm lại (GT) 9.8 KIỂM TRA VÀ SỬA LỖI CHƯƠNG 9 HÀM 9.8.1 Giới thiệu 9.8.2 Các dạng lỗi 9.8.2.1 Lỗi cú pháp Ví dụ 10.20: #include main() { int i, i2 for (i = 0; i < 10; i++) { i2 = i * i; printf (“%d x %d = %d\n”, i, i, i2); } } CHƯƠNG 9 HÀM 9.8.2 Các dạng lỗi 9.8.2.2 Lỗi ngữ cảnh Ví dụ 10.21: #include main() { int i, i2; for (i = 0; i < 10; i++) i2 = i * i; printf (“%d x %d = %d\n”, i, i, i2); } 9.8 KIỂM TRA VÀ SỬA LỖI CHƯƠNG 9 HÀM 9.8.2 Các dạng lỗi 9.8.2.2 Lỗi ngữ cảnh Ví dụ 10.22: Chương trình tính tổng 1+2+ + n, với n là trị nguyên dương được nhập từ bàn phím. Chương trình được thiết kế với hàm tính tổng. #include int tinh_tong (int n); // prototype của hàm main() { int so; int tong; printf (“Moi nhap mot so nguyen duong: ”); 9.8 KIỂM TRA VÀ SỬA LỖI CHƯƠNG 9 HÀM 9.8.2 Các dạng lỗi 9.8.2.2 Lỗi ngữ cảnh scanf (“%d”, &so); tong = tinh_tong (n); printf (“Tong tu 1 + + %d = %d\n”, n, tong); } int tinh_tong (int n) { int tong; int i; for (i = 1; i <= n; i++) tong += i; return tong; } 9.8 KIỂM TRA VÀ SỬA LỖI CHƯƠNG 9 HÀM 9.8.2 Các dạng lỗi 9.8.2.3 Lỗi giải thuật Ví dụ 10.23: #include #include void gptb1 (double a, double b); main() { double a, b; clrscr(); printf ("Nhap 2 he so phuong trinh bac nhat: "); scant ("%lf %lf", &a, &b); gptb1 (a, b); getch(); } 9.8 KIỂM TRA VÀ SỬA LỖI CHƯƠNG 9 HÀM 9.8.2 Các dạng lỗi 9.8.2.3 Lỗi giải thuật Ví dụ 10.23: void gptb1 (double a, double b) { printf ("Phuong trinh bac nhat "); printf ("co 1 nghiem: x = %5.2f \n", -b/a); } 9.8 KIỂM TRA VÀ SỬA LỖI CHƯƠNG 9 HÀM 9.8.3 Kiểm tra chương trình 9.8.3.1 Kiểm tra hộp đen Với kỹ thuật hộp đen này, chúng ta cĩ thể kiểm tra xem dữ liệu nhập và xuất của chương trình cĩ phù hợp khơng, mà khơng cần phải biết cấu trúc lệnh trong chương trình. 9.8 KIỂM TRA VÀ SỬA LỖI CHƯƠNG 9 HÀM 9.8.3 Kiểm tra chương trình 9.8.3.1 Kiểm tra hộp trắng Kỹ thuật kiểm tra hộp trắng tổng quát sử dụng các code tìm lỗi được đặt trong chương trình một cách cĩ tính tốn. Các code này cĩ thể kiểm tra các điều kiện để chỉ ra lỗi sai làm chương trình khơng thực thi đúng. Khi cĩ một lỗi sai được tìm ra, code sẽ in ra một thơng điệp cảnh báo, hiển thị một vài thơng tin cĩ giá trị về lỗi, hoặc là làm cho chương trình kết thúc sớm. Vì các code tìm lỗi này xác nhận các điều kiện cụ thể cần giữ trong suốt quá trình chương trình thực thi, nên chúng ta gọi các code này là sự xác nhận. 9.8 KIỂM TRA VÀ SỬA LỖI CHƯƠNG 9 HÀM 9.8.4 Gỡ rối chương trình (debuging) 9.8.4.1 Kỹ thuật phi thể thức 9.8.4.2 Gỡ rối cấp nguồn - Điểm ngắt (Breakpoints) - Thực thi từng bước (Single-Stepping) - Hiển thị giá trị 9.8 KIỂM TRA VÀ SỬA LỖI CHƯƠNG 9 HÀM 9.8.5 Tính đúng đắn khi lập trình 9.8.5.1 Xác định thật rõ các chi tiết Ví dụ 10.25: int Giaithua (int n) { int i; int ketqua = 1; // Kiểm tra trị nhập if (n 31) { printf (“Trị sai, cần trị trong khoảng 1-31.\n”); ketqua = -1; } else for (i = 1; i <= n; i++) ketqua *= i; return ketqua; } 9.8 KIỂM TRA VÀ SỬA LỖI CHƯƠNG 9 HÀM 9.8.5 Tính đúng đắn khi lập trình 9.8.5.2 Thiết kế theo từng khối 9.8.5.3 Lập trình dự phịng 9.8 KIỂM TRA VÀ SỬA LỖI BÀI TẬP CUỐI CHƯƠNG 1. Thiết kế hàm giải phương trình ax 2 + bx + c = 0. Viết chương trình chính sử dụng hàm này. 2. Thiết kế hàm in ra màn hình chuỗi số Fibonaci, với thông số nhập là một số ngẫu nhiên trong số từ 1 đến 100. Hướng dẫn: Sử dụng hàm random() và randomize() để tạo số ngẫu nhiên. Dãy Fibonacci : 0, 1, 1, 2, 3... CHƯƠNG 9 HÀM BÀI TẬP CUỐI CHƯƠNG 3. Thiết kế hàm tính các biểu thức sau đây: S =(1)! + (1+2)! +...+ (1+...+n)! 4. Thiết kế hàm vẽ ra màn hình hình sau: * * * * * * * * * n nhập * * * * * * * ... ... ! ! ! 1 1 2 1 2 n T 1 2 n CHƯƠNG 9 HÀM BÀI TẬP CUỐI CHƯƠNG 5. Thiết kế hàm và vẽ ra màn hình hình sau: * * * * * * * * * * * * * * * * * * * * * * * n nhập là số chẵn * * * * * * * * * * * * * * * * * * * * * * * CHƯƠNG 9 HÀM BÀI TẬP CUỐI CHƯƠNG 6. Viết chương trình thiết kế hai hàm max() và min() cho phép tìm số lớn nhất và nhỏ nhất trong loạt số đã nhập. Loạt số nhập này sẽ kết thúc việc nhập bằng việc nhấn phím 7. Viết một chương trình cho phép nhập một chuỗi. Hãy thiết kế một hàm cho phép cắt chuỗi đó ra làm nhiều từ và in ra màn hình mỗi từ trên một hàng. CHƯƠNG 9 HÀM BÀI TẬP CUỐI CHƯƠNG 8. Viết một hàm nhận một chuỗi và cho phép đảo chuỗi đó, in ra kết quả. 9. Viết một hàm cho phép nhận một số nguyên dương. In ra màn hình ký số thứ n tính từ bên phải qua của số đó. Ví dụ: Nhập: 12345 4 Xuất: 2 CHƯƠNG 9 HÀM BÀI TẬP CUỐI CHƯƠNG 10. Thiết kế một hàm đệ quy cho phép nhận một số nguyên dương, in ra màn hình số đó ở dạng nhị phân. 11. Viết hàm đệ quy tính x n . 12. Viết một hàm nhận một số dương có phần lẻ và in ra màn hình phần nguyên và phần lẻ riêng biệt. 13. Viết chương trình với hàm tính tổng sau: S=1-x 2 /2!+x 4 /4!-xn/n! 14. Tương tự như bài 10.13, nhưng tính tổng sau: S=1-x 3 /3!+x 5 /5!-xn/n! CHƯƠNG 9 HÀM KẾT THÚC CHƯƠNG 9 CHƯƠNG 9 HÀM
File đính kèm:
- bai_giang_he_thong_may_tinh_va_ngon_ngu_c_chuong_9_ham.pdf