Bài giảng Tin học đại cương - Bài 5: Chương trình con - Nguyễn Thị Phương Thảo

HÀM DO NGƯỜI DÙNG ĐỊNH NGHĨA • C++ cho phép người lập trình tự viết hàm của riêng mình • Xây dựng các khối chương trình ◦ Thành các phần nhỏ để dễ thực hiện ◦ Dễ đọc và sửa lỗi ◦ Có thể sử dụng lại • Định nghĩa hàm có thể nằm: ◦ Cùng file với hàm main(), hoặc ◦ Trong file riêng rẽ để những người khác cũng có thể sử dụng

pdf55 trang | Chia sẻ: thanhle95 | Lượt xem: 397 | Lượt tải: 1download
Bạn đang xem trước 20 trang tài liệu Bài giảng Tin học đại cương - Bài 5: Chương trình con - Nguyễn Thị Phương Thảo, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
TIN ĐẠI CƯƠNG Bài 5: CHƯƠNG TRÌNH CON Nguyễn Thị Phương Thảo Bộ môn KTMT và M, Khoa CNTT Trường Đại học Thủy Lợi Nội dung chính 1. Giới thiệu về hàm (chương trình con) 2. Truyền tham số cho hàm 3.Phạm vi của biến (scope) 4. Bài tập Giới thiệu về hàm 3 • Xây dựng các khối cho chương trình • Cách gọi trong các ngôn ngữ khác ◦ Thủ tục, chương trình con, phương thức ◦ Trong C++: hàm • I-P-O ◦ Đầu vào - Xử lý - Đầu ra ◦ Là các thành phần cơ bản của mỗi chương trình ◦ Sử dụng hàm cho mỗi thành phần này Hàm định nghĩa trước • Trong các thư viện có sẵn rất nhiều hàm • Hai kiểu hàm: ◦ Hàm trả về giá trị ◦ Hàm không trả về giá trị (void) • Phải khai báo #include thư viện phù hợp khi dùng hàm định nghĩa trước trong chương trình 4 Lời gọi hàm 6 • Xét lệnh gán: a= fabs(-4.2); ◦ Biểu thức “fabs(-4.2)” được hiểu như là một lời gọi hàm ◦ Đối số trong lời gọi hàm (-4.2) có thể là một literal, một biến, hoặc một biểu thức • Lời gọi có thể là một phần của biểu thức: ◦ VD: bonus = sqrt(a*2+13)/10; ◦ Dựa vào kiểu trả về của hàm để biết nơi được phép sử dụng lời gọi hàm Một số hàm định nghĩa trước • #include , thư viện gồm các hàm: ◦ abs() // Trả về giá trị tuyệt đối của một số int ◦ labs() // Trả về giá trị tuyệt đối của một số long int ◦ fabs() // Trả về giá trị tuyệt đối của một số float • Hàm pow(x, y): Trả về x mũ y ◦ VD: Cho biết kết quả in ra của đoạn mã lệnh double result, x = 3.0, y = 2.0; result = pow(x, y); cout << result; 9 rMột số hàm toán học 10 rMột số hàm toán học Hàm void định nghĩa trước • Không trả về giá trị • Thực hiện một hành động, nhưng không gửi câu trả lời • Khi được gọi, bản thân nó là một câu lệnh VD: exit(1); //Không trả về giá trị, do vậy không được sử dụng để gán • Các khía cạnh khác tương tự như hàm trả về giá trị 12 HÀM DO NGƯỜI DÙNG ĐỊNH NGHĨA 16 • C++ cho phép người lập trình tự viết hàm của riêng mình • Xây dựng các khối chương trình ◦ Thành các phần nhỏ để dễ thực hiện ◦ Dễ đọc và sửa lỗi ◦ Có thể sử dụng lại • Định nghĩa hàm có thể nằm: ◦ Cùng file với hàm main(), hoặc ◦ Trong file riêng rẽ để những người khác cũng có thể sử dụng Các thành phần của hàm 17 • Khai báo hàm/nguyên mẫu hàm ◦ Thông tin cho trình biên dịch ◦ Thông dịch chính xác lời gọi • Định nghĩa hàm ◦ Sự thực thi hay mã lệnh thực hiện công việc của hàm • Lời gọi hàm ◦ Chuyển điều khiển cho hàm Vị trí đặt định nghĩa hàm • Đặt sau hàm main(), không nằm bên trong hàm main() • Các hàm là bình đẳng, không hàm nào là thành phần của hàm khác • Các tham số hình thức trong định nghĩa Giữ chỗ cho dữ liệu gửi vào Sử dụng tên biến để tham chiếu tới dữ liệu trong định nghĩa • Lệnh return Trả dữ liệu về cho lời gọi 20 ([Danh sách các tham số]); Trong đó: - Kiểu trả về: là kiểu dữ liệu của giá trị mà hàm trả về - Tên hàm: là tên thực sự của hàm, - Danh sách các tham số: các tham số cần thiết để thực hiện hàm. (Một hàm có thể có tham số hoặc không) Ví dụ: Khai báo hàm tính tổng hai số nguyên int tinhtong (int so1, int so2); HÀM TRẢ VỀ GIÁ TRỊ - KHAI BÁO HÀM Cấu trúc: ([Danh sách các tham số ])//tiêu đề { Thân hàm } Trong đó: Tiêu đề tương tự như khai báo, không có dấu “;” Thân hàm bao gồm tập hợp các lệnh xác định những gì mà hàm thực hiện. HÀM TRẢ VỀ GIÁ TRỊ- ĐỊNH NGHĨA HÀM Ví dụ: Định nghĩa hàm tính tổng đã được khai báo ở trên int tinhtong (int so1, int so2) { int tong; tong = so1+so2; return tong; } HÀM TRẢ VỀ GIÁ TRỊ - VÍ DỤ Định nghĩa hàm có phần tiêu đề tương tự như phần khai báo chỉ khác là không có dấu “;” Định nghĩa hàm phải liệt kê tên các tham số sau tên hàm Hàm trả về giá trị luôn luôn có lệnh return. Giá trị trả về của hàm được xác định khi lệnh return được thực thi Mọi câu lệnh sau lệnh return đều không được thực thi. Nếu định nghĩa hàm đầy đủ được đặt trước lời gọi đến nó thì khai báo hàm có thể bỏ đi HÀM TRẢ VỀ GIÁ TRỊ - CÁC CHÚ Ý Khi muốn sử dụng hàm, lập trình viên phải gọi hàm bằng cách sử dụng lời gọi hàm Lời gọi hàm được sử dụng như một biểu thức trong câu lệnh (không được gọi như một câu lệnh độc lập) Hàm có thể được gọi bất cứ khi nào (sau khi có khai báo hoặc định nghĩa) Khi gọi hàm các đối số được truyền tới các tham số theo thứ tự của nó và cần đảm bảo sự đồng nhất về kiểu dữ liệu Cần lưu trữ các giá trị trả về của hàm. HÀM TRẢ VỀ GIÁ TRỊ - GỌI HÀM HÀM TRẢ VỀ GIÁ TRỊ - VÍ DỤ #include using namespace std; int tinhtong(int so1, int so2);//khai bao ham int main() { int a =6; int b =7; //a,b la cac gia triduoc truyen vao cac tham bien khi goi ham int ketqua;//dung de luu gia tri tra ve cua ham ketqua = tinhtong(a,b);//goi ham cout<<"tong 2 so "<<a<< " va "<< b<< " la: "<<ketqua; return 0; } int tinhtong(int so1, int so2)//dinh nghia ham { int tong; tong = so1+so2; return tong; } HÀM TRẢ VỀ GIÁ TRỊ - VÍ DỤ #include using namespace std; int tinhtong(int so1, int so2)//dinh nghia ham { int tong; tong = so1+so2; return tong; } //int tinhtong(int so1, int so2); Khi dinh nghia ham dat truoc loi goi no thi khong Bài tập Bài 1: Viết hàm tính tổng sau: 𝑆 = 1 + 1 2 + 1 3 +⋯+ 1 𝑛 Viết chương trình sử dụng hàm để tính tổng S với n được nhập vào từ bàn phím Bài 2: Viết hàm kiểm tra số nguyên tố Viết chương trình sử dụng hàm để xác định xem một số nguyên n được nhập vào từ bàn phím có phải số nguyên tố không? Bài 3: Viết hàm kiểm tra số hoàn chỉnh Viết chương trình sử dụng hàm để xác định xem một số nguyên n được nhập vào từ bàn phím có phải số hoàn chỉnh không? Tương tự như hàm trả về giá trị chỉ khác ở một số điểm sau: Sử dụng từ khóa void trong phần khai báo kiểu dữ liệu trả về của hàm (hiểu là không có giá trị nào được trả về). Lời gọi hàm kết thúc bởi dấu “;” (dùng như câu lệnh độc lập Việc gọi hàm void giống như copy thân hàm vào chương trình ở vị trí lời gọi hàm xuất hiện Trong hàm void, lệnh return là tùy chọn (không bắt buộc phải có) HÀM VOID Khai báo hàm: void ([Danh sách các tham số]); Ví dụ: Khai báo hàm in ra số lớn nhất trong 2 số void in_so_max (int so1, int so2); Định nghĩa hàm: void in_so_max (int so1, int so2) {//thân hàm if (so1>so2) cout<<“so lon nhat trong 2 so la:”<<so1; else cout<<“so lon nhat trong 2 so la:”<<so2; } HÀM VOID HÀM VOID - GỌI HÀM , của hàm  Nguyên tắc đặt tên giống như cách đặt tên biến  Nên đặt tên hàm thể hiện được nội dung công việc mà hàm làm  Là danh sách các biến cần trao đổi giữa hàm và bên ngoài  Danh sách các tham số có thể rỗng Ví dụ : void hello() { cout << "Hello world!" ; } Hàm trả về giá trị Cách 1 Hàm trả về giá trị Cách 2 HÀM VOID - GỌI HÀM Khai báo hàm thay thế • Khai báo hàm cung cấp thông tin cho bộ biên dịch • Bộ biên dịch chỉ cần biết: Giá trị trả về Tên hàm Danh sách tham số • Không cần tên tham số hình thức: float TBC(float, float); • Tuy nhiên vẫn nên đưa vào cho dễ đọc 24 Hàm gọi hàm • Ví dụ: hàm main() gọi tới các hàm khác • Khai báo hàm phải xuất hiện trước lời gọi hàm • Hàm có thể gọi đến chính nó “Đệ quy” 25 HÀM VOID • Khai báo hàm/nguyên mẫu hàm: void Tên hàm(); Kiểu trả về là “void”, nghĩa là không trả về gì • Định nghĩa hàm: Tương tự như hàm trả về giá trị nhưng không có câu lệnh return 27 Gọi hàm void • Giống như gọi hàm void định nghĩa trước • Thực hiện như một câu lệnh độc lập Chú ý: Không sử dụng để gán, vì không có giá trị trả về • Các đối số thực sự Được truyền cho hàm. Khi đó, hàm được gọi để thực hiện công việc với dữ liệu được truyền 29 Câu lệnh return  Chuyển điều khiển về cho lời gọi hàm Phải có câu lệnh return nếu kiểu trả về khác void Thường là câu lệnh cuối cùng trong định nghĩa hàm 30 Hàm main() • main() là một hàm trong chương trình • Chỉ tồn tại duy nhất một hàm main() trong một chương trình • Hàm main() được gọi bởi hệ điều hành • Nó thường có câu lệnh return Giá trị được trả về cho hệ điều hành • Nên trả về “int” hoặc “void” 31 Khối lệnh • Khai báo dữ liệu bên trong lệnh kép Lệnh kép được gọi là một “khối” và có “phạm vi khối” • Các định nghĩa hàm đều là khối Tạo ra “phạm vi hàm” cục bộ • Khối lặp: for (int ctr=0;ctr<10;ctr++) { sum+=ctr; } Biến crt chỉ có phạm vi trong khối thân vòng lặp • Các biến có cùng tên được phép khai báo trong nhiều khối 34  Truyền tham trị Cú pháp: ( tên biến) Ví dụ: float TrungBinhCong(float x, float y) ; Truyền tham trị không làm thay đổi giá trị của các biến được truyền  Truyền tham chiếu Cú pháp : (& tên biến) Ví dụ: float TrungBinhCong(float& x, float& y) ; Khi truyền tham chiếu, những tác động lên biến tham chiếu bên trong hàm có ảnh hưởng đến biến được truyền  Có thể khai báo cả tham trị và tham chiếu trong danh sách Ví dụ : float TrungBinhCong(float& x, float y) ; 3. Tham chiếu và tham trị Tham số truyền giá trị (tham trị) • Bản sao của đối số thực sự được truyền • Là “biến cục bộ” bên trong hàm • Nếu sửa đổi, chỉ “bản sao cục bộ” thay đổi Hàm không truy cập tới “đối số thực sự” từ lời gọi • Đây là phương pháp mặc định: Được sử dụng trong tất cả các ví dụ phía trước 36 Ví dụ 39 1. Viết hàm in ra số lớn nhất trong 2 số nguyên 2. Viết hàm đổi chỗ 2 số nguyên Ví dụ truyền giá trị 39 Lỗi thường gặp khi truyền giá trị • Khai báo lại tham số bên trong hàm double fee(int hoursWorked, int minutesWorked) { int quarterHours; // local variable int minutesWorked // Báo lỗi } • Đối số khi truyền theo tham trị giống như “biến cục bộ”, nhưng hàm tự động có nó mà không cần khai báo 40 Tham số truyền tham chiếu • Cung cấp truy cập đến đối số thực sự của lời gọi • Dữ liệu của lời gọi có thể được sửa đổi bởi hàm được gọi • Thường được sử dụng cho hàm đầu vào • Xác định bằng dấu &, sau khi nhập danh sách tham số hình thức • Tham chiếu quay về đối số thực sự của lời gọi ◦ Trỏ đến vùng nhớ của đối số thực sự ◦ Được gọi là “địa chỉ”, là một số duy nhất trỏ đến một vùng riêng biệt của bộ nhớ 41 Ví dụ truyền tham chiếu 42 Tham số tham chiếu hằng • Sử dụng đối số tham chiếu có nhiều rủi ro ◦ Dữ liệu của lời gọi có thể bị thay đổi ◦ Đôi khi chúng ta không mong muõn điều này • Để bảo vệ dữ liệu, và vẫn truyền tham chiếu ◦ Sử dụng từ khóa const void sendConstRef( const int &par 1,const int &par2); ◦ Tạo đối số “chỉ đọc” bởi hàm ◦ Không cho phép thay đổi bên trong thân hàm 45 Danh sách tham số trộn • Kết hợp các kỹ thuật truyền, bao gồm các tham số truyền giá trị và truyền tham biến • Trật tự của các đối số trong danh sách là rất quan trọng: 46 Danh sách tham số trộn • Lời gọi hàm: 46  Truyền tham trị: là truyền giá trị của tham số  Khi hàm được gọi, chương trình sẽ khởi tạo các ô nhớ tương ứng với danh sách tham số truyền vào; sao chép giá trị của tham số vào các ô nhớ mới này. Do đó, các thay đổi trong ô nhớ mới không ảnh hưởng đến các tham số truyền vào.  Ví dụ 1: xét lời gọi hàm của các hàm tính tổng 2 số và đổi chỗ 2 số sau với giá trị truyền vào là a = 5, b = 8: TRUYỀN THAM TRỊ int tinhtong(int so1, int so2) { int tong; tong = so1+so2; return tong; } void doicho(int so1, int so2) { int temp = so1; so1 = so2; so2 = temp; }  Với lời gọi hàm ketqua = tinhtong(a, b); thì với a = 5, b = 8, kết quả sẽ trả về giá trị là 13  Với a = 5, b = 8 và lời gọi hàm doicho(a, b); cùng với lệnh in ra màn hình a, b sau khi đổi chỗ thì kết quả trước và sau khi thực hiện không thay đổi  Nguyên nhân: do khi truyền tham số, trình biên dịch sao chép a, b sang các tham số so1, so2 và thực hiện đổi chỗ trên 2 ô nhớ này, như vậy giá trị của a, b là không đổi (hay mọi thay đổi trong hàm sẽ không ảnh hưởng đến chương trình).  Khắc phục: ??? NHẬN XÉT  Truyền tham chiếu sẽ làm thay đổi giá trị của biến truyền vào. Vì vậy các thao tác làm thay đổi biến được truyền vào thì kết thúc hàm vẫn được giữ nguyên.  Để sử dụng các truyền tham chiếu, trong khai báo và định nghĩa của hàm, các tham số có dấu “&” trước tên của tham số đầu vào  Ví dụ: Hàm đổi chỗ khi truyền tham chiếu sẽ thực hiện việc đổi chỗ 2 số một cách chính xác void doicho (int &so1, int &so2); TRUYỀN THAM CHIẾU  Hàm đổi chỗ 2 số dùng cách truyền tham trị: void Swap1(int so1, int so2) { int temp = so1; so1 = so2; so2 = temp; }  Hàm đổi chỗ 2 số dùng cách tham chiếu: void Swap2(int& so1, int& so2) { int temp = so1; so1 = so2; so2 = temp; } VÍ DỤ SO SÁNH  Khi a = 1521, b = 3000, kết quả thực hiện chương trình: a = 1521, b = 3000 Truyen theo tham tri (Swap1): a = 1521, b = 3000 Truyen theo tham chieu (Swap2): a = 3000, b = 1521  Giải thích: - Trong truyền tham trị (gọi Swap1(a,b)), các tham số so1 và so2 là bản sao của a và b nên các thay đổi của so1 và so2 trong hàm Swap1() không ảnh hưởng tới giá trị của a,b. - Trong truyền tham chiếu (gọi Swap2(a,b), các tham số so1 và so2 chính là a và b nên các thay đổi của so1 và so2 trong hàm Swap1() làm thay đổi giá trị của a,b. VÍ DỤ SO SÁNH  Trong trường hợp cần thay đổi giá trị của biến, nên sử dụng tham chiếu.  Trong trường hợp không cần thay đổi giá trị của biến, nên sử dụng tham trị.  Ngoài 2 cách truyền tham số trên, người lập trình cũng có thể sử dụng con trỏ CÁC CÁCH TRUYỀN THAM SỐ- CHÚ Ý 4. Phạm vi của biến (scope) ◮ Biến toàn cục (global) được khai báo bên ngoài tất cả các hàm ◮ Biến cục bộ (local) được khai báo bên trong một hàm hoặc một khối lệnh (giữa hai dấu { }) ◮ Sau khi được khai báo, biến toàn cục có thể được sử dụng ở bất cứ chỗ nào trong chương trình ◮ Phạm vi của biến cục bộ chỉ giới hạn trong khối lệnh nơi nó được khai báo Phạm vi của biến • Biến cục bộ Được khai báo bên trong thân của một hàm Chỉ tồn tại trong hàm đó • Có thể khai báo các biến có cùng tên trong các hàm khác nhau Phạm vi cục bộ: hàm là phạm vi của nó • Lợi ích của biến cục bộ Duy trì kiểm soát riêng rẽ với dữ liệu Hàm nên khai báo bất kỳ dữ liệu cục bộ nào mà nó cần 32 Hằng toàn cục và biến toàn cục • Được khai báo bên ngoài thân hàm ◦ Toàn cục với tất cả các hàm trong file • Khai báo toàn cục cho hằng: ◦ Khai báo là toàn cục do vậy có phạm vi với tất cả các hàm const pi=3.14159; • Biến toàn cục ◦ Được phép nhưng hiếm khi sử dụng ◦ Khó kiểm soát khi sử dụng 33 Phạm vi của biến  Đa số các biến có phạm vi cục bộ  Các khai báo hàm thường có phạm vi toàn cục  Các hằng thường được khai báo ở phạm vi toàn cục / / t i n h dien t i c h hinh tron #include using namespace std; const double p i = 3.14159; Biến toàn cục double d ient ich(double r ) { double d t ; dt = p i * r * r ; return d t ; } i n t main() { double bankinh = 2 . ; cout << "Dien t i ch " << dient ich(bankinh); return 0; } Biến cục bộ Bài tập Bài 1 Viết chương trình con tính tổng của ba số thực và nhân tổng đó với 5. Bài 2 Viết chương trình con có kiểu trả về void để chuyển đơn vị từ g sang kg. Bài 3 Viết chương trình con hoán đổi giá trị hai số thực.
Tài liệu liên quan