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

pdf 107 trang phuongnguyen 2760
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

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:

  • pdfbai_giang_lap_trinh_cc_chuong_8_ham_le_thanh_sach.pdf