Bài giảng Ngôn ngữ lập trình C - Hàm
Mục đích
 Biết cách xây dựng các chương trình từ
các hàm
 Cách tạo ra các hàm mới
 Cơ cấu truyền thông tin giữa các hàm
 Cách dùng và viết hàm đệ quy
 Giới thiệu hàm toán học trong thư viện C
chuẩn
àm toán học trong thư viện C 
chuẩn
Nội dung
 Khai báo và định nghĩa hàm
 Tham số trong lời gọi hàm
 Địa chỉ và con trỏ
 Con trỏ hàm
Khái niệm
Khai báo biến con trỏ hàm
Tham số hình thức của hàm là con trỏ hàm
 Đệ quy
Ví dụ
/*func1.c*/
#include 
#include 
int square(int);
void main()
{
int i;
for (i=1; i<=10; i++)
printf("%5d", square(i));
printf("\n");
getch();
}
int square(int x)
{
int y;
y = x*x;
return y;
}
Nguyên mẫu 
của hàm
Lời gọi hàm
Định nghĩa hàm
Khái niệm liên quan đến hàm
 Tên hàm
 Kiểu giá trị của hàm
 Khai báo hàm
 Thân hàm
 Lời gọi hàm
 Tham số hình thức (đối)
 Tham số thực
 Tên_hàm là tên hợp lệ
 Kiểu giá trị trả về là kiểu dữ liệu của kết quả trả
lại cho hàm gọi nó
 Nếu là void thì hàm không trả lại giá trị
 Nếu không xác định kiểu giá trị trả về trình biên dịch 
sẽ ngầm định là int
 Danh sách tham số: mô tả kiểu dữ liệu cùng 
thứ tự của các tham số hàm nhận khi được gọi
 Nếu hàm không nhận tham số, danh sách tham số là
void
 Cần ghi rõ kiểu của tham số, nếu không ghi được 
ngầm định là int
Khai báo và định nghĩa hàm
 Khai báo hàm (nguyên mẫu của hàm):
[kiểu giá trị trả về] Tên_hàm([danh sách tham số]);
Ví dụ: int square(int);
 Định nghĩa hàm:
[kiểu giá trị trả về] Tên_hàm([danh sách tham số])
{
Các khai báo
… (Thân hàm)
Các câu lệnh
}
Định nghĩa hàm (tiếp)
 Các khai báo và câu lệnh trong cặp dấu { và } 
tạo thành thân hàm
 Khai báo và cài đặt một hàm không được đặt trong 
hàm khác
 Trả lại giá trị cho hàm:
[return [biểu thức];]
 Có thể có nhiều câu lệnh return
 Giá trị của biểu thức trong câu lệnh return được gán cho 
hàm
 Có thể không sử dụng return
 return; ~ hàm không trả về giá trị (có thể không có)
Ví dụ
Hàm trả về giá trị là một số
nguyên. Tham số là hai số nguyên
int max(int a, int b) {…..}
Hàm trả về giá trị là một con trỏ
thực. Tham số là một số nguyên
float *nhap(int n) {…..}
Hàm trả về một số thực. Tham số
là một biến mảng thực hoặc một 
con trỏ thực
float sum(float *a) {…..}
Hàm trả về giá trị là một số
nguyên. Tham số là một mảng số
thực 20 phần tử
int count(float a[20]) {…..}
Ý nghĩaĐịnh nghĩa hàm
Hàm nguyên mẫu
 Thông báo cho trình biên dịch biết kiểu dữ
liệu hàm trả lại, số lượng, kiểu và thứ tự
của các tham số được truyền cho hàm
Dùng để kiểm tra lời gọi hàm
Không cần chỉ rõ tên của tham số hình thức
Tham số trong lời gọi hàm
 Khái niệm
Tham số hình thức: là các tham số được khai 
báo trong phần danh sách tham số trong định 
nghĩa hàm
Tham số thực: các thông tin được truyền cho 
hàm trong các lời gọi hàm
 Mỗi tham số thực tương ứng với một tham số hình 
thức
 Kiểu dữ liệu của tham số hình thức quyết định kiểu 
giá trị của tham số thực
Các bước xây dựng hàm:
 Khai báo kiểu hàm
 Đặt tên hàm
 Khai báo các đối
 Viết các câu lệnh
Chú ý
 Hàm không cho giá trị thì dùng kiểu void
 Hàm không đối dùng void để khai báo đối
 Giá trị của biểu thức được chuyển kiểu 
