Các hàm trong C | Cách khai báo hàm trong C chi tiết

1. Các hàm trong C

Trong hướng dẫn này, bạn sẽ được giới thiệu về các hàm trong C (cả hàm do người dùng định nghĩa và hàm thư viện chuẩn). Ngoài ra, bạn cũng sẽ biết được lý do tại sao các hàm lại được sử dụng trong lập trình.

ham trong c

Hàm trong C (ngôn ngữ lập trình) là một khối mã thực hiện một nhiệm vụ cụ thể.

Giả sử, bạn cần viết một lập trình để tạo một hình tròn trụ và tô màu cho nó. Bạn cần chọn nửa đường kính và sắc tố. Bạn hoàn toàn có thể tạo 2 hàm dưới đây để triển khai trách nhiệm trên :

  • Tạo một hàm vẽ hình tròn: createCircle() function
  • Tạo một hàm tô màu: color() function

Việc phân chia các vấn đề phức tạp thành các vấn đề nhỏ hơn giúp lập trình của bạn dễ hiểu và dễ sử dụng lại hơn.

Có hai loại hàm trong C:

  • Các hàm thư viện tiêu chuẩn
  • Các hàm do người dùng định nghĩa

1.1 Các hàm thư viện tiêu chuẩn

Các hàm thư viện tiêu chuẩn chính là các hàm sẵn có trong lập trình C .
Các hàm này được xác lập trong các header files ( tệp có phần lan rộng ra. h )

  • Printf() là một hàm thư viện chuẩn có chức năng xuất kết quả đã được định dạng sẵn ra màn hình (hiển thị kết quả trên màn hình). Hàm này được xác định trong tệp tiêu đề stdio.h. Do đó, để sử dụng hàm printf (), chúng ta cần bao gồm tệp tiêu đề stdio.h bằng cách sử dụng #include .
  • Hàm sqrt() có chức năng tính căn bậc hai của một số. Hàm được xác định trong tệp tiêu đề math.h.

Truy cập vào các hàm thư viện tiêu chuẩn trong lập trình C để tìm hiểu và khám phá thêm .

1.2 Các hàm do người dùng xác định

Bạn cũng có thể tạo các hàm trong C phù hợp với nhu cầu của mình. Các hàm do người dùng tạo ra được gọi là hàm do người dùng xác định.

Hàm do người dùng xác lập hoạt động giải trí như thế nào ?

#include

void functionName ( )
{
… .. …
… .. …
}
int main ( )
{
… .. …
… .. …
functionName ( ) ;
… .. …
… .. …
}
Lập trình này sẽ thực thi các mã sau hàm main ( )
Khi trình biên dịch gặp hàm functionName ( ) :, điều khiển và tinh chỉnh của lập trình sẽ nhảy tới
void functionName ( )
Và, trình biên dịch mở màn thực thi các mã bên trong functionName ( ) .
Điều khiển lập trình sẽ quay lại hàm main ( ) sau khi mã bên trong hàm này được thực thi .
Lưu ý, tên hàm là định danh và phải là duy nhất .

Ưu điểm của các hàm trong C do người dùng xác định

  • Lập trình này sẽ dễ hiểu, dễ bảo trì và dễ sửa lỗi hơn.
  • Các mã tái sử dụng có thể được dùng trong những lập trình khác
  • Một lập trình lớn có thể được chia thành các mô-đun nhỏ hơn. Do đó, có thể chia một dự án lớn thành nhiều phần và mỗi lập trình viên đảm nhận một phần.

2. Các hàm trong C do người dùng xác lập

2.1 Ví dụ: Hàm trong C do người dùng xác định

Đây là ví dụ về việc thêm 2 số nguyên. Để thực thi trách nhiệm này, bạn cần tạo hàm addNumbers do người dùng xác lập .

#include

int addNumbers ( int a, int b ) ; / / function prototype
int main ( )
{
int n1, n2, sum ;
printf ( “ Enters two numbers : “ ) ;
scanf ( “ % d % d ”, và n1, và n2 ) ;
sum = addNumbers ( n1, n2 ) ; / / function call
printf ( “ sum = % d ”, sum ) ;
return 0 ;
}
int addNumbers ( int a, int b ) / / function definition
{
int result ;
result = a + b ;
return result ; / / return statement
}

