2. Cú pháp khai báo hàm
Cú pháp khai báo hàm nằm trên một dòng, kết
thúc bằng dấu chấm phẩy.
Kiểu_trả_về Tên_hàm(Kiểu_1 Tên_tham_số_1, Kiểu_2 Tên_tham_số_2, );
Ví dụ: float inchtomet(float x);
int cong(int a, int b);
Một khai báo hàm không cho biết những gì có
trong thân hàm. Nó chỉ báo cho trình biên dịch
biết về tên hàm, kiểu của hàm, số lượng các tham
số và kiểu của các tham số.
2. Cú pháp khai báo hàm (tiếp)
Khai báo hàm có thể đặt ở bất kỳ đâu trước khi gọi
hàm. Tốt nhất là để ở đầu tệp chứa chương trình chính
(chứa hàm main) hoặc để trước một hàm sẽ gọi nó.
Trong các chương trình nhiều file thì các khai báo hàm
thường để trong các file header có đuôi .h, còn các định
nghĩa hàm để trong các file thư viện có đuôi obj hoặc
lib.
Nếu hàm được định nghĩa ở đâu đó trước khi gọi hàm
thì có thể không cần khai báo hàm. Tuy nhiên vẫn nên
có khai báo hàm nhất là trong các chương trình có
nhiều hàm lớn hay các chương trình nằm trên nhiều
file.
17 trang |
Chia sẻ: thanhle95 | Lượt xem: 504 | Lượt tải: 1
Bạn đang xem nội dung tài liệu Bài giảng Lập trình C - Chương 8: Hàm trong C - Ngô Công Thắng, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 1
Chương 8. Hàm trong C
I. Khai báo hàm
II. Định nghĩa hàm
III. Sử dụng hàm
IV. Con trỏ trỏ tới hàm
V. Xây dựng thư viện hàm
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 2
I. Khai báo hàm
1. Giới thiệu về hàm
2. Cú pháp khai báo hàm
3. Các tham số trong khai báo hàm
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 3
1. Giới thiệu về hàm
² Trong C tất cả các chương trình con đều gọi là hàm.
² Ngoài các hàm thư viện có sẵn, người lập trình có
thể tự tạo ra các hàm. Để tạo ra một hàm người lập
trình phải khai báo và định nghĩa nó.
² Khai báo hàm (function declaration or prototype) là
xác định tên của hàm, kiểu dữ liệu trả về, số lượng
tham số và kiểu của từng tham số.
² Định nghĩa hàm (function definition) là xác định
công việc mà hàm sẽ thực hiện thông qua các lệnh
của hàm.
² Các hàm trong C không lồng nhau, tức là trong một
hàm ta không thể định nghĩa một hàm khác.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 4
2. Cú pháp khai báo hàm
²Cú pháp khai báo hàm nằm trên một dòng, kết
thúc bằng dấu chấm phẩy.
Kiểu_trả_về Tên_hàm(Kiểu_1 Tên_tham_số_1, Kiểu_2 Tên_tham_số_2,);
Ví dụ: float inchtomet(float x);
int cong(int a, int b);
²Một khai báo hàm không cho biết những gì có
trong thân hàm. Nó chỉ báo cho trình biên dịch
biết về tên hàm, kiểu của hàm, số lượng các tham
số và kiểu của các tham số.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 5
2. Cú pháp khai báo hàm (tiếp)
² Khai báo hàm có thể đặt ở bất kỳ đâu trước khi gọi
hàm. Tốt nhất là để ở đầu tệp chứa chương trình chính
(chứa hàm main) hoặc để trước một hàm sẽ gọi nó.
Trong các chương trình nhiều file thì các khai báo hàm
thường để trong các file header có đuôi .h, còn các định
nghĩa hàm để trong các file thư viện có đuôi obj hoặc
lib.
² Nếu hàm được định nghĩa ở đâu đó trước khi gọi hàm
thì có thể không cần khai báo hàm. Tuy nhiên vẫn nên
có khai báo hàm nhất là trong các chương trình có
nhiều hàm lớn hay các chương trình nằm trên nhiều
file.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 6
3. Các tham số trong khai báo hàm
²Nếu hàm không có tham số thì trong dấu
ngoặc đơn của khai báo hàm để trống. Ví dụ:
int xoa();
²Tên của các tham số trong khai báo hàm có
thể không cần xác định. Ví dụ:
float inchtomet(float, float);
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 7
II. Định nghĩa hàm
1. Cú pháp định nghĩa hàm
2. Lệnh return
3. Hàm không trả về giá trị
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 8
1. Cú pháp định nghĩa hàm
Kiểu_trả_về Tên_hàm(Kiểu_1 Tên_tham_số_1, Kiểu_2 Tên_tham_số_2,)
{
//Các lệnh của hàm để đây
}
Ví dụ:
int cong(int a, int b)
{
int z;
z = a + b;
return z;
}
Không có dấu
chấm phẩyThân hàm
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 9
1. Cú pháp định nghĩa hàm (tiếp)
²Dòng đầu tiên trong định nghĩa hàm giống
trong khai báo hàm, chỉ khác là không có dấu
chấm phẩy và các tham số bắt buộc phải có
tên.
²Khi đã có khai báo hàm thì định nghĩa hàm
thường để sau hàm main hoặc để trong một
tệp obj (lib). Để quen dần với việc viết các
chương trình lớn, khi thực hành chúng ta viết
các khai báo hàm trong tệp .h, còn các định
nghĩa hàm để trong tệp .obj (lib).
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 10
2. Lệnh return
² Lệnh return được sử dụng trong một hàm. Lệnh
return thực hiện hai chức năng:
n Làm cho một hàm trở về chương trình gọi nó.
n Được dùng để trả về một giá trị.
² Cú pháp dùng lệnh return như sau:
return Giá_trị_trả_về;
hoặc return;
² Lệnh return có thể dùng ở bất kỳ vị trí nào trong
hàm nhưng thường ở cuối hàm.
² Với các hàm có trả về giá trị thì lệnh return bắt buộc
phải có.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 11
3. Hàm không trả về giá trị
²Với các hàm không trả về giá trị thì khi khai
báo và định nghĩa hàm ta phải khai báo kiểu
trả về là void. Ví dụ:
void chao();
²Nếu sử dụng lệnh return trong hàm không trả
về giá trị thì chỉ dùng được dạng:
return;
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 12
III. Sử dụng hàm
1. Lời gọi hàm
2. Truyền đối số theo giá trị
3. Truyền con trỏ tới hàm
4. Truyền mảng tới hàm
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 13
1. Lời gọi hàm
²Một hàm, sau khi được định nghĩa và khai báo, có
thể được thực hiện bằng một lệnh gọi hàm (lời gọi
hàm) ở đâu đó trong chương trình. Có thể gọi từ
hàm main, có thể gọi từ một hàm khác hoặc có thể
gọi từ một hàm thành viên của lớp.
² Cú pháp gọi hàm như sau:
Tên_hàm(Danh sách các đối số, nếu có);
² Nếu hàm được khai báo và định nghĩa là có các
tham số thì khi gọi hàm ta phải truyền giá trị cho
hàm qua các tham số. Các giá trị truyền cho hàm gọi
là các đối số. Các đối số có thể là hằng, biến, mảng,
con trỏ,
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 14
1. Lời gọi hàm (tiếp)
² Ví dụ: giả sử ta khai báo một hàm cộng hai giá trị
float
int cong(int a, int b);
Ta gọi hàm này như sau:
cong(7,8);
² Lời gọi một hàm có trả về giá trị có thể sử dụng
trong các biểu thức, còn lời gọi một hàm không trả
về giá trị không dùng được trong biểu thức. Khi
dùng trong biểu thức thì không có dấu chấm phẩy
sau lời gọi hàm. Ví dụ:
a = cong(7,8) +2; cout<<a;
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 15
1. Lời gọi hàm (tiếp)
²Hoạt động của lời gọi hàm
sdfghjkl
sdfghjkl
func1();
sdfghjkl
sdfghjkl
func1();
sdfghjkl
sdfghjkl
func1();
sdfghjkl
Chương trình
gọi hàm
Lời gọi hàm
void func1()
{
sdfghjkl
sdfghjkl
sdfghjkl
}
Cùng một mã được dùng
cho tất cả các lời gọi hàm
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 16
Ví dụ về hàm
²Viết chương trình tính số các chỉnh hợp chập k từ n
phần tử. Chương trình phải sử dụng hàm để tính giai
thừa.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 17
2. Truyền đối số
²Trong C, các đối số truyền vào cho hàm là
truyền theo giá trị.
²Khi truyền đối số cho hàm theo giá trị thì
hàm sẽ tạo ra các biến mới (tên các biến này
là tên của các tham số), copy giá trị của các
đối số vào các biến mới và thao tác trên các
biến mới này. Bởi vậy sau khi gọi hàm các
đối số không bị thay đổi giá trị mặc dù bên
trong hàm giá trị của đối số bị thay đổi.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 18
2. Truyền đối số theo giá trị (tiếp)
#include
void DoiCho(int a, int b);
int main()
{
int x=12,y=15;
printf("Truoc khi doi cho: x= %d, y= %d“,x,y);
DoiCho(x,y);
printf(“Sau khi doi cho: x= %d, y= %d“,x,y);
return 0;
}
void DoiCho(int a,int b) //Khai bao de truyen doi so theo gia tri
{
int tmp=a;
a=b;
b=tmp;
}
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 19
3. Truyền con trỏ tới hàm
²Để truyền con trỏ tới hàm ta phải thực hiện
hai bước:
n Khai báo các tham số (khi khai báo và định
nghĩa) là con trỏ.
n Khi gọi hàm thì đối số truyền cho hàm là địa chỉ.
Ví dụ:
void DoiCho(int *a, int* b);
int x = 12,y = 15;
DoiCho(&x,&y);
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 20
3. Truyền con trỏ tới hàm (tiếp)
² Khi truyền con trỏ tới hàm thì biến do con trỏ trỏ tới
có thể bị thay đổi bởi hàm.
Ví dụ: Đổi chỗ giá trị của hai biến
void DoiCho(int* a,int* b);
. . . .
DoiCho(&x,&y);
. . . .
void DoiCho(int* a,int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 21
4. Truyền mảng tới hàm
² Khi tên mảng được sử dụng mà không có chỉ số
kèm theo thì nó là địa chỉ bắt đầu của mảng. Do đó,
nếu dùng mảng làm đối số truyền tới một hàm thì
chỉ có địa chỉ của mảng được truyền tới hàm chứ
không phải toàn bộ mảng. Điều này có nghĩa rằng
khi khai báo tham số của hàm thì tham số phải có
kiểu con trỏ.
² Bởi vì địa chỉ của mảng được truyền tới hàm nên
mọi thay đổi của hàm lên mảng sẽ giữ nguyên khi
hàm kết thúc.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 22
4. Truyền mảng tới hàm
² Tóm lại, truyền mảng tới hàm cần:
² Truyền vào tên biến mảng
² Truyền vào số phần tử dữ liệu đang chứa trong
biến mảng
² Khi khai báo, định nghĩa hàm, phải khai báo hai
tham số: tham số thứ nhất là con trỏ, tham số thứ
hai là kiểu int.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 23
4. Truyền mảng tới hàm (tiếp)
² Ví dụ: Viết một hàm đưa ra các phần tử của mảng
void print(int* m, int n);
. . . . .
int x[7]={2,5,8,1,6,7,10};
. . . . .
print(x,7);
. . . . .
void print(int* m, int n)
{
int i;
for(i=0;i<n;i++) printf(“%d ”,m[i]);
}
Ví dụ
1) Nhập vào 1 dãy số nguyên có n phần tử.
Viết hàm xóa phần tử thứ m trong dãy (1 <=
m <=n).
2) Nhập vào 1 dãy số nguyên có n phần tử.
Tính tổng dãy số. Trong chương trình có khai
báo, định nghĩa hàm tính tổng dãy số và phải
dùng mảng động để chứa dãy số.
3) Tính tổng các phần tử của ma trận nguyên
có kích thước mxn. Y/c khai báo, định nghĩa
hàm tính tổng.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 24
Truyền mảng nhiều chiều tới hàm
Cách 1 (dùng mảng tĩnh):
• Truyền vào tên biến mảng nhiều chiều
• Truyền vào số phần tử hiện tại theo các chiều
• Khai báo, định nghĩa: tham số ứng với mảng
được khai báo là mảng có cùng kích thước với
mảng đối số sẽ truyền vào, hai tham số sau có
kiểu int.
Ví dụ: Nhập vào một ma trận nguyên kích
thước mxn. Viết hàm tính tổng các phần tử của
ma trận truyền vào qua đối số.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 25
Truyền mảng nhiều chiều tới hàm
Cách 2 (dùng mảng động):
• Truyền vào tên biến mảng nhiều chiều
• Truyền vào số phần tử hiện tại theo các chiều
• Khai báo, định nghĩa: tham số ứng mảng được
khai báo là con trỏ, các tham số sau là kiểu int.
Ví dụ: Nhập vào một ma trận nguyên kích
thước mxn. Viết hàm tính tổng các phần tử của
ma trận truyền vào qua đối số.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 26
Truyền xâu ký tự tới hàm
• Chỉ truyền vào tên biến xâu
• Tham số ứng với biến xâu được khai báo là
con trỏ trỏ tới kiểu char
• Ví dụ: Viết hàm tính giá trị của số nhị phân
được truyền vào cho hàm dưới dạng xâu ký
tự.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 27
Hàm trả về mảng
• Là trả về tên biến mảng nên kiểu trả về là
con trỏ
• Mảng trả về phải là mảng động
• BTVN: 1) Viết hàm cộng hai ma trận số
thực kích thước mxn và hàm đưa ma trận ra
màn hình theo dạng hàng, cột.
2) Viết hàm nhân hai ma trận
Cmxn = Amxp * Bpxn
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 28
Hàm trả về xâu ký tự
• Là trả về tên biến xâu nên kiểu trả về là con
trỏ trỏ tới kiểu char.
• Xâu ký tự trả về phải là biến xâu động
• Ví dụ: Viết hàm trả về xâu ký tự số nhị phân
của số nguyên được truyền vào qua đối số.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 29
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 30
IV. Con trỏ trỏ tới hàm
²Một đặc điểm rất mạnh của C là con trỏ hàm.
Mặc dù hàm không phải là biến nhưng nó
vẫn có địa chỉ trong bộ nhớ. Địa chỉ này có
thể chứa trong một con trỏ. Vì địa chỉ của
hàm chứa trong con trỏ nên ta có thể sử dụng
con trỏ thay cho tên hàm.
²Để có địa chỉ của hàm ta dùng tên hàm không
có đối số (giống như tên biến mảng là địa chỉ
của mảng).
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 31
IV. Con trỏ trỏ tới hàm (tiếp)
² Để có con trỏ có thể chứa địa chỉ của hàm ta khai
báo con trỏ trỏ tới kiểu giống kiểu trả về của hàm,
theo sau là các tham số của hàm đặt trong ngoặc
đơn. Ví dụ: giả sử hàm Tong có hai tham số kiểu
int, kiểu trả về cũng là int. Khi đó ta khai báo con
trỏ trỏ tới hàm này như sau:
int Tong(int a, int b); //Khai bao hàm
int (*p) (int a, int b); //Khai báo con trỏ hàm
p = Tong; //Gán địa chỉ của hàm Tong cho p
(*p)(10,15); //Gọi hàm Tong qua con trỏ
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 32
IV. Con trỏ trỏ tới hàm (tiếp)
²Ví dụ: Viết chương trình tính tổng, hiệu, tích
và thương của hai số nguyên nhập vào từ bàn
phím. Chương trình yêu cầu người sử dụng
lựa chọn một trong các cách tính.
V-Xây dựng thư viện hàm
1) Các khai báo hàm để trong tệp header (.h)
2) Các định nghĩa hàm để trong tệp .cpp
3) Biên dịch tệp định nghĩa hàm thành tệp .obj
bcc32 –c vd.cpp
4) Tạo tệp thư viện hàm có đuôi .lib bằng trình tlib.
Vd: tlib thuvien.lib + ctc1.obj, ctc2.obj
5) Tệp .h và .lib để trong cùng thư mục với tệp chương
trình. Thêm đường dẫn vào tệp cấu hình tlink32.cfg
6) Khai báo thư viện hàm trong tệp chương trình
chính: #include”thuvien.h”
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 33
Ví dụ
Xây dựng thư viện hàm chứa hàm tìm
USCLN và kiểm tra một số nguyên có phải là
số nguyên tố không.
Sử dụng thư viện hàm, nhập vào 2 số nguyên
dương, tìm USCLN của 2 số nguyên đã nhập
và cho biết 2 số đó có phải là số nguyên tố
không.
Lập trình nâng cao - Chương 08 - Ngô Công Thắng 34