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
55 trang |
Chia sẻ: thanhle95 | Lượt xem: 505 | Lượt tải: 1
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.