Khái niệm
Hàm là một khối các câu lệnh thực hiện một nhiệm vụ
nhất định, và có thể được gọi khi cần
Mỗi hàm có một tên (các hàm trong C không được trùng
tên nhau), một số tham số, và một giá trị trả về
Sử dụng hàm giúp:
Chia nhỏ chương trình thành nhiều bài toán con
Sử dụng lại trong một hoặc nhiều chương trình
Cách khai báo:
() {
Khai báo các biến dùng cho hàm
Các câu lệnh của hàm
}
Câu lệnh return dùng để thoát khỏi hàm và trả kết quả
22 trang |
Chia sẻ: phuongt97 | Lượt xem: 463 | Lượt tải: 0
Bạn đang xem trước 20 trang nội dung tài liệu Bài giảng Kỹ thuật lập trình - Bài 5: Hàm và thư viện - Đào Trung Kiên, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Bài 5: Hàm và thư viện
1
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Hàm
(functions)
2
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Khái niệm
Hàm là một khối các câu lệnh thực hiện một nhiệm vụ
nhất định, và có thể được gọi khi cần
Mỗi hàm có một tên (các hàm trong C không được trùng
tên nhau), một số tham số, và một giá trị trả về
Sử dụng hàm giúp:
Chia nhỏ chương trình thành nhiều bài toán con
Sử dụng lại trong một hoặc nhiều chương trình
Cách khai báo:
() {
Khai báo các biến dùng cho hàm
Các câu lệnh của hàm
}
Câu lệnh return dùng để thoát khỏi hàm và trả kết quả
3
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Ví dụ
Hàm tính tổng hai số
double sum(double x, double y) {
double z = x+y;
return z;
}
int main() {
double x = 10, y = sum(2,3);
printf("x + y = %g", sum(x,y));
return 0;
}
Các tham số và các biến nội bộ chỉ giới hạn trong phạm
vi của hàm
4
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Phạm vi của biến, hằng
Biến toàn cục: được khai báo ở ngoài các hàm, có phạm vi trong
toàn chương trình và tồn tại trong suốt quá trình chạy
Biến địa phương: được khai báo ở trong một hàm hoặc một khối
lệnh, chỉ có phạm vi trong hàm/khối đó, và bị huỷ sau khi kết thúc
chạy hàm/khối đó
Khai báo biến địa phương sẽ “che” mất biến cùng tên khác có phạm vi rộng hơn
Trong C, biến địa phương phải được khai báo ở đầu hàm hoặc khối lệnh
Ví dụ biến địa phương của hàm:
int x = 10, y = 20; /* phải khai báo trước hàm sum() */
int sum() {
int z = x+y;
return z;
}
int main() {
int x = 1, y = 2;
int z = sum(); /* trả về: 10+20 */
return 0;
}
5
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Biến trong khối lệnh
Trong một khối lệnh { } ta có thể khai thêm biến, biến đó chỉ tồn tại
từ khi chương trình chạy vào tới khi thoát khỏi khối lệnh đó
Ví dụ:
int x = 1, y = 2;
int sum(int x, int y) {
return x+y;
}
int a = 1000, b = 2000;
int main() {
int x = 10, y = 20;
{
int x = 100, y = 200;
x+y;
}
x+y;
sum(a,b);
return 0;
}
6
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Biến trong khối lệnh: vòng lặp
Chỉ có phạm vi trong một lần chạy của vòng lặp, mỗi
lần lặp sẽ tạo ra biến mới và khởi tạo lại
Ví dụ:
int x = 20;
for (i=0; i<10; i++) {
int y = 20;
x++; y++;
printf("%d %d\n", x, y);
}
7
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Biến static
Là biến chỉ có phạm vi địa phương nhưng vẫn tồn tại ngay cả khi
chưa vào hoặc đã thoát khỏi hàm/khối
Khai báo bằng cách thêm từ khoá static
int callCount() {
static int count = 0;
count++;
return count;
}
Cũng có biến static toàn cục: thuộc nội bộ của một file nguồn
static int tic_time = 0;
void tic() {
tic_time = clock();
}
int toc() {
return clock() - tic_time;
}
Hàm static: tự tìm hiểu thêm
8
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Câu lệnh return
Kết thúc hàm và trả về một giá trị cho nơi gọi nó
int find(int number, int a[], int n) {
int i;
for (i=0; i<n; i++)
if (number == a[i])
return i;
return -1;
}
Hàm void: không trả về giá trị gì
void copy(int *a, int *b, int n) {
if (a==NULL || b==NULL || a==b || n==0)
return;
for (; n>0; n--)
*a++ = *b++;
}
Câu lệnh return không có tham số
Không cần lệnh return ở cuối hàm
9
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Tham số kiểu giá trị và kiểu tham chiếu
Tham số của hàm là biến tạm thời, tạo ra khi gọi và huỷ khi hàm kết
thúc gán giá trị cho tham số không ảnh hưởng tới biến nơi gọi
void assign10(int x) { x = 10; }
int main() {
int a = 20;
assign10(a);
printf("a = %d", a);
return 0;
}
Dùng con trỏ nếu muốn thay đổi giá trị của biến ở nơi gọi
void assign10(int *x)
{ *x = 10; }
int a = 20;
assign10(&a);
Tham số con trỏ thường được dùng như một cách khác để trả về
thêm giá trị, vì mỗi hàm chỉ có một giá trị trả về theo đúng nghĩa
10
x (int)
a
copy
a
x (int*)
&a
copy
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Hàm trả về con trỏ
Vấn đề với hàm trả về biến địa phương
int* sum(int x, int y) {
int z = x+y;
return &z;
}
int* p = sum(2, 3); /* sai */
Cấp phát bộ nhớ trong hàm
int* sum(int x, int y) {
int* z = (int*)malloc(sizeof(int));
*z = x+y;
return z;
}
int* p = sum(2, 3);
/* ... */
free(p);
11
p
zint* sum() { }
copy
*z
p
zint* sum() { }
copy
địa chỉ
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Nguyên mẫu (prototype) của hàm
Là việc khai báo hàm trước, nội dung của nó được triển
khai sau thường khai báo ở đầu file hoặc trong file .h
Ví dụ:
double tong(double x, double y);
double tich(double x, double y);
int main() {
double x = 5., y = 10.;
tong(x, y);
tich(x, y);
return 0;
}
double tong(double x, double y) { return x+y; }
double tich(double x, double y) { return x*y; }
12
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Hàm đệ quy (recursive function)
Là hàm có câu lệnh gọi chính nó
Ví dụ 1: giai thừa một số n
unsigned int giai_thua(unsigned int n) {
if (n <= 1) return 1;
return n * giai_thua(n-1);
}
Ví dụ 2: x mũ n
double mu(double x, unsigned int n) {
double y;
if (n == 0) return 1;
y = mu(x, n/2);
if (n%2 == 0) return y*y;
return y*y*x;
}
Không hiệu quả nếu sinh quá nhiều lệnh gọi hạn chế
13
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Con trỏ hàm
Là con trỏ trỏ tới một hàm là một kiểu dữ liệu trong C, thường
được dùng để gọi một hàm chưa biết trước
double (*SomeOpt)(double, double);
typedef double (*OptFunc)(double, double);
OptFunc SomeOpt;
Ví dụ:
double sum(double x, double y) { return x+y; }
double prod(double x, double y) { return x*y; }
int main() {
double (*SomeOpt)(double, double) = ∑
SomeOpt(2., 5.); /* sum(2., 5.); */
SomeOpt = prod;
(*SomeOpt)(2., 5.); /* prod(2., 5.); */
return 0;
}
Phép gán có thể dùng & hoặc không, gọi cũng có thể dùng * hoặc
không
14
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Macro
Macro là đoạn mã được đại diện bằng một tên, mà mỗi khi tên đó
xuất hiện trong chương trình thì sẽ được thay thế bằng đoạn mã
tương ứng
#define ERROR { printf("Error, exit now!"); exit(-1); }
int main(int argc, char* argv[]) {
if (argc != 3) ERROR
/* */
return 0;
}
Macro có thể được thay thế khi định nghĩa macro khác cùng tên
Huỷ bỏ macro đã định nghĩa: #undef ERROR
Kiểm tra xem macro đã định nghĩa chưa
#ifdef ERROR
/* ... */
#else
/* ... */
#endif
15
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Macro (tiếp)
Macro có thể có tham số đôi khi được dùng như hàm
#define MIN(x,y) x<y ? x:y
z = MIN(2,4); /* z = 2<4 ? 2:4; */
#define PI 3.1415
#define AREA(R) R*R*PI
z = AREA(5); /* z = 5*5*3.1415; */
Chú ý các hiệu ứng phụ
#define MUL(x,y) x*y
z = MUL(2,4); /* z = 2*4; */
z = MUL(2+1,4); /* z = 2+1*4; */
z = 8/MUL(1+1,2); /* z = 8/1+1*2; */
#define MUL(x,y) ((x)*(y))
z = MUL(2+1,4); /* z = ((2+1)*(4)); */
z = 8/MUL(1+1,2); /* z = 8/((1+1)*(2)); */
#define SQR(x) ((x)*(x))
z = SQR(i); /* z = ((i)*(i)); */
z = SQR(i++); /* z = ((i++)*(i++)); */
16
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Thư viện hàm
(libraries)
17
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Thư viện hàm
Một chương trình có thể được chia nhỏ làm nhiều file, mỗi file chứa
một nhóm những hàm liên quan tới một phần của chương trình
Một số hàm có thể được dùng trong nhiều chương trình khác nhau
thư viện hàm
Một thư viện hàm gồm 2 phần:
File header có đuôi .h chứa prototype các hàm có thể dùng được của thư
viện
File mã nguồn có đuôi .c chứa nội dung các hàm, hoặc file .obj, .lib nếu
đã được dịch ra các dạng tương ứng
Dùng thư viện hàm trong một file mã nguồn:
#include /* trong đường dẫn mặc định */
#include "ten_file.h" /* cùng thư mục với file dịch */
Dẫn hướng #include có tác dụng như chèn nội dung file được khai báo
vào file đang dịch ở vị trí xuất hiện
18
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Lưu ý với tạo và sử dụng file .h
Trong file abcd.h
Để tránh lỗi khi bị #include nhiều lần, thêm vào đầu và cuối
#pragma once
#ifndef __ABCD_H__
#define __ABCD_H__
/* Nội dung file abcd.h */
#endif
Các biến toàn cục phải được khai báo trong file .c, nếu muốn
được export thì trong file .h khai báo thêm bằng extern:
extern int bien_toan_cuc;
Sử dụng file abcd.h
#include "abcd.h" /* .h cùng thư mục */
#include /* .h trong thư mục thư viện */
19
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Ví dụ: Thư viện tính diện tích các hình
dientich.h
#ifndef __DIENTICH_H__
#define __DIENTICH_H__
extern const double PI;
double dt_tron(double r);
double dt_elip(double r1, double r2);
double dt_vuong(double l);
double dt_chu_nhat(double l1, double l2);
#endif
dientich.c
const double PI = 3.1415;
double dt_tron(double r)
{ return r*r*PI; }
double dt_elip(double r1, double r2)
{ return r1*r2*PI; }
double dt_vuong(double l)
{ return l*l; }
double dt_chu_nhat(double l1, double l2)
{ return l1*l2; }20
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Một số thư viện chuẩn
Tên Chức năng
stdio.h Xuất, nhập với màn hình, file, bàn phím,
ctype.h Kiểm tra các lớp ký tự (chữ số, chữ cái,)
string.h Xử lý chuỗi và bộ nhớ
memory.h Cấp phát và quản lý bộ nhớ động
math.h Một số hàm toán học
stdlib.h Chuyển đổi dữ liệu số-chuỗi, cấp phát bộ
nhớ,
time.h Các hàm về thời gian
21
EE3490: Kỹ thuật lập trình – HK1 2017/2018
TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
Bài tập
1. Viết hàm cấp phát bộ nhớ và nhập giá trị cho một mảng, trả về con
trỏ mảng và số phần tử
2. Viết hàm prime() trả về mảng các số nguyên tố bé hơn n
3. Định nghĩa mảng các struct MenuItem { Tiêu đề, Hàm xử lý }, in ra
màn hình menu, nhận lựa chọn của người dùng và thực hiện chức
năng tương ứng
4. Viết hàm tính số Fibonacci thứ n được định nghĩa:
Fib0 = 0, Fib1 = 1
Fibn = Fibn-1 + Fibn-2 (n ≥ 2)
5. Định nghĩa kiểu chuỗi String và viết thư viện một số hàm xử lý
chuỗi: khởi tạo, copy, nối, tìm kiếm,
6. Định nghĩa kiểu struct Shape rồi viết thư viện có hàm tính diện
tích, chu vi của hình tuỳ theo dạng của nó. Dùng 2 cách: switch và
con trỏ hàm
22
Các file đính kèm theo tài liệu này:
- bai_giang_ky_thuat_lap_trinh_bai_5_ham_va_thu_vien_dao_trung.pdf