Lập trình C Aptech - Bài 15: Hàm

Mục tiêu:

 

Kết thúc bài học này, bạn có 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.

 

doc20 trang | Chuyên mục: C/C++ | Chia sẻ: dkS00TYs | Lượt xem: 1967 | Lượt tải: 1download
Tóm tắt nội dung Lập trình C Aptech - Bài 15: Hàm, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
iên, có thể có 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 có thể thay đổi giá trị của các đối số của hàm gọi. 
Ví 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 
	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;
	}
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à v trong swap() là khác với các biến u và v được dùng trong main(). Truyền bằng tham chiếu có 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 mà 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 có 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).
Ví dụ, định nghĩa hàm
	getstr(char *ptr_str, int *ptr_int)
đối số ptr_str trỏ đến kiểu char và 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ỏ và đị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ờ có thể gán các giá trị đế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. Mã lệnh tương tự như sau:
	#include 
	void main()
	{
	int x, y, *px, *py;
	/* Storing address of x in px */ 
	px = &x;
	/* Storing address of y in py */ 
	py = &y;
	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 và py được khai báo, và địa chỉ của biến x và 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 là 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 có phải là chuỗi đọc xuôi - đọc ngược như nhau hay không, là một ví 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 mã lệnh theo sau đây:
	main()
	{
	.
	.
	palindrome();
	.
	.
	}
	palindrome()
	{
	.
	.
	getstr();
	reverse();
	cmp();
	.
	.
	}
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() và cmp(). Hàm getstr() để nhận một chuỗi ký 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.
Vì 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 là đượ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 có thể được định nghĩa là 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 là 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 là một biến, nhưng nó có địa chỉ vật lý trong bộ nhớ nơi có 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 rõ 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, mã nguồn được chuyển thành mã đối tượng và 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ì 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 
	#include 
	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);
	}
	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ỏ ký tự và một con trỏ hàm. Trong hàm check(), các đối số được khai báo là các con trỏ ký tự và 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 đó là kiểu trả về của hàm. Cặp dấu ngoặc () bao quanh *cmp là 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.
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 là các đối số thực trong hàm gọi và đố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 và 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 và 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 có thể được định nghĩa là static hay external.
Mã lệnh và dữ liệu được định nghĩa bên trong một hàm không thể tương tác với mã 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 là 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.
Kiểm tra tiến độ học tập
Một_________ là 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ể.
Các đối số xuất hiện trong cặp dấu ngoặc () còn được gọi là _____________.
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 mã lệnh. Điều này được gọi là ____________.
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à ________.
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ỉ có 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ỳ mã lệnh nào.
8. _________ quyết định một đoạn mã lệnh có thể truy xuất đến một đoạn mã lệnh khác hayhoặc dữ liệu hay không.
9. Các đối số được gọi là 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ố.

File đính kèm:

  • docLập trình C Aptech - Bài 15 Hàm.doc