&

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 đó

: kiểu bất kỳ của C (char, int, long,

float,…). Nếu không trả về thì là void.

: theo quy tắc đặt tên định danh. • : tham số hình thức đầu vào

giống khai báo biến, cách nhau bằng dấu ,

: trả về cho hàm qua lệnh return.

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)