Bài giảng Nhập môn Lập trình C - Chương 6: Hàm (Function) - Trần Thị Kim Chi

1. Khái niệm và cú pháp 2. Tầm vực 3. Tham số và lời gọi hàm 4. Đệ quy Đặt vấn đề 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.

ppt74 trang | Chia sẻ: candy98 | Lượt xem: 885 | Lượt tải: 0download
Bạn đang xem trước 20 trang tài liệu Bài giảng Nhập môn Lập trình C - Chương 6: Hàm (Function) - Trần Thị Kim Chi, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Nội dungNMLT - Hàm (Function)Khái niệm và cú pháp1Tầm vực2Tham số và lời gọi hàm3Đệ quy4Đặt vấn đề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.NMLT - Hàm (Function)Chương trìnhchínhNhậpa, b, c > 0TínhS = a! + b! + c!Xuấtkết quả SNhậpa > 0Nhậpb > 0Nhậpc > 0Tínhs1=a!Tínhs2=b!Tínhs3=c!Đặt vấn đề3 đoạn lệnh nhập a, b, c > 0NMLT - Hàm (Function)do { printf(“Nhap mot so nguyen duong: ”); scanf(“%d”,&a);} while (a 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Đoạn lệnh tính giai thừa tổng quát, n = a, b, cNMLT - Hàm (Function)do { printf(“Nhap mot so nguyen duong: ”); scanf(“%d”,&n);} while (n .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.NMLT - Hàm (Function)HàmCú phápTrong đó : 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.NMLT - Hàm (Function) ([danh sách tham số]){ [return ;]}Các bước viết hàmCầ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ó).NMLT - Hàm (Function)Tên hàmĐầu vào 1Đầu vào 2Đầu vào nĐầu ra (nếu có)Các công việcsẽ thực hiệnHàmVí dụ 1Tên hàm: XuatTongCô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óNMLT - Hàm (Function)void XuatTong(int x, int y){ int s; s = x + y; printf(“%d+%dy=%dx“,x,y,s);}HàmVí dụ 2Tên hàm: TinhTongCô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 + yNMLT - Hàm (Function)int TinhTong(int x, int y){ int s; s = x + y; return s;}Chương trình con - FunctionVí dụ 3Tên hàm: NhapXuatTongCô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óNMLT - Hàm (Function)void NhapXuatTong(){ int x, y; printf(“Nhap 2 so nguyen: ”); scanf(“%d%d”,&x,&y); printf(“%d+%dy=%dx“,x,y,x+y);}Tầm vựcKhái niệmLà 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ó.NMLT - Hàm (Function)Tầm vựcNMLT - Hàm (Function)int a; int Ham1() { int a1; } int Ham2() { int a2; { int a21; } } void main() { int a3; }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.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àyTổ chức một chương trình “C/C++”Cách 1: chương trình gồm 3 phầnPHẦN KHAI BÁO TOÀN CỤCPHẦN KHAI BÁO VÀ ĐỊNH NGHĨA HÀMHÀ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ỤCPHẦN KHAI BÁO HÀM NGUYÊN MẪUHÀM main()PHẦN ĐỊNH NGHĨA HÀMVí dụ: cách 1#include int min(int a, int b){ if (aint min(int a, int b); //prototypevoid main(){ int a=40, b=30; int min1 = min(a,b); printf(“Min = %d“,min1);}int min(int a, int b){ if (avoid doubleNum(int a); //prototypevoid main(){ int a=40; doubleNum(a); printf(“Bên trong hàm main:\n”); printf(“a = %d“, a);}void doubleNum(int a){ a = a*2; printf(“Inside doubleNum function. a = %d“,a);}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ếuhay void Swap(int & a,int & b); // truyền bằng tham chiếuTruyề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.NMLT - Hàm (Function)void TruyenDiaChi(int *x){ *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.NMLT - Hàm (Function)void TruyenThamChieu(int &x){ x++;}Các phương pháp truyền tham sốCác phương pháp truyền tham sốVí dụ: Khảo sát chương trình sau#include void doubleNum(int a); //prototypevoid main(){ int a=40; doubleNum(a); printf(“Inside main function:\n”); printf(“a =%d “ , a);}void doubleNum(int &a){ a = a*2; printf(“Inside doubleNum function. a = %d“, a);}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.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.NMLT - Hàm (Function)void HonHop(int x, int &y){ x++; 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.NMLT - Hàm (Function)int TinhTong(int x, int y){ return x + y;}void TinhTong(int x, int y, int &tong){ tong = x + y;}void TinhTongHieu(int x, int y, int &tong, int &hieu){ tong = x + y; hieu = x – y;}Lời gọi hàmCách thực hiệnGọ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 ( ) (, , );NMLT - Hàm (Function)Lời gọi hàmVí dụNMLT - Hàm (Function){ Các hàm được khai báo ở đây }void main(){ 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);}Lời gọi chương trình conVí dụNMLT - Hàm (Function)void HoanVi(int &a, int &b);void main(){ HoanVi(2912, 1706); int x = 2912, y = 1706; HoanVi(x, y);}void HoanVi(int &a, int &b){ int tam = a; a = b; b = tam;}3. Hàm gọi đệ qui: một lệnh trong thân hàm gọi đến chính nó. Số lần 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.#include int giaiThua(int n);void main(){ int gt4, gt7; gt4 = giaiThua(4); gt7 = giaiThua(7); cout b thì UCLN(a, b) = UCLN(a-b, b)− nếu a 0{ if (a b) UCLN(a-b, b);}Đệ quyVí 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;}Đệ quyNạ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ị 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(){ 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}Một số gợi ý khi thiết kế hàmXá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.Một số gợi ý khi thiết kế hàmXá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.Phạm vi (scope) của các đối tượngPhạ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)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;}Phạm vi (scope) của các đối tượngVí dụ:  1:  /* Scopes in nested block */2:  #include 3:4:  main()5:  {6:     int i = 32;   /* block scope 1*/7:8:     cout4:  int x = 1234;         /* program scope */5:  double y = 1.234567;  /* program scope */7:  void function_1()8:  {9:     coutint x=3; // biến x toàn cụcconst int MAX = 10;void fct(int x);void main(){ int x=1; // x cục bộ của hàm main() fct(x);{ int y=4; x += y;}cout Các tập tin nguyên mẫu của thư viện C++, chứa trong thư mục Borlandc\Include 2: #include “đường dẫn\tệp” 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. Các chỉ thị tiền xử lýb. Chỉ thị macro #defineCú pháp: #define tên_macro xaukituTrướ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ụ:#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 1if (i 8 cout b? a: b);}Thư viện 2. tên tệp: MATHFUNC.H#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; cout b? a: b);}#endifCâu hỏi và bài tập Nêu cách khai báo hàm, định nghĩa hàm, cách gọi hàm.Phạm vi của một đối tượng (biến, hằng) trong chương trình ?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ỏ)Nêu cách thiết kế hàm mà theo Anh (Chị) cho là đạt yêu cầu.Cho ví dụ về hàm xuất/nhập.Cho ví dụ về hàm kiểm tra một giá trị nguyên thỏa tính chất “P” nào đó.Cho ví dụ về hàm xác định giá trị nguyên thỏa tính chất “P” nào đó.Trình bày cách tổ chức một chương trình “C/C++”.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:− 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 dạng n = 120 = 2*2*2*3*5.− 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.Câu hỏi và bài tập 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 xongC: 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 returnB: Phải có ít nhất 1 câu lệnh return cho hàmC: Các câu lệnh return được phép nằm ở vị trí bất kỳ trong thân hàmD: 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 returnCâu hỏi và bài tập 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àmB: 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ọiD: 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àm13. Để 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ị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:#include void mul(int&,int,int&);int main( ) { int x = 4, y = 3, z = 2; mul( y, z, x ); cout void f( int x, int & y, int z );void g( int & x, int y, int & z );int main() { int x = 2, y = 3, z = 4; f( y, z, x ); cout << "\nX = " << x; cout << "\nY = " << y; cout << "\nZ = " << z; return 0;}void f( int x, int & y, int z ){ g( z, y, x ); x += y; y += z; z += x;}void g( int & a, int b, int & c ) { a *= b; b *= c; c *= a;}Bài tập thực hànhBài 4, 5, 6, 7, 8 trang 140-141 chương 8 (Câu lệnh điều kiện và rẽ nhánh)Viết hàm đổi một ký tự hoa sang ký tự thường.Viết thủ tục giải phương trình bậc nhất.Viết thủ tục giải phương trình bậc hai.Viết hàm trả về giá trị nhỏ nhất của 4 số nguyên. Viết thủ tục hoán vị hai số nguyên.Viết thủ tục sắp xếp 4 số nguyên tăng dần.NMLT - Hàm (Function)Bài tập thực hànhBà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:Trả về số đảo của số đó.Có phải là số đối xứng (Trả về True/False)Có phải là số chính phương.Có phải là số nguyên tố.Tổng các chữ số lẻ. Tổng các chữ số nguyên tố.Tổng các chữ số chính phương.NMLT - Hàm (Function)Bài tập thực hànhBà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:S = 1 + 2 + + nS = 12 + 22 + + n2S = 1 + 1/2 + + 1/nS = 1 * 2 * * nS = 1! + 2! + + n!Hàm trả về USCLN của 2 số nguyên.In ra n phần tử của dãy Fibonacy.NMLT - Hàm (Function)