2.2 Nguyên mẫu hàm

Nguyên mẫu hàm chính là sự khai báo hàm : tên hàm, các tham số và kiểu trả về. Nó không phải là phần thân của hàm .
Nguyên mẫu hàm thông tin cho trình biên dịch rằng hàm đó hoàn toàn có thể sẽ được sử dụng trong lập trình này .
Cú pháp của nguyên mẫu hàm
returnType functionName ( type1 argument1, type2 argument2, … ) ;

note: argument: đối số

Trong ví dụ trên, int addNumbers ( int a, int b ) ; chính là nguyên mẫu hàm cung ứng thông tin cho trình biên dịch :

  • tên của hàm là addNumbers ()
  • kiểu trả về của hàm là int
  • hai đối số kiểu int được chuyển cho hàm

Không cần tạo nguyên mẫu hàm nếu hàm do người dùng xác lập được đặt trước hàm main ( ) .

2.3 Lời gọi hàm

Quyền trấn áp lập trình được chuyển sang cho hàm do người dùng xác lập trải qua lời gọi hàm
Cú pháp của lời gọi hàm
functionName ( argument1, argument2, … ) ;
Trong ví dụ trên, lời gọi hàm được thực thi bằng lệnh addNumbers ( n1, n2 ) ; nằm trong hàm main ( ) .

2.4 Định nghĩa hàm

Định nghĩa hàm chứa khối mã để triển khai một trách nhiệm đơn cử. Trong ví dụ trên, định nghĩa hàm chính là thêm 2 số và trả lại nó .
Cú pháp định nghĩa hàm
returnType functionName ( type1 argument1, type2 argument2, … )
{
/ / body toàn thân of the function
}
Khi một hàm được gọi, quyền tinh chỉnh và điều khiển của lập trình sẽ được chuyển sang định nghĩa hàm. Và trình biên dịch mở màn thực thi các mã bên trong phần thân của hàm .

2.5 Truyền đối số cho một hàm

Trong lập trình, đối số ám chỉ một biến được truyền cho hàm. Trong ví dụ trên, 2 biến số n1 và n2 được truyền thông qua quy trình gọi hàm .
Các tham số a và b gật đầu các đối số được truyền vào trong định nghĩa hàm. Các đối số này được gọi là tham số chính thức của hàm .
Loại đối số được truyền cho một hàm và các tham số chính thức phải khớp nhau. Nếu không, trình biên dịch sẽ báo lỗi .
Nếu n1 thuộc kiểu char thì a cũng phải thuộc kiểu char. Nếu n2 thuộc kiểu float thì biến b cũng phải thuộc kiểu float .
Cũng hoàn toàn có thể gọi một hàm mà không cần truyền đối số .

2.6 Câu lệnh return (trả về)

Câu lệnh return kết thúc việc thực thi một hàm và trả về giá trị cho hàm đang gọi. Điều khiển của lập trình sẽ được chuyển cho hàm đang gọi nằm sau câu lệnh return .
Trong ví dụ trên, giá trị của biến result được trả về cho hàm main. Biến sum trong hàm main ( ) được gán giá trị này .
Cú pháp của câu lệnh return
return ( expression ) ;
Ví dụ ,
return a ;
return ( a + b ) ;
Kiểu giá trị được trả về từ hàm, kiểu trả về được chỉ định trong nguyên mẫu hàm và định nghĩa hàm phải khớp nhau .
Truy cập vào đây để biết thêm thông tin chi tiết cụ thể về cách truyền đối số và giá trị trả về từ một hàm .

3. Khai báo hàm trong C

Trong phần này, bạn sẽ được tìm hiểu và khám phá về các giải pháp tiếp cận khác nhau để xử lý cùng một yếu tố bằng cách sử dụng, khai báo hàm trong C .
4 lập trình dưới đây sẽ kiểm tra xem số nguyên mà người dùng nhập vào có phải là số nguyên tố không .
Đầu ra của tổng thể các lập trình dưới đây đều giống nhau, và tôi chỉ tạo một hàm do người dùng xác lập trong mỗi ví dụ. Tuy nhiên, cách tiếp cận mà tôi thực thi trong mỗi ví dụ là khác nhau .

Ví dụ 1: Không có đối số nào được truyền và không có giá trị nào trả về