phù hợp với kiểu của hàm trước khi được 
gán cho hàm
Ví dụ - max
#include 
#include 
float max(float, float);
void main()
{
float a, b, c, d;
printf("Nhap 4 so thuc:\n");
scanf("%f%f%f%f",&a,&b,&c,&d);
printf("Max cua 4 so vua nhap la: 
%f",max(a,max(b,max(c,d))));
getch();
}
float max(float x, float y)
{
return (x>y?x:y);
}
Truyền thông tin cho hàm
 Truyền theo trị
 Tạo ra một bản sao giá trị của tham số thực
 Giá trị của tham số thực không bị thay đổi
 Tham số thực có thể là biến, hằng, biểu thức
 Truyền theo tham biến
 Truyền trực tiếp giá trị tham số cho hàm được gọi 
(tham số hình thức và thực là một)
 Tham số thực bắt buộc phải là biến
 Giá trị của tham số thực có thể bị thay đổi
Truyền tham số trong C
 Trong C, tất cả các tham số được truyền theo trị
/*swap1.c*/
#include 
#include 
void swap(int x, int y);
void main()
{
int x=3, y=4;
clrscr();
printf("Gia tri truoc khi goi ham\n");
printf("%5d %5d\n",x,y);
swap(x,y);
printf("Sau khi goi ham\n");
printf("%5d %5d",x,y);
getch();
}
void swap(int x, int y)
{
int t;
t = x;
x = y;
y = t;
}
Địa chỉ
 Các khái niệm liên quan đến biến
Tên biến
Kiểu biến
Giá trị của biến
Địa chỉ của biến là số thứ tự của byte đầu 
tiên trong một dãy các byte liên tiếp máy dành 
cho biến
Phép toán lấy địa chỉ: &
Con trỏ
 Khái niệm: con trỏ là một biến/hằng có giá
trị là địa chỉ của một đối tượng khác
Đối tượng: biến hoặc hàm
Cho phép ta tham chiếu đến một biến thông 
qua địa chỉ
Khai báo biến con trỏ
 Cú pháp: type *ptr_name
 type là kiểu dữ liệu của biến mà con trỏ chứa 
địa chỉ
ptr_name là tên của biến trỏ
 type* là một kiểu dữ liệu con trỏ
Biến trỏ chưa chỉ đến địa chỉ nào có giá trị
NULL
Tham số hình thức của hàm là con 
trỏ
 Tham số hình thức của hàm là con trỏ
Tham số thực tương ứng phải là một địa chỉ
Có thể thay đổi giá trị của biến với địa chỉ 
được truyền
Ví dụ
#include "stdio.h"
#include "conio.h"
void swap(float *x, float *y) {
float t;
t = *x;
*x = *y;
*y = t;
}
main()
{
float a=3, b=4;
clrscr();
printf("Gia tri truoc khi thay doi\n%8.2f\t%8.2f\n",a,b);
swap(&a,&b);
printf("Gia tri sau khi thay doi\n%8.2f\t%8.2f\n",a,b);
getch();
}
Kết quả
Khi nào sử dụng đối con trỏ
Con trỏ kiểu int
(float, double)
Địa chỉ kiểu int
(float, double)
Biến kiểu int
(float, double)
Giá trị kiểu int
(float, double)
Đối tương ứngTham số thực
Ví dụ
void nhap(int *k)
{
printf("Nhap ");
scanf("%d",k);
}
void show(int k)
{
printf("\n%d\n",k);
getch();
}
void swap1(int i, int j){
int temp;
temp = i;
i = j;
j = temp;
}
void swap2(int *i, int *j){
int temp;
temp = *i;
*i = *j;
*j = temp;
}
void main(){
int n,m;
nhap(&n); nhap(&m);
show(n); show(m);
printf("\nswap1\n");
swap1(n,m);
printf("%d\t%d",n,m);
printf("\nswap2\n");
swap2(&n,&m);
printf("%d\t%d",n,m);
getch();
}
Kết quả
Ví dụ
#include 
#include 
void nhap(char *c) {
printf("Nhap ");
fflush(stdin);
scanf("%c",c);
}
void show(char c) {
printf("%c\n",c);
}
void upcase1(char c){
if (c>='a'&&c<='z')
c = c - 32;
}
void upcase2(char *c){
if ((*c>='a')&&(*c<='z'))
*c = *c - 32;
}
void main(){
char ch;
clrscr();
nhap(&ch);
show(ch);
upcase1(ch);
show(ch);
upcase2(&ch);
show(ch);
getch();
}
Kết quả
Hàm đệ quy
 Khái niệm hàm đệ quy
 Cách dùng đệ quy
Sử dụng đệ quy cho bài toán nào?
Cách xây dựng hàm đệ quy
Khái niệm hàm đệ quy
 Bên trong thân của hàm có lời gọi tới 
chính hàm đó
 Khi gọi đệ quy
Máy tạo ra một tập các biến cục bộ độc lập 
với tập biến cục bộ đã được tạo ra trong các 
lần gọi trước
Có bao nhiêu lần gọi tới hàm thì cũng có bấy 
nhiêu lần thoát ra khỏi hàm
Cách dùng đệ quy
 Áp dụng cho lớp bài toán
Dễ dàng giải quyết trong trường hợp riêng 
(trường hợp suy biến)
Trường hợp tổng quát:
 Đưa về bài toán cùng dạng, tham số thay đổi
 Sau một số hữu hạn bước biến đổi, dẫn tới trường 
hợp suy biến
Cách dùng đệ quy
 Cách xây dựng hàm đệ quy
if (trường hợp suy biến) {
Trình bày cách giải
}
else /*trường hợp tổng quát*/ {
Gọi đệ quy tới hàm (đang lập)
với giá trị khác của tham số
}
Ví dụ - chỉnh hợp, tổ hợp
long giaithua(int);
void main()
{
int n, k;
printf("Nhap n, k= ");
scanf("%d%d",&n,&k);
printf("%n!=%ld\n",n,giaithua(n));
printf("%n!=%ld\n",n,giaithua(k));
printf("C(%d,%d)=%ld\n",n,k,giaithua(n)/(giaithua(n-
k)*giaithua(k)));
printf("A(%d,%d)=%ld",n,k,giaithua(n)/giaithua(n-k));
getch();
}
long giaithua(int n)
{
if (n==1||n==0)
return 1;
else return (giaithua(n-1)*n);
}
Ví dụ - ước chung lớn nhất
int ucln(int x, int y){
if (x==y) return x;
else if (x>y) return ucln(x-y,y);
else return ucln(x,y-x);
}
Con trỏ hàm
 Con trỏ hàm là con trỏ trỏ đến điểm xâm 
nhập vào hàm
Có thể sử dụng thay cho tên hàm
Cho phép các hàm cũng được truyền như là
các tham số cho các hàm khác
Khai báo biến con trỏ hàm
 Cú pháp:
[kiểu giá trị] (*tên biến con trỏ hàm)([danh 
sách tham số]);
 Con trỏ hàm nhận giá trị là tên của các 
hàm có cùng kiểu giá trị trả về và kiểu giá
trị của các tham số
Ví dụ
 float (*f)(float)
Khai báo f là con trỏ hàm kiểu float và có đối 
là float
 double (*g)(int, double)
Khai báo g là con trỏ hàm kiểu double có các 
đối int và double
Tác dụng của con trỏ hàm
 Chứa địa chỉ của hàm
Thực hiện phép gán tên hàm cho con trỏ hàm
Kiểu hàm và kiểu con trỏ phải tương thích
Ví dụ
#include 
#include 
float max(float x, float y){
return (x>y?x:y);
}
int main(){
float x = 3, y = 5;
float (*f)(float, float) = max;
printf("max=%f\n",f(x,y));
getch();
return 0;
}
Kết quả
Đối con trỏ hàm
 Hàm có tham số thực trong lời gọi tới nó
là tên của một hàm khác
Tham số hình thức tương ứng phải là một con 
trỏ hàm
 Cách dùng
Nếu đối được khai báo: float (*f)(float, int)
Sử dụng trong thân hàm: f(x,n) hoặc (f)(x,n) 
hoặc (*f)(x,n)
Ví dụ
#include 
#include 
#include 
double tichphan(double (*f)(double), double a, double b)
{
double s, h;
int i, n;
n = 10000;
h = (b-a)/n;
s = (f(a)+f(b))/2;
for (i=1; i<n; i++){
s = s + f(a+i*h);
}
return s*h;
}
double g(double x){
double s;
s = (exp(x) - 2*sin(x*x)/(1+pow(x,4)));
return s;
}
void main()
{
clrscr();
printf("TP1 = %f\n",tichphan(sin,0,M_PI/2));
printf("TP2 = %f\n",tichphan(cos,0,M_PI/2));
printf("TP3 = %f\n",tichphan(exp,0,1.0));
printf("TP4 = %f\n",tichphan(g,0,2.0));
getch();
}
Kết quả
Thư viện các hàm toán học
cos(0.0)=1cos của xcos(x)
tan(0.0)=0tan của xtan(x)
sin(0.0)=0sin của x (x theo radian)sin(x)
fmod(13.657,2.333)=1.992Phần dư của phép chia x cho yfmod(x,y)
pow(2,7)=128x mũ ypow(x,y)
floor(-9.8)=-10Làm tròn xuốngfloor(x)
ceil(9.2)=10.0Làm tròn lênceil(x)
fabs(x)=|x|Trị tuyệt đối của xfabs(x)
log10(1.0)=0.0logarithm cơ số 10 của xlog10(x)
log(2.718282)=1.0logarithm cơ số e của xlog(x)
exp(1.0)=2.718282Hàm mũ exexp(x)
sqrt(9.00)=3.0Căn bậc 2 của xsqrt(x)
Ví dụMô tảHàm
File đính kèm:
Bài giảng Ngôn ngữ lập trình C - Hàm.pdf

