Các hàm trong lập trình C với ví dụ: Đệ quy & nội tuyến
Hàm trong C là gì?
Chức năng trong lập trình C là một khối mã có thể tái sử dụng giúp chương trình dễ hiểu, dễ kiểm tra hơn và có thể dễ dàng sửa đổi mà không cần thay đổi chương trình gọi. Các hàm phân chia mã và mô-đun hóa chương trình để có kết quả tốt hơn và hiệu quả hơn. Nói tóm lại, một chương trình lớn hơn được chia thành nhiều chương trình con khác nhau được gọi là hàm
Khi bạn chia một chương trình lớn thành nhiều chức năng khác nhau, việc quản lý từng chức năng riêng lẻ sẽ trở nên dễ dàng. Bất cứ khi nào xảy ra lỗi trong chương trình, bạn có thể dễ dàng điều tra các chức năng bị lỗi và chỉ sửa những lỗi đó. Bạn có thể dễ dàng gọi và sử dụng các chức năng bất cứ khi nào chúng được yêu cầu, điều này sẽ tự động giúp tiết kiệm thời gian và không gian.
Thư viện Vs. Hàm do người dùng xác định
Mỗi chương trình 'C' có ít nhất một chức năng là chức năng chính, nhưng một chương trình có thể có bất kỳ số chức năng nào. Hàm main() trong C là điểm bắt đầu của chương trình.
Trong lập trình 'C', các hàm được chia thành hai loại:
- Chức năng thư viện
- Các chức năng do người dùng xác định
Sự khác biệt giữa thư viện và các hàm do người dùng định nghĩa trong C là chúng ta không cần viết mã cho hàm thư viện. Nó đã có sẵn bên trong tệp tiêu đề mà chúng tôi luôn đưa vào đầu chương trình. Bạn chỉ cần nhập tên của một hàm và sử dụng nó cùng với cú pháp thích hợp. Printf, scanf là những ví dụ về chức năng thư viện.
Trong khi đó, hàm do người dùng định nghĩa là một loại hàm trong đó chúng ta phải viết phần thân của hàm và gọi hàm bất cứ khi nào chúng ta yêu cầu hàm thực hiện một số thao tác trong chương trình của mình.
Một hàm do người dùng định nghĩa trong C luôn được người dùng viết, nhưng sau đó nó có thể là một phần của thư viện 'C'. Đây là một lợi thế lớn của lập trình 'C'.
Các chức năng lập trình C được chia thành ba hoạt động như,
- Khai báo hàm
- Định nghĩa hàm
- Gọi hàm
Khai báo hàm
Khai báo hàm có nghĩa là viết tên của một chương trình. Đây là phần bắt buộc khi sử dụng các hàm trong mã. Trong khai báo hàm, chúng ta chỉ xác định tên của hàm mà chúng ta sẽ sử dụng trong chương trình của mình giống như khai báo biến. Chúng ta không thể sử dụng một hàm trừ khi nó được khai báo trong chương trình. Việc khai báo hàm còn được gọi là “Hàm nguyên mẫu".
Việc khai báo hàm (gọi là nguyên mẫu) thường được thực hiện phía trên hàm main() và có dạng tổng quát:
return_data_type function_name (data_type arguments);
- Sản phẩm return_data_type: là kiểu dữ liệu của hàm giá trị được trả về câu lệnh gọi.
- Sản phẩm Tên chức năng: theo sau là dấu ngoặc đơn
- Lập luận các tên có khai báo kiểu dữ liệu tùy chọn được đặt bên trong dấu ngoặc đơn.
Chúng ta hãy xem xét chương trình sau đây cho thấy cách khai báo một hàm khối để tính giá trị khối của một biến số nguyên
#include <stdio.h> /*Function declaration*/ int add(int a,b); /*End of Function declaration*/ int main() {
Hãy nhớ rằng một hàm không nhất thiết phải trả về một giá trị. Trong trường hợp này, từ khóa void được sử dụng.
Ví dụ: khai báo hàm out_message chỉ ra rằng hàm không trả về giá trị: void out_message();
Định nghĩa hàm
Định nghĩa hàm có nghĩa là chỉ viết phần thân của hàm. Phần thân của một hàm bao gồm các câu lệnh sẽ thực hiện một nhiệm vụ cụ thể. Phần thân hàm bao gồm một hoặc một khối câu lệnh. Nó cũng là một phần bắt buộc của một chức năng.
int add(int a,int b) //function body { int c; c=a+b; return c; }
Gọi hàm
Lệnh gọi hàm có nghĩa là gọi một hàm bất cứ khi nào nó được yêu cầu trong một chương trình. Bất cứ khi nào chúng ta gọi một hàm, nó sẽ thực hiện một thao tác được thiết kế cho nó. Lời gọi hàm là một phần tùy chọn của chương trình.
result = add(4,5);
Đây là mã hoàn chỉnh:
#include <stdio.h> int add(int a, int b); //function declaration int main() { int a=10,b=20; int c=add(10,20); //function call printf("Addition:%d\n",c); getch(); } int add(int a,int b) //function body { int c; c=a+b; return c; }
Đầu ra:
Addition:30
Đối số hàm
Các đối số của hàm được sử dụng để nhận các giá trị cần thiết bằng lệnh gọi hàm. Chúng được kết hợp theo vị trí; đối số đầu tiên được truyền cho tham số đầu tiên, đối số thứ hai được truyền cho tham số thứ hai, v.v.
Theo mặc định, các đối số được truyền theo giá trị trong đó một bản sao dữ liệu được cung cấp cho hàm được gọi. Biến thực sự được truyền sẽ không thay đổi.
Chúng ta xem xét chương trình sau đây minh họa các tham số được truyền theo giá trị:
int add (int x, int y); int main() { int a, b, result; a = 5; b = 10; result = add(a, b); printf("%d + %d\ = %d\n", a, b, result); return 0;} int add (int x, int y) { x += y; return(x);}
Đầu ra của chương trình là:
5 + 10 = 15
Hãy nhớ rằng các giá trị của a và b được truyền vào hàm add không bị thay đổi vì chỉ có giá trị của nó được truyền vào tham số x.
Phạm vi biến đổi
Phạm vi biến có nghĩa là khả năng hiển thị của các biến trong mã của chương trình.
Trong C, các biến được khai báo bên trong hàm là cục bộ của khối mã đó và không thể tham chiếu ra bên ngoài hàm. Tuy nhiên, các biến được khai báo bên ngoài tất cả các hàm đều mang tính toàn cục và có thể truy cập được từ toàn bộ chương trình. Các hằng số được khai báo bằng a #định nghĩa ở đầu chương trình có thể truy cập được từ toàn bộ chương trình. Chúng ta xem xét chương trình sau in giá trị của biến toàn cục từ cả hàm chính và hàm do người dùng định nghĩa:
#include <stdio.h> int global = 1348; void test(); int main() { printf("from the main function : global =%d \n", global); test () ; return 0;} void test (){ printf("from user defined function : global =%d \n", global);}
Kết quả:
from the main function : global =1348 from user defined function : global =1348
Chúng tôi thảo luận về các chi tiết của chương trình:
- Chúng tôi khai báo một biến toàn cục số nguyên với 1348 là giá trị ban đầu.
- Chúng ta khai báo và định nghĩa một hàm test() không nhận đối số cũng như không trả về giá trị. Hàm này chỉ in giá trị biến toàn cục để chứng minh rằng các biến toàn cục có thể được truy cập ở bất kỳ đâu trong chương trình.
- Chúng tôi in biến toàn cục trong hàm chính.
- Chúng tôi gọi hàm kiểm tra để in giá trị biến toàn cục.
Trong C, khi các đối số được truyền cho các tham số của hàm, các tham số đó đóng vai trò là các biến cục bộ và sẽ bị hủy khi thoát khỏi hàm.
Khi bạn sử dụng biến toàn cục, hãy sử dụng chúng một cách thận trọng vì có thể dẫn đến lỗi và chúng có thể thay đổi ở bất kỳ đâu trong chương trình. Chúng nên được khởi tạo trước khi sử dụng.
Biến tĩnh
Các biến tĩnh có phạm vi cục bộ. Tuy nhiên, chúng không bị hủy khi thoát khỏi chức năng. Do đó, một biến tĩnh sẽ giữ nguyên giá trị của nó mãi mãi và có thể được truy cập khi nhập lại hàm. Một biến tĩnh được khởi tạo khi được khai báo và cần có tiền tố tĩnh.
Chương trình sau sử dụng biến tĩnh:
#include <stdio.h> void say_hi(); int main() { int i; for (i = 0; i < 5; i++) { say_hi();} return 0;} void say_hi() { static int calls_number = 1; printf("Hi number %d\n", calls_number); calls_number ++; }
Chương trình hiển thị:
Hi number 1 Hi number 2 Hi number 3 Hi number 4 Hi number 5
Các hàm đệ quy
Xét giai thừa của một số được tính như sau 6! =6* 5 * 4 * 3 * 2 * 1.
Phép tính này được thực hiện dưới dạng tính toán lặp đi lặp lại thực tế * (thực tế -1) cho đến khi thực tế bằng 1.
Hàm đệ quy là hàm tự gọi chính nó và bao gồm điều kiện thoát để kết thúc các lệnh gọi đệ quy. Trong trường hợp tính số giai thừa, điều kiện thoát là thực tế bằng 1. Đệ quy hoạt động bằng cách “xếp chồng” các lệnh gọi cho đến khi điều kiện thoát là đúng.
Ví dụ:
#include <stdio.h> int factorial(int number); int main() { int x = 6; printf("The factorial of %d is %d\n", x, factorial(x)); return 0;} int factorial(int number) { if (number == 1) return (1); /* exiting condition */ else return (number * factorial(number - 1)); }
Chương trình hiển thị:
The factorial of 6 is 720
Ở đây, chúng tôi thảo luận về chi tiết chương trình:
- Chúng ta khai báo hàm giai thừa đệ quy nhận một tham số nguyên và trả về giai thừa của tham số này. Hàm này sẽ tự gọi và giảm số lượng cho đến khi thoát hoặc đạt đến điều kiện cơ bản. Khi điều kiện đúng, các giá trị được tạo trước đó sẽ được nhân với nhau và trả về giá trị giai thừa cuối cùng.
- Chúng ta khai báo và khởi tạo một biến số nguyên có giá trị”6”, sau đó in giá trị giai thừa của nó bằng cách gọi hàm giai thừa.
Hãy xem xét biểu đồ sau để hiểu rõ hơn về cơ chế đệ quy bao gồm việc gọi chính hàm đó cho đến khi đạt đến trường hợp cơ sở hoặc điều kiện dừng, sau đó, chúng ta thu thập các giá trị trước đó:
Hàm nội tuyến
Hàm trong lập trình C được sử dụng để lưu trữ các lệnh được sử dụng thường xuyên nhất. Nó được sử dụng để mô-đun hóa chương trình.
Bất cứ khi nào một hàm được gọi, con trỏ lệnh sẽ nhảy tới định nghĩa hàm. Sau khi thực thi một hàm, con trỏ lệnh quay trở lại câu lệnh từ nơi nó nhảy tới định nghĩa hàm.
Bất cứ khi nào chúng tôi sử dụng các chức năng, chúng tôi yêu cầu thêm con trỏ head để chuyển đến định nghĩa hàm và quay lại câu lệnh. Để loại bỏ sự cần thiết của các đầu con trỏ như vậy, chúng tôi sử dụng các hàm nội tuyến.
Trong hàm nội tuyến, lệnh gọi hàm được thay thế trực tiếp bằng mã chương trình thực tế. Nó không nhảy tới bất kỳ khối nào vì tất cả các thao tác được thực hiện bên trong hàm nội tuyến.
Các hàm nội tuyến chủ yếu được sử dụng cho các tính toán nhỏ. Chúng không phù hợp khi liên quan đến tính toán lớn.
Hàm nội tuyến tương tự như hàm bình thường ngoại trừ từ khóa inline được đặt trước tên hàm. Hàm nội tuyến được tạo bằng cú pháp sau:
inline function_name () { //function definition }
Chúng ta hãy viết một chương trình để thực hiện một hàm nội tuyến.
inline int add(int a, int b) //inline function declaration { return(a+b); } int main() { int c=add(10,20); printf("Addition:%d\n",c); getch(); }
Đầu ra:
Addition: 30
Chương trình trên trình bày cách sử dụng hàm nội tuyến để cộng hai số. Như chúng ta có thể thấy, chúng ta đã trả về phép cộng cho hai số chỉ trong hàm nội tuyến mà không viết thêm bất kỳ dòng nào. Trong khi gọi hàm, chúng ta vừa truyền các giá trị mà chúng ta phải thực hiện phép cộng.
Tổng kết
- Hàm là một chương trình nhỏ hoặc một chương trình con.
- Các hàm được sử dụng để module hóa chương trình.
- Thư viện và do người dùng định nghĩa là hai loại chức năng.
- Một hàm bao gồm phần khai báo, phần thân hàm và phần gọi hàm.
- Khai báo hàm và phần thân là bắt buộc.
- Lệnh gọi hàm có thể là tùy chọn trong một chương trình.
- Chương trình C có ít nhất một hàm; đó là hàm chính ().
- Mỗi hàm có một tên, kiểu dữ liệu giá trị trả về hoặc một khoảng trống, các tham số.
- Mỗi hàm phải được xác định và khai báo trong chương trình C của bạn.
- Hãy nhớ rằng bình thường các biến trong hàm C bị hủy ngay khi chúng ta thoát khỏi lệnh gọi hàm.
- Các đối số được truyền cho một hàm sẽ không bị thay đổi vì chúng không được truyền theo giá trị theo địa chỉ.
- Phạm vi biến được gọi là khả năng hiển thị của các biến trong một chương trình
- Có các biến toàn cục và cục bộ trong lập trình C