Contents

Giới thiệu về hàm C

Bạn có thể đã nắm được cú pháp C cơ bản với các ví dụ đơn giản và hiện đang tự hỏi làm thế nào để tạo các chương trình thực tế lớn hơn. Để bắt đầu, bạn sẽ muốn sắp xếp mã của mình thành các phần hiệu quả, ít lặp lại nhất. Trong C, cũng như trong hầu hết các ngôn ngữ, câu trả lời cho vấn đề của bạn chính là hàm.

Việc sử dụng các hàm trong C mang lại một quy trình liền mạch mang lại nhiều lợi ích. Việc triển khai các chức năng cho phép phân tách các ứng dụng phức tạp thành các thành phần có thể quản lý được. Hơn nữa, chúng tạo điều kiện thuận lợi cho việc tái chế, cả trong chương trình chính cũng như trong các thư viện liên kết hoặc các dự án độc lập.

Để bắt đầu, điều bắt buộc là phải hiểu rõ các khái niệm liên quan đến khai báo hàm, khởi tạo nguyên mẫu, đặc tả tham số và cú pháp câu lệnh trả về.

Hàm trong C là gì?

/vi/images/an-introduction-to-c-functions.jpg

Trong lĩnh vực lập trình C, một hàm có thể được hiểu là một phần mã được chỉ định để thực hiện một tác vụ cụ thể khi được gọi. Bằng cách sử dụng các hàm, mã của một người trở nên có cấu trúc và tổ chức hơn, đồng thời cho phép lặp lại một thao tác cụ thể mà không cần phải nhắc lại việc triển khai nó.

Phiên bản chính hiện tại được thể hiện bằng hàm main(), đóng vai trò là cổng chính cho bất kỳ chương trình C nào. Hơn nữa, việc sử dụng các chức năng thư viện đã được người khác xây dựng trước cũng là một lựa chọn khả thi. Ngoài ra, người dùng có thể chọn viết các chức năng tùy chỉnh của riêng mình để đáp ứng các yêu cầu cụ thể.

Hàm: Khai báo, Định nghĩa và Gọi

Việc sử dụng các chức năng được xác định dựa trên ba yếu tố quan trọng đóng vai trò là nền tảng cho ứng dụng của chúng.

Khai báo hàm

Nguyên mẫu hàm dùng để cung cấp thông tin liên quan đến tên, kiểu trả về và tham số của hàm trước khi định nghĩa đầy đủ. Mục đích của nó là cho phép sử dụng chức năng trước thông số kỹ thuật chi tiết của nó. Cấu trúc cơ bản của một nguyên mẫu hàm tuân theo định dạng sau:

 return_type function_name(parameters); 

Ở đâu:

Kiểu trả về của hàm biểu thị phân loại dữ liệu của giá trị được trả về, có thể bao gồm bất kỳ cấu trúc dữ liệu C hợp lệ nào hoặc có thể bao gồm null nếu hàm không mang lại giá trị kết quả.

Mã định danh được gán cho một thực thể chức năng đóng vai trò là chỉ định cho chức năng nói trên, tạo điều kiện thuận lợi cho việc gọi nó vào thời điểm tương lai.

Các tham số đầu vào của hàm được biểu diễn dưới dạng danh sách và bao gồm một kiểu dữ liệu cùng với tên tham số được phân cách bằng dấu phẩy. Danh sách này được gọi là “tham số” và đóng vai trò là chỉ báo về các yêu cầu đầu vào cho hàm.

Ví dụ: đây là một khai báo hàm đơn giản:

 int add(int a, int b); 

Định nghĩa hàm

Khi gọi một hàm, nó sẽ thực thi các hướng dẫn được nêu trong phần khai báo của nó, bao gồm mã định danh, kiểu trả về, danh sách tham số và mã quản lý hành vi của nó. Cú pháp tuân theo cấu trúc này:

 return_type function_name(parameters) {
    // Function body - code that defines what the function does
    // Return a value if applicable
    return value;
} 

Hãy chia nhỏ các phần của cú pháp:

Tập hợp các câu lệnh được đặt trong dấu ngoặc cong { } tạo thành phần thân của hàm, bao gồm một loạt các chỉ thị mô tả các đặc điểm hành vi của hàm khi gọi.

