C# - C Sharp: Hàm (Function)
Giới thiệu
Hầu hết các chương trình viết bằng ngôn ngữ C# (cũng như viết bằng những ngôn ngữ khác như C++, Java, C, Python) thường được phân nhỏ thành các hàm (function) trong đó có một hàm chính là Main() và chương trình luôn luôn bắt đầu từ hàm Main(). Hàm (Function) là phần kiến thức rất quan trọng trong C#, nắm tốt kiến thức về hàm bạn sẽ có được thuận lợi khi tìm hiểu các ngôn ngữ lập trình khác.
Khái niệm
Hàm là đoạn chương trình thực hiện trọn vẹn một công việc nhất định (cụ thể). Hàm giúp chia cắt việc lớn thành nhiều việc nhỏ hơn, điều này tương đương với việc chia bài toán lớn thành các bài toán nhỏ hơn để giải, như vậy thì việc giải bài toán sẽ trở nên dễ dàng hơn. Ngoài ra, hàm còn giúp cho chương trình trở nên sáng sủa, dễ sửa, nhất là đối với các chương trình lớn.
Ta có thể sử dụng hàm nhiều lần và ở nhiều nơi khác nhau trong chương trình.
Định nghĩa hàm
Để định nghĩa hay tạo một hàm, ta có thể sử dụng cú pháp như sau:
Trong đó:
+ [static]: Nếu muốn hàm được gọi trực tiếp từ hàm static khác thì ta cần sử dụng từ khóa static này, nhưng nếu muốn gọi hàm thông qua một đối tượng thì không có từ khóa này.
+ kiểu_trả_về: Là kiểu của dữ liệu mà ta muốn hàm trả về.
+ Tên_hàm: Do ta tự đặt nhưng không được trùng với bất kỳ từ khóa nào. Trong C# thường đặt tên theo cách thức viết hoa ký tự đầu của từng từ, ví dụ như NhapLieu, TinhTong, TinhBietThucDelta.
+ Cặp () sau Tên_hàm là bắt buộc phải có, ngay cả khi không có danh_sách_tham_số.
+ [danh_sách_tham_số]: Dùng để tiếp nhận dữ liệu cho hàm. Nếu hàm cần dữ liệu thì ta cần sử dụng danh_sách_tham_số để tiếp nhận, nhưng nếu hàm không cần dữ liệu để xử lý thì sẽ không có danh_sách_tham_số.
+ Cặp {} là bắt buộc phải có đối với mọi định nghĩa hàm.
+ [return giá_trị;]: Lệnh này dùng để trả về giá trị cho hàm, nếu kiểu_trả_về của hàm không phải là void thì lệnh này buộc phải có, ngược lại thì không có hoặc lệnh sẽ thành return;. giá_trị có thể là một hằng, giá trị của biến, giá trị của biểu thức hoặc giá trị trả về từ một lời gọi hàm khác.
Một số chú ý đối với hàm:
- Có thể thể gọi một hàm từ hàm khác nhưng bạn không được định nghĩa hàm bên trong hàm (kể cả trong hàm Main()).
- Kiểu dữ liệu của giá_trị nên tương ứng kiểu (có thể nhỏ hơn nhưng không được lớn hơn) với kiểu_trả_về của hàm.
- Bạn có thể định nghĩa hàm nằm trên hoặc nằm dưới hàm Main().
- Mỗi hàm chỉ có thể trả về được duy nhất một giá_trị. Trong trường hợp bạn muốn trả về nhiều hơn một giá_trị thì bạn có thể sử dụng phương pháp tham chiếu.
- Nơi mà hàm trả về giá_trị chính là nơi mà nó được gọi.
- Sau khi định nghĩa xong hàm thì hàm không thể tự động được thực thi, ta phải thực hiện việc gọi hàm để thực thi hàm.
Một số ví dụ
Ví dụ 1: Kiểu trả về là void và không có tham số
namespace Demo1 { internal class demo1 { static void Demo() { Console.WriteLine("You are in Demo() function"); } static void Main(string[] args) { } } }
Trong ví dụ trên:
- Định nghĩa một hàm có tên là Demo.
- Hàm này có kiểu trả về là void, tức là hàm không trả về giá_trị, như vậy thì sẽ không có lệnh return giá_trị;.
- Hàm không có danh_sách_tham_số, tức là hàm không cần dữ liệu để xử lý.
- Phần khối_lệnh có 1 lệnh duy nhất.
Ví dụ 2: Kiểu trả về là void và có tham số
namespace Demo1 { internal class demo1 { static void Demo() { Console.WriteLine("You are in Demo() function"); } static void TinhTong(float a, float b) { float tong = a + b; Console.WriteLine($"{a:F2} + {b:F2} = {tong:F2}"); } static void Main(string[] args) { TinhTong(10, 20); } } }
Trong ví dụ trên:
- Định nghĩa thêm hàm có tên TinhTong.
- Hàm có kiểu trả về là void nên cũng không có lệnh return giá_trị;.
- Hàm có hai tham số a có kiểu float và b có kiểu float, hai tham số này sẽ có nhiệm vụ tiếp nhận hai dữ liệu có kiểu float hoặc thấp hơn (int, short, ...).
Ví dụ 3: Kiểu trả về khác void và có tham số
namespace Demo1 { internal class demo1 { static void Demo() { Console.WriteLine("You are in Demo() function"); } static void TinhTong(float a, float b) { float tong = a + b; Console.WriteLine($"{a:F2} + {b:F2} = {tong:F2}"); } static double TinhBietThucDelta(float a, float b, float c) { double delta = b * b - 4 * a * c; return delta; } static void Main(string[] args) { TinhTong(10, 20); } } }
Trong ví dụ trên:
- Định nghĩa thêm hàm có tên TinhBietThucDelta.
- Hàm có kiểu trả về là double, tức là hàm bắt buộc phải có lệnh return giá_trị;.
- Hàm có ba tham số a, b, c kiểu float.
Gọi hàm
Như đã nói ở trên, sau khi định nghĩa hàm xong thì hàm không thể tự thực hiện, thay vào đó ta cần phải gọi hàm (call function).
Ta có thể gọi hàm nhiều lần ở nhiều nơi khác nhau.
Để gọi hàm ta tuân theo cú pháp như sau:
* Đối với hàm có kiểu trả về là void thì sẽ cần cú pháp gọi hàm theo lệnh (gọi là lệnh gọi hàm), tức là kết thúc lời gọi hàm phải có ;:
Tên_hàm([danh_sách_đối_số]);
Trong đó:
- danh_sách_đối_số: dùng để truyền dữ liệu đến danh_sách_tham_số.
- Số lượng và kiểu đối số trong_danh_sách_đối_số sẽ phải bằng và tương ứng với số lượng và kiểu của danh_sách_tham_số ở phần định nghĩa hàm.
Ví dụ như với các hàm Demo và TinhTong ở trên thi ta có thể gọi chúng như sau:
Demo(); TinhTong(10, 20);
Khi được gọi thì các lệnh ở phần khối_lệnh của các hàm sẽ được thực thi.
* Đối với hàm có kiểu trả về khác void thì lời gọi hàm thường xen lẫn trong các lệnh hoặc thậm chí là cả ở phần tham số.
Ví dụ như với hàm TinhBietThucDelta ở trên thì ta có thể gọi hàm như sau:
double d; d = TinhBietThucDelta(10, 30, 20);
Hoặc:
System.out.printf("Delta = " + TinhBietThucDelta(10, 30, 20));
Sau đây là ví dụ hoàn chỉnh cho việc định nghĩa và gọi các hàm ở trên:
namespace Demo1 { internal class demo1 { static void Demo() { Console.WriteLine("You are in Demo() function"); } static void TinhTong(float a, float b) { float tong = a + b; Console.WriteLine($"{a:F2} + {b:F2} = {tong:F2}"); } static double TinhBietThucDelta(float a, float b, float c) { double delta = b * b - 4 * a * c; return delta; } static void Main(string[] args) { Demo(); TinhTong(10, 20); double d; d = TinhBietThucDelta(10, 30, 20); Console.WriteLine($"Delta = {d}"); Console.WriteLine("Hoac:"); Console.WriteLine($"Delta = {TinhBietThucDelta(10, 30, 20)}"); } } }
Kết quả:
You are in Demo() function
10.00 + 20.00 = 30.00
Delta = 100
Hoac:
Delta = 100
Sau đây là một ví dụ áp dụng hàm, đó là viết chương trình tính giai thừa: S = n! (=1*2*3*4*…*n). Chương trình được viết như sau:
namespace Demo1 { internal class demo1 { static float GiaiThua(int n) { //định nghĩa hàm GiaiThua() có kiểu trả về là float có một đối số kiểu int float KQ = 1.0F; //đây là biến cục bộ for (int i = 1; i <= n; i++) //n ở đây là tham số của hàm KQ *= i; return KQ; //hàm trả về nơi gọi giá trị lưu trong biến KQ } static void Main(string[] args) { int n; //khai báo biến nguyên n Console.Write("Nhap n: "); n = int.Parse(Console.ReadLine()); //nhập liệu cho n Console.WriteLine($"Giai thua cua {n} la {GiaiThua(n)}"); //gọi đến hàm Giaithua() trong đó truyền giá trị của n (thuộc hàm main()) cho đối số n của hàm Giaithua() } } }
Dưới đây là một kết quả thực hiện chương trình trên:
Nhap n: 6
Giai thua cua 6 la 720