VI. Hàm
1.Khái niệm định nghĩa hàm
a. Khái niệm
-Hàm là 1 đoạn chương trình độc lập , thực hiện trọn vẹn
công việc nhất định
Mục đích sử dụng hàm
+ Khi có 1 công việc giống nhau cần thực hiện ở nhiều vị trí
+ Khi cần chia 1 chương trình lớn thành các cá thể đơn
b. Khai báo hàm
<kiểu giá trị trả về><tên hàm>(danh sác biến đối);
VD : int tong(int);
Hàm
c. Định nghĩa hàm
Cú pháp
<kiểu trả về><câu lệnh> (danh sách các tham số)
{
khai báo biến toàn cục của hàm;// chỉ dùng riêng cho hàm
này
Dãy lệnh của hàm;
return (biểu thức trả về);
}
Hàm
Ví Dụ: Định nghĩa hàm tính lũy thừa n( n nguyên)
double luythua(float x,int n)
{
int i;
double kq=1;
for (i=1;i<=n; i++);
ketqua*=x;
return Kq;
}
Hàm
Chú ý khai báo và định nghĩa hàm
-
Danh sách đối trong khai báo hàm có thể chứa hoặc không
chứa tên đối
-
Cuối khai báo hàm phải có dấy chấm phẩy (;)m trong khi
cuối dòng đầu tiên của định nghĩa hàm không có dấu chấm
phẩy
-
Hàm có thể không có đối , tuy nhiên cặp dấu ngoặc sau yên
hàm vẫn phải được viết
-
Một hàm có thể không cần khai báo nó , được định nghĩa
trước khi có hàm nào đó gọi đến nó
Hàm
2. Tham số trong lời gọi hàm
Cú pháp tên hàm (danh sách tham chiếu
thực sự);
-
Lời gọi hàm được phép xuất hiện trong bất kì
biểu thức , câu lệnh bất kì
-
Ví dụ addition(5,3) // hàm addition với tham
số 5 và 3
Hàm
•
3.Hàm với đối số mặc định
Cú pháp <kiểu hàm><tên hàm>(d1,…,dn,đmd1=giá
trị1,đmđm=gía trị m);
-
Các đối dd1,…,đn với đối số mặc định đmđ1…đmđm
đều được khai báo như cũ, gồm có kiểu đối và tên đối
-
VD
Xét hàm xmh(int n=100);// trong đó n mặc định là 100
Hàm
4. Khai báo hàm trùng tên
-
Hàm trùng tên hay còn giụ là hàm chồng đè
-
Đây là 1 kĩ thuật cho phép sử dụng cùng 1 ten gọi cho các hàm
giống nhau nhưng xử lí trên các kiểu dữ liệu khác nhau
-
VD : Tìm số lớn nhất trong 2 số nguyên
int max(int a,int b)
{
return (a>b) ? A:b;
}
Hàm
5.Biến đối tham chiếu
Cú pháp
<kiểu biến>&<tên biến tham chiếu>=<tên
biến được tham chiếu>;
VD int &ty=hung;// khai báo biến tham chiếu ty
theo tham chieu đến
VD Xét ví dụ đổi biến số
Bảng tóm tắt 3 cách viết hàm thông qua
ví dụ đổi biến số
Tham trị Tham chiếu Dẫn trỏ
Khai báo đối void swap(int x,inty) void swap(int
&x,int&y)
void swap(int
*x,int*y)
Câu lệnh t=x;x=y;y=t; t=x;x=y;y=t t=*x;x=*y;*y=t
Lời gọi swap(a,b); swap(a,b) swap(&a,&b)
Tác dụng a,b không đổi a,b thay đổi a,b thay đổi
6. Hàm và mảng dữ liệu
a.Truyền mảng 1 chiều cho con trỏ
-Thông thường chúng ta xây dựng các hàm làm việc trên mảng
nhưvesctohay ma trận các phần tử.Khi đó tham đối thực sự của hàm sẽ
là các mảng dữ liệu này
-VD Hàm nhập giá trị cho các véc tơ
void nhâp(int x[],int n)// n số phần tử
{ int I;
for (i=0;i<n;i++) cin>>x[i];
}
void main in(int *p,int n)
{
int for (i=0,i<n;i++) cout<<(*p+i)
}
main()
{
int a[10];// mảng a chứa tối đa 10 phần tử
nhap(a,7);//vào 7 phần tử đầu tiên cho a
Int(a,3);// ra 3 phần tử đầu tiên của a
}
b. Truyền mảng 2 chiều cho con trỏ
-
VD tính tổng các số hạng trong ma trận
float tong(float x[][10],int m,int n)
{ float t=0;
int i,j;
for(i=0;i<m;i++)
for (j=0;j<n;j++)
t=x[i][j];
return t;
}
main()
{float a[8][10],b[5][7];
int i, j, ma, na, mb, nb;
cout<<“ Nhạp số dòng ,số cột ma trận a:”;cin>>ma>>na;
for(i=0;i<ma;i++)//nhập ma trận a
for(j=0;j<n;j++)
{ cout <<“a[“<<i<<“,”<<j<<“]=“;cin>>a[i][j];
}
cout<<“ Nhạp số dòng ,số cột ma trận b:”;cin>>mb>>nb;
for(i=0;i<mb;i++)//nhập ma trận b
for(j=0;j<n;j++)
{ cout <<“b[“<<i<<“,”<<j<<“]=“;cin>>b[i][j];}
cout<<tong(a,ma,na);// in tỏng các ma trận
cout<<tong(b,mb,nb);//sai visos cột cuarb khác 10
}
}
c.Giá trị trả lại của hàm 1 mảng
-nếu muốn trả lại giá trị con trỏ thì vùng dữ liệu mà nó trỏ đến phải được cấp
phát 1 cách bình tường minh, chứ không để chương trình tự động cấp phát và
thu hồi.
VD
int* tragiatri1()//giá trị trả lại là con trỏ đến dãy số nguyên
{
int kp[3]={1,2,3}; tạo mảng kết quả với 3 giá trị 1,2,3
return kb;// trả lại địa chỉ cho con trỏ kết quả hàm
}
main()
{ int *a, I;
a= trả giatri1();
for (i=0;i<3;i++) cout *(a+i);// không phải là 1 ,2,3
a=tragia2(i);
for (i=0;i<3;i++) cout*(a+i);//1,2,3
}
d. Đối và giá trị trả lại là xâu kí tự
- Giống các trường hợp đã xét với mảng 1 chiều ,
đối của các xâu kí tự có thể khai báo dưới 2
dạng: mảng kí tự hoặc con trỏ kí tự. Giá trị trả lại
luôn luôn là con trỏ kí tự.ngoài ra hàm cũng có
thể trả lại giá trị vào trong các đối con trỏ trong
danh sách biến
e. Đối là hằng con trỏ
VD Đối con trỏ in ra 1 xâu kí tự
void inhoa(const char*s)
{
char *t;
strcpy(t,s);
cout<<s<<strupr(i); //khong dùng đc trong strupr(s)
}
main()
{
Char+s= abdce”;
inhoa(s)
}
7. Cấp lưu trữ và phạm vi hoạt động của các đối tượng
a.Biến cục bộ
-
Là biến được khai báo trong thân của
hàm và chỉ có tác dụng trong hàm này, kể cả các
biến khai báo trong hàm main() cũng chỉ có tác
dụng riêng tronghamf main()
-
Các biến trong hàm này được phép trùng nhau.Các
biến của hàm nào sẻ chỉ tồn tại trong thời gian
hàm đó hoạt động
-
=> một hàm được xem như 1 đơn vị độc lập khép
kín.
b. Biến ngoài
-
Là các biến được khai báo bên ngoài của tất cả
các hàm. Vị trí khai báo của chúng có thể từ
đầu văn bản chương trình hoặc tại một một vị
trí bất kì nào đó giữa văn bản chương trình.
-
Thời gian hoạt động của nó từ lúc chương
trình bắt đầu chạy đến khi kết thúc chương
trình giống như các biến tronghamf main()
-
=> Biến ngoài sẽ có tác dụng lên toàn bộ
chương trình
c. Biến hằng với từ khóa const
-
Để sử dụng hằng có thể khai bái thêm từ khóa const trước
khai báo biến. Phạm vi và miền tác dụng cũng như biến, có
nghĩa biến hằng cũng có thể ở dạng cục bộ hoặc toàn thể.
Biến hằng luôn được khởi tạo trước.
-
VD
-
Const int max=30;// toàn thể
-
Void vidu(const int*p)//cục bộ
{
Const mã=10;//cục bộ
….
}
d. Biến tĩnh và từ khóa static
- Được khai báo bằng từ khóa static. Là biến cục
bộ nhưng vẫn giử giá trị sau khi ra khỏi hàm.
Phạm vi tác dụng như biến cục bộ ,nghĩa là nó
được sử dụng trong hàm khai báonó. Tuy nhiên
thời tác dụng được xem như biến toàn thể, tức
sau khi hàm thực hiện xong trong biến vẫn còn
tồn tại và vẫn lưu lại giá trị sau khi ra khỏi hàm.
8. Con trỏ hàm
a, Khai báo
•
<kiểu giá trị>(*tên biến hàm)(danh sách tham số);
•
<kiểu giá trị>(*tên biến hàm)(danh sách tham đối)=tên
hàm>;
b.Khởi tạo
<biến con trỏ hàm>= tên hàm;
VD
float luythua(float,int);
float(*y)(float, int);
f= luythua;// con trỏ trỏ đến hamfluyx thừa
c. Sử dụng con trỏ hàm
- Để sử dụng con trỏ hàm ta phải gán nó với tên hàm cụ thể và sâu bất
kuf nơi nào được phép xuất hiện tên hàm thì ta dều có thể thay thế nó
bằng tên con trỏ
- VD Dùng tên con trỏ để gọi hàm
float bphuong(floatx)// hàm trả lại x2
{
return x*x;
}
void main()
{
float (*f)float);
f=bphuong;
cout<<“ Binh phuongcua 3.5laf”<<f(3.5);
}
d. Mảng con trỏ hàm
-
Các con trỏ hàmgiốngnhau có thể viết gộp vào trong 1 mảng
-
VD
void cong(int a,int b){cout<<a<<“+”<<b<<“=“<<a+b;} void tru(int a,int b)
{cout<<a<<“-”<<b<<“=“<<a-b;}
void nhan(int a,int b){cout<<a<<“*”<<b<<“=“<<a*b;}
void chia(int a,int b){cout<<a<<“/”<<b<<“=“<<a/b;}
main ()
{ clrscr();
void(*f[4])(int, int)={cong, tru, nhan.chia};//khai báo khởi tạo 4 con trỏ
int m,n;
cout<<“ Nhập m,n”;cin>>m>>n;
for (int i=0;i<4;i++)
f[i](m,n);
getch();
}
9. Đệ qui
a.Định nghĩa
-
Một hàm gọi đến hàm khác là bình thường, nhưng nếu
hàm lại gọi đến chính nó thì ta gọi hàm là đệ qui
-VD Tính n!
main()
{
int n; double kq=1;cCout<<“n=“;cin>>n;
for (int i=1;i<=n;i++)
kq*=i;
cout<<n<<“!=“<<kq;
}
b.Lớp các bài toán giải đc bằng đệ qui
Phương pháp đệ qui thường đc dùng để giải các bài
toán có đặc điểm:
- Giải quyết đc dễ dàng trong các trường hợp riêng gọi
là trường hợp suy biến hay cơ sở , trong trường hợp
này hàm được tính bình thường mà không cần gọi lại
chính nó
-
Đối với trường hợp tổng quát, bài toán có thể giải
được bằng bài toán cùng dangjnhuwng với tham đối
khác có kích thước nhỏ hơn tham số ban đầu. Và sau
một số bước hữu hạn biến đổi cùng dạng , bài toán
chưa được về trường hợp suy biến.
c. Cấu trúc chung của 1 hàm đệ qui
if ( trường hợp suy biến)
{
trình bày cách giải
}
else
{
gọi hàm với tham số bé hơn
}