Bài giảng Lập trình C - Chương 4: Lập trình hàm - Trần Minh Thái

Khái niệm

Hàm (chương trình con - subroutine) là một khối lệnh, thực hiện trọn vẹn một công việc nhất định (module), được đặt tên và được gọi thực thi nhiều lần tại nhiều vị trí

Khi nào sử dụng hàm?

Khi có một công việc giống nhau cần thực hiện ở nhiều vị trí

Khi cần chia nhỏ chương trình để dễ quản lý

pptx 63 trang yennguyen 2940
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Lập trình C - Chương 4: Lập trình hàm - Trần Minh Thái", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: Bài giảng Lập trình C - Chương 4: Lập trình hàm - Trần Minh Thái

Bài giảng Lập trình C - Chương 4: Lập trình hàm - Trần Minh Thái
Lập trình C  Chương 4. Lập trình hàm(3 tiết) 
Trần Minh Thái 
Email: minhthai@huflit.edu.vn 
Website: www.minhthai.edu.vn 
Cập nhật: 09/11/2016 
Mục tiêu 
Trình bày kỹ thuật lập trình bằng phương pháp thủ tục hàm 
Cách thức phân tích bài toán thành các hàm con 
Giới thiệu về hàm đệ quy 
Cấu trúc chương trình 
Khai báo 
Cài đặt hàm 
Hàm main() 
CHƯƠNG TRÌNH C 
Khai báo thư viện hàm 
Khai báo hàm 
Khai báo hằng số  
Cài đặt tất cả những hàm con 
đã được khai báo 
Gọi thực hiện các hàm theo 
yêu cầu của bài toán 
Xét chương trình nhập vào số nguyên dương n, in ra màn hình các số nguyên tố nhỏ hơn n 
Ví dụ: 
	Nhập n = 10 
	Kết quả in ra màn hình là: 2, 3, 5, 7 
Ví dụ 
int main() 
{ 
	int n; 
	printf( "Nhap so nguyen duong: " ); 
	scanf( "%d" , &n); 
	printf( "Cac so nguyen to nho hon %d la:\n" , n); 
	for ( int so = 2; so < n; so++) 
	{ 
	int d = 0; 
	for ( int i = 1; i <= so; i++) 
	{ 
	if (so%i == 0) 
	d++; 
	} 
	if (d == 2) 
	printf( "%d\t" , so); 
	} 
	getch(); 
	return 0; 
} 
Kiểm tra xem giá trị của so có phải là số nguyên tố? 
int main() 
{ 
	int n; 
	printf( "Cac so nguyen to nho hon %d la:\n" , n); 
	for ( int so = 2; so < n; so++) 
	{ 
	} 
	getch(); 
	 return 0; 
} 
Nhập số nguyên dương n 
Kiểm tra xem so có phải là số nguyên tố không? 
Nếu là số nguyên tố thì in so ra màn hình 
Tham số: dùng để truyền giá trị vào 
void NhapSoNguyen ( int & n ) 
{ 
	printf ( "Nhap so nguyen duong: " ); 
	scanf ( "%d" , & n ); 
} 
int LaSNT ( int k ) 
{ 
	int d = 0; 
	for ( int i = 1; i <= k ; i++) 
	{ 
	if ( k %i == 0) 
	d++; 
	} 
	if (d == 2) 
	 return 1; 
	return 0; 
} 
Hàm LaSNT dùng để kiểm tra một số nguyên k bất kỳ ( được truyền vào từ hàm khác ) có phải là số nguyên tố không? 
- Trả về 1: Nếu k là số nguyên tố 
- Ngược lại trả về 0 
int main () 
{ 
int n; 
NhapSoNguyen (n); 
printf ( "Cac so nguyen to nho hon %d la: \n" , n); 
for ( int so = 2; so < n; so++) 
{ 
	if ( LaSNT (so) == 1 ) 
	printf ( " %d \t" , so); 
} 
getch (); 
return 0; 
} 
Gọi hàm 
Truyền đối số 
Gọi hàm 
Truyền đối số 
Khái niệm 
Hàm (chương trình con - subroutine) là một khối lệnh, thực hiện trọn vẹn một công việc nhất định (module), được đặt tên và được gọi thực thi nhiều lần tại nhiều vị trí 
Khi nào sử dụng hàm? 
Khi có một công việc giống nhau cần thực hiện ở nhiều vị trí 
Khi cần chia nhỏ chương trình để dễ quản lý 
9 
Khái niệm 
Hàm có thể được gọi từ chương trình chính (hàm main) hoặc từ 1 hàm khác 
Hàm có giá trị trả về hoặc không 
Nếu hàm không có giá trị trả về gọi là thủ tục (procedure) 
Khái niệm 
Hàm thư viện : là những hàm đã được xây dựng sẵn. Muốn sử dụng các hàm thư viện phải khai báo thư viện chứa nó trong phần khai báo #include 
Hàm do người dùng định nghĩa 
Mẫu hàm 
Kiểu dữ liệu trả về của hàm (kết quả của hàm/ đầu ra), gồm: 
void : Không trả về giá trị 
float / int / long / char */ kiểu cấu trúc /  : Trả về kết quả tính được với KDL tương ứng 
 TênHàm([ds tham số]); 