#include

void checkPrimeNumber ( ) ;
int main ( )
{
checkPrimeNumber ( ) ; / / argument is not passed
return 0 ;
}
/ / return type is void meaning doesn’t return any value
void checkPrimeNumber ( )
{
int n, i, flag = 0 ;
printf ( “ Enter a positive integer : “ ) ;
scanf ( “ % d ”, và n ) ;
for ( i = 2 ; i < = n / 2 ; + + i ) { if ( n % i = = 0 ) { flag = 1 ; } } if ( flag = = 1 ) printf ( “ % d is not a prime number. ”, n ) ; else printf ( “ % d is a prime number. ”, n ) ; } Hàm checkPrimeNumber ( ) nhận nguồn vào từ người dùng, kiểm tra xem nó có phải là số nguyên tố hay không và hiển thị nó lên màn hình hiển thị . Các dấu ngoặc đơn trống trong câu lệnh checkPrimeNumber ( ) ; bên trong hàm main ( ) có nghĩa là không có đối số nào được truyền vào hàm . Kiểu trả về của hàm là void. Do đó, không có giá trị nào được trả về từ hàm này .

Ví dụ 2: Không có đối số nào được truyền nhưng có giá trị trả về

#include

int getInteger ( ) ;
int main ( )
{
int n, i, flag = 0 ;
/ / no argument is passed
n = getInteger ( ) ;
for ( i = 2 ; i < = n / 2 ; + + i ) { if ( n % i = = 0 ) { flag = 1 ; break ; } } if ( flag = = 1 ) printf ( “ % d is not a prime number. ”, n ) ; else printf ( “ % d is a prime number. ”, n ) ; return 0 ; } / / returns integer entered by the user int getInteger ( ) { int n ; printf ( “ Enter a positive integer : “ ) ; scanf ( “ % d ”, và n ) ; return n ; } Các dấu ngoặc đơn trống trong câu lệnh n = getInteger ( ) ; đồng nghĩa tương quan với việc không có đối số nào được truyền cho hàm này. Và giá trị được trả về từ hàm được gán cho n . Hàm getInteger ( ) nhận nguồn vào từ người dùng và trả về nó. Mã nằm trong hàm main ( ) sẽ kiểm tra xem số nhập vào có phải là số nguyên tố hay không

Ví dụ 3: Đối số được truyền nhưng không có giá trị trả về

#include

void checkPrimeAndDisplay ( int n ) ;
int main ( )
{
int n ;
printf ( “ Enter a positive integer : “ ) ;
scanf ( “ % d ”, và n ) ;
/ / n is passed to the function
checkPrimeAndDisplay ( n ) ;
return 0 ;
}
/ / return type is void meaning doesn’t return any value
void checkPrimeAndDisplay ( int n )
{
int i, flag = 0 ;
for ( i = 2 ; i < = n / 2 ; + + i ) { if ( n % i = = 0 ) { flag = 1 ;

break;

}
}
if ( flag = = 1 )
printf ( “ % d is not a prime number. ”, n ) ;
else
printf ( “ % d is a prime number. ”, n ) ;
}
Giá trị số nguyên do người dùng nhập vào sẽ được truyền vào hàm checkPrimeAndDisplay ( )
Hàm checkPrimeAndDisplay ( ) sẽ kiểm tra xem đối số được truyền vào có phải là số nguyên tố hay không và hiển thị thông tin thích hợp .

Ví dụ 4: Đối số được truyền và có giá trị trả về

#include

int checkPrimeNumber ( int n ) ;
int main ( )
{
int n, flag ;
printf ( “ Enter a positive integer : “ ) ;
scanf ( “ % d ”, và n ) ;
/ / n is passed to the checkPrimeNumber ( ) function
/ / the returned value is assigned to the flag variable
flag = checkPrimeNumber ( n ) ;
if ( flag = = 1 )
printf ( “ % d is not a prime number ”, n ) ;
else
printf ( “ % d is a prime number ”, n ) ;
return 0 ;
}
/ / int is returned from the function
int checkPrimeNumber ( int n )
{
int i ;
for ( i = 2 ; i < = n / 2 ; + + i ) { if ( n % i = = 0 ) return 1 ; } return 0 ; } Đầu vào được người dùng nhập vào sẽ được truyền đến hàm checkPrimeNumber ( ) . Hàm checkPrimeNumber ( ) kiểm tra xem đối số được truyền vào có phải là số nguyên tố hay không . Nếu đối số được truyền vào là số nguyên tố, hàm trả về 0. Nếu đối số được truyền vào không phải là số nguyên tố, hàm trả về 1. Giá trị trả về được gán cho biến flag . Tùy thuộc vào việc biến flag là 0 hay 1 thì đầu ra sẽ hiển thị thông tin thích hợp từ hàm main ( )

