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ý
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
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:
- bai_giang_lap_trinh_c_chuong_4_lap_trinh_ham_tran_minh_thai.pptx