Mẫu hàm 
TênHàm: Đặt tên theo qui ước sao cho phản ánh đúng chức năng thực hiện của hàm 
Danh sách các tham số (nếu có): đầu vào của hàm 
Trong một số trường hợp có thể là đầu vào và đầu ra của hàm nếu kết quả đầu ra có nhiều giá trị - Tham số này gọi là tham chiếu, phần này sẽ đề cập sau 
Hàm không trả về giá trị 
Cài đặt 
void TênHàm([danh sách các tham số]) 
{ 
 Khai báo các biến cục bộ 
	 Các câu lệnh / khối lệnh hay lời gọi đến hàm khác. 
} 
Gọi hàm 
TênHàm(danh sách tên các đối số); 
Những phương thức loại này thường rơi vào những nhóm chức năng: Nhập / xuất dữ liệu , thống kê, sắp xếp, liệt kê 
Ví dụ 
Viết chương trình nhập số nguyên dương n và in ra màn hình các ước số của n 
Phân tích bài toán: 
Input: n (Để xác định tham số) 
 KDL: số nguyên dương ( int ). 
Output: In ra các ước số của n (KDL trả về của hàm) 
Xuất ra màn hình Không trả về giá trị KDL của hàm là void 
Xác định tên hàm: Hàm này dùng in ra các ước số của n nên có thể đặt là LietKeUocSo 
void LietKeUocSo(int n); 
#include 
#include 
#pragma warning ( disable : 4996) 
void LietKeUocSo ( int n ) ; 
void LietKeUocSo ( int n ) 
{ 
	 for ( int i = 1; i <= n ; i++) 
	 { 
	if ( n % i == 0) 
	printf ( " %d \t" , i); 
	} 
} 
int main () 
{ 
	int n; 
	printf ( "Nhap so nguyen duong n: " ); 
	scanf ( "%d" , &n); 
	printf ( "Cac uoc so cua %d la: " , n); 
	 LietKeUocSo(n); 
	getch (); 
	return 0; 
} 
Muốn thực thi hàm thì phải gọi hàm 
Hàm có trả về giá trị 
Cài đặt 
 TênHàm([danh sách các tham số]) 
{ 
	 kq; 
 	Khai báo các biến cục bộ 
	Các câu lệnh / khối lệnh hay lời gọi đến hàm khác. 
 	 return kq; 
} 
Hàm có trả về giá trị 
Gọi hàm 
 Tên biến = TênHàm (danh sách tên các đối số); 
Những hàm này thường rơi vào các nhóm: Tính tổng, tích, trung bình, đếm, kiểm tra, tìm kiếm 
Ví dụ 
Viết chương trình nhập số nguyên dương n và tính tổng 
Phân tích bài toán: 
	Input: n (Tham số) 
KDL: số nguyên dương ( int ). 
	Output : Tổng S (KDL phương thức) 
Trả về giá trị của S. 
S là tổng các số nguyên dương nên S cũng là số nguyên dương KDL trả về của hàm là int (hoặc long ). 
	TênHàm : Dùng tính tổng S nên có thể đặt là TinhTong 
int TinhTong(int n); 
#include 
#include 
#pragma warning ( disable : 4996) 
int TinhTong ( int n ); 
int TinhTong ( int n ) 
{ 
int kq = 0; 
for ( int i = 1; i <= n ; i++) 
	kq += i; 
return kq; 
} 
int main () 
{ 
int n, s; 
printf ( "Nhap vao so nguyen n: " ); 
scanf ( "%d" , &n); 
s = TinhTong (n); 
printf ( "Tong tu 1 den n = %d \n" , s); 
getch (); 
return 0; 
} 
Lưu giá trị trả về của hàm TinhTong 
Tầm vực của biến 
Phạm vi khối 
Phạm vi hàm 
Phạm vi tập tin 
Phạm vi chương trình 
Phạm vi khối 
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 đó 
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ộ ( local variable ) 
Phạm vi khối (tt) 
Kết quả 
Gia tri i ben trong khoi: 10 
Gia tri i ben ngoai khoi: 20 
int main () 
{ 
int i = 20; 
{ 
	int i = 10; 
	printf ( "Gia tri i ben trong khoi: %d \n" , i); 
} 
printf ( "Gia tri i ben ngoai khoi: %d " , i); 
getch(); 
return 0; 
} 
Phạm vi hàm 
H oạt động từ đầu đến cuối một hàm , chỉ có tác dụng trong hàm 
int main () 
{ 
int k; 
float m; 
double x; 
//Các lệnh khác 
// 
getch (); 
return 0; 
} 
Phạm vi tập tin 
Biến được khai báo toàn cục và có kèm từ khóa static 
int x = 0; 
static int y = 0; 
static float z = 0.0; 
int main () 
{ 
int i; 
//Các lệnh 
getch (); 
return 0; 
} 
Phạm vi chương trình 
Được khai báo bên ngoài hàm biến toàn cục ( global variable ) 
Không nên “lạm dụng” biến toàn cục nếu không thực sự cần thiết, vì nó sẽ gây khó khăn trong quá trình dò tìm lỗi khi debug chương trình 
int a, b; 
void Nhap () 
{ 
printf ( "Nhap a: " ); 
scanf ( "%d" , &a); 
printf ( "Nhap b: " ); 
scanf ( "%d" , &b); 
} 
int main () 
{ 
int c; 
Nhap (); 
c = a + b; 
printf ( "Tong = %d " , c); 
getch (); 
return 0; 
} 
Vấn đề tham số 
Hay nhap vao so nguyen: 30 
Gia tri n sau khi goi ham nhap: 0 
void Nhap ( int n ) 
{ 
printf ( "Hay nhap vao so nguyen: " ); 
scanf ( "%d" , & n ); 
} 
int main () 
{ 
int n = 0; 
Nhap (n); 
printf ( "Gia tri n sau khi goi ham nhap: %d " , n); 
getch (); 
return 0; 
} 
Tham trị (cục bộ) 
Vấn đề tham số 
Hàm main() 
Hàm Nhap() 
n = 0 
n 
!!! Hai biến n riêng biệt cho hai hàm 
Vấn đề tham số 
Nhu cầu biến n là chung của hai hàm main () và Nhap () 
Khi nhập giá trị n trong hàm Nhap() thì cả hàm main () và hàm Nhap () đều sử dụng chung giá trị Tham chiếu 
Hàm main() 
Hàm Nhap() 
n = 0 
Tham số là tham chiếu 
Tham số làm kết quả đầu ra 
Tham số vừa làm đầu vào và đầu ra 
Dùng dấu & phía trước tên tham số khi cài đặt hàm 
Ví dụ 
Xét chương trình hoán vị 2 số nguyên a, b cho trước 
Viết chương trình với 2 trường hợp 
Trường hợp không dùng tham chiếu 
Trường hợp dùng tham chiếu 
void HoanVi ( int a , int b ) 
{ 
int tam = a ; 
a = b ; 
b = tam; 
printf ( "Trong ham HoanVi: a = %d ; b = %d \n" , a , b ); 
} 
void main () 
{ 
int a = 5, b = 21; 
printf ( "Truoc khi goi ham HoanVi: a = %d ; b = %d \n" , a, b); 
HoanVi (a, b); 
printf ( "Sau khi goi ham HoanVi: a = %d ; b = %d \n" , a, b); 
} 
Kết quả 
Truoc khi goi ham HoanVi: a = 5; b = 21 
Trong ham HoanVi: a = 21; b = 5 
Sau khi goi ham HoanVi: a = 5; b = 21 
Hàm main() 
Hàm HoanVi () 
a = 5, b = 21 
a = 21, b = 5 
Cần phải thay đổi thành tham chiếu 
Hàm main() 
Hàm HoanVi () 
a = 5, b = 21 
void HoanVi ( int & a , int & b ) 
{ 
int tam = a ; 
a = b ; 
b = tam; 
printf ( "Trong ham HoanVi: a = %d ; b = %d \n" , a , b ); 
} 
void main () 
{ 
int a = 5, b = 21; 
printf ( "Truoc khi goi ham HoanVi: a = %d ; b = %d \n" , a, b); 
HoanVi (a, b); 
printf ( "Sau khi goi ham HoanVi: a = %d ; b = %d \n" , a, b); 
} 
Tham chiếu 
Kết quả 
Truoc khi goi ham HoanVi: a = 5; b = 21 
Trong ham HoanVi: a = 21; b = 5 
Sau khi goi ham HoanVi: a = 21; b = 5 
Hàm main() 
Hàm HoanVi () 
a = 5, b = 21 
Thay đổi giá trị a, b của hàm HoanVi() cũng là a, b của hàm main() 
Nguyên tắc xây dựng hàm 
Kết quả của hàm? KDL trả về của hàm 
Hàm làm gì? Xác định tên hàm 
Hàm cần những thông tin gì truyền vào? Tham số 
	Ứng với mỗi thông tin đã xác định, xác định xem đã có giá trị trước khi vào hàm chưa? 
	- Nếu chưa có Tham chiếu 
	- Nếu có mà sau khi thực hiện xong hàm vẫn không thay đổi Tham trị 
	- Nếu có mà sau khi thực hiện xong hàm thì giá trị cũng bị thay đổi theo Tham chiếu 