Cách tiếp cận nào tốt hơn?

Để nhìn nhận cách tiếp cận nào tốt hơn thì phải xem xét đến yếu tố mà bạn đang muốn xử lý. Nhưng trong trường hợp này, truyền đối số và trả về giá trị từ một hàm ( ví dụ 4 ) là tốt nhất .
Một tính năng nên thực thi một trách nhiệm đơn cử. Hàm checkPrimeNumber ( ) không hề lấy đầu vào từ người dùng cũng như không hề hiển thị thông tin thích hợp được. Nó chi có công dụng kiểm tra 1 số ít có phải là số nguyên tố hay không .

4. Đệ quy trong lập trình C

Trong phần này, bạn sẽ được học cách khai báo hàm đệ quy trong lập trình C trải qua ví dụ .
Một hàm có năng lực tự gọi chính nó thì được xem là hàm đệ quy. Và kỹ thuật này được gọi là đệ quy .
Đệ quy hoạt động giải trí như thế nào ?
void recurse ( )
{
… .. …
recurse ( ) ;
… .. …
}
int main ( )
{
… .. …
recurse ( ) ;
… .. …
}
Đệ quy diễn ra liên tục cho đến khi nó bị ngăn lại bởi một vài điều kiện kèm theo nhất định .
Để ngăn ngừa đệ quy lặp vô hạn, bạn sử dụng câu lệnh if … else ( hoặc cách tiếp cận tương tự như ) tại vị trí mà một nhánh triển khai lệnh gọi đệ quy và nhánh còn lại thì không .

Ví dụ: Tổng các số tự nhiên sử dụng đệ quy

#include

int sum ( int n ) ;

int main ( ) {
int number, result ;

printf ( “ Enter a positive integer : “ ) ;
scanf ( “ % d ”, và number ) ;

result = sum ( number ) ;

printf ( “ sum = % d ”, result ) ;
return 0 ;
}

int sum ( int n ) {
if ( n ! = 0 )
/ / sum ( ) function calls itself
return n + sum ( n-1 ) ;
else
return n ;
}
Đầu ra
Enter a positive integer : 3
sum = 6
Đầu tiên, hàm sum ( ) được gọi từ hàm main ( ) với number được truyền dưới dạng đối số .
Giả sử khởi đầu giá trị của n bên trong sum ( ) là 3. Trong lần gọi hàm tiếp theo, 2 được chuyển cho hàm sum ( ). Quá trình này liên tục cho đến khi n bằng 0 .
Khi n bằng 0, điều kiện kèm theo if không thành công xuất sắc và phần else được thực thi, trả về tổng số ở đầu cuối của các số nguyên cho hàm main ( ) .

Ưu điểm và nhược điểm của đệ quy

Đệ quy giúp lập trình trở nên ngắn gọn hơn. Tuy nhiên, dùng vòng lặp thay vì đệ quy sẽ khiến lập trình diễn ra chậm hơn nhiều .
Tóm lại, đệ quy là một khái niệm quan trọng. Nó thường được sử dụng trong cấu trúc tài liệu và các thuật toán. Ví dụ, đệ quy thường được sử dụng để xử lý những yếu tố như duyệt cây .

5. Lớp lưu trữ trong lập trình C

Trong phần này, bạn sẽ được khám phá về khoanh vùng phạm vi và thời hạn sống sót của các biến cục bộ và các biến toàn cục. Bên cạnh đó, bạn cũng sẽ biết thêm thông tin về biến tĩnh và biến register .
Tất cả các biến trong lập trình C đều có 2 tính năng : loại và lớp tàng trữ .
Loại đề cập đến kiểu tài liệu của một biến. Và lớp tàng trữ xác lập khoanh vùng phạm vi, năng lực hiển thị và thời hạn sống sót của một biến .
Có 4 loại lớp tàng trữ :

  1. Tự động
  2. bên ngoài
  3. tĩnh
  4. register

