Chương trình con trong c++ là gì năm 2024

Phần trước: [C++ Cơ bản] Phần 10: Toán tử (tiếp) Ta không thể đặt thẳng giá trị của chúng như vậy được - nếu như ta viết

a = b; b = a;

thì giá trị của

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

3 sẽ bằng giá trị của

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

4 lúc ban đầu, và dòng code thứ hai sẽ không có tác dụng gì hết.

Giải pháp là sử dụng một biến tạm thời để lưu trữ giá trị cũ của

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

3, để gán về sau cho

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

4.

int temp = a; a = b; b = temp;

Nhưng nếu ta phải thực hiện công việc tầm 10 lần trong chương trình thì sao? Việc viết ba dòng code này mỗi khi cần đảo giá trị là một điều rất bất hợp lý - code sẽ dài và không trực quan (không có chỗ nào trong 3 dòng code ghi là đây là lệnh để đảo giá trị

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

3 và

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

4 cả). Hơn nữa, nếu phải sửa một chỗ nào đó trong việc đảo giá trị - ví dụ kiểm tra hai giá trị được đảo có cùng kiểu dữ liệu không chẳng hạn - ta sẽ phải sửa hàng chục lần.

Giải pháp là sử dụng hàm (function, hay còn được gọi là chương trình con).

Định nghĩa hàm

Hàm là một nhóm lệnh, yêu cầu chương trình phải hoàn thành một công việc nào gì đó.

Hàm có thể được yêu cầu trả lại một giá trị nào đó (ví dụ: hàm tính lũy thừa của một số), hoặc không (hàm trả lại kiểu

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

9 - ví dụ như hàm

void printNumber(int value) {

cout << value;
}

0 của

void printNumber(int value) {

cout << value;
}

1).

void printNumber(int value) {

cout << value;
}

2 là một hàm tiêu biểu, trả lại kiểu

void printNumber(int value) {

cout << value;
}

3 là kết quả chạy của chương trình.

Người dùng có thể tự định nghĩa hàm mới trong chương trình của mình.

Cách định nghĩa hàm mới

Cú pháp để định nghĩa hàm mới là

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

Kiểu dữ liệu trả về

Hàm có thể chỉ thực hiện thao tác lên giá trị mà không trả về kiểu gì cả - khi đó kiểu dữ liệu trả về được đặt là

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

9 (không giá trị).

Hàm cũng có thể sử dụng để thực hiện phép tính toán và trả lại kết quả - có thể là các kiểu dữ liệu nguyên thủy như

void printNumber(int value) {

cout << value;
}

3,

void printNumber(int value) {

cout << value;
}

6,

void printNumber(int value) {

cout << value;
}

7,… hay các kiểu dữ liệu người dùng định nghĩa (sẽ được nói tới trong các bài sau).

Tên của hàm

Quy tắc đặt tên của hàm cũng giống như quy tắc đặt tên biến - trừ trong trường hợp overloading (viết đè hàm). Overloading sẽ được giải thích trong các bài viết sau.

Các tham số của hàm

Một hàm có thể được truyền vào một hoặc nhiều biến tham số để hoạt động. Ví dụ: hàm

void printNumber(int value) {

cout << value;
}

0 của

void printNumber(int value) {

cout << value;
}

1 cần có một xâu kí tự là địa chỉ của file cần mở, và một giá trị bitmask

int tong(int a, int b) {

return a + b;
}

0 không bắt buộc.

Các tham số của hàm được định nghĩa theo cú pháp như khai báo biến -

int tong(int a, int b) {

return a + b;
}

1 - và được phân cách nhau bằng dấu phẩy (

int tong(int a, int b) {

return a + b;
}

2).

Các tham số giống như biến local của hàm - chúng chỉ tồn tại bên trong hàm, và sẽ không thể truy cập được từ bên ngoài. Nếu như có biến global trùng tên, thì biến tham số của hàm sẽ được sử dụng trong hàm của nó.

Ta không được phép đặt tên biến local trùng tên biến tham số của hàm.

Hàm không bắt buộc phải có tham số - ví dụ như hàm

void printNumber(int value) {

cout << value;
}

2. Khi đó ta bỏ qua mục này trong ngoặc tròn.

Tham số của hàm có 3 dạng - các dạng của tham số sẽ được nói rõ hơn ở phần sau của bài viết.

Nội dung của hàm

Nội dung của hàm là những việc ta cần hàm thực hiện, được biểu diễn trong khối lệnh ngoặc nhọn.

Ví dụ: Nội dung của hàm có khả năng in ra giá trị của một số

void printNumber(int value) {

cout << value;
}

Đối với các hàm có giá trị trả về (khác

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

9), ta cần phải sử dụng lệnh

int tong(int a, int b) {

return a + b;
}

5 để thông báo kết thúc chương trình và giá trị trả về.

Ví dụ: Nội dung của hàm có khả năng trả về tổng của hai số

int tong(int a, int b) {

return a + b;
}

Từ khóa

