=
=

Bài 5: Hàm

I. Giới thiệu hàm

I.1 Khái niệm

Một chương trình viết trong ngôn ngữ C là một dãy các hàm, trong đó có một hàm chính (hàm main()). Hàm chia các bài toán lớn thành các công việc nhỏ hơn, giúp thực hiện những công việc lặp lại nào đó một cách nhanh chóng mà không phải viết lại đoạn chương trình. Thứ tự các hàm trong chương trình là bất kỳ, song chương trình bao giờ cũng đi thực hiện từ hàm main(). Hàm có thể xem là một đơn vị độc lập của chương trình. Các hàm có vai trò ngang nhau, vì vậy không có phép xây dựng một hàm bên trong các hàm khác.

I.2. Quy tắc xây dựng một hàm

Xây dựng một hàm bao gồm: khai báo kiểu hàm, đặt tên hàm, khai báo các tham số và đưa ra câu lệnh cần thiết để thực hiện yêu cầu đề ra cho hàm. Một hàm được viết theo mẫu sau:

kiểu_hàm tên_hàm (danh sách các tham số)
{
 Khai báo các biến cục bộ
 Các câu lệnh
 [return[biểu thức];]
}

Trong dòng đầu tiên của khai báo hàm chứa các thông tin về: kiểu hàm, tên hàm, kiểu và tên mỗi tham số.

Khai báo các tham số có dạng: Kiểu_tham_số 1 tên_tham_số _1, kiểu_tham_số_2 tên_tham_số_2,..., kiểu_tham_số_n tên_tham_số_n. Các tham số này còn gọi là tham số hình thức phân biệt với tham số thực khi gọi hàm.

Ví dụ:
float max3s(float a, float b, float c)

Khai báo hàm: kiểu hàm là float, tên hàm là max3s, các tham số là a, b, c cùng có kiểu là float.

Kế tiếp là thân hàm. Thân hàm là nội dung chính của hàm bắt đầu và kết thúc bằng các dấu { }.

Trong thân hàm chứa các câu lệnh cần thiết để thực hiện một yêu cầu nào đó đã đề ra cho hàm. Thân hàm có thể sử dụng một câu lệnh return, có thể dùng nhiều câu lệnh return ở các chỗ khác nhau, và cũng có thể không sử dụng câu lệnh này.

Dạng tổng quát của return là:

return [biểu thức];

Giá trị của biểu thức trong câu lệnh return sẽ được gán cho hàm.

Ví dụ:

Xét bài toán: Tìm giá trị lớn nhất của ba số mà giá trị mà giá trị của chúng được đưa vào bàn phím.

Xây dựng chương trình và tổ chức thành hai hàm: Hàm main() và hàm max3s. Nhiệm vụ của hàm max3s là tính giá trị lớn nhất của ba số đọc vào, giả sử là a,b,c. Nhiệm vụ của hàm main() là đọc ba giá trị vào từ bàn phím, rồi dùng hàm max3s để tính như trên, rồi đưa kết quả ra màn hình.

Chương trình có thể được viết như sau:

Nhập 3 số lẻ bất kỳ cách nhau bởi khoảng trắng vào ô Stdin Inputs và nhấn nút Execute màu xanh để xem kết quả.

Các hàm không cho giá trị giống như thủ tục (procedure) trong ngôn ngữ lập trình PASCAL. Trong trường hợp này, kiểu của nó là void.

Ví dụ hàm tìm giá trị max trong ba số là max3s ở trên có thể được viết thành thủ tục hiển thị số cực đại trong ba số như sau.

Nhập 3 số lẻ bất kỳ cách nhau bởi khoảng trắng vào ô Stdin Inputs và nhấn nút Execute màu xanh để xem kết quả.

Lúc này, trong hàm main ta gọi hàm max3s bằng câu lệnh: max3s(x,y,z);

I.3. Gọi hàm

Một cách tổng quát lời gọi hàm có dạng sau: tên hàm ([Danh sách các tham số thực])

Số các tham số thực tế phải bằng số tham số hình thức trong danh sách tham số và lần lượt chúng có kiểu tương ứng với nhau. Có thể xem lại ví dụ cách sử dụng hàm max3s(x,y,z) ở trên.

I.4. Nguyên tắc hoạt động của hàm

Khi gặp một lời gọi hàm thì nó sẽ bắt đầu được thực hiện. Nói cách khác, khi máy gặp lời gọi hàm ở một vị trí nào đó trong chương trình, máy sẽ tạm dời chỗ đó và chuyển đến hàm tương ứng. Quá trình đó diễn ra theo trình tự sau:

