Kỹ thuật lập trình - Chương 3: Hàm và thư viện
3.1 Hàmvàlậptrìnhhướnghàm
3.2 Khaibáo, ₫ịnhnghĩahàm
3.3 Truyềnthamsốvàtrảvềkếtquả
3.4 Thiếtkếhàmvàthưviện
3.5 ThưviệnchuẩnANSI-C
3.6 LàmviệcvớitệptinsửdụngthưviệnC++
3.7 NạpchồngtênhàmC++
3.8 Hàminline trongC++
l,... — Hàm truy nhập thuộc tính: Có thể chọn là ₫ộng từ hoặc danh từ kết hợp kiểu ₫ối tượng chủ thể, ví dụ length, size, numberOfColums, getMatrixElem, putShapeColor — Trong C++ nhiều hàm có thể giống tên (nạp chồng tên hàm), có thể chọn tên ngắn, ví dụ sort, print, display, add, putColor, getColor => nguyên tắc ₫a hình/₫a xạ theo quan ₫iểm hướng ₫ối tượng — Trong C++ còn có thể ₫ịnh nghĩa hàm toán tử ₫ể có thể sử dụng các ký hiệu toán tử ₫ịnh nghĩa sẵn như *, /, +, - thay cho lời gọi hàm. 36 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện Chọn tham số ₫ầu vào (=> tham biến) — Đặc tả ý nghĩa: Thể hiện rõ vai trò tham số — Đặt tên: Ngắn gọn, tự mô tả — Chọn kiểu: Kiểu nhỏ nhất mà ₫ủ biểu diễn — Chọn cách truyền tham số: cân nhắc giữa truyền giá trị hay truyền ₫ịa chỉ/tham chiếu vào kiểu hằng Chọn tham số ₫ầu ra (=> tham biến truyền qua ₫ịa chỉ/qua tham chiếu hoặc sử dụng giá trị trả về) — Đặc tả ý nghĩa, ₫ặt tên, chọn kiểu tương tự như tham số ₫ầu vào Định nghĩa bổ sung các kiểu dữ liệu mới như cần thiết Mô tả rõ tiền trạng (pre-condition): ₫iều kiện biên cho các tham số ₫ầu vào và các ₫iều kiện ngoại cảnh cho việc gọi hàm Mô tả rõ hậu trạng (post-condition): tác ₫ộng của việc sử dụng hàm tới ngoại cảnh, các thao tác bắt buộc sau này,... Thiết kế thân hàm dựa vào các chức năng ₫ã phân tích, sử dụng lưu ₫ồ thuật toán với các cấu trúc ₫iều kiện/rẽ nhánh (kể cả vòng lặp) => có thể phân chia thành các hàm con nếu cần 37 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện 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ố ₫ầu tiên! Phân tích: — Dữ kiện: N - số số nguyên tố ₫ầu tiên cần tìm — Kết quả: Một dãy N số nguyên tố ₫ầu tiên — Các chức năng cần thực hiện: z Nhập dữ liệu? KHÔNG! z Kiểm tra dữ kiện vào (N)? Có/không (Nếu kiểm tra mà N nhỏ hơn 0 thì hàm làm gì?) z Cho biết k số nguyên tố ₫ầu tiên, xác ₫ịnh số nguyên tố tiếp theo z Lưu trữ kết quả mỗi lần tìm ra vào một cấu trúc dữ liệu phù hợp (dãy số cần tìm) z In kết quả ra màn hình? KHÔNG! 38 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện Đặt tên hàm: findPrimeSequence Tham số vào: 1 — Ý nghĩa: số các số nguyên tố cần tìm — Tên: N — Kiểu: số nguyên ₫ủ lớn (int/long) — Truyền tham số: 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ền tham số: qua ₫ịa chỉ (int* hoặc long*) Tiền trạng: — Tham số N phải là số không âm (có nên chọn kiểu unsigned?) – primes phải mang ₫ịa chỉ của mảng số nguyên có ít nhất N phần tử Hậu trạng: không có gì ₫ặc biệt 39 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện Khai báo hàm: void findPrimeSequence(int N, int* primes); Start N>0 primes[0]=1 k=1 k<N primes[k]=findNextPrime ++k Stop false true true false Thiết kế thân hàm — Lưu ₫ồ thuật toán như hình vẽ — Phân chia, bổ sung một hàm mới: findNextPrime Lặp lại qui trình thiết kế hàm cho findNextPrime (Bài tập về nhà!) 40 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện 3.5 Thư viện chuẩn ANSI-C Thư viện vào/ra (nhập/xuất) Xử lý ký tự và chuỗi ký tự , Thư viện hàm toán , Thời gian, ngày tháng , Cấp phát bộ nhớ ₫ộng Các hàm ký tự rộng , Các hàm khác , ... 41 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện 3.6 Làm việc với tệp tin trong C++ #include #include Khai báo một biến: ifstream fin; // input ofstream fout; // output fstream fio; // input and output Mở/tạo một tệp tin: fin.open("file1.txt"); fout.open("file2.dat"); fio.open("file3.inf"); Kết hợp khai báo biến và mở/tạo một tệp tin ifstream fin("file1.txt"); // input ofstream fout("file2.inf");// output fstream fio("file3.dat"); // input and output 42 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện Ghi dữ liệu ra tệp tin — Tương tự như sử dụng cout — Tệp tin có thể chứa dữ liệu kiểu hỗn hợp, ví dụ: fout << "Nguyen Van A" << endl; fout << 21 << endl << false; Đọc dữ liệu từ một tệp tin — Tương tự như sử dụng cin char name[32]; int age, married; fin.getline(name,32); fin >> age >> married; Đóng một tệp tin: — Tự ₫ộng khi kết thúc phạm vi { }, — Hoặc gọi hàm thành viên close(): fin.close(); fout.close(); fio.close(); 43 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện Ví dụ: làm việc với tệp tin #include #include void main() { { ofstream fout("file1.dat");// output fout << "Nguyen Van A" << endl << 21 << endl << false; } { ifstream fin("file1.dat"); // input char name[32]; int age; int married; fin.getline(name,32); fin >> age >> married; cout << "Name:\t" << name << endl; cout << "Age:\t" << age << endl; cout << "Married:" << (married ? "Yes" : "No"); } char c; cin >> c; } 44 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện 3.7 Nạp chồ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ạp chồng tên hàm là: — Đơn giản hóa cho người xây dựng hàm trong việc chọn tên (thay vì maxInt, maxDouble, maxDouble3, maxDoubleSequence,...) — Đơn giản hóa cho người sử dụng hàm, chỉ cần nhớ 1 tên quen thuộc thay cho nhiều tên phức tạp 45 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện 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) { if (kq < seq[i])kq = seq[i]; ++i; } return kq; } 46 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện 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); // ? } Â Đẩy trách nhiệm kiểm tra và tìm hàm phù hợp cho compiler! 47 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện Một số qui tắc về nạp chồng tên hàm Các hàm cùng tên ₫ược ₫ịnh nghĩa cùng trong một file/ trong một thư viện hoặc sử dụng trong cùng một chương trình phải khác nhau ít nhất về: — Số lượng các tham số, hoặc — Kiểu của ít nhất một tham số (int khác short, const int khác int, int khác int&, ...) Â Không thể chỉ khác nhau ở kiểu trả về Tại sao vậy? — Compiler cần có cơ sở ₫ể quyết ₫ịnh gọi hàm nào — Dựa vào cú pháp trong lời gọi (số lượng và kiểu các tham số thực tế) compiler sẽ chọn hàm có cú pháp phù hợp nhất — Khi cần compiler có thể tự ₫ộng chuyển ₫ổi kiểu theo chiều hướng hợp lý nhất (vd short=>int, int => double) 48 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện 3.8 Hàm inline trong C++ Vấn ₫ề: Hàm tiện dụng, nhưng nhiều khi hiệu suất không cao, ₫ặc biệt khi mã thực thi hàm ngắn — Các thủ tục như nhớ lại trạng thái chương trình, cấp phát bộ nhớ ngăn xếp, sao chép tham số, sao chép giá trị trả về, khôi phục trạng thái chương trìnhmất nhiều thời gian — Nếu mã thực thi hàm ngắn thì sự tiện dụng không bõ so với sự lãng phí thời gian Giải pháp trong C: Sử dụng macro, ví dụ #define max(a,b) a>b?a:b — Vấn ₫ề: Macro do tiền xử lý chạy (preprocessor), không có kiểm tra kiểu, không có phân biệt ngữ cảnh => gây ra các hiệu ứng phụ không mong muốn Ví dụ dòng lệnh l=max(k*5-2,l); sẽ ₫ược thay thế bằng l=k*5-2>k?k*5-2:l; // OOPS! — Những cách giải quyết như thêm dấu ngoặc chỉ làm mã khó ₫ọc, không khắc phục triệt ₫ể các nhược ₫iểm 49 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện Giải pháp hàm inline trong C++ Điều duy nhất cần làm là thêm từ khóa inline vào ₫ầu dòng khai báo và ₫ịnh nghĩa hàm inline 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ực chất không phải là một hàm! — Khi gọi hàm thì lời gọi hàm ₫ược thay thế một cách thông minh bởi mã nguồn ₫ịnh nghĩa hàm, không thực hiện các thủ tục gọi hàm Ví dụ: l=max(k*5-2,l); Được thay thế bằng các dòng lệnh kiểu như: int x=k*5-2; // biến tạm trung gian l=(x>l)?x:l; // OK 50 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện Khi nào nên dùng hàm inline Ưu ₫iểm của hàm inline: — Tiện dụng như hàm bình thường — Hiệu suất như viết thẳng mã, không gọi hàm — Tin cậy, an toàn hơn nhiều so với sử dụng Macro Nhược ₫iểm của hàm inline: — Nếu gọi hàm nhiều lần trong chương trình, mã chương trình có thể lớn lên nhiều (mã thực hiện hàm xuất hiện nhiều lần trong chương trình) — Mã ₫ịnh nghĩa hàm phải ₫ể mở => ₫ưa trong header file Lựa chọn xây dựng và sử dụng hàm inline khi: — Mã ₫ịnh nghĩa hàm nhỏ (một vài dòng lệnh, không chứa vòng lặp) — Yêu cầu về tốc ₫ộ ₫ặt ra trước dung lượng bộ nhớ 51 © 2 0 0 4 , H O À N G M I N H S Ơ N Chương 3: Hàm và thư viện Bài tập về nhà Xây dựng hàm tìm N số nguyên tố ₫ầu tiên — Hoàn thiện thiết kế hàm — Định nghĩa hàm Viết chương trình minh họa cách sử dụng
File đính kèm:
- C3_Functions_and_Library.pdf