Câu lệnh return được sử dụng khi hàm trả về một giá trị có kiểu dữ liệu không trống. Mục đích của câu lệnh này là truyền giá trị được trả về cho bên gọi, đảm bảo rằng nó phù hợp với kiểu trả về được chỉ định.

Chắc chắn, đây là một cách thể hiện tao nhã của một khai báo hàm bằng tiếng Anh chuẩn:pythondef hello(name):print(“Xin chào,"+ name + “!”)

 int add(int a, int b) {
    int sum = a \+ b;
    return sum;
}

Lệnh gọi hàm

Về bản chất, giống như người ta phải tuân thủ các bước cụ thể khi chuẩn bị một món ăn bằng cách sử dụng một công thức và các nguyên liệu khác nhau, người ta cũng cần phải thực hiện cẩn thận các hướng dẫn được cung cấp để đạt được kết quả thành công khi gọi một hàm. Quá trình gọi một hàm bao gồm việc cung cấp cho nó các đối số được chỉ định, được thực thi theo cú pháp được xác định trước như sau:

 return_type result = function_name(arguments); 

Các đối số đề cập đến các tham số đầu vào được cung cấp cho một hàm trong quá trình thực thi nó. Chúng có thể là các giá trị hoặc biểu thức riêng lẻ và phải được phân tách bằng dấu phẩy. Điều quan trọng là đảm bảo rằng số lượng, thứ tự và kiểu dữ liệu của các đối số tương ứng chính xác với những đối số được chỉ định trong danh sách tham số của hàm.

Khi một hàm trả về một giá trị có kiểu dữ liệu không trống, người ta có thể sử dụng một biến có kiểu dữ liệu thích hợp để thu được giá trị trả về.

Đây là một ví dụ về lệnh gọi hàm:

 #include <stdio.h>

// Function prototype
int add(int a, int b);

int main() {
    int x = 5, y = 3;

    // Call the function and store the result in 'sum'
    int sum = add(x, y);
    printf("The sum of %d and %d is %d\n", x, y, sum);
    return 0;
}

// Function definition
int add(int a, int b) {
    return a \+ b;
} 

Bằng cách tuân thủ cách tiếp cận có cấu trúc bao gồm ba giai đoạn-khai báo mục đích của hàm, nêu chi tiết quy trình thực thi và gọi nó bằng cách sử dụng các tham số đầu vào phù hợp-người ta có thể khai thác hiệu quả khả năng của các hàm để thực hiện các hoạt động đa dạng trong nỗ lực lập trình của mình.

Tham số hàm và giá trị trả về

Các tham số của hàm đóng vai trò là nơi chứa các giá trị đầu vào do thực thể gọi cung cấp trong khi gọi, trong khi các giá trị trả về biểu thị kết quả do hàm tạo ra và được truyền trở lại người khởi tạo yêu cầu.

Có hai phương pháp truyền tham số.

Truyền theo giá trị

Trong phương pháp này, khi một hàm được gọi, nó sẽ chuyển giá trị của đối số thực sang tham số tương ứng. Những thay đổi được thực hiện đối với tham số bên trong hàm không ảnh hưởng đến đối số ban đầu.

Ví dụ:

 #include <stdio.h>

int square(int num) {
    num = num * num;
    return num;
}

int main() {
    int x = 5;
    int y = square(x);

    // Output: x and y after function call: 5 25
    printf("x and y after function call: %d %d\n", x, y);

    return 0;
} 

Hàm bình phương chấp nhận đầu vào số được biểu thị bằng biến “num”.

Hàm bình phương lấy một số làm đầu vào, tính căn bậc hai của nó, sửa đổi nó cho phù hợp và trả về kết quả được cập nhật.

Mục đích chính của mã này là khai báo một biến, “x”, ban đầu được gán một giá trị nguyên.

Mã tiến hành bằng cách gọi hàm bình phương và cung cấp cho nó giá trị x làm đối số. Tiếp theo hành động này là việc gán kết quả đầu ra cho một biến phụ có tên y.

Sau khi gọi hàm, hàm chính sau đó sẽ xuất ra các giá trị của x và y. Giá trị số của x vẫn không thay đổi do sửa đổi tham số’num’trong phép toán được biểu thị bằng’vuông’, vì việc điều chỉnh như vậy không ảnh hưởng đến trạng thái ban đầu của x.

Truyền theo tham chiếu

Bằng cách chuyển địa chỉ bộ nhớ (tức là con trỏ) của một biến cho một hàm, mọi sửa đổi được thực hiện đối với biến đã nói trong giới hạn của hàm đó cũng sẽ được phản ánh ở trạng thái ban đầu ngoài phạm vi của hàm.

Một điểm khác biệt đáng chú ý giữa ngôn ngữ lập trình C và các ngôn ngữ như Python nằm ở việc sử dụng con trỏ, bao gồm cả chức năng của chúng làm đối số.

 #include <stdio.h>

void square(int *num) {
    *num = *num * *num;
}

int main() {
    int x = 5;
    square(&x);

    // Output: x after function call: 25
    printf("x after function call: %d\n", x);
    return 0;
} 

Hàm bình phương chấp nhận một con trỏ nguyên làm đối số đầu vào của nó, được biểu thị bằng biến “num”. Hàm này không mang lại bất kỳ giá trị trả về nào.

Hàm bình phương lấy một số làm đầu vào, tính bình phương của nó bằng cách nhân nó với chính nó, sau đó cập nhật giá trị được lưu trong bộ nhớ được trỏ đến bởi đối số được truyền cho hàm bằng toán tử quy chiếu (\*).

Mục đích chính của đoạn mã này là tạo một biến số nguyên mới có tên “x” và khởi tạo giá trị ban đầu của nó thành 5.

Mã tiến hành bằng cách hủy tham chiếu con trỏ tới x và chuyển địa chỉ của nó, có được thông qua việc sử dụng địa chỉ của toán tử & , làm đối số cho hàm square() .

Sau khi gọi hàm “bình phương”, trình tự thực thi chính tiến hành in giá trị hiện tại của biến ‘x’, giá trị này đã được cập nhật trong hàm và hiện có giá trị số là 25. Những sửa đổi được thực hiện đối với tham số’*num’ban đầu bằng hàm"vuông"đã tạo ra kết quả này cho biến’x'.

Về bản chất, điểm khác biệt chính giữa hai cách tiếp cận này nằm ở tác động của chúng lên giá trị ban đầu bên ngoài hàm khi các tham số được sửa đổi trong hàm. Phương thức truyền theo giá trị dẫn đến việc tạo ra một bản sao, trong khi truyền bằng tham chiếu hoặc con trỏ cho phép thao tác trực tiếp giá trị ban đầu.

Các ngôn ngữ lập trình khác thường có bản sao của con trỏ C; tuy nhiên, chức năng của chúng có xu hướng nâng cao hơn về bản chất. Ví dụ: ngôn ngữ C# cung cấp hỗ trợ cho các biến “out” như một phương tiện để chỉ định rằng một giá trị phải được truyền theo tham chiếu thay vì theo giá trị.

Hàm vô hiệu

Các hàm trong ngôn ngữ lập trình C thiếu giá trị trả về xác định có thể được phân loại là hàm void. Các hàm này phục vụ mục đích thực hiện một hành động hoặc hoàn thành một nhiệm vụ mà không cần tạo ra kết quả. Mặc dù các hàm void có thể sử dụng tham chiếu truyền qua để sửa đổi các tham số đầu vào của chúng nhưng đây không phải là yêu cầu bắt buộc.

Đây là một ví dụ về hàm void:

 #include <stdio.h>

// Void function with no parameters
void greet() {
    printf("Hello, All Things N!");
}

int main() {
    // Call the void function, output: "Hello, All Things N!"
    greet();

    return 0;
} 

Hàm void đóng vai trò là phương tiện hiệu quả để thực hiện các hoạt động như thực thi lệnh, hiển thị thông báo, thao tác thông tin và hoàn thành mục tiêu mà không cần truy xuất kết quả cụ thể.

Khám phá các hàm trong lập trình C

Có thể nâng cao khả năng hiểu và thành thạo lập trình C của một người bằng cách tích cực tạo ra các hàm. Điều này không chỉ cải thiện độ rõ ràng và khả năng bảo trì của mã mà còn mở rộng tính linh hoạt trong việc áp dụng các chức năng trong các tình huống khác nhau. Nên khám phá nhiều ứng dụng dựa trên chức năng để có được lợi ích tối ưu.

Khi bạn đã hiểu rõ về các kỹ thuật lập trình C cơ bản và đang tìm kiếm sự kích thích trí tuệ hơn nữa, việc khám phá logic đệ quy có thể là bước thích hợp tiếp theo để bạn thực hiện.