Bài tập ví dụ 
Viết chương trình tính diện tích và chu vi hình tròn với bán kính là số nguyên được nhập từ bàn phím 
Chương trình gồm các yêu cầu: 
Nhập bán kính hình tròn 
Tính chu vi hình tròn 
Tính diện tích hình tròn 
Xuất kết quả 
Bài tập ví dụ 
Hàm nhập bán kính hình tròn 
Đầu vào: bán kính r (số nguyên), sau khi nhập xong r thì giá trị được nhập và hàm gọi thực hiện phải có cùng giá trị r là tham chiếu 
Đầu ra: không có giá trị trả về KDL trả về của hàm là void 
 Nguyên mẫu hàm: void NhapBanKinh(int &r); 
Bài tập ví dụ 
Hàm tính chu vi hình tròn 
Đầu vào: bán kính r của hình tròn 
Đầu ra: chu vi của hình tròn (số thực – do nhân với pi là số thực) KDL trả về của hàm là float 
 Nguyên mẫu hàm: float TinhChuVi(int r); 
Bài tập ví dụ 
Hàm tính diện tích hình tròn 
Đầu vào: bán kính r của hình tròn 
Đầu ra: diện tích của hình tròn (số thực – do nhân với pi) KDL trả về của hàm là float 
 Nguyên mẫu hàm: float TinhDienTich(int r); 
Bài tập ví dụ 
Hàm xuất kết quả 
Đầu vào: bán kính r của hình tròn 
Đầu ra: xuất chu vi và diện tích của hình tròn Không trả về giá trị KDL trả về của hàm là void 
 Nguyên mẫu hàm: void XuatKetQua(int r); 
