&
VC
Nội dung
BB
Khái niệm và cú pháp
1
Tầm vực
2
Tham số và lời gọi hàm
3
Đệ quy
4
1 1
NMLT - Hàm (Function)
&
VC
Đặt vấn đề
BB
Viết chương trình tính S = a! + b! + c! với a, b, c
là 3 số nguyên dương nhập từ bàn phím.
Chương trình chính
Nhập a, b, c > 0
Tính S = a! + b! + c!
Xuất kết quả S
Nhập a > 0
Nhập b > 0
Nhập c > 0
Tính s1=a!
Tính s2=b!
Tính s3=c!
2 2
NMLT - Hàm (Function)
&
VC
Đặt vấn đề
BB
3 đoạn lệnh nhập a, b, c > 0
cout<<“Nhap mot so nguyen duong: ”; cin>>a;
cout<<“Nhap mot so nguyen duong: ”; cin>>b;
cout<<“Nhap mot so nguyen duong: ”; cin>>c;
do { } while (a <= 0); do { } while (b <= 0); do { } while (c <= 0);
3 3
NMLT - Hàm (Function)
&
VC
Đặt vấn đề
BB
3 đoạn lệnh tính s1 = a!, s2 = b!, s3 = c!
{ Tính s1 = a! = 1 * 2 * … * a } s1 = 1; for (i = 2; i <= a ; i++) s1 = s1 * i; { Tính s2 = b! = 1 * 2 * … * b } s2 = 1; for (i = 2; i <= b ; i++) s2 = s2 * i; { Tính s3 = c! = 1 * 2 * … * c } s3 = 1; for (i = 2; i <= c ; i++) s3 = s3 * i;
4 4
NMLT - Hàm (Function)
&
VC
Đặt vấn đề
BB
Giải pháp => Viết 1 lần và sử dụng nhiều lần Đoạn lệnh nhập tổng quát, với n = a, b, c
cout<<“Nhap mot so nguyen duong: ”; cin>>n;
do { } while (n <= 0);
Đoạn lệnh tính giai thừa tổng quát, n = a, b, c
{ Tính s = n! = 1 * 2 * … * n } s = 1; for (i = 2; i <= n ; i++)
s = s * i;
5 5
NMLT - Hàm (Function)
&
VC
Hàm
BB
Khái niệm
Một đoạn chương trình có tên, đầu vào và
đầu ra.
Có chức năng giải quyết một số vấn đề chuyên biệt cho chương trình chính.
Được gọi nhiều lần với các tham số khác
nhau.
Được sử dụng khi có nhu cầu:
• Tái sử dụng. • Sửa lỗi và cải tiến.
6 6
NMLT - Hàm (Function)
&
VC
Hàm
BB
Các đặc trưng của Hàm
Nằm trong hoặc ngoài văn bản có chương trình gọi
đến hàm. Một văn bản có thể chứa nhiều hàm.
Được gọi từ chương trình chính (main), từ hàm khác
hoặc từ chính nó (đệ quy).
Không lồng nhau. Có 3 cách truyền giá trị: Truyền theo tham trị, tham
biến và tham trỏ.
Các biến cục bộ trong hàm được tạo ra khi hàm được
gọi và biến mất khi hàm thực thi xong.
7 7
NMLT - Hàm (Function)
&
VC
Hàm
8 8
NMLT - Hàm (Function)
BB
&
VC
Hàm
BB
Có 2 loại hàm trong NNLT “C/C++”: Hàm thư viện (library functions):
Do chương trình dịch “C/C++” cung cấp.
Để sử dụng các hàm này trong chương trình, đầu
chương trình phải chứa các khai báo và định nghĩa
hằng, biến, hàm nguyên mẫu, . . . bằng các chỉ thị
tiền xử lý #include
Ví dụ: #include
#include
Hàm tự tạo:
Do người sử dụng định nghĩa thêm các hàm khác
phục vụ cho nhu cầu lập trình của mình.
9 9
NMLT - Hàm (Function)
&
VC
Hàm
BB
Cú pháp
[return ;]
([danh sách tham số])
{
}
Trong đó
•
float,…). Nếu không trả về thì là void.
•
giống khai báo biến, cách nhau bằng dấu ,
•
10 10
NMLT - Hàm (Function)
&
VC
Các bước viết hàm
BB
Cần xác định các thông tin sau đây:
Tên hàm. Hàm sẽ thực hiện công việc gì. Các đầu vào (nếu có). Đầu ra (nếu có).
Đầu vào 1
Đầu vào 2
Đầu ra (nếu có)
Đầu vào n
Tên hàm Các công việc sẽ thực hiện
11 11
NMLT - Hàm (Function)
&
VC
Hàm
BB
Ví dụ 1
Tên hàm: XuatTong Công việc: tính và xuất tổng 2 số nguyên Đầu vào: hai số nguyên x và y Đầu ra: không có
int s;
s = x + y;
cout<
void XuatTong(int x, int y)
{
}
12 12
NMLT - Hàm (Function)
&
VC
Hàm
BB
Ví dụ 2
Tên hàm: TinhTong
Công việc: tính và trả về tổng 2 số nguyên
Đầu vào: hai số nguyên x và y
Đầu ra: một số nguyên có giá trị x + y
int s;
s = x + y;
return s;
int TinhTong(int x, int y)
{
}
13 13
NMLT - Hàm (Function)
&
VC
Chương trình con - Function
BB
Ví dụ 3
Tên hàm: NhapXuatTong
Công việc: nhập và xuất tổng 2 số nguyên
Đầu vào: không có
Đầu ra: không có
int x, y;
cout<<“Nhap 2 so nguyen: ”;
cin>>x>>y;
cout<
void NhapXuatTong()
{
}
14 14
NMLT - Hàm (Function)
&
VC
Tầm vực
BB
Khái niệm
Là phạm vi hoạt động của biến và hàm.
Biến:
• Toàn cục: khai báo ngoài tất cả các hàm (kể cả
hàm main) và có tác dụng lên toàn bộ chương
trình.
• Cục bộ: khai báo trong hàm hoặc khối { } và chỉ có
tác dụng trong bản thân hàm hoặc khối đó (kể cả
khối con nó). Biến cục bộ sẽ bị xóa khỏi bộ nhớ khi
kết thúc khối khai báo nó.
15 15
NMLT - Hàm (Function)
&
VC
Tầm vực
BB
int a1;
int a21;
int a2;
{
}
int Ham1()
{
}
int Ham2()
{
}
int a3;
int a;
void main()
{
}
16 16
NMLT - Hàm (Function)
&
VC
Hàm nguyên mẫu (function prototype)
Hàm nguyên mẫu:
Được dùng để cung cấp thông tin cho chương trình dịch về
tên hàm, kiểu giá trị trả về, số lượng, thứ tự và kiểu của các
tham số của hàm.
Chương trình dịch căn cứ vào các thông tin này để kiểm tra
các lời gọi hàm trong chương trình.
Hàm nguyên mẫu được đặt sau phần khai báo toàn cục và
ngay trước hàm main() hoặc có thể đặt trong tập tin khác.
BB
[] ([]) ;
Khai báo:
Ví dụ: Khai báo hàm nguyên mẫu có chức năng xác định trị
min giữa 2 số nguyên.
int Min(int, int) ;
int Min(int a, int b) ; // nên dùng cách khai báo này
17 17
&
VC
Tổ chức một chương trình “C/C++”
Cách 1: chương trình gồm 3 phần
PHẦN KHAI BÁO TOÀN CỤC
PHẦN KHAI BÁO VÀ ĐỊNH NGHĨA HÀM
HÀM main()
Cách 2: chương trình gồm 4 phần (nên dùng cách này)
PHẦN KHAI BÁO TOÀN CỤC
PHẦN KHAI BÁO HÀM NGUYÊN MẪU
HÀM main()
PHẦN ĐỊNH NGHĨA HÀM
18 18
BB
&
VC
Tổ chức một chương trình “C/C++”
Ví dụ: cách 1
Ví dụ: Cách 2
#include
int min(int a, int b);
//prototype
int min1 = min(a,b);
cout << “Min = “ << min1;
int min1 = min(a,b);
cout << “Min = “ << min1;
#include
int min(int a, int b)
{ if (a
void main()
{ int a=40, b=30;
}
int min(int a, int b)
{ if (a
19 19
BB
&
VC
Các phương pháp truyền tham số
Có hai loại tham số:
Tham số thực (actual parameter):là tham số trong lời gọi hàm.
Tham số hình thức (formal parameter): là tham số trong phần
khai báo và định nghĩa. Tham số hình thức chỉ là tên đại diện cho
tham số thực tương ứng. Kiểu của tham số hình thức sẽ qui định
kiểu của tham số thực.
20 20
BB
&
VC
Các phương pháp truyền tham số
Ví dụ:
if(a
int min(int a, int b) //a,b là tham số hình thức
{
else return b;
}
void main()
{ int minAB =min(7,10)//Gọi hàm
// a = 7, b=10
} // Lúc này a,b là tham số thực
21 21
BB
&
VC
Các phương pháp truyền tham số
BB
Có hai cách truyền tham số:
1. Truyền tham trị (call by value):
Chương trình dịch cấp phát vùng nhớ riêng cho từng tham số
hình thức, sau đó sao chép giá trị của tham số thực tương ứng
vào các tham số hình thức.
Khi kết thúc thực hiện hàm, chương trình dịch sẽ thu hồi các vùng
nhớ đã cấp phát cho các tham số hình thức, và các biến cục bộ
khai báo bên trong hàm.
Như vậy, mọi sự thay đổi trị của các tham số hình thức đều không
ảnh hưởng đến các tham số thực bên ngoài hàm.
Cách truyền:
void F(int, int ); // truyền bằng trị
hay
void F(int a, int b); // truyền bằng trị
22 22
&
VC
Các phương pháp truyền tham số
BB
Truyền Giá trị (Call by Value)
Truyền đối số cho hàm ở dạng giá trị.
Có thể truyền hằng, biến, biểu thức nhưng
hàm chỉ sẽ nhận giá trị.
Được sử dụng khi không có nhu cầu thay đổi
giá trị của tham số sau khi thực hiện hàm.
…
x++;
void TruyenGiaTri(int x)
{
}
23 23
NMLT - Hàm (Function)
&
VC
Các phương pháp truyền tham số
Ví dụ: Khảo sát chương trình sau
doubleNum(a);
cout << “Inside main function:” << endl;
cout << “a = “ << a << endl;
a = a*2;
cout << “Inside doubleNum function. a = “ << a;
#include
void doubleNum(int a); //prototype
void main()
{ int a=40;
}
void doubleNum(int a)
{
}
24 24
BB
&
VC
Các phương pháp truyền tham số
2. Truyền tham chiếu(call by reference):
Chương trình dịch sẽ truyền địa chỉ của các tham số thực tương
ứng cho các tham số hình thức.
Nghĩa là ta có thể xem tham số hình thức cũng chính là tham số
thực, hay nói cách khác tham số hình thức là tên gọi khác của
tham số thực.
Mọi sự thay đổi trị của tham số hình thức bên trong hàm chính là
thay đổi trị của tham số thực bên ngoài hàm.
Cách truyền:
void Swap(int &,int &); // truyền bằng tham chiếu
hay
void Swap(int & a,int & b); // truyền bằng tham chiếu
25 25
BB
&
VC
Các phương pháp truyền tham số
BB
Truyền Địa chỉ (Call by Address)
Truyền đối số cho hàm ở dạng địa chỉ (con
trỏ).
Không được truyền giá trị cho tham số này.
Được sử dụng khi có nhu cầu thay đổi giá trị
của tham số sau khi thực hiện hàm.
…
*x++;
void TruyenDiaChi(int *x)
{
}
26 26
NMLT - Hàm (Function)
&
VC
Các phương pháp truyền tham số
BB
Truyền Tham chiếu (Call by Reference) (C++)
Truyền đối số cho hàm ở dạng địa chỉ (con
trỏ). Được bắt đầu bằng & trong khai báo.
Không được truyền giá trị cho tham số này.
Được sử dụng khi có nhu cầu thay đổi giá trị
của tham số sau khi thực hiện hàm.
…
x++;
void TruyenThamChieu(int &x)
{
}
27 27
NMLT - Hàm (Function)
&
VC
Các phương pháp truyền tham số
Ví dụ: Khảo sát chương trình sau
doubleNum(a);
cout << “Inside main function:” << endl;
cout << “a = “ << a << endl;
a = a*2;
cout << “Inside doubleNum function. a = “ << a;
#include
void doubleNum(int a); //prototype
void main()
{ int a=40;
}
void doubleNum(int &a)
{
}
28 28
BB
&
VC
Các phương pháp truyền tham số
Chú ý:
Trong cách truyền tham chiếu, tham số thực tương ứng phải là
một biến. Còn trong cách truyền trị, tham số thực tương ứng có
thể là biến, hằng, lời gọi hàm, hoặc một biểu thức cùng kiểu với
tham số hình thức.
Các tham số hình thức trong cách truyền bằng giá trị được gọi là
tham trị. Còn các tham số hình thức trong cách truyền bằng tham
chiếu được gọi là tham biến.
29 29
BB
&
VC
Lưu ý khi truyền đối số
BB
Lưu ý
Trong một hàm, các tham số có thể truyền
theo nhiều cách.
…
x++;
y++;
void HonHop(int x, int &y)
{
}
30 30
NMLT - Hàm (Function)
&
VC
Lưu ý khi truyền đối số
BB
Lưu ý
Sử dụng tham chiếu là một cách để trả về giá
trị cho chương trình.
return x + y;
tong = x + y;
tong = x + y; hieu = x – y;
31 31
NMLT - Hàm (Function)
int TinhTong(int x, int y)
{
}
void TinhTong(int x, int y, int &tong)
{
}
void TinhTongHieu(int x, int y, int &tong, int &hieu)
{
}
&
VC
Lời gọi hàm
BB
Cách thực hiện
Gọi tên của hàm đồng thời truyền các đối số
(hằng, biến, biểu thức) cho các tham số theo
đúng thứ tự đã được khai báo trong hàm.
Các biến hoặc trị này cách nhau bằng dấu ,
Các đối số này được được đặt trong cặp dấu
ngoặc đơn ( )
(<đối số 1>,… , <đối số n>);
32 32
NMLT - Hàm (Function)
&
VC
Lời gọi hàm
BB
Ví dụ
int n = 9;
XuatTong(1, 2);
XuatTong(1, n);
TinhTong(1, 2);
int tong = TinhTong(1, 2);
TruyenGiaTri(1);
TruyenGiaTri(n);
TruyenDiaChi(1);
TruyenDiaChi(&n);
TruyenThamChieu(1);
TruyenThamChieu(n);
33 33
{ Các hàm được khai báo ở đây }
void main()
{
}
NMLT - Hàm (Function)
&
VC
Lời gọi chương trình con
BB
Ví dụ
HoanVi(2912, 1706);
int x = 2912, y = 1706;
HoanVi(x, y);
int tam = a;
a = b;
b = tam;
34 34
void HoanVi(int &a, int &b);
void main()
{
}
void HoanVi(int &a, int &b)
{
}
NMLT - Hàm (Function)
&
VC
Đệ quy
3. Hàm gọi đệ qui: một lệnh trong thân hàm gọi đến chính nó. Số lần
BB
gọi này phải có giới hạn (điểm dừng)
Ví dụ: chương trình tính giai thừa của n.
int gt;
if(n==1) return(1);
// goi de qui
gt = giaiThua(n-1)*n;
return gt;
int giaiThua(int n)
{
}
gt4 = giaiThua(4);
gt7 = giaiThua(7);
cout << “4! =“ << gt4 << endl;
cout << “7! =“ << gt7 << endl;
#include
int giaiThua(int n);
void main()
{ int gt4, gt7;
}
35 35
&
VC
BB
Đệ quy
Đặc điểm của hàm đệ qui:
Chương trình viết rất gọn,
Việc thực hiện gọi đi gọi lại hàm rất nhiều lần phụ thuộc vào độ
lớn của đầu vào. Do đó chương trình sẽ mất thời gian để lưu giữ
các thông tin của hàm gọi trước khi chuyển điều khiển đến thực
hiện hàm được gọi. Mặt khác các thông tin này được lưu trữ
nhiều lần trong ngăn xếp sẽ dẫn đến tràn ngăn xếp nếu n lớn.
Tuy nhiên, đệ qui là cách viết rất gọn, dễ viết và đọc chương
trình, mặt khác có nhiều bài toán hầu như tìm một thuật toán lặp
cho nó là rất khó trong khi viết theo thuật toán đệ qui thì lại rất dễ
dàng.
36 36
&
VC
Đệ quy
Lớp các bài toán giải được bằng đệ qui
Giải quyết được dễ dàng trong các trường hợp riêng gọi là
trường hợp suy biến hay cơ sở, trong trường hợp này hàm được
tính bình thường mà không cần gọi lại chính nó,
Đối với trường hợp tổng quát, bài toán có thể giải được bằng bài
toán cùng dạng nhưng với tham đối khác có kích thước nhỏ hơn
tham đối ban đầu. Và sau một số bước hữu hạn biến đổi cùng
dạng, bài toán đưa được về trường hợp suy biến.
37 37
BB
&
VC
Đệ quy
Các ví dụ
Ví dụ 1 : Tìm UCLN của 2 số a, b. Bài toán có thể được định
nghĩa dưới dạng đệ qui như sau:
− nếu a = b thì UCLN = a
− nếu a > b thì UCLN(a, b) = UCLN(a-b, b)
− nếu a < b thì UCLN(a, b) = UCLN(a, b-a)
Chương trình đệ qui để tính UCLN của a và b như sau.
int UCLN(int a, int b) // qui uoc a, b > 0
{ if (a < b) UCLN(a, b-a);
if (a == b) return a;
if (a > b) UCLN(a-b, b);
}
38 38
BB
&
VC
Đệ quy
Ví dụ 2 : Tính số hạng thứ n của dãy Fibonaci là dãy f(n) được
định nghĩa:
− f(0) = f(1) = 1
− f(n) = f(n-1) + f(n-2) với n ≥ 2.
long Fib(int n)
{ long kq;
if (n==0 || n==1) kq = 1; else kq = Fib(n-1) + Fib(n-2);
return kq;
}
39 39
BB
&
VC
Nạp chồng hàm (Function overloading)
Nạp chồng hàm là dùng chung một danh hiệu để đặt tên cho các
hàm khác nhau.
Chỉ nạp chồng hàm đối với những hàm giống nhau về bản chất,
nhưng khác nhau ở số lượng, và kiểu dữ liệu của các tham số.
Khả năng nạp chồng hàm kết hợp với hàm có tham số với giá trị
double x = 20.0;
int y = 10;
F(x, y); // mơ hồ! chương trình
dịch không biết gọi hàm nào
ngầm định có thể gây ra tình trạng nhập nhằng, mơ hồ
void F(int, double)
{ …. }
void F(int)
{ …. }
void F(double)
{ … }
void main()
{
}
40 40
BB
&
VC
Một số gợi ý khi thiết kế hàm
Xác định rõ chức năng, nhiệm vụ của hàm.
Chỉ nên thiết kế hàm theo phương châm “mỗi hàm chỉ thực hiện
một nhiệm vụ duy nhất”, và nên thiết kế sao cho có thể sử dụng
lại hàm để hổ trợ cho các việc khác (reusable).
Đặt tên hàm sao cho có tính gợi nhớ (Memonic)
Nên đặt chú thích, ghi rõ các thông tin về hàm như chức năng,
điều kiện dữ liệu vào, xác định dữ liệu ra của hàm, . . .
Xác định trị trả về: hàm có cần trả về giá trị? Nếu có, xác định rõ
kiểu trả về. Đối với các hàm có chức năng nhập/xuất dữ liệu, trị
trả về thường là void. Còn đối với loại hàm kiểm tra một tính chất
P nào đó, ta thường trả về giá trị 0 hoặc 1, i.e. trả về trị của một
biểu thức logic.
41 41
BB
&
VC
Một số gợi ý khi thiết kế hàm
Xác định số lượng tham số và kiểu của từng tham số: hàm có
nhận tham số hay không? Bao nhiêu tham số? Kiểu của từng
tham số?
Xác định rõ phương pháp truyền tham số: nếu không có nhu cầu
làm thay đổi trị của tham số thực truyền vào cho hàm thì áp
dụng phương pháp truyền bằng giá trị. Còn ngược lại thì áp
dụng cách truyền bằng tham chiếu.
42 42
BB
&
VC
Phạm vi (scope) của các đối tượng
Phạm vi là vùng chương trình mà đối tượng được nhận biết và có
thể được sử dụng.
Phạm vi của một đối tượng trải dài từ nơi nó được khai báo đến
cuối khối, hàm, hay tập tin chứa đối tượng đó. Có các loại phạm vi
sau:
Phạm vi cục bộ (local scope)
− Phạm vi khối (Block scope)
− Phạm vi hàm (Function scope)
Phạm vi toàn cục (global scope)
− Phạm vi tập tin (File scope)
− Phạm vi chương trình (Program scope)
43 43
BB
&
VC
Phạm vi (scope) của các đối tượng
Phạm vi khối: Trong C, một khối được giới hạn bởi ngoặc {}. Biến
khai báo trong khối đó có phạm vi khối, nghĩa là nó chỉ hoạt động
trong khối đó mà thôi. Phạm vi này còn gọi là cục bộ, và biến đưọc
gọi là biến cục bộ.
Ví dụ: int main()
{
int i; /* block scope */
.
.
.
return 0;
}
44 44
BB
&
VC
Phạm vi (scope) của các đối tượng
BB
Ví dụ: 1: /* Scopes in nested block */
2: #include
3:
4: main()
5: {
6: int i = 32; /* block scope 1*/
7:
8: cout<<"Within the outer block: i=“<
Kết quả:
Within the outer block:
i=32
Within the inner block:
i= 0, j=10
i= 1, j= 9
i= 2, j= 8
i= 3, j= 7
i= 4, j= 6
i= 5, j= 5
i= 6, j= 4
i= 7, j= 3
i= 8, j= 2
i= 9, j= 1
i=10, j= 0
Within the outer block:
i=32
45 45
&
VC
Phạm vi (scope) của các đối tượng
Phạm vi hàm: chỉ định một biến có phạm vi hoạt động từ đầu đến
cuối một hàm (không nhầm lẫn với biến có phạm vi khối). Trong C,
chỉ có nhãn (label) đối với lệnh goto là có phạm vi hàm.
Ví dụ : int main()
.
.
.
.
return 0;
{ int i; /* block scope */
start: /* A goto label has function scope */
goto start; /* the goto statement */
.
.
}
46 46
BB
&
VC
Phạm vi (scope) của các đối tượng
Phạm vi chương trình: Biến có phạm vi chương trình khi nó được
khai báo bên ngoài các hàm.
Ví dụ:
.
.
return 0;
int x = 0; /* program scope */
float y = 0.0; /* program scope */
int main()
{ int i; /* block scope */
}
Biến này còn gọi là biến toàn cục
47 47
BB
&
VC
Phạm vi (scope) của các đối tượng
Ví dụ:
BB
Kết quả:
From function_1:
x=1234, y=1.234567
Within the main block:
x=4321, y=1.234567
From function_1:
x=1234, y=1.234567
Within the nested block:
x=4321, y=7.654321
1: /* Program scope vs block scope */
2: #include
4: int x = 1234; /* program scope */
5: double y = 1.234567; /* program scope */
7: void function_1()
8: {
9: cout<<"From function_1: x=,”<
48 48
&
VC
Phạm vi (scope) của các đối tượng
Phạm vi tập tin: Trong C, biến được khai báo là toàn cục và static
được gọi là có phạm vi tập tin.
int x = 0; /* program scope */
static int y = 0; /* file scope */
static float z = 0.0; /* file scope */
int main()
{ int i; /* block scope */
.
.
.
return 0;
}
49 49
BB
&
VC
Phạm vi (scope) của các đối tượng
Ví dụ:
cout<<”Y = “<
bị hủy, không thể truy
xuất
fct(x);
cout<<”X của hàm main() = “<
“<
}
#include
int x=3; // biến x toàn cục
const int MAX = 10;
void fct(int x);
void main()
{ int x=1; // x cục bộ của hàm main()
{
int y=4;
x += y;
}
50 50
BB
&
VC
Phạm vi (scope) của các đối tượng
Biến toàn cục (local variable)
Biến cục bộ (Global variable)
Biến cục bộ là biến khai báo bên
trong khối hay hàm của khối.
Biến toàn cục là biến khai báo
bên ngoài mọi hàm
Chỉ có thể được truy xuất bên trong
phạm vi khối hay hàm đó mà thôi.
Có thể được truy xuất ở mọi nơi
trong chương trình.
Các biến cục bộ có thời gian tồn tại
tương đối ngắn. Chúng sẽ bị hủy
mỗi khi ra khỏi khối hay kết thúc
thực hiện hàm chứa nó.
Các biến toàn cục có thời gian
tồn tại là thời gian của chương
trình
51 51
BB
&
VC
Cấp lưu trữ của các đối tượng
Cấp lưu trữ (storage class) là cách thức NNLT cấp phát vùng nhớ và lưu
trữ biến. Cấp lưu trữ của một biến được xác định bằng các từ khóa sau:
auto, register, static, extern.
Biến auto (còn gọi là biến tự động, biến cục bộ):
Mọi biến khai báo bên trong một khối hay hàm mặc nhiên có
tính chất auto, trừ khi xác định rõ cấp lưu trữ khác.
Ví dụ, khai báo int x; tương đương với khai báo auto int x;.
Biến auto có phạm vi cục bộ bên trong hàm hay khối và có
thời gian tồn tại ngắn, do được cấp phát trong vùng nhớ
STACK.
52 52
BB
&
VC
Cấp lưu trữ của các đối tượng
Biến register (ít dùng)
Để tăng tốc độ truy xuất biến, chương trình dịch lưu trữ
biến trong thanh ghi. Chương trình dịch có thể bỏ qua
không đáp ứng lời yêu cầu này nếu có quá nhiều lời đề
nghị loại này hoặc nếu không còn đủ thanh ghi để cấp
phát.
Ví dụ: int main()
{ /* block scope with the register specifier */
register int i;
. . .
for (i=0; i
53 53
BB
&
VC
Cấp lưu trữ của các đối tượng
Biến static (còn gọi là biến tĩnh)
Là biến được cấp phát trong vùng nhớ DATA do đó
có tính chất cố định, lâu dài.
Biến static khai báo bên trong một khối, hay hàm sẽ
không bị hủy khi ra khỏi khối hay hàm đó, và vẫn
lưu giữ giá trị cũ của lần gọi hàm trước.
Biến static phải được khởi tạo giá trị khi khai báo.
Chương trình dịch sẽ chỉ khởi tạo giá trị cho biến
static duy nhất một lần trong lần gọi hàm đầu tiên.
54 54
BB
&
VC
Cấp lưu trữ của các đối tượng
lanthu++;
i = 2 * i;
cout << "Hàm chạy lần thứ " << lanthu << ", i = " << i ;
…
Ví dụ: Biến Static
int i = 1;
void ham()
{ static int lanthu = 0;
}
main()
{ ham(); // Hàm chạy lần thứ 1, i = 2
ham(); // Hàm chạy lần thứ 2, i = 4
ham(); // Hàm chạy lần thứ 3, i = 6
…}
55 55
BB
&
VC
Cấp lưu trữ của các đối tượng
Biến extern
Phạm vi của một biến extern trong chương trình có thể được
trải dài trên nhiều tập tin.
Chương trình dịch sẽ không cấp phát thêm vùng nhớ cho biến
có khai báo extern mà sử dụng chung vùng nhớ đã cấp phát
trước đó.
Ví dụ: int x = 0; /* a global variable */
extern int y; /* an allusion to a global variable y */
int main()
{ extern int z; /* an allusion to a global variable z */
int i; /* a local variable */
.
.
return 0;
}
56 56
BB
&
VC
Cấp lưu trữ của các đối tượng
Ví dụ: Biến Extern
int i = 1;
in();
extern i = 1;
in();
cout << i ;
void in();
void main()
{
}
void in()
{
}
void in();
void main()
{
}
void in()
{
cout << i ;
}
Lỗi (cú pháp) vì i là biến cục bộ trong main(), trong in() không nhận biết i,
nếu trong hoặc trước in() khai báo thêm i thì lỗi ngữ nghĩa (tức chương trình
in giá trị i khác không theo ý muốn của lập trình viên).
57 57
BB
&
VC
Cấp lưu trữ của các đối tượng
Ví dụ: Biến Extern
Giả thiết 2 chương trình trên nằm trong 2 tệp khác nhau. Để liên
kết (link) biến i giữa 2 chương trình cần định nghĩa tổng thể i
trong một và khai báo extern trong chương trình kia.
extern i;
cout << i ;
i = 1;
in();
/* program2.cpp */
void in()
{
}
/* program1.cpp*/
void in();
int i;
void main()
{
}
58 58
BB
&
VC
Cấp lưu trữ của các đối tượng
Tóm tắt về cấp lưu trữ biến (Storage class)
59 59
BB
&
VC
Các chỉ thị tiền xử lý
a. Chỉ thị bao hàm tệp #include
Cho phép ghép nội dung các tệp đã có khác vào chương trình
trước khi dịch. Các tệp cần ghép thêm vào chương trình thường là
các tệp chứa khai báo nguyên mẫu của các hằng, biến, hàm … có
sẵn trong C hoặc các hàm do lập trình viên tự viết.
1: #include
Có hai dạng viết chỉ thị này.
2: #include “đường dẫn\tệp”
Các tập tin nguyên mẫu của thư viện C++, chứa trong thư mục
Borlandc\Include
Tìm tệp theo đường dẫn, nếu không có đường dẫn sẽ tìm trong
thư mục hiện tại. Tệp thường là các tệp (thư viện) được tạo bởi
lập trình viên và được đặt trong cùng thư mục chứa chương trình.
60 60
BB
&
VC
Các chỉ thị tiền xử lý
#define tên_macro xaukitu
b. Chỉ thị macro #define
Cú pháp:
Trước khi dịch bộ tiền xử lý sẽ tìm trong chương trình và thay thế
bất kỳ vị trí xuất hiện nào của tên_macro bởi xâu kí tự. Ta thường
sử dụng macro để định nghĩa các hằng hoặc thay cụm từ này
bằng cụm từ khác dễ nhớ hơn.
Ví dụ:
Viết
Ok = TRUE;
cout << i ;
if (i < MAX) then
begin
end
#define then // thay then bằng dấu cách
#define begin { // thay begin bằng dấu {
#define end } // thay end bằng dấu }
#define MAX 100 // thay MAX bằng 100
#define TRUE 1 // thay TRUE bằng 1
Ct dịch
Ok = 1;
cout << i ;
if (i < 100 then
{
}
61 61
BB
&
VC
Các chỉ thị tiền xử lý
#if dãy lệnh … #endif
#if dãy lệnh … #else dãy lệnh … #endif,
c. Các chỉ thị biên dịch có điều kiện #if, #ifdef, #ifndef
Chỉ thị:
Báo cho chương trình dịch biết đoạn lệnh giữa #if (điều kiện) và
#endif chỉ được dịch nếu điều kiện đúng.
Ví dụ:
cout << i+i ;
cout << i ;
cout << i*i ;
const int M = 10;
void main() {
int i = 5;
#if M > 8
#else
#endif
}
const int M = 1;
void main() {
int i = 5;
#if M ==1
#endif
}
62 62
BB
&
VC
Các chỉ thị tiền xử lý
d. Chỉ thị #ifdef và #ifndef
Chỉ thị này báo cho chương trình dịch biết đoạn lệnh có được dịch
hay không khi một tên gọi đã được định nghĩa hay chưa.
Để định nghĩa một tên gọi ta dùng chỉ thị #define tên.
Chỉ thị này đặc biệt có ích khi chèn các tệp thư viện vào để sử
dụng. Một tệp thư viện có thể được chèn nhiều lần trong văn bản
do vậy nó có thể sẽ được dịch nhiều lần, điều này sẽ gây ra lỗi vì
các biến được khai báo nhiều lần.
63 63
BB
&
VC
Các chỉ thị tiền xử lý
d. Chỉ thị #ifdef và #ifndef
Thư viện 1. tên tệp: MYLIB.H
int max(int a, int b)
{
return (a>b? a: b);
}
Thư viện 2. tên tệp: MATHFUNC.H
>> b >> c;
#include "mylib.h"
int max(int a, int b)
{
return (a>b? a: b);
}
Hàm main của chúng ta nhập 3 số,
in ra max của từng cặp số và max
của cả 3 số. Chương trình cần phải
sử dụng cả 2 thư viện.
#include "mylib.h"
#include "mathfunc.h"
main()
{
int a, b, c;
cout << "a, b, c = " ; cin >> a
cout << max(a,b) << max(b,c)
<< max(a,c) << max(a,b,c) ;
}
C++ sẽ báo lỗi (do hàm int max(inta, int b) được khai báo hai lần
64 64
BB
&
VC
Các chỉ thị tiền xử lý
Khắc phục
return (a>b? a: b);
// tệp mylib.h
#ifndef _MYLIB_ // nếu chưa định nghĩa tên gọi _MYLIB_
#define _MYLIB_ // thì định nghĩa nó
int max(int a, int b) // và các hàm khác
{
}
#endif
65 65
BB
&
VC
Câu hỏi và bài tập
1. Nêu cách khai báo hàm, định nghĩa hàm, cách gọi hàm.
2. Phạm vi của một đối tượng (biến, hằng) trong chương trình ?
3. Trình bày các phương pháp truyền tham số cho hàm (truyền
bằng giá trị, bằng tham chiếu, và bằng tham trỏ)
4. Nêu cách thiết kế hàm mà theo Anh (Chị) cho là đạt yêu cầu.
5. Cho ví dụ về hàm xuất/nhập.
6. Cho ví dụ về hàm kiểm tra một giá trị nguyên thỏa tính chất “P”
nào đó.
7. Cho ví dụ về hàm xác định giá trị nguyên thỏa tính chất “P” nào
đó.
8. Trình bày cách tổ chức một chương trình “C/C++”.
66 66
BB
&
VC
Câu hỏi và bài tập
BB
8. Trình bày cấp lưu trữ của một đối tượng (auto, register,
static, extern).
9. Khai báo các hàm nguyên mẫu sau:
dạng n = 120 = 2*2*2*3*5.
− Giải phương trình bậc 2 ax2 + bx + c = 0
− In bảng cửu chương theo chiều dọc, ngang.
− Kiểm tra 1 bộ ngày, tháng, năm có hợp lệ hay không ?
− Vẽ hình tam giác với chiều cao h dạng …
− Phân tích số n > 0 thành tích các thừa số nguyên tố theo
− Kiểm tra số tự nhiên n > 0 có phải là số nguyên tố ?
− Tính trị max của 2 số nguyên.
− Tính trị min của 2 số nguyên.
− Tính USCLN của 2 số tự nhiên.
67 67
&
VC
Câu hỏi và bài tập
BB
10 Chọn câu sai trong các câu sau đây:
A: Hàm không trả lại giá trị thì không cần khai báo kiểu giá trị
của hàm.
B: Các biến được khai báo trong hàm là cục bộ, tự xoá khi hàm
thực hiện xong
C: Hàm không trả lại giá trị sẽ có kiểu giá trị ngầm định là void.
D: Hàm là đơn vị độc lập, không được khai báo hàm lồng nhau.
11 Chọn câu đúng nhất trong các câu sau đây:
A: Hàm phải được kết thúc với 1 câu lệnh return
B: Phải có ít nhất 1 câu lệnh return cho hàm
C: Các câu lệnh return được phép nằm ở vị trí bất kỳ trong thân
hàm
D: Không cần khai báo kiểu giá trị trả lại của hàm nếu hàm
không có lệnh return
68 68
&
VC
Câu hỏi và bài tập
BB
12. Chọn câu sai trong các câu sau đây:
A: Số tham số thực sự phải bằng số tham số hình thức trong lời
gọi hàm
B: Các biến cục bộ trong thân hàm được chương trình dịch cấp
phát bộ nhớ
C: Các tham số hình thức sẽ được cấp phát bộ nhớ tạm thời khi
hàm được gọi
D: Kiểu của tham số thực sự phải bằng kiểu của tham số hình
thức tương ứng với nó trong lời gọi hàm
13. Để thay đổi giá trị của tham biến, các đối của hàm cần khai
báo dưới dạng:
A: biến bình thường và tham đối được truyền theo giá trị
B: biến con trỏ và tham đối được truyền theo giá trị
C: biến bình thường và tham đối được truyền theo địa chỉ
D: biến tham chiếu và tham đối được truyền theo giá trị
69 69
&
VC
Câu hỏi và bài tập
Hãy cho biết trị in ra màn hình của các biến x, y, và z của các chương trình sau:
int x = 4, y = 3, z = 2;
cout << "\nX = " << x;
cout << "\nY = " << y;
cout << "\nZ = " << z;
return 0;
x *= y;
y *= z;
z *= x;
#include
void mul(int&,int,int&);
int main( ) {
mul( y, z, x );
}
void mul( int & x,int y, int & z ) {
}
70 70
BB
&
VC
Câu hỏi và bài tập
Hãy cho biết trị in ra màn hình của các biến x, y, và z của các chương trình sau:
g( z, y, x );
x += y;
y += z;
z += x;
int x = 2, y = 3, z = 4;
f( y, z, x );
cout << "\nX = " << x;
cout << "\nY = " << y;
cout << "\nZ = " << z;
return 0;
a *= b;
b *= c;
c *= a;
#include
void f( int x, int & y, int z );
void g( int & x, int y, int & z );
int main() {
}
void f( int x, int & y, int z
){
}
void g( int & a, int b, int &
c ) {
}
71 71
BB
&
VC
Bài tập thực hành
BB
5. Bài 4, 5, 6, 7, 8 trang 140-141 chương 8 (Câu
lệnh điều kiện và rẽ nhánh)
a. Viết hàm đổi một ký tự hoa sang ký tự thường.
b. Viết thủ tục giải phương trình bậc nhất.
c. Viết thủ tục giải phương trình bậc hai.
d. Viết hàm trả về giá trị nhỏ nhất của 4 số nguyên.
e. Viết thủ tục hoán vị hai số nguyên.
f. Viết thủ tục sắp xếp 4 số nguyên tăng dần.
72 72
NMLT - Hàm (Function)
&
VC
Bài tập thực hành
BB
6. Bài tập 3 trang 155 chương 9 (Câu lệnh lặp). Hàm
nhận vào một số nguyên dương n và thực hiện:
a. Trả về số đảo của số đó.
b. Có phải là số đối xứng (Trả về True/False)
c. Có phải là số chính phương.
d. Có phải là số nguyên tố.
e. Tổng các chữ số lẻ.
f. Tổng các chữ số nguyên tố.
g. Tổng các chữ số chính phương.
73 73
NMLT - Hàm (Function)
&
VC
Bài tập thực hành
BB
7. Bài tập 4 trang 156 chương 9 (Câu lệnh lặp). Hàm
nhận vào một số nguyên dương n và thực hiện:
a. S = 1 + 2 + … + n
b. S = 12 + 22 + … + n2
c. S = 1 + 1/2 + … + 1/n
d. S = 1 * 2 * … * n
e. S = 1! + 2! + … + n!
8. Hàm trả về USCLN của 2 số nguyên.
In ra n phần tử của dãy Fibonacy.
9.
74 74
NMLT - Hàm (Function)
void XuatTong(int x, int y) { }
12 12
NMLT - Hàm (Function)
&
VC
Hàm
BB
Ví dụ 2
Tên hàm: TinhTong Công việc: tính và trả về tổng 2 số nguyên Đầu vào: hai số nguyên x và y Đầu ra: một số nguyên có giá trị x + y
int s; s = x + y; return s;
int TinhTong(int x, int y) { }
13 13
NMLT - Hàm (Function)
&
VC
Chương trình con - Function
BB
Ví dụ 3
Tên hàm: NhapXuatTong Công việc: nhập và xuất tổng 2 số nguyên Đầu vào: không có Đầu ra: không có
int x, y;
cout<<“Nhap 2 so nguyen: ”;
cin>>x>>y;
cout<
void NhapXuatTong()
{
}
14 14
NMLT - Hàm (Function)
&
VC
Tầm vực
BB
Khái niệm
Là phạm vi hoạt động của biến và hàm.
Biến:
• Toàn cục: khai báo ngoài tất cả các hàm (kể cả
hàm main) và có tác dụng lên toàn bộ chương
trình.
• Cục bộ: khai báo trong hàm hoặc khối { } và chỉ có
tác dụng trong bản thân hàm hoặc khối đó (kể cả
khối con nó). Biến cục bộ sẽ bị xóa khỏi bộ nhớ khi
kết thúc khối khai báo nó.
15 15
NMLT - Hàm (Function)
&
VC
Tầm vực
BB
int a1;
int a21;
int a2;
{
}
int Ham1()
{
}
int Ham2()
{
}
int a3;
int a;
void main()
{
}
16 16
NMLT - Hàm (Function)
&
VC
Hàm nguyên mẫu (function prototype)
Hàm nguyên mẫu:
Được dùng để cung cấp thông tin cho chương trình dịch về
tên hàm, kiểu giá trị trả về, số lượng, thứ tự và kiểu của các
tham số của hàm.
Chương trình dịch căn cứ vào các thông tin này để kiểm tra
các lời gọi hàm trong chương trình.
Hàm nguyên mẫu được đặt sau phần khai báo toàn cục và
ngay trước hàm main() hoặc có thể đặt trong tập tin khác.
BB
[] ([]) ;
Khai báo:
Ví dụ: Khai báo hàm nguyên mẫu có chức năng xác định trị
min giữa 2 số nguyên.
int Min(int, int) ;
int Min(int a, int b) ; // nên dùng cách khai báo này
17 17
&
VC
Tổ chức một chương trình “C/C++”
Cách 1: chương trình gồm 3 phần
PHẦN KHAI BÁO TOÀN CỤC
PHẦN KHAI BÁO VÀ ĐỊNH NGHĨA HÀM
HÀM main()
Cách 2: chương trình gồm 4 phần (nên dùng cách này)
PHẦN KHAI BÁO TOÀN CỤC
PHẦN KHAI BÁO HÀM NGUYÊN MẪU
HÀM main()
PHẦN ĐỊNH NGHĨA HÀM
18 18
BB
&
VC
Tổ chức một chương trình “C/C++”
Ví dụ: cách 1
Ví dụ: Cách 2
#include
int min(int a, int b);
//prototype
int min1 = min(a,b);
cout << “Min = “ << min1;
int min1 = min(a,b);
cout << “Min = “ << min1;
#include
int min(int a, int b)
{ if (a
void main()
{ int a=40, b=30;
}
int min(int a, int b)
{ if (a
19 19
BB
&
VC
Các phương pháp truyền tham số
Có hai loại tham số:
Tham số thực (actual parameter):là tham số trong lời gọi hàm.
Tham số hình thức (formal parameter): là tham số trong phần
khai báo và định nghĩa. Tham số hình thức chỉ là tên đại diện cho
tham số thực tương ứng. Kiểu của tham số hình thức sẽ qui định
kiểu của tham số thực.
20 20
BB
&
VC
Các phương pháp truyền tham số
Ví dụ:
if(a
int min(int a, int b) //a,b là tham số hình thức
{
else return b;
}
void main()
{ int minAB =min(7,10)//Gọi hàm
// a = 7, b=10
} // Lúc này a,b là tham số thực
21 21
BB
&
VC
Các phương pháp truyền tham số
BB
Có hai cách truyền tham số:
1. Truyền tham trị (call by value):
Chương trình dịch cấp phát vùng nhớ riêng cho từng tham số
hình thức, sau đó sao chép giá trị của tham số thực tương ứng
vào các tham số hình thức.
Khi kết thúc thực hiện hàm, chương trình dịch sẽ thu hồi các vùng
nhớ đã cấp phát cho các tham số hình thức, và các biến cục bộ
khai báo bên trong hàm.
Như vậy, mọi sự thay đổi trị của các tham số hình thức đều không
ảnh hưởng đến các tham số thực bên ngoài hàm.
Cách truyền:
void F(int, int ); // truyền bằng trị
hay
void F(int a, int b); // truyền bằng trị
22 22
&
VC
Các phương pháp truyền tham số
BB
Truyền Giá trị (Call by Value)
Truyền đối số cho hàm ở dạng giá trị.
Có thể truyền hằng, biến, biểu thức nhưng
hàm chỉ sẽ nhận giá trị.
Được sử dụng khi không có nhu cầu thay đổi
giá trị của tham số sau khi thực hiện hàm.
…
x++;
void TruyenGiaTri(int x)
{
}
23 23
NMLT - Hàm (Function)
&
VC
Các phương pháp truyền tham số
Ví dụ: Khảo sát chương trình sau
doubleNum(a);
cout << “Inside main function:” << endl;
cout << “a = “ << a << endl;
a = a*2;
cout << “Inside doubleNum function. a = “ << a;
#include
void doubleNum(int a); //prototype
void main()
{ int a=40;
}
void doubleNum(int a)
{
}
24 24
BB
&
VC
Các phương pháp truyền tham số
2. Truyền tham chiếu(call by reference):
Chương trình dịch sẽ truyền địa chỉ của các tham số thực tương
ứng cho các tham số hình thức.
Nghĩa là ta có thể xem tham số hình thức cũng chính là tham số
thực, hay nói cách khác tham số hình thức là tên gọi khác của
tham số thực.
Mọi sự thay đổi trị của tham số hình thức bên trong hàm chính là
thay đổi trị của tham số thực bên ngoài hàm.
Cách truyền:
void Swap(int &,int &); // truyền bằng tham chiếu
hay
void Swap(int & a,int & b); // truyền bằng tham chiếu
25 25
BB
&
VC
Các phương pháp truyền tham số
BB
Truyền Địa chỉ (Call by Address)
Truyền đối số cho hàm ở dạng địa chỉ (con
trỏ).
Không được truyền giá trị cho tham số này.
Được sử dụng khi có nhu cầu thay đổi giá trị
của tham số sau khi thực hiện hàm.
…
*x++;
void TruyenDiaChi(int *x)
{
}
26 26
NMLT - Hàm (Function)
&
VC
Các phương pháp truyền tham số
BB
Truyền Tham chiếu (Call by Reference) (C++)
Truyền đối số cho hàm ở dạng địa chỉ (con
trỏ). Được bắt đầu bằng & trong khai báo.
Không được truyền giá trị cho tham số này.
Được sử dụng khi có nhu cầu thay đổi giá trị
của tham số sau khi thực hiện hàm.
…
x++;
void TruyenThamChieu(int &x)
{
}
27 27
NMLT - Hàm (Function)
&
VC
Các phương pháp truyền tham số
Ví dụ: Khảo sát chương trình sau
doubleNum(a);
cout << “Inside main function:” << endl;
cout << “a = “ << a << endl;
a = a*2;
cout << “Inside doubleNum function. a = “ << a;
#include
void doubleNum(int a); //prototype
void main()
{ int a=40;
}
void doubleNum(int &a)
{
}
28 28
BB
&
VC
Các phương pháp truyền tham số
Chú ý:
Trong cách truyền tham chiếu, tham số thực tương ứng phải là
một biến. Còn trong cách truyền trị, tham số thực tương ứng có
thể là biến, hằng, lời gọi hàm, hoặc một biểu thức cùng kiểu với
tham số hình thức.
Các tham số hình thức trong cách truyền bằng giá trị được gọi là
tham trị. Còn các tham số hình thức trong cách truyền bằng tham
chiếu được gọi là tham biến.
29 29
BB
&
VC
Lưu ý khi truyền đối số
BB
Lưu ý
Trong một hàm, các tham số có thể truyền
theo nhiều cách.
…
x++;
y++;
void HonHop(int x, int &y)
{
}
30 30
NMLT - Hàm (Function)
&
VC
Lưu ý khi truyền đối số
BB
Lưu ý
Sử dụng tham chiếu là một cách để trả về giá
trị cho chương trình.
return x + y;
tong = x + y;
tong = x + y; hieu = x – y;
31 31
NMLT - Hàm (Function)
int TinhTong(int x, int y)
{
}
void TinhTong(int x, int y, int &tong)
{
}
void TinhTongHieu(int x, int y, int &tong, int &hieu)
{
}
&
VC
Lời gọi hàm
BB
Cách thực hiện
Gọi tên của hàm đồng thời truyền các đối số
(hằng, biến, biểu thức) cho các tham số theo
đúng thứ tự đã được khai báo trong hàm.
Các biến hoặc trị này cách nhau bằng dấu ,
Các đối số này được được đặt trong cặp dấu
ngoặc đơn ( )
(<đối số 1>,… , <đối số n>);
32 32
NMLT - Hàm (Function)
&
VC
Lời gọi hàm
BB
Ví dụ
int n = 9;
XuatTong(1, 2);
XuatTong(1, n);
TinhTong(1, 2);
int tong = TinhTong(1, 2);
TruyenGiaTri(1);
TruyenGiaTri(n);
TruyenDiaChi(1);
TruyenDiaChi(&n);
TruyenThamChieu(1);
TruyenThamChieu(n);
33 33
{ Các hàm được khai báo ở đây }
void main()
{
}
NMLT - Hàm (Function)
&
VC
Lời gọi chương trình con
BB
Ví dụ
HoanVi(2912, 1706);
int x = 2912, y = 1706;
HoanVi(x, y);
int tam = a;
a = b;
b = tam;
34 34
void HoanVi(int &a, int &b);
void main()
{
}
void HoanVi(int &a, int &b)
{
}
NMLT - Hàm (Function)
&
VC
Đệ quy
3. Hàm gọi đệ qui: một lệnh trong thân hàm gọi đến chính nó. Số lần
BB
gọi này phải có giới hạn (điểm dừng)
Ví dụ: chương trình tính giai thừa của n.
int gt;
if(n==1) return(1);
// goi de qui
gt = giaiThua(n-1)*n;
return gt;
int giaiThua(int n)
{
}
gt4 = giaiThua(4);
gt7 = giaiThua(7);
cout << “4! =“ << gt4 << endl;
cout << “7! =“ << gt7 << endl;
#include
int giaiThua(int n);
void main()
{ int gt4, gt7;
}
35 35
&
VC
BB
Đệ quy
Đặc điểm của hàm đệ qui:
Chương trình viết rất gọn,
Việc thực hiện gọi đi gọi lại hàm rất nhiều lần phụ thuộc vào độ
lớn của đầu vào. Do đó chương trình sẽ mất thời gian để lưu giữ
các thông tin của hàm gọi trước khi chuyển điều khiển đến thực
hiện hàm được gọi. Mặt khác các thông tin này được lưu trữ
nhiều lần trong ngăn xếp sẽ dẫn đến tràn ngăn xếp nếu n lớn.
Tuy nhiên, đệ qui là cách viết rất gọn, dễ viết và đọc chương
trình, mặt khác có nhiều bài toán hầu như tìm một thuật toán lặp
cho nó là rất khó trong khi viết theo thuật toán đệ qui thì lại rất dễ
dàng.
36 36
&
VC
Đệ quy
Lớp các bài toán giải được bằng đệ qui
Giải quyết được dễ dàng trong các trường hợp riêng gọi là
trường hợp suy biến hay cơ sở, trong trường hợp này hàm được
tính bình thường mà không cần gọi lại chính nó,
Đối với trường hợp tổng quát, bài toán có thể giải được bằng bài
toán cùng dạng nhưng với tham đối khác có kích thước nhỏ hơn
tham đối ban đầu. Và sau một số bước hữu hạn biến đổi cùng
dạng, bài toán đưa được về trường hợp suy biến.
37 37
BB
&
VC
Đệ quy
Các ví dụ
Ví dụ 1 : Tìm UCLN của 2 số a, b. Bài toán có thể được định
nghĩa dưới dạng đệ qui như sau:
− nếu a = b thì UCLN = a
− nếu a > b thì UCLN(a, b) = UCLN(a-b, b)
− nếu a < b thì UCLN(a, b) = UCLN(a, b-a)
Chương trình đệ qui để tính UCLN của a và b như sau.
int UCLN(int a, int b) // qui uoc a, b > 0
{ if (a < b) UCLN(a, b-a);
if (a == b) return a;
if (a > b) UCLN(a-b, b);
}
38 38
BB
&
VC
Đệ quy
Ví dụ 2 : Tính số hạng thứ n của dãy Fibonaci là dãy f(n) được
định nghĩa:
− f(0) = f(1) = 1
− f(n) = f(n-1) + f(n-2) với n ≥ 2.
long Fib(int n)
{ long kq;
if (n==0 || n==1) kq = 1; else kq = Fib(n-1) + Fib(n-2);
return kq;
}
39 39
BB
&
VC
Nạp chồng hàm (Function overloading)
Nạp chồng hàm là dùng chung một danh hiệu để đặt tên cho các
hàm khác nhau.
Chỉ nạp chồng hàm đối với những hàm giống nhau về bản chất,
nhưng khác nhau ở số lượng, và kiểu dữ liệu của các tham số.
Khả năng nạp chồng hàm kết hợp với hàm có tham số với giá trị
double x = 20.0;
int y = 10;
F(x, y); // mơ hồ! chương trình
dịch không biết gọi hàm nào
ngầm định có thể gây ra tình trạng nhập nhằng, mơ hồ
void F(int, double)
{ …. }
void F(int)
{ …. }
void F(double)
{ … }
void main()
{
}
40 40
BB
&
VC
Một số gợi ý khi thiết kế hàm
Xác định rõ chức năng, nhiệm vụ của hàm.
Chỉ nên thiết kế hàm theo phương châm “mỗi hàm chỉ thực hiện
một nhiệm vụ duy nhất”, và nên thiết kế sao cho có thể sử dụng
lại hàm để hổ trợ cho các việc khác (reusable).
Đặt tên hàm sao cho có tính gợi nhớ (Memonic)
Nên đặt chú thích, ghi rõ các thông tin về hàm như chức năng,
điều kiện dữ liệu vào, xác định dữ liệu ra của hàm, . . .
Xác định trị trả về: hàm có cần trả về giá trị? Nếu có, xác định rõ
kiểu trả về. Đối với các hàm có chức năng nhập/xuất dữ liệu, trị
trả về thường là void. Còn đối với loại hàm kiểm tra một tính chất
P nào đó, ta thường trả về giá trị 0 hoặc 1, i.e. trả về trị của một
biểu thức logic.
41 41
BB
&
VC
Một số gợi ý khi thiết kế hàm
Xác định số lượng tham số và kiểu của từng tham số: hàm có
nhận tham số hay không? Bao nhiêu tham số? Kiểu của từng
tham số?
Xác định rõ phương pháp truyền tham số: nếu không có nhu cầu
làm thay đổi trị của tham số thực truyền vào cho hàm thì áp
dụng phương pháp truyền bằng giá trị. Còn ngược lại thì áp
dụng cách truyền bằng tham chiếu.
42 42
BB
&
VC
Phạm vi (scope) của các đối tượng
Phạm vi là vùng chương trình mà đối tượng được nhận biết và có
thể được sử dụng.
Phạm vi của một đối tượng trải dài từ nơi nó được khai báo đến
cuối khối, hàm, hay tập tin chứa đối tượng đó. Có các loại phạm vi
sau:
Phạm vi cục bộ (local scope)
− Phạm vi khối (Block scope)
− Phạm vi hàm (Function scope)
Phạm vi toàn cục (global scope)
− Phạm vi tập tin (File scope)
− Phạm vi chương trình (Program scope)
43 43
BB
&
VC
Phạm vi (scope) của các đối tượng
Phạm vi khối: Trong C, một khối được giới hạn bởi ngoặc {}. Biến
khai báo trong khối đó có phạm vi khối, nghĩa là nó chỉ hoạt động
trong khối đó mà thôi. Phạm vi này còn gọi là cục bộ, và biến đưọc
gọi là biến cục bộ.
Ví dụ: int main()
{
int i; /* block scope */
.
.
.
return 0;
}
44 44
BB
&
VC
Phạm vi (scope) của các đối tượng
BB
Ví dụ: 1: /* Scopes in nested block */
2: #include
3:
4: main()
5: {
6: int i = 32; /* block scope 1*/
7:
8: cout<<"Within the outer block: i=“<
Kết quả:
Within the outer block:
i=32
Within the inner block:
i= 0, j=10
i= 1, j= 9
i= 2, j= 8
i= 3, j= 7
i= 4, j= 6
i= 5, j= 5
i= 6, j= 4
i= 7, j= 3
i= 8, j= 2
i= 9, j= 1
i=10, j= 0
Within the outer block:
i=32
45 45
&
VC
Phạm vi (scope) của các đối tượng
Phạm vi hàm: chỉ định một biến có phạm vi hoạt động từ đầu đến
cuối một hàm (không nhầm lẫn với biến có phạm vi khối). Trong C,
chỉ có nhãn (label) đối với lệnh goto là có phạm vi hàm.
Ví dụ : int main()
.
.
.
.
return 0;
{ int i; /* block scope */
start: /* A goto label has function scope */
goto start; /* the goto statement */
.
.
}
46 46
BB
&
VC
Phạm vi (scope) của các đối tượng
Phạm vi chương trình: Biến có phạm vi chương trình khi nó được
khai báo bên ngoài các hàm.
Ví dụ:
.
.
return 0;
int x = 0; /* program scope */
float y = 0.0; /* program scope */
int main()
{ int i; /* block scope */
}
Biến này còn gọi là biến toàn cục
47 47
BB
&
VC
Phạm vi (scope) của các đối tượng
Ví dụ:
BB
Kết quả:
From function_1:
x=1234, y=1.234567
Within the main block:
x=4321, y=1.234567
From function_1:
x=1234, y=1.234567
Within the nested block:
x=4321, y=7.654321
1: /* Program scope vs block scope */
2: #include
4: int x = 1234; /* program scope */
5: double y = 1.234567; /* program scope */
7: void function_1()
8: {
9: cout<<"From function_1: x=,”<
48 48
&
VC
Phạm vi (scope) của các đối tượng
Phạm vi tập tin: Trong C, biến được khai báo là toàn cục và static
được gọi là có phạm vi tập tin.
int x = 0; /* program scope */
static int y = 0; /* file scope */
static float z = 0.0; /* file scope */
int main()
{ int i; /* block scope */
.
.
.
return 0;
}
49 49
BB
&
VC
Phạm vi (scope) của các đối tượng
Ví dụ:
cout<<”Y = “<
bị hủy, không thể truy
xuất
fct(x);
cout<<”X của hàm main() = “<
“<
}
#include
int x=3; // biến x toàn cục
const int MAX = 10;
void fct(int x);
void main()
{ int x=1; // x cục bộ của hàm main()
{
int y=4;
x += y;
}
50 50
BB
&
VC
Phạm vi (scope) của các đối tượng
Biến toàn cục (local variable)
Biến cục bộ (Global variable)
Biến cục bộ là biến khai báo bên
trong khối hay hàm của khối.
Biến toàn cục là biến khai báo
bên ngoài mọi hàm
Chỉ có thể được truy xuất bên trong
phạm vi khối hay hàm đó mà thôi.
Có thể được truy xuất ở mọi nơi
trong chương trình.
Các biến cục bộ có thời gian tồn tại
tương đối ngắn. Chúng sẽ bị hủy
mỗi khi ra khỏi khối hay kết thúc
thực hiện hàm chứa nó.
Các biến toàn cục có thời gian
tồn tại là thời gian của chương
trình
51 51
BB
&
VC
Cấp lưu trữ của các đối tượng
Cấp lưu trữ (storage class) là cách thức NNLT cấp phát vùng nhớ và lưu
trữ biến. Cấp lưu trữ của một biến được xác định bằng các từ khóa sau:
auto, register, static, extern.
Biến auto (còn gọi là biến tự động, biến cục bộ):
Mọi biến khai báo bên trong một khối hay hàm mặc nhiên có
tính chất auto, trừ khi xác định rõ cấp lưu trữ khác.
Ví dụ, khai báo int x; tương đương với khai báo auto int x;.
Biến auto có phạm vi cục bộ bên trong hàm hay khối và có
thời gian tồn tại ngắn, do được cấp phát trong vùng nhớ
STACK.
52 52
BB
&
VC
Cấp lưu trữ của các đối tượng
Biến register (ít dùng)
Để tăng tốc độ truy xuất biến, chương trình dịch lưu trữ
biến trong thanh ghi. Chương trình dịch có thể bỏ qua
không đáp ứng lời yêu cầu này nếu có quá nhiều lời đề
nghị loại này hoặc nếu không còn đủ thanh ghi để cấp
phát.
Ví dụ: int main()
{ /* block scope with the register specifier */
register int i;
. . .
for (i=0; i
53 53
BB
&
VC
Cấp lưu trữ của các đối tượng
Biến static (còn gọi là biến tĩnh)
Là biến được cấp phát trong vùng nhớ DATA do đó
có tính chất cố định, lâu dài.
Biến static khai báo bên trong một khối, hay hàm sẽ
không bị hủy khi ra khỏi khối hay hàm đó, và vẫn
lưu giữ giá trị cũ của lần gọi hàm trước.
Biến static phải được khởi tạo giá trị khi khai báo.
Chương trình dịch sẽ chỉ khởi tạo giá trị cho biến
static duy nhất một lần trong lần gọi hàm đầu tiên.
54 54
BB
&
VC
Cấp lưu trữ của các đối tượng
lanthu++;
i = 2 * i;
cout << "Hàm chạy lần thứ " << lanthu << ", i = " << i ;
…
Ví dụ: Biến Static
int i = 1;
void ham()
{ static int lanthu = 0;
}
main()
{ ham(); // Hàm chạy lần thứ 1, i = 2
ham(); // Hàm chạy lần thứ 2, i = 4
ham(); // Hàm chạy lần thứ 3, i = 6
…}
55 55
BB
&
VC
Cấp lưu trữ của các đối tượng
Biến extern
Phạm vi của một biến extern trong chương trình có thể được
trải dài trên nhiều tập tin.
Chương trình dịch sẽ không cấp phát thêm vùng nhớ cho biến
có khai báo extern mà sử dụng chung vùng nhớ đã cấp phát
trước đó.
Ví dụ: int x = 0; /* a global variable */
extern int y; /* an allusion to a global variable y */
int main()
{ extern int z; /* an allusion to a global variable z */
int i; /* a local variable */
.
.
return 0;
}
56 56
BB
&
VC
Cấp lưu trữ của các đối tượng
Ví dụ: Biến Extern
int i = 1;
in();
extern i = 1;
in();
cout << i ;
void in();
void main()
{
}
void in()
{
}
void in();
void main()
{
}
void in()
{
cout << i ;
}
Lỗi (cú pháp) vì i là biến cục bộ trong main(), trong in() không nhận biết i,
nếu trong hoặc trước in() khai báo thêm i thì lỗi ngữ nghĩa (tức chương trình
in giá trị i khác không theo ý muốn của lập trình viên).
57 57
BB
&
VC
Cấp lưu trữ của các đối tượng
Ví dụ: Biến Extern
Giả thiết 2 chương trình trên nằm trong 2 tệp khác nhau. Để liên
kết (link) biến i giữa 2 chương trình cần định nghĩa tổng thể i
trong một và khai báo extern trong chương trình kia.
extern i;
cout << i ;
i = 1;
in();
/* program2.cpp */
void in()
{
}
/* program1.cpp*/
void in();
int i;
void main()
{
}
58 58
BB
&
VC
Cấp lưu trữ của các đối tượng
Tóm tắt về cấp lưu trữ biến (Storage class)
59 59
BB
&
VC
Các chỉ thị tiền xử lý
a. Chỉ thị bao hàm tệp #include
Cho phép ghép nội dung các tệp đã có khác vào chương trình
trước khi dịch. Các tệp cần ghép thêm vào chương trình thường là
các tệp chứa khai báo nguyên mẫu của các hằng, biến, hàm … có
sẵn trong C hoặc các hàm do lập trình viên tự viết.
1: #include
Có hai dạng viết chỉ thị này.
2: #include “đường dẫn\tệp”
Các tập tin nguyên mẫu của thư viện C++, chứa trong thư mục
Borlandc\Include
Tìm tệp theo đường dẫn, nếu không có đường dẫn sẽ tìm trong
thư mục hiện tại. Tệp thường là các tệp (thư viện) được tạo bởi
lập trình viên và được đặt trong cùng thư mục chứa chương trình.
60 60
BB
&
VC
Các chỉ thị tiền xử lý
#define tên_macro xaukitu
b. Chỉ thị macro #define
Cú pháp:
Trước khi dịch bộ tiền xử lý sẽ tìm trong chương trình và thay thế
bất kỳ vị trí xuất hiện nào của tên_macro bởi xâu kí tự. Ta thường
sử dụng macro để định nghĩa các hằng hoặc thay cụm từ này
bằng cụm từ khác dễ nhớ hơn.
Ví dụ:
Viết
Ok = TRUE;
cout << i ;
if (i < MAX) then
begin
end
#define then // thay then bằng dấu cách
#define begin { // thay begin bằng dấu {
#define end } // thay end bằng dấu }
#define MAX 100 // thay MAX bằng 100
#define TRUE 1 // thay TRUE bằng 1
Ct dịch
Ok = 1;
cout << i ;
if (i < 100 then
{
}
61 61
BB
&
VC
Các chỉ thị tiền xử lý
#if dãy lệnh … #endif
#if dãy lệnh … #else dãy lệnh … #endif,
c. Các chỉ thị biên dịch có điều kiện #if, #ifdef, #ifndef
Chỉ thị:
Báo cho chương trình dịch biết đoạn lệnh giữa #if (điều kiện) và
#endif chỉ được dịch nếu điều kiện đúng.
Ví dụ:
cout << i+i ;
cout << i ;
cout << i*i ;
const int M = 10;
void main() {
int i = 5;
#if M > 8
#else
#endif
}
const int M = 1;
void main() {
int i = 5;
#if M ==1
#endif
}
62 62
BB
&
VC
Các chỉ thị tiền xử lý
d. Chỉ thị #ifdef và #ifndef
Chỉ thị này báo cho chương trình dịch biết đoạn lệnh có được dịch
hay không khi một tên gọi đã được định nghĩa hay chưa.
Để định nghĩa một tên gọi ta dùng chỉ thị #define tên.
Chỉ thị này đặc biệt có ích khi chèn các tệp thư viện vào để sử
dụng. Một tệp thư viện có thể được chèn nhiều lần trong văn bản
do vậy nó có thể sẽ được dịch nhiều lần, điều này sẽ gây ra lỗi vì
các biến được khai báo nhiều lần.
63 63
BB
&
VC
Các chỉ thị tiền xử lý
d. Chỉ thị #ifdef và #ifndef
Thư viện 1. tên tệp: MYLIB.H
int max(int a, int b)
{
return (a>b? a: b);
}
Thư viện 2. tên tệp: MATHFUNC.H
>> b >> c;
#include "mylib.h"
int max(int a, int b)
{
return (a>b? a: b);
}
Hàm main của chúng ta nhập 3 số,
in ra max của từng cặp số và max
của cả 3 số. Chương trình cần phải
sử dụng cả 2 thư viện.
#include "mylib.h"
#include "mathfunc.h"
main()
{
int a, b, c;
cout << "a, b, c = " ; cin >> a
cout << max(a,b) << max(b,c)
<< max(a,c) << max(a,b,c) ;
}
C++ sẽ báo lỗi (do hàm int max(inta, int b) được khai báo hai lần
64 64
BB
&
VC
Các chỉ thị tiền xử lý
Khắc phục
return (a>b? a: b);
// tệp mylib.h
#ifndef _MYLIB_ // nếu chưa định nghĩa tên gọi _MYLIB_
#define _MYLIB_ // thì định nghĩa nó
int max(int a, int b) // và các hàm khác
{
}
#endif
65 65
BB
&
VC
Câu hỏi và bài tập
1. Nêu cách khai báo hàm, định nghĩa hàm, cách gọi hàm.
2. Phạm vi của một đối tượng (biến, hằng) trong chương trình ?
3. Trình bày các phương pháp truyền tham số cho hàm (truyền
bằng giá trị, bằng tham chiếu, và bằng tham trỏ)
4. Nêu cách thiết kế hàm mà theo Anh (Chị) cho là đạt yêu cầu.
5. Cho ví dụ về hàm xuất/nhập.
6. Cho ví dụ về hàm kiểm tra một giá trị nguyên thỏa tính chất “P”
nào đó.
7. Cho ví dụ về hàm xác định giá trị nguyên thỏa tính chất “P” nào
đó.
8. Trình bày cách tổ chức một chương trình “C/C++”.
66 66
BB
&
VC
Câu hỏi và bài tập
BB
8. Trình bày cấp lưu trữ của một đối tượng (auto, register,
static, extern).
9. Khai báo các hàm nguyên mẫu sau:
dạng n = 120 = 2*2*2*3*5.
− Giải phương trình bậc 2 ax2 + bx + c = 0
− In bảng cửu chương theo chiều dọc, ngang.
− Kiểm tra 1 bộ ngày, tháng, năm có hợp lệ hay không ?
− Vẽ hình tam giác với chiều cao h dạng …
− Phân tích số n > 0 thành tích các thừa số nguyên tố theo
− Kiểm tra số tự nhiên n > 0 có phải là số nguyên tố ?
− Tính trị max của 2 số nguyên.
− Tính trị min của 2 số nguyên.
− Tính USCLN của 2 số tự nhiên.
67 67
&
VC
Câu hỏi và bài tập
BB
10 Chọn câu sai trong các câu sau đây:
A: Hàm không trả lại giá trị thì không cần khai báo kiểu giá trị
của hàm.
B: Các biến được khai báo trong hàm là cục bộ, tự xoá khi hàm
thực hiện xong
C: Hàm không trả lại giá trị sẽ có kiểu giá trị ngầm định là void.
D: Hàm là đơn vị độc lập, không được khai báo hàm lồng nhau.
11 Chọn câu đúng nhất trong các câu sau đây:
A: Hàm phải được kết thúc với 1 câu lệnh return
B: Phải có ít nhất 1 câu lệnh return cho hàm
C: Các câu lệnh return được phép nằm ở vị trí bất kỳ trong thân
hàm
D: Không cần khai báo kiểu giá trị trả lại của hàm nếu hàm
không có lệnh return
68 68
&
VC
Câu hỏi và bài tập
BB
12. Chọn câu sai trong các câu sau đây:
A: Số tham số thực sự phải bằng số tham số hình thức trong lời
gọi hàm
B: Các biến cục bộ trong thân hàm được chương trình dịch cấp
phát bộ nhớ
C: Các tham số hình thức sẽ được cấp phát bộ nhớ tạm thời khi
hàm được gọi
D: Kiểu của tham số thực sự phải bằng kiểu của tham số hình
thức tương ứng với nó trong lời gọi hàm
13. Để thay đổi giá trị của tham biến, các đối của hàm cần khai
báo dưới dạng:
A: biến bình thường và tham đối được truyền theo giá trị
B: biến con trỏ và tham đối được truyền theo giá trị
C: biến bình thường và tham đối được truyền theo địa chỉ
D: biến tham chiếu và tham đối được truyền theo giá trị
69 69
&
VC
Câu hỏi và bài tập
Hãy cho biết trị in ra màn hình của các biến x, y, và z của các chương trình sau:
int x = 4, y = 3, z = 2;
cout << "\nX = " << x;
cout << "\nY = " << y;
cout << "\nZ = " << z;
return 0;
x *= y;
y *= z;
z *= x;
#include
void mul(int&,int,int&);
int main( ) {
mul( y, z, x );
}
void mul( int & x,int y, int & z ) {
}
70 70
BB
&
VC
Câu hỏi và bài tập
Hãy cho biết trị in ra màn hình của các biến x, y, và z của các chương trình sau:
g( z, y, x );
x += y;
y += z;
z += x;
int x = 2, y = 3, z = 4;
f( y, z, x );
cout << "\nX = " << x;
cout << "\nY = " << y;
cout << "\nZ = " << z;
return 0;
a *= b;
b *= c;
c *= a;
#include
void f( int x, int & y, int z );
void g( int & x, int y, int & z );
int main() {
}
void f( int x, int & y, int z
){
}
void g( int & a, int b, int &
c ) {
}
71 71
BB
&
VC
Bài tập thực hành
BB
5. Bài 4, 5, 6, 7, 8 trang 140-141 chương 8 (Câu
lệnh điều kiện và rẽ nhánh)
a. Viết hàm đổi một ký tự hoa sang ký tự thường.
b. Viết thủ tục giải phương trình bậc nhất.
c. Viết thủ tục giải phương trình bậc hai.
d. Viết hàm trả về giá trị nhỏ nhất của 4 số nguyên.
e. Viết thủ tục hoán vị hai số nguyên.
f. Viết thủ tục sắp xếp 4 số nguyên tăng dần.
72 72
NMLT - Hàm (Function)
&
VC
Bài tập thực hành
BB
6. Bài tập 3 trang 155 chương 9 (Câu lệnh lặp). Hàm
nhận vào một số nguyên dương n và thực hiện:
a. Trả về số đảo của số đó.
b. Có phải là số đối xứng (Trả về True/False)
c. Có phải là số chính phương.
d. Có phải là số nguyên tố.
e. Tổng các chữ số lẻ.
f. Tổng các chữ số nguyên tố.
g. Tổng các chữ số chính phương.
73 73
NMLT - Hàm (Function)
&
VC
Bài tập thực hành
BB
7. Bài tập 4 trang 156 chương 9 (Câu lệnh lặp). Hàm
nhận vào một số nguyên dương n và thực hiện:
a. S = 1 + 2 + … + n
b. S = 12 + 22 + … + n2
c. S = 1 + 1/2 + … + 1/n
d. S = 1 * 2 * … * n
e. S = 1! + 2! + … + n!
8. Hàm trả về USCLN của 2 số nguyên.
In ra n phần tử của dãy Fibonacy.
9.
74 74
NMLT - Hàm (Function)
void NhapXuatTong() { }
14 14
NMLT - Hàm (Function)
&
VC
Tầm vực
BB
Khái niệm
Là phạm vi hoạt động của biến và hàm. Biến:
• Toàn cục: khai báo ngoài tất cả các hàm (kể cả hàm main) và có tác dụng lên toàn bộ chương trình.
• Cục bộ: khai báo trong hàm hoặc khối { } và chỉ có tác dụng trong bản thân hàm hoặc khối đó (kể cả khối con nó). Biến cục bộ sẽ bị xóa khỏi bộ nhớ khi kết thúc khối khai báo nó.
15 15
NMLT - Hàm (Function)
&
VC
Tầm vực
BB
int a1;
int a21;
int a2; { }
int Ham1() { } int Ham2() { }
int a3;
int a;
void main() { }
16 16
NMLT - Hàm (Function)
&
VC
Hàm nguyên mẫu (function prototype)
Hàm nguyên mẫu:
Được dùng để cung cấp thông tin cho chương trình dịch về tên hàm, kiểu giá trị trả về, số lượng, thứ tự và kiểu của các tham số của hàm.
Chương trình dịch căn cứ vào các thông tin này để kiểm tra
các lời gọi hàm trong chương trình.
Hàm nguyên mẫu được đặt sau phần khai báo toàn cục và ngay trước hàm main() hoặc có thể đặt trong tập tin khác.
BB
[] ([]) ;
Khai báo: Ví dụ: Khai báo hàm nguyên mẫu có chức năng xác định trị
min giữa 2 số nguyên. int Min(int, int) ; int Min(int a, int b) ; // nên dùng cách khai báo này
17 17
&
VC
Tổ chức một chương trình “C/C++”
Cách 1: chương trình gồm 3 phần PHẦN KHAI BÁO TOÀN CỤC PHẦN KHAI BÁO VÀ ĐỊNH NGHĨA HÀM HÀM main()
Cách 2: chương trình gồm 4 phần (nên dùng cách này)
PHẦN KHAI BÁO TOÀN CỤC PHẦN KHAI BÁO HÀM NGUYÊN MẪU
HÀM main()
PHẦN ĐỊNH NGHĨA HÀM
18 18
BB
&
VC
Tổ chức một chương trình “C/C++”
Ví dụ: cách 1
Ví dụ: Cách 2
#include
//prototype
int min1 = min(a,b); cout << “Min = “ << min1;
int min1 = min(a,b); cout << “Min = “ << min1;
#include void main()
{ int a=40, b=30;
}
int min(int a, int b)
{ if (a
19 19 BB & VC Có hai loại tham số: Tham số thực (actual parameter):là tham số trong lời gọi hàm. Tham số hình thức (formal parameter): là tham số trong phần
khai báo và định nghĩa. Tham số hình thức chỉ là tên đại diện cho
tham số thực tương ứng. Kiểu của tham số hình thức sẽ qui định
kiểu của tham số thực. 20 20 BB & VC Ví dụ: if(a
int min(int a, int b) //a,b là tham số hình thức
{
else return b;
}
void main()
{ int minAB =min(7,10)//Gọi hàm
// a = 7, b=10
} // Lúc này a,b là tham số thực 21 21 BB & VC BB Khi kết thúc thực hiện hàm, chương trình dịch sẽ thu hồi các vùng
nhớ đã cấp phát cho các tham số hình thức, và các biến cục bộ
khai báo bên trong hàm. Như vậy, mọi sự thay đổi trị của các tham số hình thức đều không ảnh hưởng đến các tham số thực bên ngoài hàm. Cách truyền: 22 22 & VC BB 23 23 NMLT - Hàm (Function) & VC Ví dụ: Khảo sát chương trình sau doubleNum(a);
cout << “Inside main function:” << endl;
cout << “a = “ << a << endl; a = a*2;
cout << “Inside doubleNum function. a = “ << a; #include 24 24 BB & VC 2. Truyền tham chiếu(call by reference):
Chương trình dịch sẽ truyền địa chỉ của các tham số thực tương ứng cho các tham số hình thức. Nghĩa là ta có thể xem tham số hình thức cũng chính là tham số
thực, hay nói cách khác tham số hình thức là tên gọi khác của
tham số thực. Mọi sự thay đổi trị của tham số hình thức bên trong hàm chính là thay đổi trị của tham số thực bên ngoài hàm. Cách truyền: void Swap(int &,int &); // truyền bằng tham chiếu hay void Swap(int & a,int & b); // truyền bằng tham chiếu 25 25 BB & VC BB 26 26 NMLT - Hàm (Function) & VC BB 27 27 NMLT - Hàm (Function) & VC Ví dụ: Khảo sát chương trình sau doubleNum(a);
cout << “Inside main function:” << endl;
cout << “a = “ << a << endl; a = a*2;
cout << “Inside doubleNum function. a = “ << a; #include 28 28 BB & VC Chú ý:
Trong cách truyền tham chiếu, tham số thực tương ứng phải là
một biến. Còn trong cách truyền trị, tham số thực tương ứng có
thể là biến, hằng, lời gọi hàm, hoặc một biểu thức cùng kiểu với
tham số hình thức. Các tham số hình thức trong cách truyền bằng giá trị được gọi là
tham trị. Còn các tham số hình thức trong cách truyền bằng tham
chiếu được gọi là tham biến. 29 29 BB & VC BB 30 30 NMLT - Hàm (Function) & VC BB 31 31 NMLT - Hàm (Function) & VC BB 32 32 NMLT - Hàm (Function) & VC BB 33 33 NMLT - Hàm (Function) & VC BB 34 34 NMLT - Hàm (Function) & VC 3. Hàm gọi đệ qui: một lệnh trong thân hàm gọi đến chính nó. Số lần BB int gt;
if(n==1) return(1);
// goi de qui
gt = giaiThua(n-1)*n;
return gt; int giaiThua(int n)
{
} gt4 = giaiThua(4);
gt7 = giaiThua(7);
cout << “4! =“ << gt4 << endl;
cout << “7! =“ << gt7 << endl; #include 35 35 & VC BB Đặc điểm của hàm đệ qui:
Chương trình viết rất gọn,
Việc thực hiện gọi đi gọi lại hàm rất nhiều lần phụ thuộc vào độ
lớn của đầu vào. Do đó chương trình sẽ mất thời gian để lưu giữ
các thông tin của hàm gọi trước khi chuyển điều khiển đến thực
hiện hàm được gọi. Mặt khác các thông tin này được lưu trữ
nhiều lần trong ngăn xếp sẽ dẫn đến tràn ngăn xếp nếu n lớn.
Tuy nhiên, đệ qui là cách viết rất gọn, dễ viết và đọc chương
trình, mặt khác có nhiều bài toán hầu như tìm một thuật toán lặp
cho nó là rất khó trong khi viết theo thuật toán đệ qui thì lại rất dễ
dàng. 36 36 & VC Lớp các bài toán giải được bằng đệ qui Giải quyết được dễ dàng trong các trường hợp riêng gọi là
trường hợp suy biến hay cơ sở, trong trường hợp này hàm được
tính bình thường mà không cần gọi lại chính nó, Đối với trường hợp tổng quát, bài toán có thể giải được bằng bài
toán cùng dạng nhưng với tham đối khác có kích thước nhỏ hơn
tham đối ban đầu. Và sau một số bước hữu hạn biến đổi cùng
dạng, bài toán đưa được về trường hợp suy biến. 37 37 BB & VC Các ví dụ
Ví dụ 1 : Tìm UCLN của 2 số a, b. Bài toán có thể được định nghĩa dưới dạng đệ qui như sau:
− nếu a = b thì UCLN = a
− nếu a > b thì UCLN(a, b) = UCLN(a-b, b)
− nếu a < b thì UCLN(a, b) = UCLN(a, b-a) Chương trình đệ qui để tính UCLN của a và b như sau. int UCLN(int a, int b) // qui uoc a, b > 0
{ if (a < b) UCLN(a, b-a);
if (a == b) return a;
if (a > b) UCLN(a-b, b);
} 38 38 BB & VC Ví dụ 2 : Tính số hạng thứ n của dãy Fibonaci là dãy f(n) được định nghĩa: − f(0) = f(1) = 1 − f(n) = f(n-1) + f(n-2) với n ≥ 2. long Fib(int n) { long kq; if (n==0 || n==1) kq = 1; else kq = Fib(n-1) + Fib(n-2); return kq; } 39 39 BB & VC Nạp chồng hàm là dùng chung một danh hiệu để đặt tên cho các hàm khác nhau. Chỉ nạp chồng hàm đối với những hàm giống nhau về bản chất,
nhưng khác nhau ở số lượng, và kiểu dữ liệu của các tham số.
Khả năng nạp chồng hàm kết hợp với hàm có tham số với giá trị double x = 20.0;
int y = 10;
F(x, y); // mơ hồ! chương trình
dịch không biết gọi hàm nào ngầm định có thể gây ra tình trạng nhập nhằng, mơ hồ
void F(int, double)
{ …. }
void F(int)
{ …. }
void F(double)
{ … } void main()
{
} 40 40 BB & VC Xác định rõ chức năng, nhiệm vụ của hàm.
Chỉ nên thiết kế hàm theo phương châm “mỗi hàm chỉ thực hiện
một nhiệm vụ duy nhất”, và nên thiết kế sao cho có thể sử dụng
lại hàm để hổ trợ cho các việc khác (reusable).
Đặt tên hàm sao cho có tính gợi nhớ (Memonic)
Nên đặt chú thích, ghi rõ các thông tin về hàm như chức năng, điều kiện dữ liệu vào, xác định dữ liệu ra của hàm, . . . Xác định trị trả về: hàm có cần trả về giá trị? Nếu có, xác định rõ
kiểu trả về. Đối với các hàm có chức năng nhập/xuất dữ liệu, trị
trả về thường là void. Còn đối với loại hàm kiểm tra một tính chất
P nào đó, ta thường trả về giá trị 0 hoặc 1, i.e. trả về trị của một
biểu thức logic. 41 41 BB & VC Xác định số lượng tham số và kiểu của từng tham số: hàm có
nhận tham số hay không? Bao nhiêu tham số? Kiểu của từng
tham số? Xác định rõ phương pháp truyền tham số: nếu không có nhu cầu
làm thay đổi trị của tham số thực truyền vào cho hàm thì áp
dụng phương pháp truyền bằng giá trị. Còn ngược lại thì áp
dụng cách truyền bằng tham chiếu. 42 42 BB & VC Phạm vi là vùng chương trình mà đối tượng được nhận biết và có thể được sử dụng. Phạm vi của một đối tượng trải dài từ nơi nó được khai báo đến cuối khối, hàm, hay tập tin chứa đối tượng đó. Có các loại phạm vi
sau: Phạm vi cục bộ (local scope) − Phạm vi khối (Block scope)
− Phạm vi hàm (Function scope) Phạm vi toàn cục (global scope) − Phạm vi tập tin (File scope)
− Phạm vi chương trình (Program scope) 43 43 BB & VC Phạm vi khối: Trong C, một khối được giới hạn bởi ngoặc {}. Biến
khai báo trong khối đó có phạm vi khối, nghĩa là nó chỉ hoạt động
trong khối đó mà thôi. Phạm vi này còn gọi là cục bộ, và biến đưọc
gọi là biến cục bộ. Ví dụ: int main() {
int i; /* block scope */
.
.
.
return 0;
} 44 44 BB & VC BB 45 45 & VC Phạm vi hàm: chỉ định một biến có phạm vi hoạt động từ đầu đến
cuối một hàm (không nhầm lẫn với biến có phạm vi khối). Trong C,
chỉ có nhãn (label) đối với lệnh goto là có phạm vi hàm. Ví dụ : int main() .
. .
. return 0; { int i; /* block scope */
start: /* A goto label has function scope */
goto start; /* the goto statement */
.
.
} 46 46 BB & VC Phạm vi chương trình: Biến có phạm vi chương trình khi nó được khai báo bên ngoài các hàm. Ví dụ: .
.
return 0; int x = 0; /* program scope */
float y = 0.0; /* program scope */
int main()
{ int i; /* block scope */
} Biến này còn gọi là biến toàn cục 47 47 BB & VC Ví dụ: BB 1: /* Program scope vs block scope */
2: #include 48 48 & VC Phạm vi tập tin: Trong C, biến được khai báo là toàn cục và static được gọi là có phạm vi tập tin. int x = 0; /* program scope */
static int y = 0; /* file scope */
static float z = 0.0; /* file scope */
int main()
{ int i; /* block scope */
.
.
.
return 0;
} 49 49 BB & VC Ví dụ: cout<<”Y = “< bị hủy, không thể truy
xuất fct(x); cout<<”X của hàm main() = “< “< } #include 50 50 BB & VC Biến toàn cục (local variable) Biến cục bộ (Global variable) Biến cục bộ là biến khai báo bên
trong khối hay hàm của khối. Biến toàn cục là biến khai báo
bên ngoài mọi hàm Chỉ có thể được truy xuất bên trong
phạm vi khối hay hàm đó mà thôi. Có thể được truy xuất ở mọi nơi
trong chương trình. Các biến cục bộ có thời gian tồn tại
tương đối ngắn. Chúng sẽ bị hủy
mỗi khi ra khỏi khối hay kết thúc
thực hiện hàm chứa nó. Các biến toàn cục có thời gian
tồn tại là thời gian của chương
trình 51 51 BB & VC Cấp lưu trữ (storage class) là cách thức NNLT cấp phát vùng nhớ và lưu
trữ biến. Cấp lưu trữ của một biến được xác định bằng các từ khóa sau:
auto, register, static, extern. Biến auto (còn gọi là biến tự động, biến cục bộ): Mọi biến khai báo bên trong một khối hay hàm mặc nhiên có tính chất auto, trừ khi xác định rõ cấp lưu trữ khác. Ví dụ, khai báo int x; tương đương với khai báo auto int x;. Biến auto có phạm vi cục bộ bên trong hàm hay khối và có
thời gian tồn tại ngắn, do được cấp phát trong vùng nhớ
STACK. 52 52 BB & VC Biến register (ít dùng) Để tăng tốc độ truy xuất biến, chương trình dịch lưu trữ
biến trong thanh ghi. Chương trình dịch có thể bỏ qua
không đáp ứng lời yêu cầu này nếu có quá nhiều lời đề
nghị loại này hoặc nếu không còn đủ thanh ghi để cấp
phát. Ví dụ: int main() { /* block scope with the register specifier */
register int i;
. . .
for (i=0; i 53 53 BB & VC Biến static (còn gọi là biến tĩnh) Là biến được cấp phát trong vùng nhớ DATA do đó có tính chất cố định, lâu dài. Biến static khai báo bên trong một khối, hay hàm sẽ
không bị hủy khi ra khỏi khối hay hàm đó, và vẫn
lưu giữ giá trị cũ của lần gọi hàm trước. Biến static phải được khởi tạo giá trị khi khai báo.
Chương trình dịch sẽ chỉ khởi tạo giá trị cho biến
static duy nhất một lần trong lần gọi hàm đầu tiên. 54 54 BB & VC lanthu++;
i = 2 * i;
cout << "Hàm chạy lần thứ " << lanthu << ", i = " << i ;
… Ví dụ: Biến Static
int i = 1;
void ham()
{ static int lanthu = 0;
}
main()
{ ham(); // Hàm chạy lần thứ 1, i = 2
ham(); // Hàm chạy lần thứ 2, i = 4
ham(); // Hàm chạy lần thứ 3, i = 6
…} 55 55 BB & VC Biến extern Phạm vi của một biến extern trong chương trình có thể được trải dài trên nhiều tập tin. Chương trình dịch sẽ không cấp phát thêm vùng nhớ cho biến
có khai báo extern mà sử dụng chung vùng nhớ đã cấp phát
trước đó. Ví dụ: int x = 0; /* a global variable */ extern int y; /* an allusion to a global variable y */
int main()
{ extern int z; /* an allusion to a global variable z */
int i; /* a local variable */
.
.
return 0;
} 56 56 BB & VC Ví dụ: Biến Extern int i = 1;
in(); extern i = 1;
in(); cout << i ; void in();
void main()
{
}
void in()
{
} void in();
void main()
{
}
void in()
{
cout << i ;
} Lỗi (cú pháp) vì i là biến cục bộ trong main(), trong in() không nhận biết i,
nếu trong hoặc trước in() khai báo thêm i thì lỗi ngữ nghĩa (tức chương trình
in giá trị i khác không theo ý muốn của lập trình viên). 57 57 BB & VC Ví dụ: Biến Extern Giả thiết 2 chương trình trên nằm trong 2 tệp khác nhau. Để liên
kết (link) biến i giữa 2 chương trình cần định nghĩa tổng thể i
trong một và khai báo extern trong chương trình kia. extern i;
cout << i ; i = 1;
in(); /* program2.cpp */
void in()
{
} /* program1.cpp*/
void in();
int i;
void main()
{
} 58 58 BB & VC Tóm tắt về cấp lưu trữ biến (Storage class) 59 59 BB & VC a. Chỉ thị bao hàm tệp #include
Cho phép ghép nội dung các tệp đã có khác vào chương trình
trước khi dịch. Các tệp cần ghép thêm vào chương trình thường là
các tệp chứa khai báo nguyên mẫu của các hằng, biến, hàm … có
sẵn trong C hoặc các hàm do lập trình viên tự viết. 1: #include Có hai dạng viết chỉ thị này. 2: #include “đường dẫn\tệp” Các tập tin nguyên mẫu của thư viện C++, chứa trong thư mục
Borlandc\Include
Tìm tệp theo đường dẫn, nếu không có đường dẫn sẽ tìm trong
thư mục hiện tại. Tệp thường là các tệp (thư viện) được tạo bởi
lập trình viên và được đặt trong cùng thư mục chứa chương trình. 60 60 BB & VC #define tên_macro xaukitu b. Chỉ thị macro #define
Cú pháp:
Trước khi dịch bộ tiền xử lý sẽ tìm trong chương trình và thay thế
bất kỳ vị trí xuất hiện nào của tên_macro bởi xâu kí tự. Ta thường
sử dụng macro để định nghĩa các hằng hoặc thay cụm từ này
bằng cụm từ khác dễ nhớ hơn. Ví dụ: Viết Ok = TRUE;
cout << i ; if (i < MAX) then
begin
end #define then // thay then bằng dấu cách
#define begin { // thay begin bằng dấu {
#define end } // thay end bằng dấu }
#define MAX 100 // thay MAX bằng 100
#define TRUE 1 // thay TRUE bằng 1 Ct dịch Ok = 1;
cout << i ; if (i < 100 then
{
} 61 61 BB & VC #if dãy lệnh … #endif
#if dãy lệnh … #else dãy lệnh … #endif, c. Các chỉ thị biên dịch có điều kiện #if, #ifdef, #ifndef
Chỉ thị:
Báo cho chương trình dịch biết đoạn lệnh giữa #if (điều kiện) và #endif chỉ được dịch nếu điều kiện đúng. Ví dụ: cout << i+i ; cout << i ; cout << i*i ; const int M = 10;
void main() {
int i = 5;
#if M > 8
#else
#endif
} const int M = 1;
void main() {
int i = 5;
#if M ==1
#endif
} 62 62 BB & VC d. Chỉ thị #ifdef và #ifndef
Chỉ thị này báo cho chương trình dịch biết đoạn lệnh có được dịch hay không khi một tên gọi đã được định nghĩa hay chưa. Để định nghĩa một tên gọi ta dùng chỉ thị #define tên.
Chỉ thị này đặc biệt có ích khi chèn các tệp thư viện vào để sử dụng. Một tệp thư viện có thể được chèn nhiều lần trong văn bản
do vậy nó có thể sẽ được dịch nhiều lần, điều này sẽ gây ra lỗi vì
các biến được khai báo nhiều lần. 63 63 BB & VC d. Chỉ thị #ifdef và #ifndef
Thư viện 1. tên tệp: MYLIB.H int max(int a, int b)
{
return (a>b? a: b);
} Thư viện 2. tên tệp: MATHFUNC.H >> b >> c; #include "mylib.h"
int max(int a, int b)
{
return (a>b? a: b);
} Hàm main của chúng ta nhập 3 số,
in ra max của từng cặp số và max
của cả 3 số. Chương trình cần phải
sử dụng cả 2 thư viện.
#include "mylib.h"
#include "mathfunc.h"
main()
{
int a, b, c;
cout << "a, b, c = " ; cin >> a
cout << max(a,b) << max(b,c)
<< max(a,c) << max(a,b,c) ;
} C++ sẽ báo lỗi (do hàm int max(inta, int b) được khai báo hai lần 64 64 BB & VC Khắc phục return (a>b? a: b); // tệp mylib.h
#ifndef _MYLIB_ // nếu chưa định nghĩa tên gọi _MYLIB_
#define _MYLIB_ // thì định nghĩa nó
int max(int a, int b) // và các hàm khác
{
}
#endif 65 65 BB & VC 1. Nêu cách khai báo hàm, định nghĩa hàm, cách gọi hàm.
2. Phạm vi của một đối tượng (biến, hằng) trong chương trình ?
3. Trình bày các phương pháp truyền tham số cho hàm (truyền bằng giá trị, bằng tham chiếu, và bằng tham trỏ) 4. Nêu cách thiết kế hàm mà theo Anh (Chị) cho là đạt yêu cầu.
5. Cho ví dụ về hàm xuất/nhập.
6. Cho ví dụ về hàm kiểm tra một giá trị nguyên thỏa tính chất “P” nào đó. 7. Cho ví dụ về hàm xác định giá trị nguyên thỏa tính chất “P” nào đó. 8. Trình bày cách tổ chức một chương trình “C/C++”. 66 66 BB & VC BB dạng n = 120 = 2*2*2*3*5. − Giải phương trình bậc 2 ax2 + bx + c = 0
− In bảng cửu chương theo chiều dọc, ngang.
− Kiểm tra 1 bộ ngày, tháng, năm có hợp lệ hay không ?
− Vẽ hình tam giác với chiều cao h dạng …
− Phân tích số n > 0 thành tích các thừa số nguyên tố theo
− Kiểm tra số tự nhiên n > 0 có phải là số nguyên tố ?
− Tính trị max của 2 số nguyên.
− Tính trị min của 2 số nguyên.
− Tính USCLN của 2 số tự nhiên. 67 67 & VC BB A: Hàm không trả lại giá trị thì không cần khai báo kiểu giá trị của hàm. B: Các biến được khai báo trong hàm là cục bộ, tự xoá khi hàm thực hiện xong C: Hàm không trả lại giá trị sẽ có kiểu giá trị ngầm định là void.
D: Hàm là đơn vị độc lập, không được khai báo hàm lồng nhau. A: Hàm phải được kết thúc với 1 câu lệnh return
B: Phải có ít nhất 1 câu lệnh return cho hàm
C: Các câu lệnh return được phép nằm ở vị trí bất kỳ trong thân hàm D: Không cần khai báo kiểu giá trị trả lại của hàm nếu hàm không có lệnh return 68 68 & VC BB A: Số tham số thực sự phải bằng số tham số hình thức trong lời gọi hàm B: Các biến cục bộ trong thân hàm được chương trình dịch cấp phát bộ nhớ C: Các tham số hình thức sẽ được cấp phát bộ nhớ tạm thời khi hàm được gọi D: Kiểu của tham số thực sự phải bằng kiểu của tham số hình thức tương ứng với nó trong lời gọi hàm 13. Để thay đổi giá trị của tham biến, các đối của hàm cần khai 69 69 & VC Hãy cho biết trị in ra màn hình của các biến x, y, và z của các chương trình sau: int x = 4, y = 3, z = 2; cout << "\nX = " << x;
cout << "\nY = " << y;
cout << "\nZ = " << z;
return 0; x *= y;
y *= z;
z *= x; #include 70 70 BB & VC Hãy cho biết trị in ra màn hình của các biến x, y, và z của các chương trình sau: g( z, y, x );
x += y;
y += z;
z += x; int x = 2, y = 3, z = 4;
f( y, z, x );
cout << "\nX = " << x;
cout << "\nY = " << y;
cout << "\nZ = " << z;
return 0; a *= b;
b *= c;
c *= a; #include void f( int x, int & y, int z
){
}
void g( int & a, int b, int &
c ) {
} 71 71 BB & VC BB 72 72 NMLT - Hàm (Function) & VC BB 73 73 NMLT - Hàm (Function) & VC BB 74 74 NMLT - Hàm (Function)Các phương pháp truyền tham số
Các phương pháp truyền tham số
Các phương pháp truyền tham số
Có hai cách truyền tham số:
1. Truyền tham trị (call by value):
Chương trình dịch cấp phát vùng nhớ riêng cho từng tham số
hình thức, sau đó sao chép giá trị của tham số thực tương ứng
vào các tham số hình thức.
void F(int, int ); // truyền bằng trị
hay
void F(int a, int b); // truyền bằng trị
Các phương pháp truyền tham số
Truyền Giá trị (Call by Value)
Truyền đối số cho hàm ở dạng giá trị.
Có thể truyền hằng, biến, biểu thức nhưng
hàm chỉ sẽ nhận giá trị.
Được sử dụng khi không có nhu cầu thay đổi
giá trị của tham số sau khi thực hiện hàm.
…
x++;
void TruyenGiaTri(int x)
{
}
Các phương pháp truyền tham số
Các phương pháp truyền tham số
Các phương pháp truyền tham số
Truyền Địa chỉ (Call by Address)
Truyền đối số cho hàm ở dạng địa chỉ (con
trỏ).
Không được truyền giá trị cho tham số này.
Được sử dụng khi có nhu cầu thay đổi giá trị
của tham số sau khi thực hiện hàm.
…
*x++;
void TruyenDiaChi(int *x)
{
}
Các phương pháp truyền tham số
Truyền Tham chiếu (Call by Reference) (C++)
Truyền đối số cho hàm ở dạng địa chỉ (con
trỏ). Được bắt đầu bằng & trong khai báo.
Không được truyền giá trị cho tham số này.
Được sử dụng khi có nhu cầu thay đổi giá trị
của tham số sau khi thực hiện hàm.
…
x++;
void TruyenThamChieu(int &x)
{
}
Các phương pháp truyền tham số
Các phương pháp truyền tham số
Lưu ý khi truyền đối số
Lưu ý
Trong một hàm, các tham số có thể truyền
theo nhiều cách.
…
x++;
y++;
void HonHop(int x, int &y)
{
}
Lưu ý khi truyền đối số
Lưu ý
Sử dụng tham chiếu là một cách để trả về giá
trị cho chương trình.
return x + y;
tong = x + y;
tong = x + y; hieu = x – y;
int TinhTong(int x, int y)
{
}
void TinhTong(int x, int y, int &tong)
{
}
void TinhTongHieu(int x, int y, int &tong, int &hieu)
{
}
Lời gọi hàm
Cách thực hiện
Gọi tên của hàm đồng thời truyền các đối số
(hằng, biến, biểu thức) cho các tham số theo
đúng thứ tự đã được khai báo trong hàm.
Các biến hoặc trị này cách nhau bằng dấu ,
Các đối số này được được đặt trong cặp dấu
ngoặc đơn ( )
Lời gọi hàm
Ví dụ
int n = 9;
XuatTong(1, 2);
XuatTong(1, n);
TinhTong(1, 2);
int tong = TinhTong(1, 2);
TruyenGiaTri(1);
TruyenGiaTri(n);
TruyenDiaChi(1);
TruyenDiaChi(&n);
TruyenThamChieu(1);
TruyenThamChieu(n);
{ Các hàm được khai báo ở đây }
void main()
{
}
Lời gọi chương trình con
Ví dụ
HoanVi(2912, 1706);
int x = 2912, y = 1706;
HoanVi(x, y);
int tam = a;
a = b;
b = tam;
void HoanVi(int &a, int &b);
void main()
{
}
void HoanVi(int &a, int &b)
{
}
Đệ quy
gọi này phải có giới hạn (điểm dừng)
Ví dụ: chương trình tính giai thừa của n.
Đệ quy
Đệ quy
Đệ quy
Đệ quy
Nạp chồng hàm (Function overloading)
Một số gợi ý khi thiết kế hàm
Một số gợi ý khi thiết kế hàm
Phạm vi (scope) của các đối tượng
Phạm vi (scope) của các đối tượng
Phạm vi (scope) của các đối tượng
Ví dụ: 1: /* Scopes in nested block */
2: #include
Kết quả:
Within the outer block:
i=32
Within the inner block:
i= 0, j=10
i= 1, j= 9
i= 2, j= 8
i= 3, j= 7
i= 4, j= 6
i= 5, j= 5
i= 6, j= 4
i= 7, j= 3
i= 8, j= 2
i= 9, j= 1
i=10, j= 0
Within the outer block:
i=32
Phạm vi (scope) của các đối tượng
Phạm vi (scope) của các đối tượng
Phạm vi (scope) của các đối tượng
Kết quả:
From function_1:
x=1234, y=1.234567
Within the main block:
x=4321, y=1.234567
From function_1:
x=1234, y=1.234567
Within the nested block:
x=4321, y=7.654321
Phạm vi (scope) của các đối tượng
Phạm vi (scope) của các đối tượng
Phạm vi (scope) của các đối tượng
Cấp lưu trữ của các đối tượng
Cấp lưu trữ của các đối tượng
Cấp lưu trữ của các đối tượng
Cấp lưu trữ của các đối tượng
Cấp lưu trữ của các đối tượng
Cấp lưu trữ của các đối tượng
Cấp lưu trữ của các đối tượng
Cấp lưu trữ của các đối tượng
Các chỉ thị tiền xử lý
Các chỉ thị tiền xử lý
Các chỉ thị tiền xử lý
Các chỉ thị tiền xử lý
Các chỉ thị tiền xử lý
Các chỉ thị tiền xử lý
Câu hỏi và bài tập
Câu hỏi và bài tập
8. Trình bày cấp lưu trữ của một đối tượng (auto, register,
static, extern).
9. Khai báo các hàm nguyên mẫu sau:
Câu hỏi và bài tập
10 Chọn câu sai trong các câu sau đây:
11 Chọn câu đúng nhất trong các câu sau đây:
Câu hỏi và bài tập
12. Chọn câu sai trong các câu sau đây:
báo dưới dạng:
A: biến bình thường và tham đối được truyền theo giá trị
B: biến con trỏ và tham đối được truyền theo giá trị
C: biến bình thường và tham đối được truyền theo địa chỉ
D: biến tham chiếu và tham đối được truyền theo giá trị
Câu hỏi và bài tập
Câu hỏi và bài tập
Bài tập thực hành
5. Bài 4, 5, 6, 7, 8 trang 140-141 chương 8 (Câu
lệnh điều kiện và rẽ nhánh)
a. Viết hàm đổi một ký tự hoa sang ký tự thường.
b. Viết thủ tục giải phương trình bậc nhất.
c. Viết thủ tục giải phương trình bậc hai.
d. Viết hàm trả về giá trị nhỏ nhất của 4 số nguyên.
e. Viết thủ tục hoán vị hai số nguyên.
f. Viết thủ tục sắp xếp 4 số nguyên tăng dần.
Bài tập thực hành
6. Bài tập 3 trang 155 chương 9 (Câu lệnh lặp). Hàm
nhận vào một số nguyên dương n và thực hiện:
a. Trả về số đảo của số đó.
b. Có phải là số đối xứng (Trả về True/False)
c. Có phải là số chính phương.
d. Có phải là số nguyên tố.
e. Tổng các chữ số lẻ.
f. Tổng các chữ số nguyên tố.
g. Tổng các chữ số chính phương.
Bài tập thực hành
7. Bài tập 4 trang 156 chương 9 (Câu lệnh lặp). Hàm
nhận vào một số nguyên dương n và thực hiện:
a. S = 1 + 2 + … + n
b. S = 12 + 22 + … + n2
c. S = 1 + 1/2 + … + 1/n
d. S = 1 * 2 * … * n
e. S = 1! + 2! + … + n!
8. Hàm trả về USCLN của 2 số nguyên.
In ra n phần tử của dãy Fibonacy.
9.