5.1 Biến cục bộ

Các biến được khai báo bên trong một khối chính là biến tự động hóa hoặc biến cục bộ. Cá biến cục bộ chỉ tồn tạo bên trong một khối mà nó được khai báo .
Ví dụ :

#include

int main ( void ) {
for ( int i = 0 ; i < 5 ; + + i ) { printf ( “ C programming ” ) ; } / / Error : i is not declared at this point printf ( “ % d ”, i ) ; return 0 ; } Khi chạy, lập trình trên sẽ báo lỗi là undeclared identifier i. Bởi vì i được khai báo bên trong khối vòng lặp for. Còn bên ngoài khối đó thì nó không được khai báo . Xem thêm ví dụ dưới đây : int main ( ) { int n1 ; / / n1 is a local variable to main ( ) } void func ( ) { int n2 ; / / n2 is a local variable to func ( ) } Trong ví dụ này, n1 là biến cục bộ của hàm main ( ) và n2 là biến cục bộ của hàm func ( ) . Điều này có nghĩa là bạn không hề truy vấn vào biến n1 bên trong hàm func ( ) bởi nó chỉ sống sót bên trong hàm main ( ). Tương tự, bạn cũng không hề truy vấn vào biến n2 trong hàm main ( ) vì nó chỉ sống sót bên trong hàm func ( ) .

5.2 Biến toàn cục

Các biến được khai báo bên ngoài tổng thể các hàm được gọi là biến bên ngoài hoặc biến toàn cục. Chúng hoàn toàn có thể được truy vấn từ bất kể hàm nào trong lập trình .
Ví dụ 1 : Biến toàn cục

#include

void display ( ) ;
int n = 5 ; / / global variable
int main ( )
{
+ + n ;
display ( ) ;
return 0 ;
}
void display ( )
{
+ + n ;
printf ( “ n = % d ”, n ) ;
}
Đầu ra
n = 7
Giả sử, một biến toàn cục được khai báo trong file1. Nếu bạn cố gắng nỗ lực sử dụng biến đó trong tệp file2, trình biên dịch sẽ khiếu nại. Để xử lý yếu tố này, bạn nên sử dụng từ khóa extern trong file2 để ám chỉ rằng rằng biến bên ngoài đã được khai báo trong một tệp khác .

5.3 Biến register

Từ khóa register dùng để khai báo biến register. Biến register sẽ chạy nhanh hơn biến cục bộ .
Tuy nhiên, các trình biên dịch tân tiến có ưu điểm là tối ưu hóa mã nhanh gọn. Và sử dụng biến register cũng không giúp lập trình của bạn chạy nhanh hơn .
Trừ khi bạn thao tác trên mạng lưới hệ thống nhúng và bạn biết cách tối ưu hóa mã cho những ứng dụng nhất định thì không cần sử dụng các biến register .

5.4 Biến tĩnh

Biến tĩnh được khai báo bằng cách sử dụng từ khóa static. Ví dụ ;
static int i ;
Giá trị của biến tĩnh vẫn sống sót cho đến khi lập trình kết thúc .
Ví dụ 2 : Biến tĩnh

#include

void display ( ) ;
int main ( )
{
display ( ) ;
display ( ) ;
}
void display ( )
{
static int c = 1 ;
c + = 5 ;
printf ( “ % d “, c ) ;
}
Đầu ra

6 11

Trong lần gọi hàm tiên phong, giá trị của c được khởi tạo bằng 1. Giá trị của nó tăng thêm 5. Lúc này, giá trị của c sẽ là 6 và số 6 được in lên màn hình hiển thị
Trong lần gọi thứ 2, c không được khởi tạo từ 1 nữa vì c là một biến tĩnh. Lúc này, giá trị của c tăng thêm 5. Và giá trị của c sẽ là 11, số 11 được in lên màn hình hiển thị .

Trên đây là tất cả các kiến thức về các hàm trong C, ưu điểm của việc sử dụng hàm. Hy vọng bài viết sẽ giúp bạn có thêm kiến thức về (hàm) function trong C. Chúc bạn thành công!