Khai báo thư viện và nguyên mẫu hàm 
#include 
#include 
#pragma warning ( disable :4996) 
void NhapBanKinh ( int & r ); 
float TinhChuVi ( int r ); 
float TinhDienTich ( int r ); 
void XuatKetQua ( int r ); 
Cài đặt hàm 
void NhapBanKinh ( int & r ) 
{ 
printf ( "Nhap vao ban kinh hinh tron: " ); 
scanf ( "%d" , & r ); 
} 
float TinhChuVi ( int r ) 
{ 
	return 2 * 3.14 * r ; 
} 
float TinhDienTich ( int r ) 
{ 
	return 3.14* r * r ; 
} 
Cài đặt hàm 
void XuatKetQua ( int r ) 
{ 
float cv = TinhChuVi ( r ); 
float dt = TinhDienTich ( r ); 
printf ( "Chu vi hinh tron ban kinh %d = %f\n " , r , cv); 
printf ( "Dien tich hinh tron ban kinh %d = %f " , r , dt); 
} 
Cài đặt hàm main() 
int main () 
{ 
int r; 
NhapBanKinh (r); 
XuatKetQua (r); 
getch (); 
return 0; 
} 
Bài tập 
1. Viết chương trình tính diện tích và chu vi của hình chữ nhật với chiều dài và chiều rộng là 2 số nguyên dương được nhập từ bàn phím. 
2. Viết chương trình nhập 2 số nguyên a, b. Tìm USCLN và BSCNN của hai số nguyên đó 
3. Nhập vào 3 số nguyên a, b, c và kiểm tra xem chúng có thành lập thành 3 cạnh của một tam giác hay không? Nếu có, hãy tính diện tích, chiều dài mỗi đường cao của tam giác và in kết quả ra màn hình. 
Công thức tính diện tích hình tam giác 
	s = sqrt(p*(p-a)*(p-b)*(p-c) ) 
 với p là nửa chu vi của tam giác 
Công thức tính các đường cao: 
	h a = 2s/a, h b =2s/b, h c =2s/c. 
Bài tập 
Bài tập 
4. Viết chương trình nhập số nguyên dương n, tính tổng các ước số dương của n. 
	 Ví dụ : Nhập n=6	 
	 Tổng các ước số từ 1 đến n: 1+2+3+6=12. 
5. Nhập vào giờ, phút, giây. Kiểm tra xem giờ, phút, giây đó có hợp lệ hay không? In kết quả ra màn hình. 
6. Viết chương trình nhập số nguyên dương n gồm k chữ số, đếm xem n có bao nhiêu chữ số là số nguyên tố. 
7. Viết chương trình tính tiền thuê máy dịch vụ Internet. Với dữ liệu nhập vào là giờ bắt đầu thuê (GBD), giờ kết thúc thuê (GKT), số máy thuê (SoMay). 
Điều kiện cho dữ liệu nhập: 6<=GBD<GKT<=21 ( Giờ là số nguyên ). 
Đơn giá: 2500đ cho mỗi giờ máy trước 17:30 và 3000đ cho mỗi giờ máy sau 17:30. 
Bài tập 
8 . Viết chương trình tính tiền lương ngày cho công nhân, cho biết trước giờ vào ca, giờ ra ca của mỗi người. 
	 Giả sử rằng: 