int tong(int a, int b) {

return a + b;
}

6 sẽ thông báo kết thúc hàm ngay lập tức, và trả về giá trị nếu có.

Một hàm được định nghĩa trả về một kiểu giá trị khác

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

9 mà kết thúc không có

int tong(int a, int b) {

return a + b;
}

6 sẽ khiến chương trình bị lỗi

int tong(int a, int b) {

return a + b;
}

9. Các bộ dịch không nhất thiết cần phải thông báo lỗi này (nhưng thường sẽ có cảnh báo), và chương trình vẫn có thể được dịch thành công kể cả khi có lỗi này. Khi đó giá trị trả về có thể là bất cứ giá trị nào. Để tránh sai sót, hãy luôn kết thúc các hàm một cách hợp lệ.

Từ khóa

int tong(int a, int b) {

return a + b;
}

6 cũng có thể sử dụng trong hàm kiểu

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

9 để kết thúc hàm đó. Trong trường hợp này, ta không cần có phần giá trị trả về.

Ví dụ:

void testing() {

cout << "Dong nay se duoc in ra!";
return;
cout << "Dong nay se khong duoc in ra, vi chuong trinh con ket thuc roi!";
}

Sử dụng hàm đã được định nghĩa

Sau khi đã định nghĩa hàm, ta có thể sử dụng hàm bằng cách gọi tên của hàm cùng với giá trị của các tham số của nó (nếu có).

Ví dụ thứ nhất: Chương trình sau đây gọi ra hàm

void testing() {

cout << "Dong nay se duoc in ra!";
return;
cout << "Dong nay se khong duoc in ra, vi chuong trinh con ket thuc roi!";
}

2 vừa rồi ở trong

void printNumber(int value) {

cout << value;
}

2, để kiểm tra tính năng của từ khóa

int tong(int a, int b) {

return a + b;
}

6

`

include

using namespace std; void testing() {

cout << "Dong nay se duoc in ra!";
return;
cout << "Dong nay se khong duoc in ra, vi chuong trinh con ket thuc roi!";
} int main() {
testing();
return 0;
}`

Output

Dong nay se duoc in ra!

Ví dụ thứ hai: Chương trình sau đây sẽ in ra tổng của hai giá trị được tính toán bằng hàm

void testing() {

cout << "Dong nay se duoc in ra!";
return;
cout << "Dong nay se khong duoc in ra, vi chuong trinh con ket thuc roi!";
}

5

`

include

using namespace std; int tinhTong(int a, int b) {

return a + b;
} int main() {
cout << tinhTong(1, 2);
return 0;
}`

Các kiểu tham số của hàm

Ok, giờ ta có thể áp dụng hàm vào chương trình đảo hai số như đầu bài viết đặt ra! Ta chỉ cần viết một hàm

void testing() {

cout << "Dong nay se duoc in ra!";
return;
cout << "Dong nay se khong duoc in ra, vi chuong trinh con ket thuc roi!";
}

6 như sau

void daoSo(int a, int b) {

int temp = a;
a = b;
b = temp;
}

Rồi sau đó gọi hàm này ở dưới khi nào cần đảo số:

int temp = a; a = b; b = temp;

0

Output

int temp = a; a = b; b = temp;

1

Tại sao giá trị của

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

3 và

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

4 vẫn chưa đảo?

Có 3 dạng tham số của hàm

Tham số truyền giá trị

Đây là kiểu tham số mặc định của hàm. Khi ta gọi hàm, chương trình sẽ tạo ra các biến mới, copy giá trị được truyền vào biến, và tất cả các thay đổi sẽ chỉ diễn ra trên các biến mới này. Hàm

void testing() {

cout << "Dong nay se duoc in ra!";
return;
cout << "Dong nay se khong duoc in ra, vi chuong trinh con ket thuc roi!";
}

6 ta vừa viết rơi vào trường hợp này - chỉ có giá trị của hai biến tham số

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

3 và

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

4 thay đổi,

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

3 và

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

4 ở bên ngoài vẫn không có gì thay đổi cả.

Tham số truyền biến

Để khai báo một biến tham số truyền biến, ta sử dụng cú pháp khai báo tham số

int temp = a; a = b; b = temp;

2

Kiểu tham số này thực hiện mọi thay đổi trực tiếp lên biến mà không thông qua bản copy nào.

Ví dụ, ta viết lại hàm

void testing() {

cout << "Dong nay se duoc in ra!";
return;
cout << "Dong nay se khong duoc in ra, vi chuong trinh con ket thuc roi!";
}

6 như sau

int temp = a; a = b; b = temp;

3

Cho chạy chương trình với đoạn code sửa đổi, ta được output

int temp = a; a = b; b = temp;

4

Hàm đảo số đã thực hiện thay đổi trực tiếp lên hai biến

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

3 và

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

4, và nhờ đó mà giá trị của chúng đã được đảo thành công.

Khi sử dụng hàm có tham số truyền biến, các tham số này bắt buộc phải là một biến - khác với tham số truyền giá trị chỉ cần truyền giá trị. Do đó nếu hàm có dạng

