Bài giảng Lập trình C/C++ - Chương 8: Hàm - Lê Thành Sách
Nội dung
n Hàm là gì?
n Lý do sử dụng hàm
n Hàm main và hàm thư viện
n Sử dụng hàm tự tạo
n Định nghĩa
n Gọi hàm
n Nguyên tắc thực thi cho lời gọi hàm
n Prototype của hàm, chữ ký hàm, quá tải hàm
n Kiểu truyền tham số
n Hàm và mảng, con trỏ
n Hàm inline
n Con trỏ hàm
n Hàm đệ quy
n Tạo thư viện hàm
n Liên kết tĩnh và động
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Lập trình C/C++ - Chương 8: Hàm - Lê Thành Sách", để tải tài liệu gốc về máy hãy click vào nút Download ở trên
Tóm tắt nội dung tài liệu: Bài giảng Lập trình C/C++ - Chương 8: Hàm - Lê Thành Sách
Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 1 Chương 06 HÀM Lê Thành Sách CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 2 Nội dung n Hàm là gì? n Lý do sử dụng hàm n Hàm main và hàm thư viện n Sử dụng hàm tự tạo n Định nghĩa n Gọi hàm n Nguyên tắc thực thi cho lời gọi hàm n Prototype của hàm, chữ ký hàm, quá tải hàm n Kiểu truyền tham số n Hàm và mảng, con trỏ n Hàm inline n Con trỏ hàm n Hàm đệ quy n Tạo thư viện hàm n Liên kết tĩnh và động CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 3 Hàm là gì? n Hàm là n Một đơn vị xử lý n Một chuỗi các lệnh có liên quan, được thực hiện cùng nhau để hoàn thành một công việc nào đó n Ví dụ: trong thư viện n Hàm sin(x) n Là chuỗi các lệnh tính toán để tính giá trị sin của một góc x được truyền vào, góc x có đơn vị tính là radian; hàm sin(x) trả về một số thực n Hàm sqrt(x) n Là chuỗi các lệnh tính toán để tính căn bậc 2 của đại lượng x được truyền vào, đại lượng x có đơn vị tính là một số thực (float hay double); hàm sqrt trả về một số thực CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 4 Hàm là gì? n Hàm là n Một đơn vị tính toán n Nhận giá trị đầu vào n Tính toán n Trả về giá trị n Minh hoạ Chuỗi lệnh của hàmCác giá trị đầu vào Các giá trị đầu ra CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 5 Hàm là gì? n Minh hoạ Tính sin(x)Vào: x (radian) Ra: sin(x) Tính sqrt(x)Vào: x (số thực) Ra: sqrt(x) CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 6 Hàm là gì? n Minh hoạ cho hàm cộng hai số n Vào: hai số a và b kiểu số thực n Tính toán: phép cộng hai số n Ra: tổng hai số 1. Tính tổng 2. Trả về tổng Vào: • Số thực a • Số thực b Ra: (a + b) CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 7 Lý do sử dụng hàm n Tránh lặp lại mã nguồn n è Tiết kiệm thời gian phát triển n è Thay đổi đoạn mã nguồn trong hàm nhanh và dễ dàng, chỉ tại một nơi n Sử dụng lại một đơn vị tính toán mà không phải viết lại n Tiết kiệm thời gian phát triển n Có thể chia sẽ đơn vị tính toán không chỉ cho một dự án mà cho nhiều dự án n Ví dụ: hãy xem xét trường hợp mà mọi dự án đều viết lại các hàm toán học: sin(x), sqrt(x), v.v. è tốn kém và lãng phí n è sử dụng thư viện CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 8 Lý do sử dụng hàm n Giúp cho việc phát triển giải thuật, việc tổ chức chương trình dễ dàng n Giải thuật: n Một kỹ thuật cơ bản của giải quyết vấn đề là: phân rã bài toán lớn thành bài toán con n è Mỗi bài toán con có thể là một đơn vị tính toán (là một hàm) n Ví dụ: bài toán cho nhập một dãy số, tính toán và in ra giá trị trung bình và độ lệch chuẩn. Có thể phân rã thành các bài toán con n (1) Nhập dãy số n (2) Tính toán giá trị trung bình và độ lệch chuẩn n (3) In ra dãy số và các giá trị trung bình và độ lệch chuẩn CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 9 Lý do sử dụng hàm n Giúp cho việc phát triển giải thuật, việc tổ chức chương trình dễ dàng n Giải thuật: n Ví dụ: bài toán cho nhập một dãy số, tính toán và in ra giá trị trung bình và độ lệch chuẩn. Có thể phân rã thành các bài toán con n (1) Nhập dãy số n (2) Tính toán giá trị trung bình và độ lệch chuẩn n (3) In ra dãy số và các giá trị trung bình và độ lệch chuẩn n è Mỗi bài toán con ở trên có thể được viết thành hàm riêng CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 10 Lý do sử dụng hàm n Giúp cho việc phát triển giải thuật, việc tổ chức chương trình dễ dàng n Tổ chức chương trình: n Nếu chương trình (ngôn ngữ C) được so sánh với một cuốn sách (Ngôn ngữ Tiếng việt) n Có cuốn sách nào trên thực tế mà tác giả viết toàn bộ cuốn sách thành các câu nối tiếp nhau; không phân ra chương, phần, phần con, đoạn hay không? n Hàm có ý nghĩa tương tự như các chương, các phần con trong các chương CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 11 Hàm main và hàm thư viện int main(){ // Các lệnh xử lý của hàm main return 0; } Giá trị trả về: kiểu số nguyên int Tên hàm: “main”. Một chương trình phải và chỉ có 01 hàm main duy nhất Trả về giá trị cho bên gọi hàm main Giá trị trả về của main: • Phải là kiểu int • Có thể là một trong 2 hằng số • EXIT_SUCCESS (hoặc 0): nếu chương trình kết thúc thành công • EXIT_FAILURE (hoặc 1): nếu chương trình kết thúc với lỗi nào đó CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 12 Hàm main và hàm thư viện #include #include int main(int argc, char* argv[]){ printf("So thong so: %3d\n", argc); for(int i=0; i < argc; i++) printf("Thong so thu %d: %s\n", i, argv[i]); return EXIT_SUCCESS; } Nếu muốn truyền tham số vào dòng lệnh arc: số lượng các thông số, kể cả tên chương trình argv: một danh sách các chuỗi, mỗi chuỗi là một thông số. Khi truyền vào, tất cả các dữ liệu điều được hiểu như chuỗi CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 13 Hàm main và hàm thư viện • Sau khi biên dịch chương trình thành công, tạo ra tập tin “Program.exe” • Chạy chương trình “Program.exe” bằng dòng lệnh như sau: Thông cho chương trình CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 14 Hàm main và hàm thư viện • Cách truyền tham số dòng lệnh trong Visual Studio • (1) Nhấn chuột phải trên trong cửa sổ “Solution Explorer” • (2) Chọn “Debug” > “Command Arguments” • (3) Xổ chọn “Edit ” trong danh sách chức năng của “Command Arguments” • (4) Gõ vào danh sách thông số: các thông số cách nhau bởi khoảng trắng hay dấu “,” CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 15 Hàm main và hàm thư viện • Cách truyền tham số dòng lệnh trong Visual Studio CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 16 Hàm main và hàm thư viện n Ví dụ hàm trong thư viện n (1) Dùng chỉ thị #include để thông báo với bộ biên dịch là có sử dụng thư viện n (2) Gọi các hàm cần thiết. Khi gọi một hàm chỉ cần biết n Tên hàm + công dụng của hàm n Các giá trị cần cung cấp cho hàm n Giá trị trả về của hàm CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 17 Hàm main và hàm thư viện n Ví dụ hàm trong thư viện n Ví dụ #include #include #include int main(int argc, char* argv[]){ printf("%-10s = %5.2f\n", "sqrt(25.0)", sqrt(25.0)); printf("%-10s = %5.2f\n", "sin(90.0)", sin(90.0f*(3.14159/180.0))); printf("%-10s = %5.2f\n", "cos(0.0)", cos(90.0f*(3.14159/180.0))); printf("\n\n"); system("pause"); return EXIT_SUCCESS; } Lời gọi hàm CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 18 Sử dụng hàm tự tạo n Gồm hai bước n (1) Tạo ra hàm n Mô tả một hàm n Hiện thực hàm n (2) Gọi hàm CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 19 Sử dụng hàm tự tạo Định nghĩa hàm #include #include int add(int a, int b) { int c; c = a + b; return c; } int main(){ printf("10 + 15 = %d", add(10, 15)); system("pause"); return EXIT_SUCCESS; } Phần mô tả một hàm, gồm: (1) Kiểu giá trị trả về: ví dụ này là int (2) Tên hàm: ví dụ này là “add” (3) Các thông số, là giá trị đầu vào. Ví dụ này có • Thông số thứ nhất: tên là “a”, kiểu là int • Thông số thứ hai: tên là “b”, kiểu là int • Danh sách thông số: bắt đầu bằng ”(“, kết thúc bằng “)” • Các thông số cách nhau bằng dấu phẩy “,” Tên hàm và tên thông số tuân theo quy tắc đặt tên danh hiệu CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 20 Sử dụng hàm tự tạo Định nghĩa hàm #include #include int add(int a, int b) { int c; c = a + b; return c; } int main(){ printf("10 + 15 = %d", add(10, 15)); system("pause"); return EXIT_SUCCESS; } Phần thân của hàm, gồm: Gồm các câu lệnh được thực hiện cùng nhau, lần lượt. Ở ví dụ này: có 3 lệnh trong thân hàm Dùng câu lệnh return để chấm dứt thực thi hàm và trả điều khiển về cho hàm gọi à chuyển thực thi về lệnh kế sau lệnh gọi hàm Các lệnh trong thân của hàm phải được gôm lại với nhau bằng cặp dấu “{“ và “}” CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 21 Sử dụng hàm tự tạo Gọi hàm #include #include int add(int a, int b) { int c; c = a + b; return c; } int main(){ printf("10 + 15 = %d", add(10, 15)); system("pause"); return EXIT_SUCCESS; } Lời gọi hàm: Dùng tên hàm và truyền vào các giá trị cho các tham số của hàm: • Thứ tự truyền vào quyết định giá trị nào sẽ được truyền cho thông số nào. • Ví dụ này: 10 được truyền cho a; 15 được truyền cho b • Phải truyền đủ (không thiếu, không thừa) tất cả các tham số • Không chấp nhận: add(), add(10), add(10, 20, 30) Phần mô tả hàm phải xuất hiện trước khi lời gọi hàm xảy ra để biên dịch không gặp lỗi danh hiệu chưa được định nghĩa : “undefined identifer” CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 22 Sử dụng hàm tự tạo Nguyên tắc thực thi khi gọi hàm n Khi lời gọi hàm được thực thi thì bộ thực thi sẽ làm các công việc n Lưu vết: lệnh kế tiếp của lệnh gọi hàm n Copy các thông số cho hàm được gọi n Làm các công việc hệ thống khác (chưa cần quan tâm cho người học lập trình C) n Chuyển điều khiển thực thi cho hàm được gọi để nó thực thi lệnh đầu tiên trong hàm được gọi n Hàm được gọi thực thi các lệnh n Khi hàm được gọi thực hiện lệnh return. n Giải phóng tất cả các biến cục bộ của nó n Trả điều khiển về lệnh theo sau lệnh gọi hàm n Hàm gọi giải phóng các thông số đã truyền và thực thi lệnh kế tiếp theo lệnh gọi hàm CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 23 Sử dụng hàm tự tạo Nguyên tắc thực thi khi gọi hàm n Trình bày trình tự thực thông qua “debug” chương trình n Minh hoạ trực tiếp n Chú ý: cho xem các lệnh Assembly CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 24 Tổ chức mã nguồn int add(int a, int b) { int c; c = a + b; return c; } Phần mô tả hàm (header) Phần thân hàm (body) Phần mô tả nên được tách riêng khỏi toàn bộ phần định nghĩa một hàm. Lý do: • Không cần quan tâm thứ tự các hàm trong mã nguồn. • Dùng lại các hàm trong dự án hoặc nhiều dự án • Phát triển thư viện các hàm à không cần chuyển giao cho bên thứ 3 (người mua thư viện) mã nguồn phần hiện thực các hàm CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 25 Tổ chức mã nguồn #include #include int add(int a, int b); int main(){ printf("10 + 15 = %d", add(10, 15)); printf("\n\n"); system("pause"); return EXIT_SUCCESS; } int add(int a, int b) { int c; c = a + b; return c; } Tách rời phần mô tả của hàm “add” và đặt trước hàm “main” (trước khi sử dụng) è Không cần thiết đặt trước toàn bộ phần định nghĩa cho hàm “add” phía trước hàm “main” CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 26 Tổ chức mã nguồn n Đưa phần mô tả vào một tập tin riêng n Gọi là tập tin mô tả (header): *.h n Có thể sử dụng lại ở nhiều tập tin khác trong dự án n Sử dụng chỉ thị #if !defined(.) endif để tránh lỗi “định nghĩa lặp lại” (redefinition) n Đưa phần hiện thực vào một tập tin riêng n Gọi là tập tin hiện thực (implementation): *.c; *.cpp n Có thể sử dụng lại ở nhiều tập tin khác trong dự án n Đưa phần hiện thực vào một tập tin riêng n Khai báo có sử dụng đến các hàm ở *.h nói trên n Gọi hàm CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 27 Tổ chức mã nguồn Tập tin chứa hàm main, có sử dụng hàm “add”. Tập tin chứa phần định nghĩa hàm “add”, có khai báo sử dụng phần mô tả *.h Tập tin chứa phần mô tả cho hàm, kiểu dữ liệu, v.v. các phần mô tả nói chung CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 28 Tổ chức mã nguồn Mô-đun Mô tả các hàm (my_math.h) Mô-đun chương trình chính (program.cpp) Mô-đun Hiện thực các hàm (my_math.cpp) phụ thuộc phụ thuộc Sự phụ thuộc được biểu thi bởi chỉ thị #include ”my_math.h” trong mã nguồn CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 29 Tổ chức mã nguồn #if !defined(MY_MATH_HEADER) #define MY_MATH_HEADER int add(int a, int b); #endif Tập tin: ”my_math.h” Phần mô tả cho hàm add MY_MATH_HEADER là một tên (danh hiệu) Ý nghĩa của cấu trúc chỉ thị #if: NẾU như trong quá trình biên dịch, đến thời điểm hiện tại, chưa thấy một tên (MY_MATH_HEADER) xuất hiện thì định nghĩa một tên mới (MY_MATH_HEADER) và thực hiện biên dịch cho cả đoạn mã nguồn nằm trong phần tương ứng khối #if NGƯỢC LẠI thì không định nghĩa tên mới và không biên dịch đoạn mã nguồn tương ứng khối if CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 30 Tổ chức mã nguồn #if !defined(MY_MATH_HEADER) #define MY_MATH_HEADER int add(int a, int b); #endif Tập tin: ”my_math.h” Phần mô tả cho hàm add MY_MATH_HEADER là một tên (danh hiệu) Nhờ chỉ thị #if mà phần mô tả của các tên như hàm add ở đây không bị lặp lại nhiều lần khi được dùng ở nhiều tập tin khác nhau, kể cả trong tập tin *.h CuuDuongThanCon ... s://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 74 Hàm và mảng, con trỏ Không cho phép hàm thay đổi phần tử trên mảng n Sử dụng từ khoá const trước tên kiểu phần tử Đã khai báo const + cố tình thay đổi phần tử trên mảng thì có lỗi Lỗi: “expression must be a modifiable lvalue” Nghĩa: arr không được dùng trong bên trái của biểu thức gán CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 75 Hàm inline n Hàm inline là gì? n Là hàm có từ khoá “inline” đứng trước kiểu trả về của hàm, như ví dụ inline void print_array1(const Point3D arr[MAX_SIZE], int size); inline void print_array2(const Point3D arr[], int size); inline void print_array3(const Point3D *arr, int size); Từ khoá inline CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 76 Hàm inline n Tác dụng của hàm inline n Hàm không inline n Tốn chi phí thực thi khi gọi hàm n COPY các tham số n Lưu trữ các thanh ghi n Phục hồi các thanh ghi n Giải phóng các tham số n V.v CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 77 Hàm inline n Tác dụng của hàm inline n Hàm inline n Thay vì làm các thủ tục để goị hàm và trả về từ hàm được gọi, mã thực thi của hàm inline được chèn trực tiếp tại vị trí gọi hàm này. n => Tiết kiệm chi phí gọi hàm n => Làm tăng kích thước tập tin thực thi (*.EXE) nếu gọi hàm inline có đoạn mã thực thi lớn và nhiều lần n => chỉ nên sử dụng hàm inline khi cần tối ưu thời gian thực thi CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 78 Con trỏ hàm n Con trỏ hàm là gì? n Ứng dụng của con trỏ hàm n Khai báo con trỏ hàm n Gọi hàm thông qua con trỏ n Định nghĩa kiểu dữ liệu con trỏ hàm n Truyền con trỏ hàm như thông số của hàm n Mảng con trỏ hàm CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 79 Con trỏ hàm Con trỏ hàm là gì? n Con trỏ đến hàm fx là địa chỉ của lệnh đầu tiên được thực thi của hàm fx. n Lấy địa chỉ của hàm như thế nào n Tên hàm chính là địa chỉ của hàm CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 80 Con trỏ hàm Ứng dụng của con trỏ hàm n Khi không có con trỏ hàm n Hàm được gọi thông qua tên hàm trong mã nguồn n è Cần biết trước tên hàm tại thời điểm biên dịch n Khi dùng con trỏ hàm n Có thể gọi hàm qua con trỏ đến hàm n è Không cần biết trước tên hàm tại thời điểm biên dịch n è Chỉ cần biết địa chỉ hàm tại thời điểm thực thi và gọi nó n è Chương trình uyển chuyển hơn CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 81 Con trỏ hàm Ứng dụng của con trỏ hàm n Ví dụ: bài toán vẽ đồ thị n Hàm vẽ chỉ cần biết: khi cho x thì nó lấy được giá trị y của hàm số nào đó, chưa cần biết tên lẫn cách tính tại thời điểm biên dịch n Chương trình xây dựng bảng hàm (mảng các địa chỉ hàm), và có thể gọi hàm thông qua địa chỉ để biết y kho cho x. n Thậm chí bảng hàm này có thể thêm vào và lấy ra tại thời điểm thực thi n Khi chương trình đang chạy, người dùng chọn thư viện có tên hàm đánh giá (tính y khi biết x), cho biết tên hàm (chuỗi) n => Chương trình có thể vẽ đồ thị các hàm mà cách tính chỉ biết tại thời điểm chạy chương trình CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 82 Con trỏ hàm Ứng dụng của con trỏ hàm n Ví dụ: Xây dựng thư viện mà hàm để làm công việc nào đó chỉ có thể biết ở thời điểm tương lai, theo mỗi dự án. n Hàm xử lý sự kiện trong thư viện phát triển ứng dụng co giao diện đồ hoạ n Hàm callback n Ví dụ: Để hiện thực bảng hàm trong ngôn ngữ C++ CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 83 Con trỏ hàm Khai báo con trỏ hàm n Những yếu tố cần xác định n Kiểu dữ liệu trả về của hàm n Danh sách kiểu dữ liệu của các tham số n Ý nghĩa của họ các hàm thoả mãn hai 2 yếu tố trên n Xác định tên phù hợp cho con trỏ CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 84 Con trỏ hàm Khai báo con trỏ hàm – ví dụ void (*print_ptr1)(Student); void (*print_ptr2)(Student) = NULL; void (*print_ptr3)(Student) = print_one_row; typedef struct{ char code[5]; char name[20]; float gpa; } Student; Student: Kiểu dữ liệu chứa thông tin sinh viên print_ptr1, print_ptr2, print_ptr3: • là các biến con trỏ hàm (là các biến chứa địa chỉ của hàm). Các hàm có thể gán cho nó là (không cần quan tâm tên) • Trả về void, không trả về • Một thông số đầu vào có kiểu là Student void print_one_row(Student student); print_one_row:Một hàm trả về void, đầu vào là một Student CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 85 Con trỏ hàm Gọi hàm qua con trỏ #include #include typedef struct{ char code[5]; char name[20]; float gpa; } Student; void print_one_row(Student student); void print_one_row(Student student){ printf("%-6s%-20s%-4.1f\n", student.code, student.name, student.gpa); } Mã nguồn thực toàn bộ Hàm in thông tin sinh viên trên một dòng CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 86 Con trỏ hàm Gọi hàm qua con trỏ Hàm main int main(){ void (*print_ptr3)(Student) = print_one_row; Student s = {"001", "Nguyen Thanh An", 9.8f}; print_ptr3(s); (*print_ptr3)(s); system("pause"); return EXIT_SUCCESS; } Lời gọi hàm qua con trỏ: dùng đến toán tử * Lời gọi hàm qua con trỏ: địa chỉ hàm ở vị trí tên hàm thông thường trong lời gọi hàm thông thường CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 87 Con trỏ hàm Gọi hàm qua con trỏ - kết quả Hàm main int main(){ void (*print_ptr3)(Student) = print_one_row; Student s = {"001", "Nguyen Thanh An", 9.8f}; print_ptr3(s); (*print_ptr3)(s); system("pause"); return EXIT_SUCCESS; } CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 88 Con trỏ hàm Định nghĩa kiểu dữ liệu con trỏ hàm typedef struct{ char code[5]; char name[20]; float gpa; } Student; typedef void (*PrintStudentPtr)(Student); Từ khoá typedef giúp rút ngắn việc khai báo biến PrintStudentPtr: có thể được sử dụng như tên kiểu mới Nó là họ các hàm có kiểu trả về void, chấp nhận 1 thông số đầu vào có kiểu Student CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 89 Con trỏ hàm Định nghĩa kiểu dữ liệu con trỏ hàm void (*print_ptr3)(Student) = print_one_row; PrintStudentPtr print_ptr = print_one_row; print_ptr3, print_ptr : là tên biến, được khởi động là địa chỉ của hàm print_one_row Nhờ có PrintStudentPtr Khai báo biến print_ptr như khai báo biến có kiểu dữ liệu nào khác, dễ hiểu và ngắn hơn. CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 90 Con trỏ hàm Định nghĩa kiểu dữ liệu con trỏ hàm #include #include typedef struct{ char code[5]; char name[20]; float gpa; } Student; typedef void (*PrintStudentPtr)(Student); void print_one_row(Student student); void print_one_row(Student student){ printf("%-6s%-20s%-4.1f\n", student.code, student.name, student.gpa); } Ví dụ hoàn chỉnh CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 91 Con trỏ hàm Định nghĩa kiểu dữ liệu con trỏ hàm int main(){ void (*print_ptr3)(Student) = print_one_row; PrintStudentPtr print_ptr = print_one_row; Student s = {"001", "Nguyen Thanh An", 9.8f}; print_ptr3(s); (*print_ptr3)(s); print_ptr(s); (*print_ptr)(s); system("pause"); return EXIT_SUCCESS; } Ví dụ hoàn chỉnh In ra 4 hàng CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 92 Con trỏ hàm Truyền con trỏ như tham số - khai báo thông số void print_list1(Student *list, int size, PrintStudentPtr print_ptr); void print_list2(Student *list, int size, void (*print_ptr)(Student)); Dùng tên kiểu đã định nghĩa bằng typedef Không dùng tên kiểu CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 93 Con trỏ hàm Truyền con trỏ như tham số - dùng thông số void print_list1( Student *list, int size, PrintStudentPtr print_ptr){ for(int i=0; i< size; i++) print_ptr(list[i]); } void print_list2( Student *list, int size, void (*print_ptr)(Student)){ for(int i=0; i< size; i++) print_ptr(list[i]); } Đều gọi hàm theo con trỏ hàm như thông thường CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 94 Con trỏ hàm Truyền con trỏ như tham số - dùng thông số #include #include typedef struct{ char code[5]; char name[20]; float gpa; } Student; typedef void (*PrintStudentPtr)(Student); void print_one_row(Student student); void print_list1(Student *list, int size, PrintStudentPtr print_ptr); void print_list2(Student *list, int size, void (*print_ptr)(Student)); CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 95 Con trỏ hàm Truyền con trỏ như tham số - dùng thông số int main(){ Student aList[] = { {"001", "Nguyen Thanh An", 9.8f}, {"002", "Tran Van Binh", 7.5f}, {"003", "Le Tan Cong", 6.7f}, }; PrintStudentPtr func_ptr = print_one_row; print_list1(aList, 3, func_ptr); printf("\n"); print_list2(aList, 3, func_ptr); printf("\n\n"); system("pause"); return EXIT_SUCCESS; } CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 96 Con trỏ hàm Truyền con trỏ như tham số - dùng thông số Kết quả xuất ra màn hình CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 97 Con trỏ hàm Mảng con trỏ hàm void (*print_ptr[10])(Student); PrintStudentPtr func_arr_ptr[10]; Khi sử dụng tên kiểu PrintStudentPtr Khi không sử dụng tên kiểu PrintStudentPtr func_arr_ptr và print_ptr là mảng của 10 con trỏ hàm. Sử dụng mảng này như mảng của các kiểu dữ liệu khác CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 98 Hàm đệ quy n Hàm đệ quy là hàm gọi lại chính nó n Trực tiếp: n foo() gọi foo() trực tiếp trong thân hàm foo() n Gán tiếp: n foo() gọi bar, bar gọi foo(); hoặc qua nhiều trung gian hàm khác CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 99 Hàm đệ quy n Ví dụ n Chương trình tính tổng của 1+2+3+ .. + N n Hàm tong(N) gọi lại tong(N-1) int tong(int N){ int ket_qua; if(N <=0) ket_qua = 0; else ket_qua = N + tong(N-1); return ket_qua; } CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 100 Hàm đệ quy n Ví dụ n Chương trình tính giai thừa: 1x2x3x x N n Hàm giai_thua(N) gọi lại giai_thua(N-1) long long giai_thua(int N){ int ket_qua; if(N <=1) ket_qua = 1; else ket_qua = N*giai_thua(N-1); return ket_qua; } CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 101 Hàm đệ quy n Yêu cầu cần thiết của một hàm đệ quy: n Điều kiện dừng quá trình gọi đệ quy n Ví dụ: int tong(int N){ ... if(N <=0) ket_qua = 0; ... } Dừng quá trình gọi đệ quy CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 102 long long giai_thua(int N){ ... if(N <=1) ket_qua = 1; ... } Hàm đệ quy n Yêu cầu cần thiết của một hàm đệ quy: n Điều kiện dừng quá trình gọi đệ quy n Ví dụ: Dừng quá trình gọi đệ quy CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 103 Hàm đệ quy n Yêu cầu cần thiết của một hàm đệ quy: n Điều kiện dừng quá trình gọi đệ quy n Có lời gọi hàm đệ quy n Hàm tong(N) gọi lại tong(N-1) n Hàm giai_thua(N) gọi lại giai_thua(N-1) CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 104 Hàm đệ quy n Giải bài toán bằng đệ quy n Lời giải của bài toán có kích thước N được tổng hợp từ lời giải của các bài toán có kích thước nhỏ hơn. n Ví dụ: n Lời giải cho bài toán tìm tổng N phần tử n Giả sử ta biết tổng của (N-1) phần tử n Vậy, lời giải của N phần tử được tổng hơp như thế nào từ kết quả trên? CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 105 Hàm đệ quy n Giải bài toán bằng đệ quy n Lời giải của bài toán có kích thước N được tổng hợp từ lời giải của các bài toán có kích thước nhỏ hơn. n Ví dụ: n Lời giải cho giai thừa N n Giả sử ta biết lời giải cho giai thừa của (N-1) n Lời giải cho giai thừa N được tổng hợp như thế nào từ lời giải trên? CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 106 Hàm đệ quy n Giải bài toán bằng đệ quy n Lời giải của bài toán có kích thước N được tổng hợp từ lời giải của các bài toán có kích thước nhỏ hơn. n Ví dụ: n Tìm số thứ N trong dãy số Fibonaci n F(1) = 1 n F(2) = 1 n N >2: F(N) = F(N-1) + F(N-2) n Lời giải n Giả sử ta có F(N-1) và F(N-2) n Lời giải cho F(N) được tổng hợp như thế nào từ các kết quả trên? CuuDuongThanCong.com https://fb.com/tailieudientucntt Trường Đại Học Bách Khoa Trung Tâm Kỹ Thuật Điện Toán © 2016 Lập trình C/C++ 107 Hàm đệ quy n Giải bài toán bằng đệ quy n Ví dụ: n Bài toán tháp Hanoi n Di chuyển chồng đĩa từ Cột đầu sang cột cuối, dùng cột giữa làm trung gian n Luôn đảm bảo trật tự kích thước các đĩa CuuDuongThanCong.com https://fb.com/tailieudientucntt
File đính kèm:
- bai_giang_lap_trinh_cc_chuong_8_ham_le_thanh_sach.pdf