Giáo trình Lập trình cơ bản C - Bài 15: Hàm

Bài 15  
Hàm  
Mục tiêu:  
Kết thúc bài học này, bạn thể:  
Tìm hiểu về cách sử dụng các hàm  
Tìm hiều về cấu trúc của một hàm  
Khai báo hàm và các nguyên mẫu hàm  
Thảo luận các kiểu khác nhau của biến  
Tìm hiểu cách gọi các hàm:  
Gọi bằng giá trị  
Gọi bằng tham chiếu  
Tìm hiểu về các qui tắc về phạm vi của hàm  
Tìm hiểu các hàm trong các chương trình có nhiều tập tin  
Tìm hiểu về các lớp lưu trữ  
Tìm hiểu về con trỏ hàm.  
Giới thiệu  
Một hàm là một đoạn chương trình thực hiện một tác vụ được định nghĩa cụ thể. Chúng thực chất là  
những đoạn chương trình nhỏ giúp giải quyết một vấn đề lớn.  
15.1 Sử dụng các hàm  
Nói chung, các hàm được sử dụng trong C để thực thi một chuỗi các lệnh liên tiếp. Tuy nhiên, cách sử  
dụng các hàm thì không giống với các vòng lặp. Các vòng lặp thể lặp lại một chuỗi các chỉ thị với  
các lần lặp liên tiếp nhau. Nhưng việc gọi một hàm sẽ sinh ra một chuỗi các chỉ thị được thực thi tại vị  
trí bất kỳ trong chương trình. Các hàm có thể được gọi nhiều lần khi có yêu cầu. Giả sử một phần của  
lệnh trong một chương trình dùng để tính tỉ lệ phần trăm cho một vài con số. Nếu sau đó, trong  
cùng chương trình, việc tính toán như vậy cần phải thực hiện trên những con số khác, thay phải viết  
lại các chỉ thị giống như trên, một hàm có thể được viết ra để tính tỉ lệ phần trăm của bất kỳ các con  
số. Sau đó chương trình có thể nhảy đến hàm đó, để thực hiện việc tính toán (trong hàm) và trở về nơi  
đã được gọi. Điều này sẽ được giải thích rõ ràng hơn khi thảo luận về cách hoạt động của các hàm.  
Một điểm quan trọng khác là các hàm thì dễ viết dễ hiểu. Các hàm đơn giản thể được viết để  
thực hiện các tác vụ xác định. Việc gỡ rối chương trình cũng dễ dàng hơn khi cấu trúc chương trình  
dễ đọc, nhờ vào sự đơn giản hóa hình thức của nó. Mỗi hàm có thể được kiểm tra một cách độc lập với  
các dữ liệu đầu vào, với dữ liệu hợp lệ cũng như không hợp lệ. Các chương trình chứa các hàm cũng  
dễ bảo trì hơn, bởi những sửa đổi, nếu yêu cầu, thể được giới hạn trong các hàm của chương  
trình. Một hàm không chỉ được gọi từ các vị trí bên trong chương trình, mà các hàm còn có thể đặt vào  
một thư viện được sử dụng bởi nhiều chương trình khác, vì vậy tiết kiệm được thời gian viết  
chương trình.  
15.2 Cấu trúc hàm  
Cú pháp tổng quát của một hàm trong C là:  
Hàm  
209  
type_specifier function_name (arguments)  
{
body of the function  
return statement  
}
type_specifier xác định kiểu dữ liệu của giá trị sẽ được trả về bởi hàm. Nếu không có kiểu được đưa  
ra, hàm cho rằng trả về một kết quả số nguyên. Các đối số được phân cách bởi dấu phẩy. Một cặp dấu  
ngoặc rỗng () vẫn phải xuất hiện sau tên hàm ngay cả khi nếu hàm không chứa bất kỳ đối số nào. Các  
tham số xuất hiện trong cặp dấu ngoặc () được gọi tham số hình thức hoặc đối số hình thức. Phần  
thân của hàm có thể chứa một hoặc nhiều câu lệnh. Một hàm nên trả về một giá trị và vì vậy ít nhất  
một lệnh return phải có trong hàm.  
15.2.1 Các đối số của một hàm  
Trước khi thảo luận chi tiết về các đối số, xem ví dụ sau,  
#include <stdio.h>  
main()  
{
int i;  
for(i =1; i <=10; i++)  
printf(“\nSquare of %d is %d “, i,squarer (i));  
}
squarer(int x)  
/* int x; */  
{
int j;  
j = x * x;  
return(j);  
}
Chương trình trên tính tính bình phương các số từ 1 đến 10. Điều này được thực hiện bằng việc gọi  
hàm squarer. Dữ liệu được truyền từ thủ tục gọi (trong trường hợp trên là hàm main()) đến hàm được  
gọi squarer thông qua các đối số. Trong thủ tục gọi, các đối số được biết như các đối số thực và  
trong định nghĩa của hàm được gọi (squarer()) các đối số được gọi là các đối số hình thức. Kiểu dữ  
liệu của các đối số thực phải cùng kiểu với các đối số hình thức. Hơn nữa, số lượng thứ tự của các  
tham số thực phải giống như của các tham số hình thức.  
Khi một hàm được gọi, quyền điều khiển sẽ được chuyển đến cho nó, ở đó các đối số hình thức được  
thay thế bởi các đối số thực. Sau đó hàm được thực thi và khi bắt gặp câu lệnh return, nó sẽ chuyển  
quyền điều khiển cho chương trình gọi nó.  
Hàm squarer() được gọi bằng cách truyền số cần được tính bình phương. Đối số x thể được khai  
báo theo một trong các cách sau khi định nghĩa hàm.  
Phương pháp 1  
squarer(int x)  
/* x được định nghĩa cùng với kiểu dữ liệu trong cặp dấu ngoặc ()*/  
Phương pháp 2  
squarer(x)  
210  
Lập trình cơ bản C  
int x;  
/* x được đặt trong cặp dấu ngoặc (), và kiểu của được khai báo  
ngay sau tên hàm */  
Chú ý, trong trường hợp sau, x phải được định nghĩa ngay sau tên hàm, trước khối lệnh. Điều này thật  
tiện lợi khi có nhiều tham số có cùng kiểu dữ liệu được truyền. Trong trường hợp như vậy, chỉ phải chỉ  
kiểu đề một lần duy nhất tại điểm bắt đầu.  
Khi các đối số được khai báo trong cặp dấu ngoặc (), mỗi đối số phải được định nghĩa riêng lẻ, cho dù  
chúng có cùng kiểu dữ liệu. dụ, nếu x và y là hai đối số của một hàm abc(), thì abc(char x,  
char y)một khai báo đúng abc(char x, y)là sai.  
15.2.2 Sự trả về từ hàm  
Lệnh return có hai mục đích:  
Ngay lập tức trả điều khiển từ hàm về chương trình gọi  
Bất kỳ cái gì bên trong cặp dấu ngoặc () theo sau return được trả về như một giá trị cho chương  
trình gọi.  
Trong hàm squarer(), một biến j kiểu int được định nghĩa để lưu giá trị bình phương của đối số truyền  
vào. Giá trị của biến này được trả về cho hàm gọi thông qua lệnh return. Một hàm có thể thực hiện  
một tác vụ xác định trả quyền điều khiển về cho thủ tục gọi nó mà không cần trả về bất kỳ giá trị  
nào. Trong trường hợp như vậy, lệnh return thể được viết dạng return(0) hoặc return. Chú ý  
rằng, nếu một hàm cung cấp một giá trị trả về và nó không làm điều đó thì nó sẽ trả về giá trị không  
thích hợp.  
Trong chương trình tính bình phương của các số, chương trình truyền dữ liệu tới hàm squarer thông  
qua các đối số. thể có các hàm được gọi mà không cần bất kỳ đối số nào. Ở đây, hàm thực hiện  
một chuỗi các lệnh trả về giá trị, nếu được yêu cầu  
Chú ý rằng, hàm squarer() cũng thể được viết như sau  
squarer(int x)  
{
return(x*x);  
}
Ở đây một biểu thức hợp lệ được xem như một đối số trong câu lệnh return. Trong thực tế, lệnh return  
thể được sử dụng theo một trong các cách sau đây:  
return;  
return(hằng);  
return(biến);  
return(biểu thức);  
return(câu lệnh đánh giá); dụ: return(a>b?a:b);  
Tuy nhiên, giới hạn của lệnh return là nó chỉ thể trả về một giá trị duy nhất.  
15.2.3 Kiểu của một hàm  
type-specifier được sử dụng để xác định kiểu dữ liệu trả về của một hàm. Trong ví dụ trên, type-  
specifier không được viết bên cạnh hàm squarer(), vì squarer() trả về một giá trị kiểu int. type-  
specifier là không bắt buộc nếu một giá trị kiểu số nguyên được trả về hoặc nếu không có giá trị nào  
Hàm  
211  
được trả về. . Tuy nhiên, tốt hơn nên chỉ ra kiểu dữ liệu trả về là int nếu một giá trị số nguyên được trả  
về tương tự dùng void nếu hàm không trả về giá trị nào.  
15.3 Gọi hàm  
thể gọi một hàm từ chương trình chính bằng cách sử dụng tên của hàm, theo sau là cặp dấu ngoặc  
(). Cặp dấu ngoặc cần thiết để nói với trình biên dịch đây một lời gọi hàm. Khi một tên hàm  
được sử dụng trong chương trình gọi, tên hàm có thể một phần của một một lệnh hoặc chính nó là  
một câu lệnh. Mà ta đã biết một câu lệnh luôn kết thúc với một dấu chấm phẩy (;). Tuy nhiên, khi định  
nghĩa hàm, không được dùng dấu chấm phầy ở cuối phần định nghĩa. Sự vắng mặt của dấu chấm phẩy  
nói với trình biên dịch đây phần định nghĩa của hàm và không được gọi hàm.  
Một số điểm cần nhớ:  
Một dấu chấm phẩy được dùng ở cuối câu lệnh khi một hàm được gọi, nhưng nó không được dùng  
sau một sự định nghĩa hàm.  
Cặp dấu ngoặc () là bắt buộc theo sau tên hàm, cho dù hàm có đối số hay không.  
Hàm gọi đến một hàm khác được gọi hàm gọi hay thủ tục gọi. Và hàm được gọi đến còn được  
gọi hàm được gọi hay thủ tục được gọi.  
Các hàm không trả về một giá trị số nguyên cần phải xác định kiểu của giá trị được trả về.  
Chỉ một giá trị thể được trả về bởi một hàm.  
Một chương trình có thể một hoặc nhiều hàm.  
15.4 Khai báo hàm  
Nếu mMột hàm nên được gọikhai báo trong hàm main() trước khi nó được định nghĩa hoặc sử dụng.  
Điều này phải được thực hiện trong trường hợp hàm được gọi trước khi nó được định nghĩa.thi hàm  
phải được khai báo trong hàm main() trước khi nó được sử dụng.  
Xem ví dụ,  
#include <stdio.h>  
main()  
{
.
.
address();  
.
.
}
address()  
{
.
.
.
}
Hàm main() gọi hàm address() và hàm address() được gọi trước khi nó được định nghĩa. Mặc dù, nó  
không được khai báo trong hàm main() thì điều này có thể thực hiện được trong một số trình biên dịch  
C, hàm address() được gọi mà không cần khai báo gì thêm cả. Đây sự khai báo không tường  
minh của một hàm.  
212  
Lập trình cơ bản C  
15.5 Các nguyên mẫu hàm  
Một nguyên mẫu hàm là một khai báo hàm trong đó xác định kiểu dữ liệu của các đối số trị trả  
về. Thông thường, các hàm được khai báo bằng cách xác định kiểu của giá trị được trả về bởi hàm, và  
tên hàm. Tuy nhiên, chuẩn ANSI C cho phép số lượng kiểu dữ liệu của các đối số hàm được khai  
báo. Một hàm abc() có hai đối số kiểu int là x và y, và trả về một giá trị kiểu char, có thể được khai  
báo như sau:  
char abc();  
hoặc  
char abc(int x, nt y);  
Cách định nghĩa sau được gọi nguyên mẫu hàm. Khi các nguyên mẫu được sử dụng, C có thể tìm  
và thông báo bất kỳ kiểu dữ liệu không hợp lệ khi chuyển đổi giữa các đối số được dùng để gọi một  
hàm với sự định nghĩa kiểu của các tham số. Một lỗi sẽ được thông báo ngay khi có sự khác nhau giữa  
số lượng các đối số được sử dụng để gọi hàm và số lượng các tham số khi định nghĩa hàm.  
Cú pháp tổng quát của một nguyên mẫu hàm:  
type function_name(type parm_namel,type parm_name2,..type  
parm_nameN);  
Khi hàm được khai báo không có các thông tin nguyên mẫu, trình biên dịch cho rằng không có thông  
tin về các tham số được đưa ra. Một hàm không có đối số thể gây ra lỗi khi khai báo không có  
thông tin nguyên mẫu. Để tránh điều này, khi một hàm không có tham số, nguyên mẫu của sử dụng  
void trong cặp dấu ngoặc (). Như đã nói trên, void cũng được sử dụng để khai báo tường minh một  
hàm không có giá trị trả về.  
dụ, nếu một hàm noparam() trả về kiểu dữ liệu char và không có các tham số được gọi, thể được  
khai báo như sau  
char noparam(void);  
Khai báo trên chỉ ra rằng hàm không có tham số, bất kỳ lời gọi truyền tham số đến hàm đó là  
không đúng.  
Khi một hàm không nguyên mẫu được gọi tất cả các kiểu char được đổi thành kiểu int tất cả kiểu  
float được đổi thành kiểu double. Tuy nhiên, nếu một hànghàm là nguyên mẫu, thì các kiểu đã đưa ra  
trong nguyên mẫu được giữ nguyên và không có sự tăng cấp kiểu xảy ra.  
15.6 Các biến  
Như đã thảo luận, các biến những vị trí được đặt tên trong bộ nhớ, được sử dụng để chứa giá trị có  
thể hoặc không thể được sửa đổi bởi một chương trình hoặc một hàm. Có ba loại biến cơ bản: biến cục  
bộ, tham số hình thức, biến toàn cục.  
1.Biến cục bộ những biến được khai báo bên trong một hàm.  
2.Tham số hình thức được khai báo trong một định nghĩa hàm như là các tham số.  
3.Biến toàn cục được khai báo bên ngoài các hàm.  
15.6.1 Biến cục bộ  
Biến cục bộ còn được gọi biến động, từ khoá auto được sử dụng để khai báo chúng. Chúng chỉ  
được tham chiếu đến bởi các lệnh bên trong của khối lệnh biến được khai báo. Để hơn, một biến  
Hàm  
213  
cục bộ được tạo ra trong lúc vào một khối bị huỷ trong lúc đi ra khỏi khối đó. Khối lệnh thông  
thường nhất mà trong đó một biến cục bộ được khai báo chính là hàm.  
Xem đoạn lệnh sau:  
void blkl(void) /* void denotes no value returned*/  
{
char ch;  
ch = ‘a’;  
.
.
}
void blk2(void)  
{
char ch;  
ch = ‘b’;  
.
.
}
Biến ch được khai báo hai lần, trong blk1() blk2(). ch trong blk1() không có liên quan đến ch  
trong blk2() bởi mỗi ch chỉ được biết đến trong khối lệnh mà nó được khai báo.  
Vì các biến cục bộ được tạo ra và huỷ đi trong một khối mà chúng được khai báo, nên nội dung của  
chúng bị mất bên ngoài phạm vi của khối. Điều này có nghĩa là chúng không thể duy trì giá trị của  
chúng giữa các lần gọi hàm.  
Từ khóa auto thể được dùng để khai báo các biến cục bộ, nhưng thường nó không được dùng vì  
mặc nhiên các biến không toàn cục được xem như biến cục bộ.  
Các biến cục bộ được sử dụng bởi các hàm thường được khai báo ngay sau dấu ngoặc mở ‘{‘ của hàm  
trước tất cả các câu lệnh. Tuy nhiên, các khai báo có thể ở bên trong một khối của một hàm. Ví dụ,  
void blk1(void)  
{
int t;  
t = 1;  
if(t > 5)  
{
char ch;  
.
.
}
.
}
Trong ví dụ trên biến ch được tạo ra và chỉ hợp lệ bên trong khối lệnh if’. Nó không thể được tham  
chiếu đến trong một phần khác của hàm blk1().  
Một trong những thuận lợi của sự khai báo một biến theo cách này đó bộ nhớ sẽ chỉ được cấp phát  
cho nó khi nếu điều kiện để đi vào khối lệnh if được thoả. Điều này là bởi vì các biến cục bộ chỉ được  
khai báo khi đi vào khối lệnh mà các biến được định nghĩa trong đó.  
Chú ý: Điều quan trọng cần nhớ tất cả các biến cục bộ phải được khai báo tại điểm bắt đầu của khối  
mà trong đó chúng được định nghĩa, trước tất cả các câu lệnh thực thi.  
214  
Lập trình cơ bản C  
dụ sau có thể không làm việc với một số các trình biên dịch.  
void blk1(void)  
{
int len;  
len = 1;  
char ch; /* This will cause an error */  
ch = ‘a’;  
.
.
}
15.6.2 Tham số hình thức  
Một hàm sử dụng các đối số phải khai báo các biến để nhận các giá trị của các đối số. Các biến này  
được gọi tham số hình thức của hàm và hoạt động giống như bất kỳ một biến cục bộ bên trong  
hàm.  
Các biến này được khai báo bên trong cặp dấu ngoặc () theo sau tên hàm. Xem ví dụ sau:  
blk1(char ch, int i)  
{
if(i > 5)  
ch = ‘a’;  
else  
i = i +1;  
return;  
}
Hàm blk1() có hai tham số: ch i.  
Các tham số hình thức phải được khai báo cùng với kiểu của chúng. Như trong ví dụ trên, ch kiều  
char i kiểu int. Các biến này có thể được sử dụng bên trong hàm như các biến cục bộ bình  
thường. Chúng bị huỷ đi khi ra khỏi hàm. Cần chú ý là các tham số hình thức đã khai báo có cùng kiểu  
dữ liệu với các đối số được sử dụng khi gọi hàm. Trong trường hợp có sai, C có thể không hiển thị lỗi  
nhưng thể đưa ra một kết quả không mong muốn. Điều này là vì, C vẫn đưa ra một vài kết quả  
trong các tình huống khác thường. Người lập trình phải đảm bảo rằng không có các lỗi về sai kiểu.  
Cũng giống như với các biến cục bộ, các phép gán cũng thể được thực hiên với tham số hình thức  
của hàm và chúng cũng thể được sử dụng bất kỳ biểu thức nào mà C cho phép.  
15.6.3 Biến toàn cục  
Các biến toàn cục biến được thấy bởi toàn bộ chương trình, và thể được sử dụng bởi một lệnh  
bất kỳ. Chúng được khai báo bên ngoài các hàm của chương trình và lưu giá trị của chúng trong suốt  
sự thực thi của chương trình. Các biến này có thể được khai báo bên ngoài main() hoặc khai báo bất  
kỳ nơi đâu trước lần sử dụng đầu tiên. Tuy nhiên, tốt nhất để khai báo các biến toàn cục tại đầu  
chương trình, nghĩa trước hàm main().  
int ctr; /* ctr is global */  
void blk1(void);  
void blk2(void);  
void main(void)  
{
Hàm  
215  
ctr = 10;  
blk1 ();  
.
.
}
void blk1(void)  
{
int rtc;  
if (ctr > 8)  
{
rtc = rtc + 1;  
blk2();  
}
}
void blk2(void)  
{
int ctr;  
ctr = 0;  
}
Trong đoạn lệnh trên, ctr một biến toàn cục được khai báo bên ngoài hàm main() và blk1(),  
nó có thể được tham chiếu đến trong các hàm. Biến ctr trong blk2(), là một biến cục bộ và không có  
liên quan với biến toàn cục ctr. Nếu một biến toàn cục cục bộ có cùng tên, tất cả các tham chiếu  
đến tên đó bên trong khối chứa định nghĩa biến cục bộ sẽ được kết hợp với biến cục bộ mà không phải  
biến toàn cục.  
Các biến toàn cục được lưu trữ trong các vùng cố định của bộ nhớ. Các biến toàn cục hữu dụng khi  
nhiều hàm trong chương trình sử dụng cùng dữ liệu. Tuy nhiên, nên tránh sử dụng biến toàn cục nếu  
không cần thiết, vì chúng giữ bộ nhớ trong suốt thời gian thực hiện chương trình. Vì vậy việc sử dụng  
một biến toàn cục ở nơi một biến cục bộ khả năng đáp ứng cho hàm sử dụng là không hiệu quả.  
dụ sau sẽ giúp làm rõ hơn điều này:  
void addgen(int i, int j)  
{
return(i + j);  
}
int i, j;  
void addspe(void)  
{
return(i + j);  
}
Cả hai hàm addgen() addspe() đều trả về tổng của các biến i j. Tuy nhiên, hàm addgen() được  
sử dụng để trả về tổng của hai số bất kỳ; trong khi hàm addspe() chỉ trả về tổng của các biến toàn cục  
i j.  
15.7 Lớp lưu trữ (Storage Class)  
Mỗi biến trong C có một đặc trưng được gọi lớp lưu trữ. Lớp lưu trữ xác định hai khía cạnh của  
biến: thời gian sống của biến phạm vi của biến. Thời gian sống của một biến thời gian mà giá  
trị của biến tồn tại. Phạm viSự thấy được của một biến xác định các phần của một chương trình sẽ có  
thể nhận ra biến. Một biến thể tầm nhìn trong một khối, một hàm, một tập tin, một nhóm các tập  
tin, hoặc toàn bộ chương trình.Một biến thể xuất hiện trong một khối, một hàm, một tập tin, một  
nhóm các tập tin, hoặc toàn bộ chương trình  
216  
Lập trình cơ bản C  
Theo cách nhìn của trình biên dịch C, một tên biến xác định một vài vị trí vật lý bên trong máy tính, ở  
đó một chuỗi các bit biểu diễn giá trị được lưu trữ của biến. Có hai loại vị trí trong máy tính mà ở đó  
giá trị của biến thể được lưu trữ: bộ nhớ hoặc thanh ghi CPU. Lớp lưu trữ của biến xác định vị trí  
biến được lưu trữ là trong bộ nhớ hay trong một thanh ghi. C có bốn lớp lưu trữ. Đó là:  
auto  
external  
static  
register  
Đó là các từ khoá. Cú pháp tổng quát cho khai báo biến như sau:  
storage_specifier type var_name;  
15.7.1 Biến tự động  
Biến tự động thật ra là biến cục bộ mà chúng ta đã nói trên. Phạm vi của một biến tự động thể nhỏ  
hơn hàm, nếu được khai báo bên trong một câu lệnh ghép: phạm vi của bị giới hạn trong câu  
lệnh ghép đó. Chúng có thể được khai báo bằng từ khóa auto, nhưng sự khai báo này là không cần  
thiết. Bất kỳ một biến được khai báo bên trong một hàm hoặc một khối lệnh thì mặc nhiên là thuộc lớp  
auto và hệ thống cung cấp vùng bộ nhớ được yêu cầu cho biến đó.  
15.7.2 Biến ngoại  
Trong C, một chương trình lớn thể được chia thành các module nhỏ hơn, các module này có thể  
được biên dịch riêng lẻ được liên kết lại với nhau. Điều này được thực hiện nhằm tăng tốc độ quá  
trình biên dịch các chương trình lớn. Tuy nhiên, khi các module được liên kết, các tập tin phải được  
chương trình thông báo cho biết về các biến toàn cục được yêu cầu. Một biến toàn cục chỉ thể được  
khai báo một lần. Nếu hai biến toàn cục có cùng tên được khai báo trong cùng một tập tin, một thông  
điệp lỗi duplicate variable name’ (tên biến trùng) có thể được hiển thị hoặc đơn giản trình biên dịch  
C chọn một biến khác. Một lỗi tương tự xảy ra nếu tất cả các biến toàn cục được yêu cầu bởi chương  
trình được chứa trong mỗi tập tin. Mặc dù trình biên dịch không đưa ra bất kỳ một thông báo lỗi nào  
trong khi biên dịch, nhưng sự thật các bản sao của cùng một biến đang được tạo ra. Tại thời điểm liên  
kết các tập tin, bộ liên kết sẽ hiển thị một thông báo lỗi như sau ‘duplicate label’ (nhãn trùng nhau) vì  
nó không biết sử dụng biến nào. Lớp extern được dùng trong trường hợp này. Tất cả các biến toàn cục  
được khai báo trong một tập tin và các biến giống nhau được khai báo như biến ngoạiở ngoài trong  
tất cả các tập tin. Xem đoạn lệnh sau:  
Filel  
File2  
int i,j;  
extern int i,j;  
char a;  
extern char a;  
main()  
xyz()  
{
{
.
i = j * 5  
.
.
.
.
}
}
abc()  
{
pqr()  
{
i = 123;  
j = 50;  
.
.
.
.
}
}
Hàm  
217  
File2 có các biến toàn cục giống như File1, ngoại trừ một điểm là các biến này có từ khóa extern  
được thêm vào sự khai báo của chúng. Từ khóa này nói với trình biên dịch là tên và kiểu của biến toàn  
cục được sử dụng mà không cần phải tạo lại sự lưu trữ cho chúng. Khi hai module được liên kết, các  
tham chiếu đến các biến ngoại được giải quyết.  
Nếu một biến không được khai báo trong một hàm, trình biên dịch sẽ kiểm tra nó có so khớp với bất  
kỳ biến toàn cục nào không. Nếu khớp với một biến toàn cục, thì trình biên dịch sẽ xem như một biến  
toàn cục đang được tham chiếu đến.  
15.7.3 Biến tĩnh  
Các biến tĩnh là các biến cố định bên trong các hàm và các tập tin. Không giống như các biến toàn  
cục, chúng không được biết đến bên ngoài hàm hoặc tập tin của chúng, nhưng chúng giữ được giá trị  
của chúng giữa các lần gọi. Điều này có nghĩa là, nếu một hàm kết thúc và sau đó được gọi lại, các  
biến tĩnh đã định nghĩa trong hàm đó vẫn giữ được giá trị của chúng. Sự khai báo biến tĩnh được bắt  
đầu với từ khóa static.  
thể định nghĩa các biến tĩnh có cùng tên như hướng dẫn với các biến ngoại. Các biến cục bộ (biến  
tĩnh cũng như biến động) độ ưu tiên cao hơn các biến ngoại và giá trị của các biến ngoại sẽ không  
ảnh hưởng bởi bất kỳ sự thay đổi nào các biến cục bộ. Các biến ngoại có cùng tên với các biến nội  
trong một hàm không thể được truy xuất trực tiếp bên trong hàm đó.  
Các giá trị khởi tạo thể được gán cho các biến trong sự khai báo các biến tĩnh, nhưng các giá trị này  
phải là các hằng hoặc các biểu thức. Trình biên dịch tự động gán một giá trị mặc nhiên 0 đến các biến  
tĩnh không được khởi tạo. Sự khởi tạo thực hiện ở đầu chương trình.  
Xem hai chương trình sau. Sự khác nhau giữa biến cục bộ: tự động tĩnh sẽ được làm rõ.  
dụ về biến tự động:  
#include <stdio.h>  
main()  
{
incre();  
incre();  
incre();  
}
incre()  
{
char var = 65;  
/* var is automatic variable*/  
printf(“\nThe character stored in var is %c”, var++);  
}
kKết quả thực thi của chương trình trên sẽ là:  
The character stored in var is A  
The character stored in var is A  
The character stored in var is A  
dụ về biến tĩnh:  
#include<stdio.h>  
main()  
218  
Lập trình cơ bản C  
{
}
incre();  
incre():  
incre():  
incre()  
{
static char var = 65; /* var is static variable */  
printf(“nThe character stored in var is %c”, var++);  
}
kKết quả thực thi của chương trình trên sẽ là:  
The character stored in var is A  
The character stored in var is B  
The character stored in var is C  
Cả hai chương trình gọi incre() ba lần. Trong chương trình thứ nhất, mỗi lần incre() được gọi, biến  
var với lớp lưu trữ auto (lớp lưu trữ mặc định) được khởi tạo lại là 65 (là mã ASCII tương ứng của ký  
tự A). Vì vậy khi kết thúc hàm, giá trị mới của var (66) bị mất đi (ASCII ứng với tự B).  
Trong chương trình thứ hai, var của lớp lưu trữ static. Ở đây var được khởi tạo là 65 chỉ một lần  
duy nhất khi biên dịch chương trình. Cuối lần gọi hàm đầu tiên, var có giá trị 66 (ASCII B) và tương  
tự ở lần gọi kế tiếp var có giá trị 67 (ASCII C). Sau lần gọi hàm cuối cùng, var được tăng giá trị theo  
sự thực thithi hành của lệnh printf(). Giá trị này bị mất khi chương trình kết thúc.  
15.7.4 Biến thanh ghi  
Các máy tính có các thanh ghi trong bộ số học logic - Arithmetic Logic Unit (ALU), các thanh ghi này  
được sử dụng để tạm thời lưu trữ dữ liệu được truy xuất thường xuyên. Kết quả tức thời của phép tính  
toán cũng được lưu vào các thanh ghi. Các thao tác thực hiện trên dữ liệu lưu trữ trong các thanh ghi  
thì nhanh hơn dữ liệu trong bộ nhớ. Trong ngôn ngữ assembly (hợp ngữ), người lập trình phải truy  
xuất đến các thanh ghi này và sử dụng chúng để giúp chương trình chạy nhanh hơn. Các ngôn ngữ lập  
trình bậc cao thường không truy xuất đến các thanh ghi của máy tính. Trong C, việc lựa chọn vị trí lưu  
trữ cho một giá trị tùy thuộc vào người lập trình. Nếu một giá trị đặc biệt được dùng thường xuyên (ví  
dụ giá trị điều khiển của một vòng lặp), lớp lưu trữ của nó có thể khai báo là register. Sau đó nếu  
trình biên dịch tìm thấy một thanh ghi còn trống, và các thanh ghi của máy tính đủ lớn để chứa biến,  
biến sẽ được đặt vào thanh ghi đó. Ngược lại, trình biên dịch sẽ xem các biến thanh ghi như các biến  
động khác, nghĩa lưu trữ chúng trong bộ nhớ. Từ khóa register được dùng khi định nghĩa các biến  
thanh ghi.  
Phạm vi sự khởi tạo của các biến thanh ghi là giống như các biến động, ngoại trừ vị trí lưu trữ.  
Các biến thanh ghi cục bộ trong một hàm. Nghĩa là, chúng tồn tại khi hàm được gọi và giá trị bị mất  
đi một khi thoát khỏi hàm. Sự khởi tạo các biến này được thực hiện bởi người lập trình.  
số lượng các thanh ghi là có hạn, lập trình viên cần xác định các biến nào trong chương trình được  
sử dụng thường xuyên để khai báo chúng là các biến thanh ghi.  
Sự hữu dụng của các biến thanh ghi thay đổi từ máy này đến một máy khác và từ một trình biên dịch  
C này đến một trình biên dịch khác. Đôi khi các biến thanh ghi không được hỗ trợ bởi tất cả từ khóa  
register vẫn được chấp nhận nhưng được xem giống như từ khóa auto. Trong các trường hợp khác,  
nếu biến thanh ghi được hỗ trợ nếu lập trình viên sử dụng chúng một cách hợp lý, chương trình sẽ  
được thực thi nhanh hơn gấp đôi.  
Hàm  
219  
Các biến thanh ghi được khai báo như bên dưới:  
register int x;  
register char c;  
Sự khai báo thanh ghi chỉ thể gắn vào các biến động và tham số hình thức. Trong trường hợp sau,  
sự khai báo sẽ giống như sau:  
f(c,n)  
register int c, n;  
{
register int i;  
.
.
.
}
Xét một dụ, ở đó chương trình hiển thị tổng lập phương các số thành phần của một số bằng chính số  
đó. dụ 370 là một số như vậy, vì:  
3
3
3
3 + 7 + 0 = 27 + 343 + 0 = 370  
Chương trình sau in ra các con số như vậy trong khoảng 1 đến 999.  
#include <stdio.h>  
main()  
{
register int i;  
int no, digit, sum;  
printf(“\nThe numbers whose Sum of Cubes of Digits is Equal  
to the number itself are:\n\n”);  
for(i = 1; i < 999; i++)  
{
sum = 0;  
no = i;  
while(no)  
{
digit = no%10;  
no = no/10;  
sum = sum + digit * digit * digit;  
}
if (sum == i)  
printf(“t%d\n”, i);  
}
}
Kết quả thực thi của chương trình trên như sau:  
The numbers whose Sum of Cubes of Digits is Equal to the  
number itself are:  
1
153  
370  
371  
220  
Lập trình cơ bản C  
407  
Trong chương trình trên, giá trị của i , thay đổi từ 1 đến 999. Với mỗi giá trị này, lập phương của từng  
con số riêng lẻ được cộng kết quả tổng được so sánh với i. Nếu hai giá trị này là bằng nahunhau, i  
được hiển thị. i được sử dụng để điều khiển sự lặp, (phần chính của chương trình), nó được khai  
báo là của lớp lưu trữ thanh ghi. Sự khai báo này làm tăng hiệu quả của chương trình.  
15.8 Các qui luật về phạm vi của một hàm  
Qui luật về phạm vi là những qui luật quyết định một đoạn lệnh thể truy xuất đến một đoạn mã  
lệnh khác hayhoặc dữ liệu hay không. Trong C, mỗi hàm của chương trình là các khối lệnh riêng lẻ.  
lệnh bên trong một hàm là cục bộ với hàm đó và không thể được truy xuất bởi bất kỳ lệnh nào ở  
ngoài hàm, ngoại trừ lời gọi hàm. Mã lệnh bên trong một hàm là ẩn đối với phần còn lại của chương  
trình, và trừ khi nó sử dụng biến hoặc dữ liệu toàn cục, nó có thể tác động hoặc bị tác động bởi các  
phần khác của chương trình. Để hơn, lệnh dữ liệu được định nghĩa bên trong một hàm không  
thể tương tác với lệnh hay dữ liệu được định nghĩa trong hàm khác bởi vì hai hàm có phạm vi khác  
nhau.  
Trong C, tất cả các hàm có cùng mức phạm vi. Nghĩa là, một hàm không thể được định nghĩa bên  
trong một hàm khác. Chính vì lý do này mà C không phải một ngôn ngữ cấu trúc khối về mặt kỹ  
thuật.  
15.9 Gọi hàm  
Một cách tổng quát, các hàm giao tiếp với nhau bằng cách truyền tham số. Các tham số được truyền  
theo một trong hai cách sau:  
Truyền bằng giá trị  
Truyền bằng tham chiếu.  
15.9.1 Truyền bằng giá trị  
Mặc nhiên trong C, tất cả các đối số của hàm được truyền bằng giá trị. Điều này có nghĩa là, khi các  
đối số được truyền đến hàm được gọi, các giá trị được truyền thông qua các biến tạm. Mọi sự thao tác  
chỉ được thực hiện trên các biến tạm này. Hàm được gọi không thể thay đổi giá trị của chúng. Xem ví  
dụ sau,  
#include <stdio.h>  
main()  
{
int a, b, c;  
a = b = c = 0;  
printf(“\nEnter 1st integer: “);  
scanf(“%d”, &a);  
printf(“\nEnter 2nd integer: “);  
scanf(“%d”, &b);  
c = adder(a, b);  
printf(“\n\na & b in main() are: %d, % d”, a, b);  
printf(“\n\nc in main() is: %d”, c);  
/* c gives the addition of a and b */  
}
adder(int a, int b)  
{
int c;  
Hàm  
221  
c = a + b;  
a *= a;  
b += 5;  
printf(“\n\na & b within adder function are: %d, %d “, a, b);  
printf(“\nc within adder function is : %d”,c);  
return(c);  
}
dụ về kết quả thực thi khi nhập vào 2 và 4:  
a & b in main() are: 2, 4  
c in main() is: 6  
a & b within adder function are: 4, 9  
c within adder function is : 6  
Chương trình trên nhận hai số nguyên, hai số này được truyền đến hàm adder(). Hàm adder() thực  
hiện như sau: nó nhận hai số nguyên như là các đối số của nó, cộng chúng lại, tính bình phương cho số  
nguyên thứ nhất, cộng 5 vào số nguyên thứ hai, in kết quả trả về tổng của các đối số thực. Các  
biến được sử dụng trong hàm main() và adder() có cùng tên. Tuy nhiên, không có gì là chung giữa  
chúng. Chúng được lưu trữ trong các vị trí bộ nhớ khác nhau. Điều này được thấy từ kết quả của  
chương trình trên. Các biến a và b trong hàm adder() được thay đổi từ 2 và 4 thành 4 và 9. Tuy nhiên,  
sự thay đổi này không ảnh hưởng đến các giá trị của a và b trong hàm main(). Các biến được lưu ở  
những vị trí bộ nhớ khác nhau. Biến c trong main() thì khác với biến c trong adder().  
vậy, các đối số được gọi truyền bằng giá trị khi giá trị của các biến được truyền đến hàm được  
gọi bất kỳ sự thay đổi trn giá trị này cũng không ảnh hưởng đến giá trị gốc của biến đã truyền.  
15.9.2 Truyền bằng tham chiếu  
Khi các đối số được truyền bằng giá trị, các giá trị của đối số của hàm đang gọi không bị thay đổi.  
Tuy nhiên, có thể trường hợp, ở đó giá trị của các đối số phải được thay đổi. Trong những trường  
hợp như vậy, truyền bằng tham chiếu được dùng. Truyền bằng tham chiếu, hàm được phép truy  
xuất đến vùng bộ nhớ thực của các đối số và vì vậy thể thay đổi giá trị của các đối số của hàm gọi.  
dụ, xét một hàm, hàm này nhận hai đối số, hoán vị giá trị của chúng và trả về các giá trị của chúng.  
Nếu một chương trình giống như chương trình dưới đây được viết để giải quyết mục đích này, thì sẽ  
không bao giờ thực hiện được.  
#include <stdio.h>  
main()  
{
int x, y;  
x = 15; y = 20;  
printf(“x = %d, y = %d\n”, x, y);  
swap(x, y);  
printf(“\nAfter interchanging x = %d, y = %d\n”, x, y);  
}
swap(int u, int v)  
{
int temp;  
temp = u;  
u = v;  
v = temp;  
return;  
222  
Lập trình cơ bản C  
}
Kết quả thực thi của chương trình trên như sau:  
x = 15, y = 20  
After interchanging x = 15, y = 20  
Hàm swap() hoán vị các giá trị của u và v, nhưng các giá trị này không được truyền trở về hàm  
main(). Điều này là bởi vì các biến u v trong swap() là khác với các biến u v được dùng trong  
main(). Truyền bằng tham chiếu thể được sử dụng trong trường hợp này để đạt được kết quả mong  
muốn, bởi vì nó sẽ thay đổi các giá trị của các đối số thực. Các con trỏ được dùng khi thực hiện truyền  
bằng tham chiếu.  
Các con trỏ được truyền đến một hàm như là các đối số để cho phép hàm được gọi của chương trình  
truy xuất các biến phạm vi của nó không vượt ra khỏi hàm gọi. Khi một con trỏ được truyền đến  
một hàm, địa chỉ của dữ liệu được truyền đến hàm nên hàm có thể tự do truy xuất nội dung của địa chỉ  
đó. Các hàm gọi nhận ra bất kỳ thay đổi trong nội dung của địa chỉ. Theo cách này, đối số hàm cho  
phép dữ liệu được thay đổi trong hàm gọi, cho phép truyền dữ liệu hai chiều giữa hàm gọi và hàm  
được gọi. Khi các đối số của hàm là các con trỏ hoặc mảng, truyền bằng tham chiếu được tạo ra đối  
nghịch với cách truyền bằng giá trị.  
Các đối số hình thức của một hàm là các con trỏ thì phải một dấu * phía trước, giống như sự khai  
báo biến con trỏ, để xác định chúng là các con trỏ. Các đối số thực kiểu con trỏ trong lời gọi hàm có  
thể được khai báo là một biến con trỏ hoặc một biến được tham chiếu đến (&var).  
dụ, định nghĩa hàm  
getstr(char *ptr_str, int *ptr_int)  
đối số ptr_str trỏ đến kiểu char ptr_int trỏ đến kiểu int. Hàm có thể được gọi bằng câu lệnh,  
getstr(pstr, &var)  
ở đó pstr được khai báo là một con trỏ địa chỉ của biến var được truyền. Gán giá trị thông qua,  
*ptr_int = var;  
Hàm bây giờ thể gán các gtrị đến biến var trong hàm gọi, cho phép truyền theo hai chiều đến và  
từ hàm.  
char *pstr;  
Quan sát ví dụ sau của hàm swap(). Bài toán này sẽ giải quyết được khi con trỏ được truyền thay vì  
dùng biến. lệnh tương tự như sau:  
#include <stdio.h>  
void main()  
{
int x, y, *px, *py;  
/* Storing address of x in px */  
px = &x;  
/* Storing address of y in py */  
py = &y;  
Hàm  
223  
x = 15; y = 20;  
printf(“x = %d, y = %d \n”, x, y);  
swap (px, py);  
/* Passing addresses of x and y */  
printf(“\n After interchanging x = %d, y = %d\n”, x, y);  
}
swap(int *u, int *v)  
/* Accept the values of px and py into u and v */  
{
int temp;  
temp = *u;  
*u = *v;  
*v = temp;  
return;  
}
Kết quả thực thi của chương trình trên như sau:  
x = 15, y = 20  
After interchanging x = 20, y = 15  
Hai biến kiểu con trỏ px py được khai báo, và địa chỉ của biến x y được gán đến chúng. Sau đó  
các biến con trỏ được truyền đến hàm swap(), hàm này hoán vị các giá trị lưu trong x và y thông qua  
các con trỏ.  
15.10 Sự lồng nhau của lời gọi hàm  
Lời gọi một hàm từ một hàm khác được gọi sự lồng nhau của lời gọi hàm. Một chương trình kiểm  
tra một chuỗi phải chuỗi đọc xuôi - đọc ngược như nhau hay không, là một dụ cho các lời gọi  
hàm lồng nhau. Từ đọc xuôi - ngược giống nhau là một chuỗi các ký tự đối xứng. Xem đoạn lệnh  
theo sau đây:  
main()  
{
.
.
palindrome();  
.
.
}
palindrome()  
{
.
.
getstr();  
reverse();  
cmp();  
.
.
}
224  
Lập trình cơ bản C  
Trong chương trình trên, hàm main() gọi hàm palindrome(). Hàm palindrome() gọi đến ba hàm khác  
getstr(), reverse() cmp(). Hàm getstr() để nhận một chuỗi tự từ người dùng, hàm reverse() đảo  
ngược chuỗi và hàm cmp() so sánh chuỗi được nhập vào và chuỗi đã được đảo.  
main() gọi palindrome(), hàm palindrome() lần lượt gọi các hàm getstr(), reverse() và cmp(),  
các lời gọi hàm này được gọi được lồng bên trong palindrome().  
Sự lồng nhau của các lời gọi hàm như trên là được phép, trong khi định nghĩa một hàm bên trong một  
hàm khác là không được chấp nhận trong C.  
15.11 Hàm trong chương trình nhiều tập tin  
Các chương trình có thể được tạo bởi nhiều tập tin. Những chương trình như vậy được tạo bởi các hàm  
lớn, ở đó mỗi hàm có thể chiếm một tập tin. Cũng như các biến trong các chương trình nhiều tập tin,  
các hàm cũng thể được định nghĩa static hoặc external. Phạm vi của hàm external có thể được  
sử dụng trong tất cả các tập tin của chương trình, và đó là cách lưu trữ mặc định cho các tập tin. Các  
hàm static chỉ được nhận biết bên trong tập tin chương trình và phạm vi của nó không vượt khỏi tập tin  
chương trình. Phần tiêu đề (header) của hàm như sau,  
static fn _type fn_name (argument list)  
hoặc  
extern fn_type fn_name (argument list)  
Từ khóa extern một tuỳ chọn (không bắt buộc) vì nó là lớp lưu trữ mặc định.  
15.12 Con trỏ đến hàm  
Một đặc tính mạnh mẽ của C vẫn chưa được đề cập, chính là con trỏ hàm. Dù rằng một hàm không  
phải một biến, nhưng nó có địa chỉ vật lý trong bộ nhớ nơi thể gán cho một con trỏ. Một địa chỉ  
hàm là điểm bắt đầuđi vào của hàm và con trỏ hàm có thể được sử dụng để gọi hàm.  
Để hiểu các con trỏ hàm làm việc như thế nào, thật sự cần phải hiểu thật một hàm được biên dịch và  
được gọi như thế nào trong C. Khi mỗi hàm được biên dịch, nguồn được chuyển thành mã đối  
tượng một điểm bắt đầuđi vào của hàm được thiết lập. Khi một lời gọi được thực hiện đến một  
hàm, một lời gọi ngôn ngữ máy được thực hiện để chuyển điều khiển đến điểm bắt đầuđi vào của hàm.  
vậy, nếu một con trỏ chứa địa chỉ của điểm bắt đầuđi vào của hàm, nó có thể được dùng để gọi hàm  
đó. Địa chỉ của một hàm có thể lấy được bằng cách sử dụng tên hàm không có dấu ngoặc () hay bất kỳ  
đối số nào. Chương trình sau sẽ minh họa khái niệm của con trỏ hàm.  
#include <stdio.h>  
#include <string.h>  
void check(char *a, char *b, int (*cmp)());  
main()  
{
char s1[80], s2[80];  
int (*p)();  
p = strcmp;  
gets(s1);  
gets(s2);  
check(s1, s2, p);  
}
Hàm  
225  
void check(char *a, char *b, int (*cmp)())  
{
printf(“Testing for equality \n”);  
if(!(*cmp)(a, b))  
printf(“Equal”);  
else  
printf(“Not Equal”);  
}
Hàm check() được gọi bằng cách truyền hai con trỏ tự một con trỏ hàm. Trong hàm check(), các  
đối số được khai báo là các con trỏ tự một hàm con trỏ. Chú ý cách khai báo một hàm con trỏ  
được khai báo. Cú pháp tương tự được dùng khi khai báo các hàm con trỏ khác bất luận đó kiểu trả  
về của hàm. Cặp dấu ngoặc () bao quanh *cmp cần thiết để chương trình biên dịch hiểu câu lệnh  
này một cách rõ ràng.  
226  
Lập trình cơ bản C  
Tóm tắt bài học  
Trong C, các hàm được dùng để thực thi một chuỗi các chỉ thị nhiều hơn một lần.  
type_specifier xác định kiểu dữ liệu của giá trị sẽ được trả về bởi hàm.  
Các đối số tới hàm có thể là các hằng, biến, biểu thức hay các hàm.  
Các đối số còn được gọi các đối số thực trong hàm gọi đối số hình thức trong hàm được  
gọi.  
Một hàm phải được khai báo trong hàm main(), trước khi nó được định nghĩa hay sử dụng.  
Trong C, mặc định, tất cả các đối số của hàm được truyền bằng giá trị.  
Có ba loại biến cơ bản: biến cục bộ, tham số hình thức biến toàn cục.  
Biến cục bộ được khai báo bên trong một hàm.  
Tham số hình thức được khai báo trong định nghĩa của tham số hàm.  
Biến toàn cục được khai báo bên ngoài tất cả các hàm.  
Lớp lưu trữ định nghĩa hai đặc tính của biến; thời gian sống của biến tầm nhìn hay phạm vi.  
Các biến tự động giống như các biến cục bộ.  
Tất cả các biến toàn cục được khai báo trong một tập tin và giống với các biến được khai báo  
extern trong tất cả các tập tin.  
Các biến static là các biến cố định bên trong các hàm hoặc tập tin của chúng.  
Không giống các biến toàn cục, các biến tĩnh không được nhận biết bên ngoài hàm hoặc tập tin  
của nó, nhưng chúng duy trì được các giá trị của chúng giữa các lần gọi.  
Nếu một giá trị đặc biệt được sử dụng thường xuyên, có thể dùng lớp lưu trữ register cho nó.  
Cũng giống như các biến trong các chương trình có nhiều tập tin, các hàm cũng thể được định  
nghĩa static hay external.  
lệnh dữ liệu được định nghĩa bên trong một hàm không thể tương tác với lệnh hay dữ  
liệu được định nghĩa trong hàm khác bởi vì hai hàm có phạm vi khác nhau.  
Một hàm không thể được định nghĩa bên trong một hàm khác.  
Một nguyên mẫu hàm là một sự khai báo hàm xác địnhđể chỉ ra các kiểu dữ liệu của các đối số.  
Lời gọi một hàm từ bên trong một hàm khác được gọi sự làm tổ của lời gọi hàm.  
Một con trỏ hàm có thể được dùng để gọi một hàm.  
Hàm  
227  
Kiểm tra tiến độ học tập  
1. Một_________ một đoạn chương trình chứa chính nó và thực hiện một tác vụ xác địnhcụ thể.  
2. Các đối số xuất hiện trong cặp dấu ngoặc () còn được gọi là _____________.  
3. Nếu không có lệnh return, điều khiển chuyển đến chương trình gọi khi gặp dấu ngoặc đóng } của  
khối lệnh. Điều này được gọi là ____________.  
4. Hàm gọi đến một hàm khác có tên là ________ và hàm đang được gọi đến có tên là ________.  
5. Một __________ là một sự khai báo hàm để xác địnhchỉ ra kiểu dữ liệu của các đối số.  
6. _________ chỉ thể được tham chiếu đến bởi các lệnh bên trong khối lệnh đã khai báo chúng.  
7. ________ được nhìn thấy bởi toàn bộ chương trình, và có thể được sử dụng ở bất kỳ lệnh nào.  
8. _________ quyết định một đoạn lệnh thể truy xuất đến một đoạn lệnh khác hayhoặc dữ  
liệu hay không.  
9. Các đối số được gọi truyền ________ khi giá trị của các biến được truyền đến hàm được gọi  
10. Trong_________, hàm được phép truy xuất vị trí bộ nhớ thật của các đối số.  
228  
Lập trình cơ bản C  
doc 20 trang Thùy Anh 26/04/2022 6060
Bạn đang xem tài liệu "Giáo trình Lập trình cơ bản C - Bài 15: Hàm", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

File đính kèm:

  • docgiao_trinh_lap_trinh_co_ban_c_bai_15_ham.doc