Cho chương trình C chưa hoàn chỉnh như sau:

☛ Bài tập:
  • Nhấn dòng liên kết Edit this program in JDoodle.com để truy cập trang chủ JDoodle.
  • Hoàn chỉnh hàm tong(n) để chương trình xuất ra giá trị 1 + 2 +...+ n. Ví dụ nhập vào ô Stdin Inputs là 3 và nhấn Execute sẽ hiển thị 1 + 2 +...+ n = 6.
  • Lưu đến tài khoản cá nhân trên JDoodle.

II. Truyền tham số cho hàm

II.1. Truyền tham trị

Là truyền giá trị của biến (không phải là địa chỉ ô nhớ), khi đó phương thức sẽ tự động tạo ra một địa chỉ ô nhớ mới để lưu trữ giá trị này, do đó nó chỉ được thay đổi trong phương thức hiện hành và giá trị của biến không bị thay đổi bên ngoài phương thức hiện hành.

Ví dụ truyền tham trị trong C. Nhấn nút Execute màu xanh để xem kết quả.

Trong ví dụ trên, giá trị của biến x không bị thay đổi bên ngoài phương thức change(), mặc dù bên trong phương thức change() chúng ta đã cố gắng thay đổi bằng cách tăng m lên 1.

II.2. Truyền tham chiếu

Là truyền địa chỉ ô nhớ của biến, do đó khi thay đổi giá trị của biến bên trong phương thức thì giá trị của biến cũng bị thay đổi bên ngoài phương thức.

Ví dụ truyền tham trị trong C. Nhấn nút Execute màu xanh để xem kết quả.

Trong ví dụ trên, giá trị của biến x bị thay đổi cả bên trong và bên ngoài phương thức change().

Lưu ý: Để hiểu về truyền tham chiếu trong C, bạn phải có hiểu biết về con trỏ (pointer) trong C và đây là nội dung trong Bài 8 - Con trỏ.

Cho chương trình C hoán vị giá trị x và y như sau:

☛ Bài tập:
  • Nhấn nút Execute để xem kết quả. Nhận xét.
  • Nhấn dòng liên kết Edit this program in JDoodle.com để truy cập trang chủ JDoodle.
  • Điều chỉnh nội dung hàm hoanvi(x, y) để xuất ra màn hình:
    Truoc khi hoan vi: x = 3 y = 5
    Sau khi hoan vi: x = 5 y = 3
  • Lưu đến tài khoản cá nhân trên JDoodle.

III. Phạm vi biến

Có 3 vị trí mà biến có thể được khai báo trong C:

III.1. Biến cục bộ

Biến cục bộ được khai báo bên trong một hàm hoặc khai báo bên trong một khối lệnh. Chúng được sử dụng bởi các lệnh trong hàm hoặc khối lệnh và không được sử dụng bên ngoài của hàm hay khối lệnh đó.

Dưới đây là ví dụ về việc sử dụng biến cục bộ. Tại đây biến a,b và c được sử dụng trong hàm main():

int main ()
{
  /* Khai bao bien cuc bo */
  int a, b;
  int c;

  /* khoi tao thuc su */
  a = 10;
  b = 20;
  c = a + b;

  return 0;
}
III.2. Biến toàn cục

Biến toàn cục được định nghĩa bên ngoài một hàm, thường là phần đầu của chương trình. Biến toàn cục có thể chứa các giá trị trong thời gian chương trình chạy và có thể được truy cập bởi bất kì hàm nào định nghĩa trong chương trình. Điều đó nghĩa là biến toàn cục được sử dụng suốt chương trình sau khi nó khai báo. Dưới đây là ví dụ minh họa cho biến cục bộ (a, b) và toàn cục (g):

#include <stdio.h>
/* Khai bao bien toan cuc */
int g;
int main ()
{
  /* Khai bao bien cuc bo */
  int a, b;
  /* khoi tao thuc su */
  a = 10;
  b = 20;
  g = a + b;

  return 0;
}

Một chương trình có thể có biến toàn cục và cục bộ trùng tên. Trong trường hợp đó biến cục bộ bên trong hàm sẽ được ưu tiên sử dụng. Dưới đây là ví dụ, nhấn nút Execute để xem kết quả:

III.3. Tham số hình thức

Tham số hình thức (xem lại mục Quy tắc xây dựng hàm) được coi như biến cục bộ bên trong hàm đó và thường có giá trị ưu tiên hơn biến toàn cục. Dưới đây là ví dụ, nhấn nút Execute để xem kết quả: