Bài giảng Kỹ thuật lập trình - Chương 3: Hàm và thư viện

pdf 51 trang cucquyet12 3850
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Kỹ thuật lập trình - Chương 3: Hàm và thư viện", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfbai_giang_ky_thuat_lap_trinh_chuong_3_ham_va_thu_vien.pdf

Nội dung text: Bài giảng Kỹ thuật lập trình - Chương 3: Hàm và thư viện

  1. Kỹ thuật lập trình Phần II: Lập trình có cấu trúc ng 1 ươ 010101010101010110000101010101010101011000010101010101010101100001 Chương3: HStateControlleràmvàth010101010010101010010101010101001010101001010101010100101010100101ư viện start() 101001100011001001001010100110001100100100101010011000110010010010 Ch stop() 110010110010001000001011001011001000100000101100101100100010000010 010101010101010110000101010101010101011000010101010101010101100001 010101010010101010010101010101001010101001010101010100101010100101 N Ơ 101001100011001001001010100110001100100100101010011000110010010010y = A*x + B*u; 110010110010001000001011001011001000100000101100101100100010000010x = C*x + d*u; LQGController010101010101010110000101010101010101011000010101010101010101100001 start() 010101010010101010010101010101001010101001010101010100101010100101 stop() 101001100011001001001010100110001100100100101010011000110010010010 110010110010001000001011001011001000100000101100101100100010000010 9/14/2005 2004, HOÀNG MINH S ©
  2. Nộidung chương 3 3.1 Hàm và lậptrìnhhướng hàm 3.2 Khai báo, ₫ịnh nghĩahàm 3.3 Truyềnthamsố và trả về kếtquả 3.4 Thiếtkế hàm và thư viện 3.5 Thư việnchuẩnANSI-C 3.6 Làm việcvớitệptin sử dụng thư việnC++ 3.7 Nạpchồng tên hàm C++ N Ơ 3.8 Hàm inline trong C++ Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 2 © 2005 - HMS ©
  3. 3.1 Hàm và lậptrìnhhướng hàm Lậptrìnhcócấutrúccóthể dựatrênmộttronghaiphương pháp: ƒ Lậptrìnhhướng hàm (function-oriented), còn gọilàhướng nhiệm vụ (task-oriented), hướng thủ tục(procedure-oriented) NV 1 NV 1a NV 1b Nhiệmvụ NV 2 NV 2a NV 2b NV 2c NV 3 NV 3 ƒ Lậptrìnhhướng dữ liệu(data-oriented) N Ơ DL 1 DL 1 DL 2 DL 2 DL 3 DL 3 Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 3 © 2005 - HMS ©
  4. Hàm là gì? ƒ Tiếng Anh: function -> hàm, chứcnăng ƒ Một ₫ơnvị tổ chứcchương trình, một ₫oạnmã chương trình có cấutrúc₫ể thựchiệnmột chức năng nhất ₫ịnh, có giá trị sử dụng lại ƒ Các hàm có quan hệ với nhau thông qua lờigọi, các biếnthamsố (₫ầuvào, ₫ầu ra) và giá trị trả về ƒ Cách thựchiệncụ thể mộthàmphụ thuộcnhiềuvào dữ kiện(thamsố, ₫ốisố củahàm): — Thông thường, kếtquả thựchiệnhàmmỗilần ₫ềugiống N nhau nếu các tham số₫ầuvàonhư nhau Ơ —Một hàm không có tham số thì giá trị sử dụng lạirấtthấp ƒ Trong C/C++: Không phân biệtgiữathủ tụcvàhàm, cả₫oạnmãchương trình chính cũng là hàm Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 4 © 2005 - HMS ©
  5. Ví dụ phân tích ƒ Yêu cầu bài toán: Tính tổng mộtdãysố nguyên (liên tục) trong phạmvi do ngườisử dụng nhập. In kếtquả ra màn hình. ƒ Các nhiệmvụ: —Nhậpsố nguyên thứ nhất: z Yêu cầungườisử dụng nhập z Nhậpsố vào mộtbiến —Nhậpsố nguyên thứ hai z Yêu cầungườisử dụng nhập z Nhậpsố vào mộtbiến N Ơ —Tínhtổng vớivònglặp —Hiểnthị kếtquả ra màn hình Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 5 © 2005 - HMS ©
  6. Phương án 4 trong 1 #include void main() { int a, b; char c; do { cout > a; cout > b; int Total = 0; for (int i = a; i > c; } while (c == 'y' || c == 'Y'); } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 6 © 2005 - HMS ©
  7. Phương án phân hoạch hàm (1) #include int ReadInt(); int SumInt(int,int); void WriteResult(int a, int b, int kq); void main() { char c; do { int a = ReadInt(); int b = ReadInt(); int T = SumInt(a,b); WriteResult(a,b,T); N cout > c; } while (c == 'y' || c == 'Y'); } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 7 © 2005 - HMS ©
  8. Phương án phân hoạch hàm (1) int ReadInt() { Không có tham số, cout > N; return N; } OK, Không thể tốthơn! int SumInt(int a, int b) { int Total = 0; for (int i = a; i <= b; ++i) Total += i; Quá nhiềuthamsố, return Total; Hiệunăng? } N Ơ void WriteResult(int a, int b, int kq) { cout << "The sum from " << a << " to " << b << " is " << kq << endl; } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 8 © 2005 - HMS ©
  9. Phương án phân hoạch hàm (1) ƒ Chương trình dễ₫ọchơn => dễ phát hiệnlỗi ƒ Chương trình dễ mở rộng hơn ƒ HàmSumIntcóthể sử dụng lạitốt ƒ Mã nguồndàihơn ƒ Mã chạylớnhơn ƒ Chạychậmhơn  Không phảicứ phân hoạch thành nhiềuhàmlàtốt, N Ơ mà vấn ₫ề nằm ở cách phân hoạch và thiếtkế hàm làm sao cho tối ưu! Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 9 © 2005 - HMS ©
  10. Phương án phân hoạch hàm (2) #include int ReadInt(const char*); int SumInt(int,int); void main() { char c; do { int a = ReadInt("Enter the first integer number :"); int b = ReadInt("Enter the second integer number:"); cout > c; } while (c == 'y' || c == 'Y'); } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 10 © 2005 - HMS ©
  11. Phương án phân hoạch hàm (2) int ReadInt(const char* userPrompt) { cout > N; return N; OK, } Đãtốthơn! int SumInt(int a, int b) { int Total = 0; for (int i = a; i <= b; ++i) Total += i; return Total; N }Ơ Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 11 © 2005 - HMS ©
  12. 3.2 Khai báo và ₫ịnh nghĩahàm ƒ Định nghĩahàm: tạomãthựcthihàm Kiểutrả về Tên hàm Tham biến (hình thức) int SumInt(int a, int b) { int Total = 0; for (int i = a; i <= b; ++i) Total += i; return Total; } ƒ Khai báo hàm thuần túy: không tạomãhàm int SumInt(int a, int b); N Ơ Kiểutrả về Tên hàm Kiểuthambiến ƒ Tại sao và khi nào cần khai báo hàm? Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 12 © 2005 - HMS ©
  13. Khai báo hàm và lờigọihàm ƒ Ý nghĩacủa khai báo hàm: —Khicầnsử dụng hàm (gọihàm) —Trìnhbiêndịch cầnlời khai báo hàm ₫ể kiểmtralờigọihàm ₫úng hay sai về cú pháp, về số lượng các tham số, kiểucác tham số và cách sử dụng giá trị trả về. int SumInt(int a, int b); —Cóthể khai báo hàm ₫ộclậpvớiviệc ₫ịnh nghĩahàm(tất nhiên phải ₫ảmbảonhất quán) ƒ Gọihàm: yêucầuthựcthimãhàmvớithamsố thực tế (tham trị) N Khi biên dịch chưacần Ơ int x = 5; phảicó₫ịnh nghĩa int k = SumInt(x, 10); hàm, nhưng phảicó Tên hàm Tham số (gọihàm) khai báo hàm! Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 13 © 2005 - HMS ©
  14. Khai báo hàm C/C++ ở₫âu? ƒ Ở phạmvi toàncục(ngoàibấtcứ hàm nào) ƒ Mộthàmphải ₫ượckhaibáotrướclờigọi ₫ầutiên trong mộttệptin mãnguồn ƒ Nếusử dụng nhiềuhàmthìsẽ cầnrấtnhiều dòng mã khai báo (mất công viết, dễ saivàmãchương trình lớnlên?): —Nếungườixâydựng hàm (₫ịnh nghĩahàm) ₫ưasẵntấtcả phần khai báo vào trong mộttệptin => Header file (*.h, *.hx, ) thì ngườisử dụng chỉ cầnbổ sung dòng lệnh N #include Ơ —Mãchương trình không lớnlên, bởi khai báo không sinh mã! ƒ Mộthàmcóthể khai báo nhiềulầntùyý! Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 14 © 2005 - HMS ©
  15. Định nghĩahàmở₫âu? ƒ Ở phạm vi toàn cục(ngoàibấtcứ hàm nào) ƒ Có thể₫ịnh nghĩa trong cùng tệptin vớimãchương trình chính, hoặctáchramộttệp tin riêng. Trong Visual C++: *.c => C compiler, *.cpp => C++ compiler ƒ Mộthàm₫ãcólờigọithìphải ₫ược ₫ịnh nghĩa chính xác 1 lần trong toàn bộ (dự án) chương trình, trướckhigọitrìnhliênkết (lệnh Build trong Visual C++) ƒ Đưatệptin mãnguồnvàodự án, không nên: #include “xxx.cpp” ƒ Mộthàmcó₫ược ₫ịnh nghĩabằng C, C++, hợpngữ hoặcbằng mộtngônngữ khác và dùng trong C/C++ => Sử dụng hàm N Ơ không cầnmãnguồn! ƒ Mộtthư viện cho C/C++ bao gồm: — Header file (thường ₫uôi *.h, *.hxx, , nhưng không bắtbuộc) —Tệptin mãnguồn(*.c, *.cpp, *.cxx, ) hoặcmã₫ích (*.obj, *.o, *.lib, *.dll, ) Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 15 © 2005 - HMS ©
  16. 3.3 Truyềnthamsố và trả về kếtquả ƒ Truyềnthamsố và trả về kếtquả là phương pháp cơ bản ₫ể tổ chứcquanhệ giữacáchàm(giữacácchứcnăng trong hệ thống) Hàm A Hàm B a d Tham số Giá trị trả Tham số Giá trị trả (₫ầu vào) b về hoặc (₫ầu vào) về hoặc ee c tham số ra tham số ra ƒ Ngoài ra, còn có các cách khác: —Sử dụng biếntoàncục: nói chung là không nên! —Sử dụng các tệp tin, streams: dù sao vẫnphảisử dụng tham số₫ể nói rõ tệp tin nào, streams nào N —Cáccơ chế giao tiếphệ thống khác (phụ thuộcvàohệ₫iều hành, Ơ nềntảng và giao thứctruyền thông) => nói chung vẫncần các tham số bổ sung ƒ Truyềnthamsố & trả về kếtquả là mộtvấn ₫ề cốtlõitrongxây dựng và sử dụng hàm, mộttrongnhững yếutốảnh hưởng quyết ₫ịnh tớichấtlượng phầnmềm! Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 16 © 2005 - HMS ©
  17. Tham biếnhìnhthức và tham số thựctế int SumInt(int a, int b) { } Tham biến (hình thức) int x = 5; int k = SumInt(x, 10); Tham số Kếtquả trả về (thựctế) (không tên) SumInt x a int a = 2; k N Ơ k = SumInt(a,x); 5 b Biến ₫ượcgán kếtquả trả về Tham biến Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 17 © 2005 - HMS ©
  18. 3.3.1 Truyềngiátrị int SumInt(int, int); // Function call void main() { int x = 5; SP int k = SumInt(x, 10); b = 10 a = 5 SP } k =k 45 x = 5 // Function definition Ngănxếp int SumInt(int a, int b) { N Ơ } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 18 © 2005 - HMS ©
  19. Thử ví dụ₫ọctừ bàn phím #include void ReadInt(const char* userPrompt, int N) { cout > N; } void main() { int x = 5; ReadInt("Input an integer number:", x); cout << "Now x is " << x; N }Ơ ƒ Kếtquả: x không hề thay ₫ổisau₫ó. Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 19 © 2005 - HMS ©
  20. Truyềngiátrị ƒ Truyềngiátrị là cách thông thường trong C ƒ Tham biếnchỉ nhận ₫ượcbảnsaocủabiến ₫ầuvào (tham số thựctế) ƒ Thay ₫ổithambiếnchỉ làm thay ₫ổivùngnhớ cụcbộ, không làm thay ₫ổibiến ₫ầuvào ƒ Tham biếnchỉ có thể mang tham số₫ầu vào, không chứa ₫ượckếtquả (tham số ra) ƒ Truyềngiátrị khá an toàn, tránh ₫ượcmộtsố hiệu N ứng phụ Ơ ƒ Truyềngiátrị trong nhiềutrường hợpkémhiệuquả do mất công sao chép dữ liệu Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 20 © 2005 - HMS ©
  21. 3.3.2 Truyền ₫ịachỉ int SumInt(int* p, int N); // Function call void main() { SP int a[] = {1, 2, 3, 4}; k =k 45 int k = SumInt(a,4); N=4 p=00A0 SP } k =k 45 a[3]=4 a[2]=3 // Function definition a[1]=2 int SumInt(int* p, int N) { a[0]=1 N int *p2 = p + N, k = 0; 00A0 Ơ while (p < p2) k += *p++; return k; } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 21 © 2005 - HMS ©
  22. Truyềnmảng tham số? int SumInt(int p[4], int N); // Function call void main() { int a[] = {1, 2, 3, 4}; Bảnchấtnhư int k = SumInt(a,4); trong ví dụ trước: Truyền ₫ịachỉ! } // Function definition int SumInt(int p[4], int N) { N int *p2 = p + N, k = 0; Ơ while (p < p2) k += *p++; return k; } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 22 © 2005 - HMS ©
  23. Thử lạivídụ₫ọctừ bàn phím #include void ReadInt(const char* userPrompt, int* pN) { cout > *pN; } void main() { int x = 5; ReadInt("Input an integer number:", &x); cout << "Now x is " << x; N Ơ } ƒ Kếtquả: x thay ₫ổigiátrị sau ₫ó(cũng là lý do tạisaohàm scanf() lạiyêucầukiểuthambiếnlàcon trỏ!) Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 23 © 2005 - HMS ©
  24. Khi nào sử dụng truyền ₫ịachỉ? ƒ Khi cầnthay₫ổi"biến ₫ầuvào" (truynhậptrựctiếp vào ô nhớ, không qua bảnsao) ƒ Khi kích cỡ kiểudữ liệulớn=> tránhsaochépdữ liệu vào ngănxếp ƒ Truyềnthamsố là mộtmảng => bắtbuộctruyền ₫ịa chỉ ƒ Lưuý: Sử dụng con trỏ₫ểtruyền ₫ịachỉ của vùng N nhớ dữ liệu ₫ầuvào. Bảnthâncon trỏ có thể thay ₫ổi Ơ ₫ược trong hàm nhưng ₫ịachỉ vùng nhớ không thay ₫ổi(nội dung của vùng nhớ₫óthay₫ổi ₫ược): xem ví dụ biến p trong hàm SumInt trang 21. Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 24 © 2005 - HMS ©
  25. 3.3.3 Truyền tham chiếu (C++) #include void ReadInt(const char* userPrompt, int& N) { cout > N; } void main() { int x = 5; ReadInt("Input an integer number:", x); cout << "Now x is " << x; N Ơ } ƒ Kếtquả: x thay ₫ổigiátrị sau ₫ó Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 25 © 2005 - HMS ©
  26. Thử ví dụ hàm swap #include void swap(int& a, int& b) { int temp = a; a = b; b = temp; } void main() { int x = 5, y = 10; swap(x,y); N Ơ cout << "Now x is " << x << ", y is " << y; } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 26 © 2005 - HMS ©
  27. Khi nào sử dụng truyền tham chiếu? ƒ Chỉ trong C++ ƒ Khi cầnthay₫ổi"biến ₫ầuvào" (truynhậptrựctiếp vào ô nhớ, không qua bảnsao) ƒ Mộtthambiếnthamchiếucóthể₫óng vai trò là ₫ầu ra (chứakếtquả), hoặccóthể vừalà₫ầuvàovà₫ầu ra ƒ Khi kích cỡ kiểudữ liệulớn=> tránhsaochépdữ liệu vào ngănxếp, ví dụ: void copyData(const Student& sv1, Student& sv2) { N Ơ sv2.birthday = sv1.birthday; } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 27 © 2005 - HMS ©
  28. 3.3.4 Kiểutrả về ƒ Kiểutrả về: gầnnhư tùy ý, chỉ không thể trả về trực tiếpmộtmảng ƒ Về nguyên tắc, có thể trả về kiểu: —Giátrị —Con trỏ —Thamchiếu ƒ Tuy nhiên, cầnrấtthậntrọng vớitrả về₫ịachỉ hoặc tham chiếu: — Không bao giờ trả về con trỏ hoặc tham chiếu vào biếncục bộ N Ơ — Không bao giờ trả về con trỏ hoặc tham chiếu vào tham biếntruyềnqua giátrị ƒ Vớingườilập trình ít có kinh nghiệm: chỉ nên trả về kiểugiátrị Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 28 © 2005 - HMS ©
  29. Cơ chế trả về int SumInt(int a, int b) { int k = 0; for (int i=a; i 45 } b = 10 a = 5 SP void main() { k k= =045 int x = 5, k = 0; x = 5 k = SumInt(x,10); Ngănxếp N Ơ } 45 Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 29 © 2005 - HMS ©
  30. Trả về con trỏ ƒ Viếthàmtrả về₫ịachỉ củaphầntử lớnnhấttrongmộtmảng: int* FindMax(int* p, int n) { int *pMax = p; int *p2 = p + n; while (p *pMax) pMax = p; ++p; } return pMax; } N voidƠ main() { int s[5] = { 1, 2, 3, 4, 5}; int *p = FindMax(s,5); } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 30 © 2005 - HMS ©
  31. Lý do trả về con trỏ hoặc tham chiếu ƒ Tương tự như lý do truyền ₫ịachỉ hoặctruyềntham chiếu: —Tránhsaochépdữ liệulớnkhôngcầnthiết — Để có thể truy cậptrựctiếpvàthay₫ổigiátrị₫ầura ƒ Có thể trả về con trỏ hoặcthamchiếuvào₫âu? — Vào biếntoàncục — Vào tham số truyền cho hàm qua ₫ịachỉ hoặcqua tham chiếu — Nói chung: vào vùng nhớ mà còn tiếptụctồntại sau khi kết N Ơ thúc hàm ƒ Con trỏ lạiphứctạpthêmmột chút? Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 31 © 2005 - HMS ©
  32. Phảnvídụ: trả về con trỏ int* f(int* p, int n) { int Max = *p; int *p2 = p + n; while (p Max) Max = *p; ++p; } return &Max; } N void main() { Ơ int s[5] = { 1, 2, 3, 4, 5}; int *p = FindMax(s,5); // get invalid address } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 32 © 2005 - HMS ©
  33. Các ví dụ nghiên cứu: Đúng / sai? int* f1(int a) { int f5(int *pa) { return &a; return *pa; } } int& f2(int &a) { int& f6(int *pa) { return a; return *pa; } } int f3(int &a) { int& f7(int a) { return a; return a; } } N int*Ơ f4(int *pa) { int *pa; int* f8() { return pa; } return pa; } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 33 © 2005 - HMS ©
  34. 3.4 Thiếtkế hàm và thư viện ƒ Viếtmộtchương trình chạytốt ₫ãkhó, viếtmộtthư việnhàmtốtcònkhóhơn! ƒ Mộtthư việnhàm₫ịnh nghĩa: —mộttậphợp các hàm (có liên quan theo mộtchủ₫ềchức năng) —những kiểudữ liệusử dụng trong các hàm —mộtsố biếntoàncục(rấthạnchế) ƒ Mộtthư việnhàmtốtcầnphải: —Thựchiệnnhững chứcnăng hữuích N Ơ — Đơngiản, dễ sử dụng —Hiệusuấtvà₫ộ tin cậycao —Trọnvẹn, nhấtquánvà₫ồng bộ Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 34 © 2005 - HMS ©
  35. Thiếtkế hàm ƒ Phân tích yêu cầu: — Làm rõ các dữ kiện(₫ầuvào) vàkếtquả (₫ầura) — Tìm ra các chứcnăng cầnthựchiện ƒ Đặt tên hàm: ngắngọn, ý nghĩaxác₫áng, tự miêu tả —Hàmchỉ hành ₫ộng: Chọntênhàmlàmột ₫ộng từ kếthợpvớikiểu ₫ốitượng chủ thể, ví dụ printVector, displayMatrix, addComplex, sortEventQueue, filterAnalogSignal, — Hàm truy nhậpthuộc tính: Có thể chọnlà₫ộng từ hoặcdanhtừ kết hợpkiểu ₫ốitượng chủ thể, ví dụ length, size, numberOfColums, getMatrixElem, putShapeColor — Trong C++ nhiềuhàmcóthể giống tên (nạpchồng tên hàm), có thể N chọntênngắn, ví dụ sort, print, display, add, putColor, getColor => Ơ nguyên tắc ₫a hình/₫axạ theo quan ₫iểmhướng ₫ốitượng — Trong C++ còn có thể₫ịnh nghĩa hàm toán tử₫ểcó thể sử dụng các ký hiệutoántử₫ịnh nghĩasẵnnhư *, /, +, - thay cho lờigọihàm. Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 35 © 2005 - HMS ©
  36. ƒ Chọnthamsố₫ầuvào(=> thambiến) — Đặctả ý nghĩa: Thể hiệnrõvaitròthamsố — Đặt tên: Ngắngọn, tự mô tả —Chọnkiểu: Kiểunhỏ nhấtmà₫ủ biểudiễn —Chọncáchtruyềnthamsố: cân nhắcgiữatruyềngiátrị hay truyền ₫ịachỉ/tham chiếuvàokiểuhằng ƒ Chọnthamsố₫ầura(=> thambiếntruyềnqua ₫ịachỉ/qua tham chiếuhoặcsử dụng giá trị trả về) — Đặctả ý nghĩa, ₫ặttên, chọnkiểutương tự như tham số₫ầuvào ƒ Định nghĩabổ sung các kiểudữ liệumớinhư cầnthiết ƒ Mô tả rõ tiềntrạng (pre-condition): ₫iềukiệnbiênchocáctham số₫ầuvàovàcác₫iềukiệnngoạicảnh cho việcgọihàm ƒ Mô tả rõ hậutrạng (post-condition): tác ₫ộng củaviệcsử dụng N Ơ hàm tớingoạicảnh, các thao tác bắtbuộc sau này, ƒ Thiếtkế thân hàm dựavàocácchứcnăng ₫ã phân tích, sử dụng lưu ₫ồ thuậttoánvớicáccấutrúc₫iềukiện/rẽ nhánh (kể cả vòng lặp) => có thể phân chia thành các hàm con nếucần Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 36 © 2005 - HMS ©
  37. Ví dụ minh họa: Tìm số nguyên tố Bài toán: Xây dựng hàm tìm N số nguyên tố₫ầutiên! ƒ Phân tích: —Dữ kiện: N - số số nguyên tố₫ầutiêncầntìm —Kếtquả: Một dãy N số nguyên tố₫ầutiên —Cácchứcnăng cầnthựchiện: z Nhậpdữ liệu? KHÔNG! z Kiểmtradữ kiện vào (N)? Có/không (NếukiểmtramàN nhỏ hơn0 thìhàmlàmgì?) z Cho biếtk số nguyên tố₫ầutiên, xác₫ịnh số nguyên tố tiếp theo N z Lưutrữ kếtquả mỗilầntìmravàomộtcấutrúcdữ liệuphù Ơ hợp(dãysố cầntìm) z In kếtquả ra màn hình? KHÔNG! Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 37 © 2005 - HMS ©
  38. ƒ Đặt tên hàm: findPrimeSequence ƒ Tham số vào: 1 —Ý nghĩa: số các số nguyên tố cầntìm —Tên: N —Kiểu: số nguyên ₫ủ lớn(int/long) —Truyềnthamsố: qua giá trị ƒ Tham số ra: 1 —Ý nghĩa: dãy N số nguyên tố₫ầu tiên tính từ 1 —Giátrị trả về hay tham biến? Tham biến! —Tên: primes —Kiểu: mảng số nguyên (của int/long) —Truyềnthamsố: qua ₫ịachỉ (int* hoặc long*) ƒ Tiềntrạng: N Ơ —Thamsố N phảilàsố không âm (có nên chọnkiểu unsigned?) – primes phảimang₫ịachỉ củamảng số nguyên có ít nhấtN phầntử ƒ Hậutrạng: không có gì ₫ặcbiệt Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 38 © 2005 - HMS ©
  39. ƒ Khai báo hàm: void findPrimeSequence(int N, int* primes); ƒ Thiếtkế thân hàm Start —Lưu ₫ồ thuậttoánnhư hình vẽ false N>0 —Phânchia, bổ sung một hàm mới: findNextPrime true primes[0]=1 ƒ Lặplạiqui trìnhthiếtkế k=1 hàm cho findNextPrime (Bài tậpvề nhà!) false k<N N true Ơ primes[k]=findNextPrime ++k Stop Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 39 © 2005 - HMS ©
  40. 3.5 Thư việnchuẩn ANSI-C ƒ Thư việnvào/ra(nhập/xuất) ƒ Xử lý ký tự và chuỗikýtự , ƒ Thư viện hàm toán , ƒ Thời gian, ngày tháng , ƒ Cấpphátbộ nhớ₫ộng ƒ Các hàm ký tự rộng , ƒ Các hàm khác , N Ơ Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 40 © 2005 - HMS ©
  41. 3.6 Làm việcvớitệptin trong C++ #include #include ƒ Khai báo mộtbiến: ifstream fin; // input ofstream fout; // output fstream fio; // input and output ƒ Mở/tạomộttệptin: fin.open("file1.txt"); fout.open("file2.dat"); fio.open("file3.inf"); N ƒƠ Kếthợp khai báo biếnvàmở/tạomộttệptin ifstream fin("file1.txt"); // input ofstream fout("file2.inf");// output fstream fio("file3.dat"); // input and output Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 41 © 2005 - HMS ©
  42. ƒ Ghi dữ liệuratệptin —Tương tự như sử dụng cout —Tệptin cóthể chứadữ liệukiểuhỗnhợp, ví dụ: fout > age >> married; ƒ Đóng mộttệptin: —Tự₫ộng khi kết thúc phạm vi { }, N Ơ —Hoặcgọi hàm thành viên close(): fin.close(); fout.close(); fio.close(); Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 42 © 2005 - HMS ©
  43. Ví dụ: làm việcvớitệptin #include #include void main() { { ofstream fout("file1.dat");// output fout > age >> married; cout > c; } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 43 © 2005 - HMS ©
  44. 3.7 Nạpchồng tên hàm trong C++ ƒ Trong C++ có thể xây dựng nhiều hàm có cùng tên, ví dụ: int max(int a, int b); double max(double a, double b); double max(double a, double b, double c); double max(double *seq, int n); ƒ Mục ₫ích của nạpchồng tên hàm là: — Đơngiảnhóachongườixâydựng hàm trong việcchọntên (thay vì maxInt, maxDouble, maxDouble3, N maxDoubleSequence, ) Ơ — Đơngiảnhóachongườisử dụng hàm, chỉ cầnnhớ 1 tên quen thuộc thay cho nhiềutênphứctạp Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 44 © 2005 - HMS ©
  45. Ví dụ: ₫ịnh nghĩa các hàm max() int max(int a, int b) { // (1) return (a > b)? a : b; } double max(double a, double b) { // (2) return (a > b)? a : b; } double max(double a, double b, double c); { // (3) if (a < b) a = b; if (a < c) a = c; return a; } double max(double *seq, int n) { // (4) int i = 0, kq = seq[0]; while (i < n) { N Ơ if (kq < seq[i])kq = seq[i]; ++i; } return kq; } Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 45 © 2005 - HMS ©
  46. Ví dụ: sử dụng các hàm max() int max(int a, int b); // (1) double max(double a, double b); // (2) double max(double a, double b, double c); // (3) double max(double *seq, int n); // (4) void main() { int k = max(5,7); // call (1) double d = max(5.0,7.0); // call (2) double a[] = {1,2,3,4,5,6}; d = max(d, a[1], a[2]); // call (3) d = max(a, 5); // call (4) d = max(5,7); // ? d = max(d, 5); // ? N }Ơ Â Đẩy trách nhiệmkiểmtravàtìmhàmphùhợpcho compiler! Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 46 © 2005 - HMS ©
  47. Mộtsố qui tắcvề nạpchồng tên hàm ƒ Các hàm cùng tên ₫ược ₫ịnh nghĩacùngtrong mộtfile/ trongmộtthư viện hoặc sử dụng trong cùng mộtchương trình phảikhácnhauítnhấtvề: —Số lượng các tham số, hoặc —Kiểucủaítnhấtmộtthamsố (int khác short, const int khác int, int khác int&, )  Không thể chỉ khác nhau ở kiểutrả về ƒ Tạisaovậy? — Compiler cầncócơ sở₫ểquyết ₫ịnh gọihàmnào N —Dựa vào cú pháp trong lờigọi(số lượng và kiểucácthamsố Ơ thựctế) compiler sẽ chọn hàm có cú pháp phù hợpnhất —Khicần compiler có thể tự₫ộng chuyển ₫ổikiểu theo chiều hướng hợplýnhất (vd short=>int, int => double) Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 47 © 2005 - HMS ©
  48. 3.8 Hàm inline trong C++ ƒ Vấn ₫ề: Hàm tiệndụng, nhưng nhiều khi hiệusuất không cao, ₫ặcbiệt khi mã thựcthihàmngắn —Cácthủ tụcnhư nhớ lạitrạng thái chương trình, cấpphátbộ nhớ ngănxếp, sao chép tham số, sao chép giá trị trả về, khôi phụctrạng thái chương trình mấtnhiềuthờigian —Nếumãthực thi hàm ngắnthìsự tiệndụng không bõ so vớisự lãng phí thờigian ƒ GiảipháptrongC: Sử dụng macro, ví dụ #define max(a,b) a>b?a:b —Vấn ₫ề: Macro do tiềnxử lý chạy (preprocessor), không có kiểmtra kiểu, không có phân biệtngữ cảnh => gây ra các hiệu ứng phụ không mong muốn N Ơ Ví dụ dòng lệnh l=max(k*5-2,l); sẽ₫ượcthaythế bằng l=k*5-2>k?k*5-2:l; // OOPS! —Những cách giảiquyếtnhư thêm dấungoặcchỉ làm mã khó ₫ọc, không khắcphụctriệt ₫ể các nhược ₫iểm Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 48 © 2005 - HMS ©
  49. Giảipháphàm inline trong C++ ƒ Điều duy nhấtcần làm là thêm từ khóa inline vào ₫ầudòngkhaibáovà₫ịnh nghĩahàm int max(int a, int b) { return (a > b)? a : b; } ƒ Hàm inline khác gì hàm bình thường: — "Hàm inline" thựcchất không phảilàmộthàm! —Khigọihàmthìlờigọihàm₫ược thay thế một cách thông minh bởimãnguồn ₫ịnh nghĩahàm, không thựchiện các thủ tụcgọihàm N Ví dụ: Ơ l=max(k*5-2,l); Đượcthaythế bằng các dòng lệnh kiểunhư: int x=k*5-2; // biếntạm trung gian l=(x>l)?x:l; // OK Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 49 © 2005 - HMS ©
  50. Khi nào nên dùng hàm inline ƒ Ưu ₫iểmcủahàminline: —Tiệndụng như hàm bình thường —Hiệusuấtnhư viếtthẳng mã, không gọihàm —Tin cậy, an toàn hơnnhiềuso vớisử dụng Macro ƒ Nhược ₫iểmcủa hàm inline: —Nếugọi hàm nhiềulầntrongchương trình, mã chương trình có thể lớnlênnhiều(mãthựchiệnhàmxuấthiệnnhiềulần trong chương trình) —Mã₫ịnh nghĩahàmphải ₫ể mở => ₫ưa trong header file ƒ Lựachọnxâydựng và sử dụng hàm inline khi: N Ơ —Mã₫ịnh nghĩahàmnhỏ (một vài dòng lệnh, không chứa vòng lặp) —Yêucầuvề tốc ₫ộ ₫ặtratrước dung lượng bộ nhớ Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 50 © 2005 - HMS ©
  51. Bài tậpvề nhà ƒ Xây dựng hàm tìm N số nguyên tố₫ầutiên —Hoànthiệnthiếtkế hàm — Định nghĩahàm ƒ Viếtchương trình minh họacáchsử dụng N Ơ Ch2004, HOÀNG MINH S ương 3: Hàm và thư viện 51 © 2005 - HMS ©