int temp = a; a = b; b = temp;

5

Thì tham số

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

3 chỉ có thể là một biến kiểu

void printNumber(int value) {

cout << value;
}

3 hoặc tương đương. Trong khi đó nếu hàm có dạng

int temp = a; a = b; b = temp;

6

Thì tham số

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

3 có thể là 1 biến, 1 biểu thức cho ra kiểu

void printNumber(int value) {

cout << value;
}

3 hoặc tương đương, hoăc một giá trị số cụ thể.

Tham số truyền con trỏ

Để khai báo một biến tham số truyền con trỏ, ta sử dụng cú pháp khai báo tham số

int temp = a; a = b; b = temp;

7

Kiểu dữ liệu này sẽ truyền giá trị địa chỉ ô nhớ của biến vào hàm. Kiểu tham số này, cùng với những kiến thức về con trỏ, sẽ được giải thích kĩ hơn ở các bài viết sau.

Đệ quy

Giả sử ta định nghĩa giai thừa của một số nguyên

Dong nay se duoc in ra!

1 như sau

0!=10!=1x!=(x−1)!∗x ∀x>0x!=(x−1)!∗x ∀x>0

Đây là một cách định nghĩa kiểu quy nạp - ta định nghĩa một giá trị cơ sở, và các giá trị quy nạp sẽ được định nghĩa từ các giá trị cơ sở trước nó.

Trong chương trình, ta cũng có thể tự gọi một hàm ở ngay bên trong nó - hành động này được gọi là đệ quy. Ví dụ với hàm tính lũy thừa của một số theo định nghĩa trên

int temp = a; a = b; b = temp;

8

Dòng lệnh trên sử dụng toán tử điều kiện - nếu như

Dong nay se duoc in ra!

1 bằng 0, giai thừa sẽ trả lại 1. Nếu

Dong nay se duoc in ra!

1 khác 0, giai thừa sẽ bằng giai thừa của

Dong nay se duoc in ra!

4 nhân với

Dong nay se duoc in ra!

1.

Chú ý rằng hành động đệ quy có thể sinh ra lặp vô hạn. Ví dụ như hàm sau

int temp = a; a = b; b = temp;

9

Hàm kia sẽ liên tục lấy hàm

Dong nay se duoc in ra!

6 của

Dong nay se duoc in ra!

4 nhân với

Dong nay se duoc in ra!

1, mà không hề có điểm dừng. Nếu gọi hàm này, chương trình hoặc sẽ không thể chạy được tiếp (do hàm này không bao giờ kết thúc), hoặc sẽ sinh lỗi tràn bộ nhớ (do phải tạo ra vô hạn biến tham số x cho mỗi lần gọi hàm).

Giá trị mặc định cho tham số

Như hàm open của

void printNumber(int value) {

cout << value;
}

1 có giá trị mặc định cho

int tong(int a, int b) {

return a + b;
}

0, ta cũng có thể đặt giá trị mặc định cho các tham số của hàm.

kiểu_dữ_liệu_trả_về tên_của_hàm(các_tham_số_của_hàm) {

nội_dung_của_hàm;
}

0

Giá trị mặc định sẽ được sử dụng khi không có giá trị nào được truyền vào tham số tương ứng.

Ví dụ: Chương trình sau sẽ gọi ra hàm tính tổng hai số mà không truyền hai số vào. Vì đã có giá trị mặc định từ trước, nên phép toán vẫn được thực hiện với hai giá trị mặc định.

Khái niệm chương trình con là gì?

Trong khoa học máy tính, chương trình con (subprogram) hay subroutine là một đoạn chương trình được đóng gói thành một đơn vị trình, nó thực hiện một số tác vụ cụ thể mà chương trình cần thực hiện nhiều lần từ nhiều nơi trong thời gian chạy của nó.

Con trỏ trong C là gì?

Trong lập trình C, con trỏ là một biến dùng để lưu trữ địa chỉ bộ nhớ của một biến khác. Con trỏ cho phép các chương trình có quyền thao tác trực tiếp vào bộ nhớ, điều này đặc biệt hữu ích khi bạn thực hiện các tác vụ như cấp phát bộ nhớ động hay làm việc với mảng.

Con trỏ trong ngôn ngữ lập trình là gì?

Trong khoa học máy tính, con trỏ (tiếng Anh: pointer) là một đối tượng ngôn ngữ lập trình, mà giá trị nó chỉ tới giá trị khác được chứa nơi nào đó trong bộ nhớ máy tính sử dụng địa chỉ bộ nhớ.

Ngôn ngữ C là hướng gì?

C là một ngôn ngữ lập trình đa năng (general purpose) cực phổ biến, đơn giản và linh hoạt. Nó là ngôn ngữ lập trình hướng cấu trúc và thủ tục, gần với ngôn ngữ máy nhưng độc lập máy (machine-independent), cơ động cao, được sử dụng rộng rãi ở các ứng dụng.