Professional Documents
Culture Documents
Ky Thuat Lap Trinh Lec3. Ham (Cuuduongthancong - Com)
Ky Thuat Lap Trinh Lec3. Ham (Cuuduongthancong - Com)
.c
Chương 3:
ng
co
Hàm
an
th
o ng
du
u
cu
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Nội dung
1. Truyền tham trị, tham biến và tham số ngầm
định
om
2. Đa năng hóa hàm (function overload)
.c
ng
3. Con trỏ hàm và tham số hóa hàm
co
4. Khái quát hóa hàm (function templates)
an
5. Biểu thức lamda và hàm nặc danh
th
o ng
du
u
cu
2
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Khái niệm về hàm
• Là một nhóm các khai báo và các câu lệnh
được gán một tên gọi
om
• Đây là khối lệnh được đặt tên nên sử dụng thuận
.c
tiện, hiệu quả
ng
• Hàm thường trả về một giá trị
co
• Là một chương trình con
an
• Khi viết chương trình C/C++ ta luôn định nghĩa một
hàm có tên là main
th
ng
• Phía trong hàm main ta có thể gọi các hàm khác
o
du
• Bản than các hàm này lại có thể gọi các hàm
u
3
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Cấu pháp
return-type name(argument-list)
{
om
local-declarations
.c
statements
ng
return return-value;
co
}
an
th
o ng
du
u
cu
4
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Ví dụ: Square
double square(double a)
om
{ Đây là định nghĩa hàm ngoài
return a * a; hàm main
.c
}
ng
int main(void)
co
{
an
double num = 0.0, sqr = 0.0;
th
printf("enter a number\n"); ng
scanf("%lf",&num);
o
Đây là chỗ gọi hàm
du
sqr = square(num);
square
u
return 0;
}
5
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Tại sao cần sử dụng hàm?
• Chia vấn đề thành nhiều tác vụ con
om
• Dễ dàng hơn khi giải quyết các vấn đề phức
tạp
.c
ng
• Tổng quát hóa được tập các câu lệnh
co
hay lặp lại
an
• Ta không phải viết cùng một thứ lặp đi lặp
lại nhiều lần
th
ng
• printf và scanf là ví dụ điển hình…
o
du
hơn nhiều
6
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Hàm và truyền tham số
• Trong C: tên hàm phải là duy nhất, lời gọi hàm phải có các
om
đối số đúng bằng và hợp tương ứng về kiểu với tham số
.c
trong đn hàm. C chỉ có duy nhất 1 cách truyền tham số:
ng
tham trị (kể cả dùng địa chỉ cũng vậy).
co
an
• Trong C++: ngoài truyền tham trị, C++ còn cho phép truyền
th
tham chiếu. Tham số trong C++ còn có kiểu tham số ngầm
o ng
định (default parameter), vì vậy số đối số trong lời gọi hàm
du
chế đa năng hóa hàm, vì vậy tên hàm không phải duy nhất.
7
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Truyền tham chiếu
om
void Swap(int *X, int *Y) {
.c
int Temp = *X;
ng
*X = *Y;
co
*Y = Temp;
an
th
} ng
o
• Để hoán đổi giá trị hai biến A và B
du
u
Swap(&A, &B);
cu
8
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Truyền tham chiếu
om
void Swap(int &X, int &Y){
.c
int Temp = X;
ng
X = Y;
co
Y = Temp;
an
}
th
ng
• Để hoán đổi giá trị hai biến A và B
o
du
Swap(A, B);
u
cu
9
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Truyền tham chiếu
#include <iostream.h>
Khi một hàm trả
om
int X = 4;
về một tham
.c
int & MyFunc(){
ng
chiếu, chúng ta return X;
co
}
có thể gọi hàm
an
int main(){
th
ở phía bên trái ng Cout << "X=“ << X << endl;
Cout << "X=“ << MyFunc() << endl;
của một phép
o
du
return 0;
}
10
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Tham số ngầm định
• Định nghĩa các giá trị tham số mặc định cho các hàm
om
• Ví dụ
.c
void MyDelay(long Loops = 1000){
ng
co
for(int I = 0; I < Loops; ++I) ;
an
}
th
ng
• MyDelay(); // Loops có giá trị là 1000
o
du
11
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Tham số ngầm định
• Nếu có prototype, các tham số có giá trị mặc định chỉ
được cho trong prototype của hàm và không được lặp
om
lại trong định nghĩa hàm.
.c
ng
• Một hàm có thể có nhiều tham số có giá trị mặc định.
co
Các tham số có giá trị mặc định cần phải được nhóm
an
lại vào các tham số cuối cùng (hoặc duy nhất) của một
th
hàm. Khi gọi hàm có nhiều tham số có giá trị mặc
ng
định, chúng ta chỉ có thể bỏ bớt các tham số theo thứ
o
• Ví dụ:
cu
12
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Đa năng hóa hàm (Overloading)
• Cung cấp nhiều hơn một định nghĩa cho tên hàm đã
om
cho trong cùng một phạm vi.
.c
• Trình biên dịch sẽ lựa chọn phiên bản thích hợp của
ng
hàm hay toán tử dựa trên các tham số mà nó được
co
gọi.
an
th
o ng
du
u
cu
13
CuuDuongThanCong.com https://fb.com/tailieudientucntt
#include <iostream.h>
#include <math.h>
int MyAbs(int X){
return abs(X);
}
om
long MyAbs(long X){
return labs(X);
.c
}
ng
double MyAbs(double X){
return fabs(X);
co
}
an
int main(){
th
int X = -7;
long Y = 200000l;
ng
double Z = -35.678;
o
cout << "Tri tuyet doi cua so nguyen " << X <<" la " <<
du
cout << "Tri tuyet doi cua so real " << Z <<" la " << MyAbs(Z)
<< endl;
return 0;
}
14
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Đa năng hoá toán tử
• Định nghĩa lại chức năng của các toán tử
đã có sẵn
om
▪ Thể hiện các phép toán một cách tự nhiên
.c
hơn
ng
co
• Ví dụ: thực hiện các phép cộng, trừ số
an
phức
th
▪ Trong C: Cần phải xây dựng các hàm
ng
AddSP(), TruSP()
o
du
15
CuuDuongThanCong.com https://fb.com/tailieudientucntt
#include <stdio.h>
struct SP {
double real;
double img;
};
om
SP SetSP(double real, double img);
.c
SP AddSP(SP C1,SP C2);
SP SubSP(SP C1,SP C2);
ng
void DisplaySP(SP C);
co
int main(void) {
an
SP C1,C2,C3,C4;
th
C1 = SetSP(1.0,2.0);
C2 = SetSP(-3.0,4.0);
ng
cout << "\nSo phuc thu nhat:"; DisplaySP(C1);
o
du
C4 = SubSP(C1,C2);
cout << "\nTong hai so phuc nay:"; DisplaySP(C3);
cout << "\nHieu hai so phuc nay:"; DisplaySP(C4);
return 0;
}
16
CuuDuongThanCong.com https://fb.com/tailieudientucntt
SP SetSP(double real,double img) {
SP tmp;
tmp.real = real; tmp.img = img;
return tmp;
om
}
SP AddSP(SP C1,SP C2) {
.c
SP tmp;
ng
tmp.real = C1.real + C2.real;
co
tmp.img = C1.img + C2.img;
an
return tmp;
th
} ng
SP SubSP(SP C1,SP C2) {
SP tmp;
o
du
return tmp;
}
void DisplaySP(SP C) {
cout << C.real << " i " << C.img;
} CuuDuongThanCong.com https://fb.com/tailieudientucntt
C++
• C++ cho phép chúng ta có thể định nghĩa lại chức năng
của các toán tử đã có sẵn một cách tiện lợi và tự nhiên.
om
Điều này gọi là đa năng hóa toán tử.
.c
• Một hàm định nghĩa một toán tử có cú pháp sau:
ng
data_type operator operator_symbol ( parameters ){
………………………………
co
}
an
th
Trong đó: ng
• data_type: Kiểu trả về.
o
CuuDuongThanCong.com https://fb.com/tailieudientucntt
#include <iostream.h>
struct { double real; double img;} SP;
SP SetSP(double real, double img);
void DisplaySP(SP C);
om
SP operator + (SP C1, SP C2);
.c
SP operator - (SP C1, SP C2);
int main() {
ng
SP C1,C2,C3,C4;
co
C1 = SetSP(1.1,2.0);
an
C2 = SetSP(-3.0,4.0);
th
cout << "\nSo phuc thu nhat:"; DisplaySP(C1);
ng
cout << "\nSo phuc thu hai:"; DisplaySP(C2);
o
du
C3 = C1 + C2;
C4 = C1 - C2;
u
cu
om
}
SP operator + (SP C1,SP C2) {
.c
SP tmp;
ng
tmp.real = C1.real + C2.real;
co
tmp.img = C1.img + C2.img;
an
return tmp;
th
}
SP operator - (SP C1,SP C2) {
ng
SP tmp;
o
du
return tmp;
}
void DisplaySP(SP C) {
cout << "(“ << C.real << ",“ << C.img << ")";
} CuuDuongThanCong.com https://fb.com/tailieudientucntt
Các giới hạn của đa năng hóa toán tử
• Không thể định nghĩa các toán tử mới.
• Hầu hết các toán tử của C++ đều có thể được đa năng
om
hóa. Các toán tử sau không được đa năng hóa là :
.c
:: Toán tử định phạm vi.
ng
.* Truy cập đến con trỏ là trường của struct hay class.
co
. Truy cập đến trường của struct hay class.
an
?: Toán tử điều kiện
sizeof
th
ng
Các ký hiệu tiền xử lý.
o
du
• Không thể thay đổi thứ tự ưu tiên của một toán tử cũng
u
• Không thể thay đổi ý nghĩa của các toán tử khi áp dụng
cho các kiểu có sẵn.
• Đa năng hóa các toán tử không thể có các tham số có giá
trị mặc định.
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Con trỏ hàm
int foo(){
return 0;
om
}
.c
int main(){
ng
co
int n = foo();
an
return 0;
th
} ng
o
du
Khi trong hàm main chạy đến dòng lệnh gọi hàm foo, hệ
u
điều hành sẽ tìm đến địa chỉ của hàm foo trên bộ nhớ ảo
cu
22
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Con trỏ hàm
int foo(){
return 0;
om
}
.c
int main(){
ng
co
cout << foo << endl;
an
return 0;
th
} ng
o
du
Kết quả:
u
013D1492
cu
23
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Cú pháp khai báo con trỏ hàm
<return_type> (*<name_of_ptr>)(<data_type_of_parameters>);
om
Ví dụ 1:
.c
int foo(){
ng
return 0;
co
}
int (*pFoo) ();
an
Ví dụ 2:
th
ng
void swapValue(int &value1, int &value2) {
o
du
value1 = value2;
cu
value2 = temp;
}
void(*pSwap) (int &, int &);
24
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Ví dụ sử dụng con trỏ hàm
void swapValue(int &value1, int &value2){
int temp = value1;
om
value1 = value2;
.c
value2 = temp;
ng
}
co
int main(){
an
void(*pSwap) (int &, int &) = swapValue;
int a = 1, b = 5;
th
ng
cout << "Before: " << a << " " << b << endl;
o
du
(*pSwap)(a, b);
u
cout << "After: " << a << " " << b << endl;
cu
return 0;
}
25
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Sắp xếp dãy số
bool ascending(int left, int right){
return left > right;
om
}
.c
bool descending(int left, int right){
return left < right;
ng
}
co
void selectionSort(int *arr, int length, bool (*comparisonFunc)(int,
int)){
an
for (int i_start = 0; i_start < length; i_start++) {
th
int minIndex = i_start;
ng
for (int i_current = i_start + 1; i_current < length; i_current++){
o
if (comparisonFunc(arr[minIndex], arr[i_current])) {
du
minIndex = i_current;
u
}
cu
}
swap(arr[i_start], arr[minIndex]); // std::swap
}
}
26
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Sắp xếp dãy số
int main() {
om
int arr[] = { 1, 4, 2, 3, 6, 5, 8, 9, 7
};
.c
ng
int length = sizeof(arr) / sizeof(int);
co
cout << "Before sorted: ";
an
printArray(arr, length);
th
selectionSort(arr, length, descending);
o ng
cout << "After sorted: ";
du
printArray(arr, length);
u
cu
return 0;
}
27
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Sắp xếp dãy số
int main() {
om
int arr[] = { 1, 4, 2, 3, 6, 5, 8, 9, 7
};
.c
ng
int length = sizeof(arr) / sizeof(int);
co
cout << "Before sorted: ";
an
printArray(arr, length);
th
selectionSort(arr, length, ascending);
o ng
cout << "After sorted: ";
du
printArray(arr, length);
u
cu
return 0;
}
28
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Khái quát hóa hàm (Function templates)
Ví dụ muốn tìm giá trị lớn nhất trong hai số:
om
• Đối với hai số nguyên:
.c
int maxval(int x, int y){
ng
return (x > y) ? x : y;
co
}
an
th
ng
• Đối với hai số thực:
o
du
return (x > y) ? x : y;
cu
29
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Khái quát hóa hàm (Function templates)
Cú pháp Khai báo khuôn mẫu hàm:
om
template < parameter-list > function-declaration
.c
ng
Ví dụ:
co
template <typename T>
an
T maxval(T x, T y){
th
ng
return (x > y) ? x : y;
o
du
}
u
cu
30
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Khái quát hóa hàm (Function templates)
#include <iostream>
using namespace std;
om
template <typename T>
.c
T maxval(T x, T y){
ng
return (x > y) ? x : y;
co
}
an
int main() {
th
int i = maxval(3, 7); // returns 7
ng
cout << i << endl;
o
double d = maxval(6.34, 18.523); // returns 18.523
du
om
biến.
.c
auto d { 5.0 }; // d will be type double
ng
auto i { 1 + 2 }; // i will be type int
co
an
• Đối với hàm (từ C++14): auto tự động xác định kiểu trả
th
về của hàm dựa vào câu lệnh return.
ng
auto add(int x, int y) -> int;
o
32
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Từ khóa auto
• Đối với kiểu tham số (từ C++14): auto tự động xác định kiểu
của tham số dựa vào giá trị được truyền.
om
• Ví dụ:
.c
auto maxval(auto x, auto y){
ng
return (x > y) ? x : y;
co
}
an
int main() {
th
int i = maxval(3, 7); // returns 7
ng
cout << i << endl;
o
double d = maxval(6.34, 18.523); // returns 18.523
du
om
với các cách dùng hàm thông thường buộc phải định
.c
nghĩa hàm sau đó dùng tên hàm truyền vào một hàm
ng
khác.
co
• Lợi ích của lambda là không nhất thiết phải khai báo
tên hàm ở một nơi khác, mà có thể tạo ngay một hàm
an
(dùng một lần hay hiểu chính xác hơn là chỉ có một
th
chỗ gọi một số tác vụ nhỏ). Như vậy, ta sẽ giảm được
ng
thời gian khai báo một hàm. Để làm rõ hơn về khái
o
du
34
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Hàm nặc danh - cú pháp lambda
#include <iostream>
using namespace std;
om
void stdio_doing(int n) {
.c
n = n + 10;
ng
cout << n << " ";
co
}
an
void for_each (int *arr, int n, void (*func)(int a)){
th
for (int i = 0; i < n; i++) { ng
func(*(arr + i));
}
o
du
}
u
cu
int main(){
int arr[] ={1, 2, 3, 4, 5} , n = 5;
for_each(arr, n, stdio_doing);
return 0;
}
35
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Hàm nặc danh - cú pháp lambda
#include <iostream>
using namespace std;
om
.c
void for_each (int *arr, int n, void (*func)(int a)){
ng
for (int i = 0; i < n; i++) {
co
func(*(arr + i));
}
an
th
} ng
int main(){
o
du
a = a + 10;
cout << a << " ";
});
return 0; 36
} CuuDuongThanCong.com https://fb.com/tailieudientucntt
Hàm nặc danh - cú pháp lambda
om
.c
ng
co
an
th
ng
(1) Mệnh đề bắt giữ (capture clause)
o
du
om
bên trong nó (từ chuẩn C++14 trở đi), và nó còn có thể
.c
truy cập, hoặc tham chiếu đến những biến bên trong
ng
khối lệnh chứa nó.
co
• Một lambda luôn bắt đầu với cặp ngoặc vuông [ ], và
an
những biến cần được bắt giữ sẽ khai báo bên trong
th
đó. Ký hiệu ( & ) là biến được truy cập bằng tham
ng
chiếu, bỏ ký hiệu ( & ) hoặc sử dụng cách khai báo [ = ]
sẽ được hiểu là truy cập giá trị.
o
du
lambda này không truy cập biến nào trong khối lệnh
cu
chứa nó.
38
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Hàm nặc danh - cú pháp lambda
Danh sách tham số
Ngoài khả năng bắt giữ các biến bên ngoài, lambda còn
om
có thể nhận đối số bằng cách khai báo danh sách tham
.c
số.
ng
co
auto y = [] (int first, int second){
an
return first + second;
th
}; ng
o
du
cho phép lambda thay đổi giá trị những biến được bắt
giữ theo giá trị.
39
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Hàm nặc danh - cú pháp lambda
Kiểu trả về của một lambda
Chúng ta có thể trả về bất kỳ kiểu dữ liệu nào giống như hàm thông
om
thường. Ví dụ:
.c
// OK: return type is int
ng
auto x1 = [](int i){ return i; };
co
an
Tuy nhiên, để chương trình được rõ ràng hơn, chúng ta nên viết
th
ng
lambda có kiểu trả về như sau:
o
du
return i;
cu
};
Thêm khai báo -> int giúp việc đọc hiểu lambda dễ dàng hơn.
40
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Hàm nặc danh - cú pháp lambda
Phần thân của một lambda
Phần thân của một lambda có thể:
om
• sử dụng những biến được bắt giữ trong mệnh đề bắt
.c
giữ.
ng
• sử dụng các tham số.
co
• sử dụng các biến được khai báo bên trong struct/class
an
chứa nó thông qua con trỏ this (OOP).
th
ng
• sử dụng các biến toàn cục, biến static.
o
du
u
cu
41
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Ví dụ
#include <iostream>
using namespace std;
om
.c
int main(){
int m = 0;
ng
int n = 0;
co
auto func = [&, n] (int a) mutable {
an
m = ++n + a;
th
}; ng
func(4);
o
cout << m << endl << n << endl;
du
}
u
cu
Kết quả:
5
0
42
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Tài liệu đọc thêm
1. Function templates: https://docs.microsoft.com/en-
us/cpp/cpp/function-templates?view=vs-2019
om
2. Auto: https://docs.microsoft.com/en-us/cpp/cpp/auto-
.c
cpp?view=vs-2019
ng
3. Lambda expression: https://docs.microsoft.com/en-
co
us/cpp/cpp/lambda-expressions-in-cpp?view=vs-
an
2019
th
o ng
du
u
cu
43
CuuDuongThanCong.com https://fb.com/tailieudientucntt