Tiền trả cho mỗi giờ trước 12 giờ: 6000đ và sau 12 gi ờ : 7500đ. 
Giờ vào ca sớm nhất là 6 giờ sáng và giờ ra ca trễ nhất là 18 giờ (Giờ là số nguyên). 
Bài tập 
Giới thiệu hàm đệ qui 
Một hàm được gọi có tính đệ qui nếu trong thân của hàm đó có lệnh gọi lại đến chính nó một cách tường minh hay tiềm ẩn. 
Phân loại đệ qui 
Đệ qui tuyến tính. 
Đệ qui nhị phân. 
Đệ qui phi tuyến. 
Đệ qui hỗ tương. 
Đệ qui tuyến tính 
Trong thân hàm có duy nhất một lời gọi hàm gọi lại chính nó 	một cách tường minh. 
 TenHam () 
{ 
	if (điều kiện dừng) 
	{ 
	. . . 
	//Trả về giá trị hay kết thúc công việc	 
	} 
	//Thực hiện một số công việc (nếu có) 
	. . . TenHam (); 
	//Thực hiện một số công việc (nếu có) 
} 
Ví dụ 
Ví dụ : Tính 
- Điều kiện dừng: S(0) = 0. 
- Qui tắc (công thức) tính: S(n) = S(n-1) + n. 
long TongS (int n) 
{ 
	if(n==0) 
	return 0; 
	return TongS(n-1) + n; 
} 
Đệ qui nhị phân 
Trong thân của hàm có hai lời gọi hàm gọi lại chính nó một cách tường minh. 
 TenHam () 
{ 
	if (điều kiện dừng) 
	{ 
	. . . 
	//Trả về giá trị hay kết thúc công việc	 
	} 
	//Thực hiện một số công việc (nếu có) 
	. . . TenHam (); //Giải quyết vấn đề nhỏ hơn 
	//Thực hiện một số công việc (nếu có) 
	. . . TenHam (); //Giải quyết vấn đề còn lại 
	//Thực hiện một số công việc (nếu có) 
} 
Ví dụ: Tính số hạng thứ n của dãy Fibonaci được định nghĩa như sau: 
f 1 = f 0 =1 ;	 
f n = f n-1 + f n-2­ ;	 	(n>1) 
Điều kiện dừng: f(0) = f(1) = 1. 
long Fibonaci (int n) 
{ 
	if(n==0 || n==1) 
	return 1; 
	return Fibonaci(n-1) + Fibonaci(n-2); 
} 
Đệ qui phi tuyến 
 TenHam () 
{ 
	for (int i = 1; i<=n; i++) 
	{	//Thực hiện một số công việc (nếu có) 
	if (điều kiện dừng) 
	{	. . . 
	//Trả về giá trị hay kết thúc công việc	 
	} 
	else 
	{	//Thực hiện một số công việc (nếu có) 
	TenHam (); 
	} 
	} 
} 
Ví dụ: Tính số hạng thứ n của dãy {X n } được định nghĩa như sau: 
X 0 =1 ;	 
X n = n 2 X 0 + (n-1) 2 X 1 +  + 1 2 X n-1­ ;	(n≥1) 
Điều kiện dừng:X(0) = 1. 
long TinhXn (int n) 
{ 
	if(n==0) 
	return 1; 
	long s = 0; 
	for (int i=1; i<=n; i++) 
	s = s + i * i * TinhXn(n-i); 
	return s; 
} 
Đệ qui phi tuyến 
Đệ qui hỗ tương 
Trong thân của hàm này có lời gọi hàm đến hàm kia và trong thân của hàm kia có lời gọi hàm tới hàm này. 
 TenHam2 (); 
 TenHam1 () 
{ 
//Thực hiện một số công việc (nếu có) 
TenHam2 (); 
//Thực hiện một số công việc (nếu có) 
} 
 TenHam2 () 
{ 
//Thực hiện một số công việc (nếu có) 
TenHam1 (); 
//Thực hiện một số công việc (nếu có) 
} 
Ví dụ: Tính số hạng thứ n của hai dãy {X n }, {Y n } được định nghĩa như sau: 
X 0 =Y 0 =1 ;	 
X n = X n-1 + Y n-1 ;	(n>0) 
Y n = n 2 X n-1 + Y n-1 ;	(n>0) 
- Điều kiện dừng: X(0) = Y(0) = 1. 
long TinhYn(int n); 
long TinhXn (int n) 
{ 
	if(n==0) 
	return 1; 
	return TinhXn(n-1) + TinhYn(n-1); 
} 
long TinhYn (int n) 
{ 
	if(n==0) 
	return 1; 
	return n*n*TinhXn(n-1) + TinhYn(n-1); 
} 
Cách hoạt động hàm đệ qui 
Ví dụ tính n! với n=5 
Q&A 

File đính kèm:

  • pptxbai_giang_lap_trinh_c_chuong_4_lap_trinh_ham_tran_minh_thai.pptx