PHẦN I. MỞ ĐẦU
Trong giai đoạn hiện nay, giai đoạn mà nền công nghệ thông tin chiếm một vị trí
hết sức quan trọng. Mọi quốc gia trên thế giới đều cố gắng nỗ lực vào, và phấn đấu
phát triển mạnh lĩnh vực công nghệ thông tin. Một trong những công cụ tiếp cận
nhanh nhất đó là tin học.
Đã qua rồi, thời mà cha ông ta phải làm và ghi nhớ mọi việc bằng những
phương tiện thô sơ. Để tính toán họ đều phải bắt đầu bằng tay và tính toán một cách
chi tiết. Còn ngày nay - Thời đại của công nghệ thông tin - Bạn không cần phải làm
như vậy nữa. Bạn chỉ cần lập ra một chương trình rồi sử dụng nó. Nó tiện ích và
thuận lợi hơn rất nhiều. Nó không hạn chế về khối lượng, con số. Thậm chí trong
một giây nó có thể giải quyết hàng vạn bài toán phức tạp vv…Do đó tốc độ làm
việc và năng suất tăng lên rất nhiều. Lợi ích rất lớn.
Để nó có thể làm việc và hoạt động được thì chúng ta cần phải lập trình, mà
muốn lập trình thì cần phải có ngôn ngữ lập trình. Có rất nhiều ngôn ngữ lập trình
như Pascal, Cobol, C
++
vv… Mỗi ngôn ngữ lập trình có một chức năng riêng, một
thế mạnh riêng, trong đó ngôn ngữ lập trình C
++
rất hay dùng và nó có thế mạnh về
quá trình can thiệp sâu vào máy tính. Nó là điều mà mọi kỹ sư lập trình đều cần
phải biết đến, là vấn đề rất quan trọng trong quá trình tiếp cận với máy tính.
Những vấn đề trong ngôn ngữ lập trình C
++
rất đáng phải quan tâm và có rất
nhiều vấn đề, nhưng ở đề án này chúng ta chỉ nghiên cứu 3 vấn đề cơ bản nhất đó
là:
Chương I: Hàm.
Chương II: Biến toàn cục, biến cục bộ.
Chương III: Chương trình có sử dụng hàm, biến toàn cục, biến cục bộ.
Trong mỗi chương sẽ có những vấn đề nhỏ, cụ thể cần nghiên cứu sẽ được thể hiện
trong phần nội dung.
Đề án của em được hoàn thành dưới sự hướng dẫn giúp đỡ của thầy TS. Đặng
Quế Vinh và những tài liệu về bài giảng của thầy cũng như một số tài liệu khác.
Một lần nữa em xin cảm ơn thầy.
1
PHẦN II. NỘI DUNG.
Nội dung chính bao gồm: Hàm, biến toàn cục, biến cục bộ.
Chương I: Hàm.
Chương trình con: Chương trình được viết theo những quy tắc đặc biệt để có thể
được gọi thực hiện bằng một chương trình khác. Chương trình chứa lời gọi thực
hiện chương trình con được gọi là chương trình chính.
Việc viết và sử dụng những chương trình con cho phép tiết kiệm công sức của
người viết chương trình rất nhiều. Trong hầu hết các ngôn ngữ lập trình bậc cao
chương trình con được chia làm 2 loại là thủ tục( x, thủ tục) và hàm(x, hàm).
I. Định nghĩa hàm.
Hàm là một chương trình con tính một giá trị và trả lại giá trị ấy thông qua tên
hàm.
Hàm chia thành 2 loại là hàm chuẩn và hàm tự định nghĩa còn gọi là hàm do
người sử dụng định nghĩa.
- Hàm chuẩn là những hàm có sẵn trong ngôn ngữ lập trình. Lập trình viên có
thể sử dụng các hàm chuẩn mà không phải định nghĩa lại các hàm đó. Hầu hết các
hàm toán học thông dụng đều là các hàm chuẩn trong các ngôn ngữ lập trình. Tập
hợp các hàm chuẩn tạo thành thư viện hàm chuẩn của ngôn ngữ lập trình thư viện
hàm chuẩn là thành phần rất quan trọng của mỗi ngôn ngữ lập trình. Nó làm cho
việc lập trình được dễ dàng hơn và làm cho khả năng của ngôn ngữ lập trình tăng
lên rất nhiều.
- Hàm tự định nghĩa: Là những hàm không có sẵn trong thư viện hàm chuẩn của
ngôn ngữ lập trình. Muốn sử dụng những hàm này người sử dụng phải tạo ra nó. Vì
vậy những hàm này mới có tên là hàm do người dùng định nghĩa. Việc tạo ra và sử
dụng những hàm tự định nghĩa làm cho chương trình ngắn gọn hơn, sáng sủa hơn
và cho phép tiết kiệm công sức của lập trình viên.
Có thể coi hàm là một phép toán do người dùng xác định. Nói chung hàm được
biểu thị bởi một tên gọi chứ không phải là một toán tử. Các toán hạng của hàm,
được gọi là các đối của nó, được xác định trong danh sách đối phân cách nhau bởi
dấu phẩy và được bao trong dấu ngoặc tròn. Kết quả của hàm thường được coi là
kiểu cho lại của nó. Hàm không cho lại giá trị nào có kiểu cho lại là Void. Các hành
động thực tại mà một hàm thực hiện được xác định trong thân hàm. Thân hàm được
bao trong ngoặc nhọn( "{ }" ) và đôi khi còn được coi là một khối.
Trong C
++
có 2 cách định nghĩa hàm:
2
Định nghĩa hàm sau hàm main( ) và định nghĩa hàm trước hàm main(). Tuy
nhiên cách định nghĩa hàm trước hàm main( ) ngăn gọn hơn và hay dùng hơn cho
nên ở đây ta nghiên cứu kỹ về chúng.
Việc định nghĩa một hàm theo mẫu sau:
Đầu_đề_hàm
{
Phần khai báo
Thân hàm
}
*Đầu đề hàm có dạng sau đây:
TĐK(từ định kiểu) : int, char;
TĐK tên hàm( TĐK1 tham số 1 [, TĐK2 tham_số 2 ]…)
TĐK(*) xác định kiểu của hàm, tức là xác định kiểu của giá trị được trả lại thông
qua tên hàm.
Các tham số có trong ngoặc tròn ( ) đi sau tên hàm được gọi là các tham số
hình thức. Toàn bộ các tham số trong ngoặc ( ) gọi là danh sách tham số hình thức.
Danh sách này gồm 1 hay nhiều tham số, tham số nọ cách tham số kia dấu phẩy.
Danh sách tham số hình thức kết thúc bởi dấu ngoặc, sau đó không có dấu chấm
phẩy.
*Phần khai báo của hàm:
Dùng để khai báo các biến được dùng trong hàm này. Các biến được khai báo
trong hàm chỉ có ý nghĩa trong hàm này nên được gọi là các biến cục bộ( địa
phương). Việc sử dụng các biến cục bộ trong chương trình khác hoặc chương trình
chính là không hợp lệ.
Một hàm được tính bất kỳ khi nào toán tử gọi( "( )") được áp dụng vào tên của
hàm. Nếu hàm cần có các đối thì các đối này, còn được gọi là các đối thực tại, sẽ
được đặt vào bên trong toán tử gọi. Mỗi đối được phân cách bởi một dấu phẩy. Nó
còn được gọi là truyền đối cho hàm.
*Thân hàm:
Giống như phần thân chương trình của một chương trình thông thường. Tuy
nhiên sau khi tính xong giá trị hàm thì trong thân hàm thường có câu lệnh return để
trả lại giá trị vừa tính được trong thân hàm cho tên hàm.
Nó có dạng:
Return Biểu thức;
3
hoặc Return( biểu thức).
Câu lệnh này có tác dụng trả cho tên hàm giá trị của biểu thức có trong câu lệnh
này. Câu lệnh return kết thúc việc thực hiện các câu lệnh trong thân hàm và trả điều
kiện về chỗ đã gọi hàm trong chương trình chính. Tuy nhiên câu lệnh return là
không bắt buộc phải có.
Hàm trả lại giá trị qua tên hàm nên hàm có thể được dùng là một toán hạng
trong biểu thức.
Trong C
++
chỉ có một loại chương trình con đó là hàm. Mỗi chương trình
Trong C
++
phải có ít nhất một hàm main( ). Hàm trong C
++
không nhất thiết phải
có tham số, trả lại giá trị( đó là kiểu void). Trong chương trình nguồn hàm có thể là
một toán hạng trong biểu thức hoặc có thể đứng một mình như một câu lệnh đơn
độc.
Ví dụ:
#include<iostream.h>
#include<conio.h>
// Dinh nghia ham BINH_PHUONG
int BINH_PHUONG(int n)
{
int ketqua;
ketqua=n*n;
return ketqua;
}
// Chuong trinh chinh
main()
{
int m;
cout<<"m=";
cin>>m;
cout<<'\n'<<m<<"binhphuong=";
cout<<BINH_PHUONG(m); (1);
getch();
}
Trong chương trình này dòng(1) có chứa lời gọi hàm là BINH_PHUONG(m). ở
đây m được gọi là tham số thực sự gặp lời gọi này máy sẽ thực hiện hàm
BINH_PHUONG mà ta đã khai báo ở trên.
II.Sử dụng hàm.
Muốn sử dụng hàm ta phải viết lời gọi hàm. Lời gọi hàm có dạng sau:
Tên hàm( [ Danh sách tham số thực sự] )
4
Danh sách tham số thực sự bao gồm một hay một số tham số thực sự cách nhau
bởi dấu phẩy. Danh sách tham số thực sự có thể là một hàm, một biến hoặc một
biểu thức. Danh sách tham số thực sự là tuỳ chọn. Số tham số thực sự trong danh
sách tham số thực sự phải bằng số tham số hình thức trong danh sách tham số hình
thức. Kiểu của tham số thực sự phải phù hợp với kiểu của tham số hình thức tương
ứng.
Một lời gọi hàm có thể làm cho 1 hay 2 điều xuất hiện. Nếu hàm đã được khai
báo là inline thì thân của hàm được mở rộng tại điểm gọi nó trong lúc dịch, ngoài ra
hàm sẽ được gọi trong lúc chạy. Một lời gọi hàm làm cho điều khiển của chương
trình được chuyển cho hàm được gọi, việc thực hiện của hàm đang chạy lúc đó bị
tạm ngừng. Khi tính toán của hàm được gọi đã hoàn tất thì hàm bị ngừng sẽ lấy lại
hoạt động tại điểm sau lời gọi. Việc gọi hàm được quản lý trong chồng khi chạy
của chương trình. Nếu một hàm không được khai báo trong chương trình trước khi
dùng nó thì sẽ có lỗi khi dịch.
Hàm chỉ được định nghĩa một lần trong chương trình. Về cơ bản định nghĩa hàm
trong tệp văn bản riêng của nó hay trong tệp văn bản có chứa nó và các hàm có liên
quan khác. Một hàm thường được dùng trong các tệp khác tệp chứa định nghĩa của
nó. Do đó cần có phương pháp phụ để khai báo hàm.
Khai báo hàm bao gồm kiểu cho lại của hàm, tên hàm và danh sách đối.
III.Truyền tham số cho hàm.
Khi gặp lời gọi hàm trong chương trình chính thì quá trình thực hiện hàm bắt
đầu. Quá trình này gồm các công việc sau:
- Máy tạm thời rời khỏi chương trình chính, cấp phát bộ nhớ cho các tham số
hình thức và các biến cục bộ.
- Gán các giá trị của tham số thực sự cho các tham số hình thức tương ứng.
- Lần lượt thực hiện các câu lệnh trong thân hàm. Nếu gặp câu lệnh return hoặc
gặp dấu “}” thì máy sẽ xoá các tham số hình thức hoặc các biến cục bộ quay về
chương trình chính ở chỗ có lời gọi hàm. Nếu thoát khỏi hàm bằng câu lệnh Return
thì giá trị biểu thức có trong câu lệnh này sẽ được gán cho tên hàm.
Khi gặp lời gọi hàm thì giá trị tham số thực sự sẽ được gán cho tham số hình
thức tương ứng, mọi tính toán trong thân hàm sẽ được thực hiện trên các tham số
hình thức. Khi thoát khỏi hàm máy sẽ xoá các tham số hình thức và các biến cục
bộ, như vậy những thay đổi đối với các tham số hình thức không thể được truyền
về chương trình chính thông qua tham số thực sự tương ứng.
Vậy làm thế nào để trong chương trình con có thể thay đổi giá trị các biến có
trong chương trình chính?
Người ta dùng con trỏ làm tham số hình thức để giải quyết vấn đề này. Khi đó
người ta truyền cho chương trình con địa chỉ của biến trước và sau lời gọi hàm( tức
5
là trước và sau khi thực hiện hàm địa chỉ này không thay đổi, hoàn toàn phù hợp
với các giả định của C
++
. Tuy nhiên trong quá trình thực hiện hàm thì giá trị chứa
trong địa chỉ đó có thể bị thay đổi, giá trị này được giữ nguyên khi thoát khỏi hàm.
Đây là phương pháp truyền giá trị từ chương trình con về chương trình chính.
VD: Truyền giá trị từ chương trình con về chương trình chính.
// Chuong trinh co ham tinh tong n so.
#include<iostream.h>
#include<conio.h>
float TONG(float *vecto, int n)
{
int i;
float s=0;
for(i=0; i<n;i++)
s=s+ *(vecto+i);
return (s);
}
main()
{
int i;
float a[4]={1,2,3,4};
float b[6]={5,1,2,3,1,4};
clrscr();
cout<<"\n tong vecto a="<<TONG(a,4);//in so 10
cout<<"\n tong vecto b="<<TONG(&b[0],6); //in ra so 10
getch();
}
IV. Sử dụng hàm trong nhiều chương trình khác.
Giả sử có một tệp gọi là: DVVECTERE.CPP
Chứa các hàm sau:
Float TONG VTF( float * vecter, int n);
Float TICH VTF ( float * vecter, int n);
Void NHAP VTF ( float * vecter, int n);
Void IN VTF ( float * vecter, int n);
// Chương trình hàm định nghĩa trong chương trình khác
#include<iostream.h>
#include<conio.h>
#include "C:\ baitap TC \ dvvecter.CPP"
main( )
{
6
int n=2;
float a[10];
NHAP VTF (a,n);
IN VTF(a,n);
TONG VTF(a,n);
TICH VTF (a,n);
Getch( );
}
V. Danh sách đối của hàm.
Các hàm khác nhau của một chương trình có thể thâm nhập chung vào các giá
trị với nhau theo 2 phương pháp. Một phương pháp là dùng biến toàn cục trong
chương trìnhl; Phương pháp thứ hai là dùng danh sách đối hình thức.
Danh sách đối đưa ra một phương pháp khác để thâm nhập chung vào các giá trị
giữa một hàm và chương trình chung. Danh sách đối cùng với kiểu cho lại của hàm
xác định ra giao diện chung của hàm. Một hàm khép kín có thể được dùng qua
nhiều chương trình, nó không nhất thiết bị giới hạn vào một ứng dụng riêng. Nếu
bỏ bớt đi một đối hay truyền cho một đối kiểu sai sẽ gây ra lỗi. Khả năng lỗi trong
truyền đối tăng lên theo kích cỡ của danh sách đối, dùng tối đa là 8 đối.
*Cú pháp danh sách.
Không được phép bỏ thiếu danh sách đối của hàm. Một hàm không có đối có
thể được biểu thị hoặc bằng danh sách đối rỗng hoặc bằng danh sách đối chỉ chứa
một từ khoá void.
//Khai báo tương đương
int fork();
int fork( void);
Danh sách đối còn được gọi là dấu hiệu của hàm bởi vì nó thường được dùng để
phân biệt một thể nghiệm của hàm này với hàm khác. Tên và dấu hiệu một hàm xác
định duy nhất nó.
Dấu hiệu bao gồm một danh sách các kiểu đối phân cách nhau bởi dấu phẩy.
Không có hai tên đối nào xuất hiện trong dấu hiệu được phép trùng nhau. Tên đối
cho phép đối đó được thâm nhập từ trong thân của hàm. Do đó tên đối không cần
viết trong khai báo hàm.
*Truyền đối.
Danh sách đối của hàm mô tả cho các đối hình thức. Mỗi đối hình thức được
cấp bộ nhớ bên trong vùng nhớ của hàm. Các biểu thức nằm giữa 2 dâu ngoặc tròn
của lời gọi hàm được gọi là các đối thực tại của lời gọi. Việc truyền đối vậy là một
tiến trình khởi đầu cho vùng nhớ của các đối hình thức theo các đối thực tại.
7
Với truyền theo giá trị, hàm không bao giờ thâm nhập vào các đối thực tại của
lời gọi, nội dung của đối thực tại không bị thay đổi. Có 2 phương án truyền theo giá
trị.
Thứ nhất là đối hình thức được khai báo là con trỏ.
Void pswap( int * x, int * y)
{
int tg=* y;
*y=* x;
*x=tg;
}
Thứ 2 để truyền theo giá trị là khai báo đối hình thức có kiểu tham khảo
Void rswap( int &x, int &y)
{
int tg= y;
y= x;
x=tg;
}
VI. Các hàm trong C
++
.
1. Tham chiếu.
Tham chiếu là một bí danh của một vùng nhớ được cấp phát cho một biến nào
đó. Một tham biến có thể là một biến tham số hình thức của hàm hay dùng làm một
giá trị trả về của hàm.
*Tham chiếu tới một biến.
VD: int n;
int &p=n;
Dấu & xác định p là một biến tham chiếu, còn dấu "=" và tên biến n để xác định
vùng nhớ mà p tham chiếu tới.
Về bản chất tham chiêu và tham trỏ giống nhau vì cùng chỉ đến đối tượng có địa
chỉ, cùng được cấp phát địa chỉ khi khai báo, nhưng cách sử dụng chúng thì khác
nhau. Khi nói đến tham chiếu "&p" ta phải gắn nó với một biến nào đó đã khai báo
qua "&p=n", trong khi đó khai báo con trỏ "*p" không nhất thiết phải khởi tạo giá
trị cho nó. Sau khi khởi tạo cho tham chiếu gắn với một biến nào đó rồi thì ta
không thể thay đổi để gắn tham chiếu với một biến khác, do vậy để truy nhập đến
vùng nhớ tương ứng với một biến chúng ta có thể sử dụng hoặc là tên biến hoặc là
tên tham chiếu tương ứng.
VD: #include<iostream.h>
8
Void main( )
{
int x=3, &y=x; // y lúc này là " bí danh" của x
cout<<"x="<<x<<"\n";
cout<<"y="<<y<<"\n";
y=7;
cout<<"x="<<x<<"\n";
<<"y="<<y<<"\n";
}
Không thể gắn một tham chiếu với một hằng số trừ trường hợp có từ khoá const
đứng trước khai báo tham chiếu.
Const int &p=3;
*Hằng tham chiếu.
Hằng tham chiếu được khai báo như sau:
Int n=5;
Const int &x=n;
Cũng giống như biến, hằng tham chiếu đến một biến hoặc một hằng.
Int n=5;
Const int &x=n;
Const int &y=100;
Hằng tham chiếu không được phép thay đổi giá trị của vùng nhớ mà nó tham
chiếu. Hằng tham chiếu thường được sử dụng làm đối của hàm để cho phép hàm sử
dụng giá trị của các tham số trong lời gọi hàm.
*Truyền tham số cho hàm bằng tham chiếu.
Nếu đối là biến hoặc hằng tham chiếu kiểu K thì tham số ( trong lời gọi hàm) phải
là biến hoặc phần tử mảng kiểu K.
VD:
/*swap.cpp*/
#include<iostream.h>
#include<conio.h>
/*Ham swap1 duoc goi voi cac tham so duoc truyen theo tham tri*/
void swap1(int x, int y)
{
int temp=x;
x=y;
y=temp;
}
/*Ham swap2 thuc hien viec truyen tham so bang tham tro*/
9
void swap2(int *x, int *y)
{
int temp=*x;
*x=*y;
*y=temp;
}
/*Ham swap3 thuc hien viec truyen tham so bang tham chieu*/
void swap3(int &x, int &y)
{
int temp=x;
x=y;
y=temp;
}
void main()
{
int a=2, b=3;
clrscr();
cout<<"Truoc khi goi swap1:\n";
cout<<"a = "<<a<<"b = "<<b<<"\n";
swap1(a,b);
cout<<"Sau khi goi ham swap1:\n";
cout<<"a = "<<a<<"b = "<<b<<"\n";
a=2;b=3;
cout<<"Truoc khi goi swap2:\n";
cout<<"a = "<<a<<"b = "<<b<<"\n";
swap2(&a,&b);
cout<<"Sau khi goi ham swap2:\n";
cout<<"a = "<<a<<"b = "<<b<<"\n";
a=2;b=3;
cout<<"Truoc khi goi swap3:\n";
cout<<"a = "<<a<<"b = "<<b<<"\n";
swap3(a,b);
cout<<"Sau khi goi ham swap3:\n";
cout<<"a = "<<a<<"b = "<<b<<"\n";
getch();
}
ket qua se la:
Truoc khi goi swap1:
a=2 b=3
Sau khi goi swap1:
a=2 b=3
Truoc khi goi swap2:
a=2 b=3
Sau khi goi swap2:
a=3 b=2
Truoc khi goi swap3:
a=2 b=3
10