1. Phạm
Ph Thế BảBảo
http://www.math.hcmuns.edu.vn/~ptbao/KTLT/
ptbao@hcmuns.edu.vn
Trường Đ i h Kh học Tự hiê Tp.HCM
T ờ Đại học Khoa h T nhiên T HCM
2. Ộ
NỘI DUNG
1. Thiết kế chương trình
2. Mảng ộ hiề h i hiề à hiề hiề
Mả một chiều, hai chiều và nhiều chiều
3. Con trỏ
4. Chuỗi ký tự
5. Cấu trúc
6. Tập tin
7. Đệ quy
8. Một số thuật toán thông dụng
3. Cách tính điểm
Điểm thực hành 50% tổng điểm
Điểm lý thuyết 50% tổng điểm
ộ g
Điểm cộng thêm 10 – 20% tổng điểm
g
4. ệ
Tài liệu tham khảo
1. Quách Tuấn Ngọc, Ngôn Ngữ Lập Trình C. Nhà Xuất
Bản Giáo Dục, 1998.
2. Mark Allen Weiss, Efficient C programming..
Prentice Hall, 1998.
3.
3 Yale N. Patt, Sanjay J. Patel, Introduction to
Yale N Patt Sanjay J Patel Introduction to
Computing System, from Bits and Gates to C and
Beyond.. McGrawHill, 1999.
4.
4 Trần Đan Thư, Giáo trình lập trình (Tập
T ầ Đ Th Giá t ì h lậ t ì h C (Tậ 1 & 2 ) NXB ).
ĐH QG TPHCM –2003.
5. Nguyễn Thanh Thuỷ, Nhập môn lập trình ngôn ngữ C.
g y ỷ, ập ập g g
NXB KH-KT – 2005.
6. Phạm Văn Ất - Kỹ thuật lập trình C cơ sở và nâng cao.
NXB KH-KT- 20062006.
5. Ebook
1. Beginning C From Novice to Professional.
2.
2 C Primer Plus 5th Edition
Edition.
3. Mastering Algorithms with C.
4.
4 Practical C Programming.
Programming
5. Expert C Programming - Deep C Secrets.
6.
6 The Complete Reference
Reference.
7. C Reference Card (ANSI).
6. Website
1. http://www.congdongcviet.com
2.
2 http://www.cprogramming.com/
htt // i /
3. http://www.programmingtutorials.com/c.aspx
4.
4 http://www.codeguru.com/
htt // d /
5. http://www.thecodeproject.com/
6.
6 http://c4swimmers.net
htt // 4 i t
7. http://www.vocw.edu.vn/
8.
8 http://www.google.com.vn/
h // l /
8. Phân lọai
1. Phương pháp trực tiếp
2. Phương pháp gián tiếp hoặc tìm kiếm lời giải
9. Phương pháp trực tiếp
• Xác định trực tiếp được lời giải qua một thủ tục tính toán (công
thức, thức,
thức hệ thức định luật …) hoặc qua các bước căn bản để có
luật, )
được lời giải.
• Việc giải quyết vấn đề trên máy tính chỉ là thao tác lập trình hay
g q y y p y
là sự chuyển đổi lời giải từ ngôn ngữ tự nhiên sang ngôn ngữ
ể ổ
máy tính kỹ thuật lập trình trên máy tính.
• Có ba loại cơ bản:
o Lọai thứ nhất, dùng để biểu diễn cho các bài toán đã có lời giải chính
xác bằng một công thức toán học nào đó. 1 + 2 + ... + n =
n(n + 1)
2
ví dụ: tính tổng n số nguyên dương.
o Loại thứ hai, biểu diễn cho các bài toán có công thức giải gần đúng
(công thức tính sin cos giải phương trình siêu việt …).
sin, cos, việt, )
ví dụ: giải phương trình bậc 2
o Loại cuối cùng, biểu diễn các lời giải không tường minh bằng kỹ thuật
đệ quy.
10. Chuyển đổi dữ liệu bài toán thành dữ liệu chương trình
Nguyên lý 1: Dữ liệu của bài toán sẽ được biểu diễn lại dưới dạng
các biến của chương trình thông qua các quy tắc xác định của
ngôn ngữ lập trình cụ thể
1 Biến - phương tiện biểi diễn dữ liệu của chương trình
1.
2. Thay đổi giá trị của biến - lệnh gán
3 Kiểu dữ liệu
3.
4. Hằng số
5 Cấu trúc một chương trình
5.
11. Chuyển đổi quá trình tính toán của bài toán thành
các cấu trúc của chương trình
Nguyên lý 2 (Định lý Bohn-Jacopini): Mọi quá trình tính toán đều
có thể mô tả và thực hiện dựa trên ba cấu trúc cơ bản: tuần tự, rẽ
nhánh và lặp.
1. Cấu trúc tuần tự
2.
2 Cấu trúc ẽ há h
Cấ t ú rẽ nhánh
1. Rẽ nhánh có điều kiện: if (condition)
rẽ nhánh đơn: if ()
rẽ nhánh đôi if () ... else ...
ẽ há h đôi: l
2. Rẽ nhiều nhánh: case
3. Rẽ nhánh không có điều kiện: LABEL và GOTO
3. Cấu trúc lặp:
ấ
1. Lặp xác định
2.
2 Lặp không xác định
12. Phân chia bài toán ban đầu thành những
bài toán nhỏ hơn
Nguyên lý 3: Mọi bài toán lớn đều có thể giải quyết bằng
cách phân chia thành những bài toán nhỏ hơn
1. Thủ tục và hàm - phương pháp phân chia chương trình thành
những chương trình con.
2. Biến cục bộ và biến toàn cục
3 Tham số - dữ liệu đầu vào/đầu ra của hàm
3.
13. Biểu diễn tính toán không tường minh bằng đệ quy
Nguyên lý 4: quá trình đệ quy trong máy tính không đơn giản
như các biểu thức quy nạp trong toán học
Sẽ t ì h bà sau này.
trình bày à
14. Phương pháp gián tiếp
gp pg p
Được sử dụng khi chưa tìm ra lời giải chính xác của vấn
đề.
đề
Đây là cách tiếp cận chủ yếu của loài người từ xưa đến
nay.
nay
Lời giải trực tiếp bao giờ cũng tốt hơn, nhưng không
phải lú nào cũng có
hải lúc à ũ ó
15. Phân lọai phương pháp gián tiếp
â ọa p ươ g p áp g á t ếp
1. Phương pháp thử - sai
1 Thử - sai hệ thố
1. i thống
2. Thử - sai phân lớp
3. Thử - sai ngẫu nhiên
i ẫ hiê
2. Phương pháp Heuristic
3. Phương pháp trí tuệ nhân tạo
16. Ph
Phương pháp thử - sai
há i
p y g g
Thomas Edison – phát biểu cách tìm một cây kim trong một đống
rơm: “trong khi chưa nghĩ ra được một cách thật hay thì cứ
việc rút từng cọng rơm cho đến khi rút được cây kim”.
Phương pháp này d t ê 3 nguyên lý
Ph há à dự trên ê lý:
1. Nguyên lý vét cạn (duyệt toàn bộ): liệt kê tất cả các trường hợp
xảy ra và xem xét chúng.
y g
Ví dụ: liệt kê tất cả số nguyên tố từ m đến n.
2. Nguyên lý ngẫu nhiên: dựa trên việc thử một số khả năng được
chọn một cách ngẫu nhiên trong tập khả năng (thường rất lớn
lớn,
nếu áp dụng nguyên lý toàn bộ sẽ tốn nhiều thời gian). Khả
năng tìm lời giải đúng (hoặc gần đúng) sẽ phụ thuộc vào chiến
lược chọn ngẫu nhiên và một số điề kiệ cụ thể
l h ẫ hiê à ột ố điều kiện thể.
Ví dụ: kiểm tra chất lượng trong quá trình sản xuất của một đoàn kiểm tra.
Một lô hàng có 1000 thùng, chọn ngẫu nhiên 10 thùng, mỗi thùng có
24 sản phNm, chọn ngẫu nhiên 5 sản phNm, ...
ả hN h ẫ hiê ả hN
17. g y ý ợ p p gp p
Nguyên lý được phát triên thành phương pháp Monté-Carlos.
Càng ngày nguyên lý ngẫu nhiên càng phát triển mạnh mẽ,
trong số đó có một phương pháp nổi bật là phươn gpháp
G ti .
Genetic
3. Nguyên lý mê cung: nguyên lý này được áp dụng khi chúng ta
không biết chính xác "hình dạng" của lời giải, mà phải xây
hình dạng
dựng lời giải dần qua từng bước, giống như tìm được ra khỏi
mê cung.
18. Thử sai - hệ thống
1. Nguyên lý vét cạn toàn bộ: muốn tìm cây kim trong đống
rơm,
rơm hãy lần lượt rút từng cọng rơm đến khi rút được cây
kim.
Thuật giải: gọi D là không gian bài toán (tập tất cả khả năng
xảy ra), D={(x1, x2, ...,xn)/xi∈Di với Di là tập hữu hạn có mi
phần tử}.
gọi f: D {true, false} là quy tắc xác định lời giải.
Ví dụ: một đàn gà và một bầy chó có tổng cộng N chân, đàn
gà đông hơn bầy chó M con. Hỏi có bao nhiêu gà và chó?
19. 2. Nguyên lý mắt lưới: lưới bắt cá chỉ bắt được những con cá có
kích thước lớn hơn kích thước mắt lưới.
Ví dụ:
Tìm nghiệm phương trình trong một đoạn
g ệ p g g ộ ạ
Khử nhiễu trong ảnh
3. Nguyên lý mê cung: Muốn thóat khỏi mê cung thì phải biết
quay lui và biết đánh dấu những nơi đã đi qua.
Ví dụ:
Tìm đường đi ngắn nhất
20. Thử - sai phân lớ
hử i hâ lớp
1.
1 Nguyên lý chung về giảm độ phức tạp của thử - sai: thu hẹp
tập trường hợp trước và trong khi duyệt, đồng thời đơn giản
hóa tối đa điều kiện chấp nhận một trường hợp.
2. Quy tắc:
1. đơn giản điều kiện: tránh tính lại trong vòng lặp và thừa kế kết quả
tính toán của bước trước: tổ hợp chỉnh hợp, heap sort, ....
ổ
2. Kỹ thuật cầm canh: mã đi tuần,
số âm đầu tiên trong mảng: điều kiện while(x[i]>0&&i<=n) do cách khác
while(x[i] 0&&i n)
a[n+1]=-1; while(x[i]>0) do
3. Nguyên lý thu gọn không gian tìm kiếm: loại bỏ những
trường hợp hoặc hó trường hợp hắ hắ không dẫn đến
t ờ h h ặ nhóm t ờ h chắc chắn khô dẫ đế
lời giải.
21. Quy tắc rút gọn:
1. Dựa trên đánh giá toàn cục: tìm điều kiện để rút gọn tập khả năng đề
cử trong một bước xây dựng một thành phần.ầ
Ví dụ: tìm tổ hợp chặp n của k.
2.
2 Dựa trên đánh giá cục bộ: xây dựng phép kiểm tra đơn giản để nhanh
chóng loại bỏ được các khả năng cho thành phần x[i] mà không phải
xây dựng toàn bộ n-i thành phần còn lại của lời giải.
Ví d cho sáu số tự nhiên A={1,7,2,9,3,5}. Tìm d con của A sao
dụ: h ố hi { } dãy
cho tổng các phần tử trong dãy con bằng 8.
4.
4 Nguyên lý đánh giá nhánh cận: nhánh có chứa quả phải nặng
hơn trọng lượng của quả.
Ví dụ: bài toán người du lịch.
5. Quay lui không dùng đệ quy
6. Phương pháp sinh lời giải
gp p g
22. Phương pháp Heuristic
Trong nhiều bài toán dùng phương pháp thử - sai sẽ dẫn
ề ẫ
đến số lượng thử quá lớn không chấp nhận được.
Heuristic chính là ước lượng về khả năng dẫn đến lời giải
ề ẫ ế
của một trạng thái: phương pháp vét cạn nhưng có thêm tri
thức đi kè tối ưu cục bộ nguyên lý h ớ đí h nguyên
hứ kèm, ối bộ, ê hướng đích, ê
lý sắp thứ tự, ....
ví d
í dụ:
Một em bé bị lạc đường về nhà, em nhớ nhà mình cao nhất
trong khu vực em sẽ tìm đến tòa nhà cao nhất trong vùng em
vực,
thấy, rồi lại tiếp tục , ...
Giải phương trình bậc 2, đoán nghiệm theo Vi-ét
Vi ét
23. Tìm kiế theo chiều sâu và chiều
kiếm h hiề hiề
rộng
Là thử - sai theo nguyên lý mê cung hay chính là thử -
sai kết hợp lần ngược.
Ngược với tìm kiếm theo chiều sâu tìm kiếm theo chiều
sâu,
rộng mang hình ảnh của vết dầu loang.
ậ
Giải thuật A*
24. Phương pháp trí tuệ nhân tạo
gp p ệ ạ
"Dạy" máy tính để có "trí thông minh" như con người
Dạy trí minh
bắt chước khả năng "suy luận" của con người.
ví dụ: bài toán đong nước có 3 bình A B và C có dung
nước, A, B,
tích 5, 8, và 13 lít. Làm sao đong được 11 lít nước trong
bình C? Bình C ban đầu đầy nước
nước.
25. Một số phương pháp chuyển giao
tri thức
1. Biểu diễn tri thức
2 Hệ chuyên gia
2. h ê i
3. Máy học
26. Mảng - Array
Phạm Thế Bảo
Trường Đại học Khoa học Tự nhiên Tp.HCM
Tp HCM
27. Mảng Array
Mả – A
Một số tính chất
Khai bá mảng t
Kh i báo ả trong C
Truy xuất các thành phần
Truyền tham số kiểu mảng cho hàm
Một số th tá cơ sở
ố thao tác ở
Mảng nhiều chiều
28. Mảng Một ố í h hấ
Mả – Mộ số tính chất
Mảng là một kiểu dữ liệu có cấu trúc do người lập
ể ấ
trình định nghĩa
Dùng biểu diễn á
Dù biể diễ các đối t tượng dữ liệ ở d
liệu dạng một ột
dãy các thành phần có cùng kiểu với nhau – kiểu cơ
sở
NNLT C luôn chỉ định một khối nhớ liên tục cho
một biến kiểu mảng
ộ g
Kích thước của mảng được xác định ngay khi khai
báo và không bao giờ thay đổi
g g y
29. Mảng Khai báo
Mả – Kh i bá trong C
typedef kiể ơ ở Tê kiể [Sốthà h hầ ];
t d f kiểucơsở Tênkiểu Sốthànhphần
Tênkiểu[Sốthànhphần]
kiểu của mỗi thành phần hằng ố ố thành hầ
hằ số, số thà h phần
tối đa của mảng
do lập trình viên đặt tên
typedef int AINT[100];
AINT[100];
//AINT
//AINT là kiểu mảng biểu diễn dãy gồm 100 thành phần int
AINT a; //a: biến kiểu AINT
30. Mảng – Ví d
dụ
#define SIZE 10
int a[5]; // a dãy gồm 5 số nguyên
long int big[100]; // big: chiếm 400 bytes!
double d[100];
[ ] // d: chiếm 800 bytes!
y
long double v[SIZE];// v:10 long doubles
long double d[2.5];
long double d[0];
long double d[-4];
long do ble d[n]
double d[n];
31. Mảng – Ví d
dụ khởi trị cho 5
thành phần
int
i a[5]
[5] = { 10 20 30 40 50}
10, 20, 30, 40, 50};
double d[100] = { 1.5, 2.7};
short primes[] = { 1, 2, 3, 5, 7, 11, 13};
long b[50] = { 0 };
2 thành phần
đầu tiên được
compiler xác định
khởi trị, phần
kích thước gồm 7
còn lại: 0
thành phần cách nhanh nhất để
khởi trị tất cả các
int i = 7;
thành phần bằng 0
const int c = 5;
int a[i];
double d[c];
short primes[];
32. Mảng – Truy xuất các phần tử
Các thành phần của mảng được truy xuất thông qua chỉ số
của chúng 0..size-1
ủ hú ..size-
i
Thao tác truy xuất không kiểm tra giới hạn của chỉ số
nhưng giá trị không kiểm soát được
int main()
a
{ 0
int a[6];
int i = 7; 1
a[0] = 59; 2
a[5] = -10; 3
a[i/2] = 2;
4
a[6] = 0;
a[-1] = 5; 5
return 0;
}
33. Truyền th
T ề tham số Mảng cho hà
ố Mả h hàm
Tham số kiể mảng đ
Th ố kiểu ả được t ề cho hà chính là đị chỉ
truyền h hàm hí h địa hỉ
của phần tử đầu tiên trên mảng
Số thành phần trong tham số mảng có thể để trống.
trống.
Số thành phần thực sự được sử dụng phải truyền qua một
tham số khác (vd: size)
(vd:
int add_e e e ts( t a[], int s e)
t add elements(int t size)
{
int add_elements(int *p, int size)
{
34. Ví dụ primes
#include <stdio.h> 1
void sum(long [] i t)
id (l [], int);
2
int main(void) {
long primes[6] = { 1, 2, 3
3, 5, 7, 11 }; 5
sum(primes, 6); 7
printf("%lin", primes[0]);
return 0; 11
} a
void sum(long a[], int sz) { sz 6
int i;
long total = 0; dùng để kiểm tra
for(i = 0; i < sz; i++) giới hạn chỉ số
total += a[i];
a[0] = total; tổng được lưu vào
} phần tử đầu tiên
35. Chú ý
Không
Khô thể th hiệ các th tá chép nội d
thực hiện á thao tác hé ội dung một mảng
ột ả
sang mảng khác.
khác.
Chép từng phần tử mảng
char A[3]={‘a’,’b’,’c’};
A[3]={‘a’,’b’,’c’};
char B[3];
B = A; // ???
for(int
for(int i=0; i<3; i++)
B[i A[i
B[i] = A[i];
hoặc chép khối bộ nhớ (sẽ được đề cập sau)
sau)
Không dùng phép so sánh trực tiếp (==) nội dung trong hai
mảng.
mảng.
Phép so sánh (A==B) so sánh địa chỉ hai vùng nhớ mà A và B
p ( ) ị g
chỉ đến.
đến.
36. Một số thao tá cơ sở
ố th tác ở
Nhập
Xuất
ấ
Thêm một thành phần dữ liệu
Loại bỏ một thành phần dữ liệu
Tìm kiếm
Sắp xếp
37. Mảng – Nhậ dữ liệu
Nhập liệ
void ReadData(int a[], int size)
{
duyệt qua tất cả các
int i; phần tử
for(i = 0; i < s e; i++)
o ( size; )
{
printf(“Nhap thanh phan %d: ”, i);
scanf(“%d”, &a[i]);
}
}
nhập dữ liệu cho a[i]
ập ệ []
38. Mảng – X ất dữ liệ ra màn hình
Xuất liệu à hì h
void WriteData(int a[], int size)
{
int i
i i;
for(i = 0; i < size; i++)
printf(“%d ”, a[i]);
printf(“n”);
}
40. Mảng – Tì vị trí X trong dãy
Tìm ị t í t dã
Bài toán: Tìm vị trí X trên mảng a đang có N thành phần.
toán: phần.
ầ
Giải pháp: Tìm tuần tự
pháp:
//input: dãy (a, N), X
//output: Vị trí của X, -1 nếu không có
int Search(int a[], int N, int X)
{
for (int i = 0; i < N; i ++)
if (a[i] == X)
return i;
return -1;
}
41. Mảng – Thê một thành phần dữ liệu
Thêm ột thà h hầ liệ
Bài toán: cần thêm thành phần dữ liệu X vào mảng a
toán: ầ ầ
đang có N thành phần.
phần.
Hai t ờ h cần xem xét:
H i trường hợp ầ xét:
ét
Dãy chưa có thứ tự
Thêm
Thê X vào cuối a.
à ối
Dãy đã có thứ tự
Tìm vị trí thích hợp, chèn X vào
42. Mảng – Thê X vào cuối dãy
Thêm à ối dã
Thêm 15 vào (a, 7)
0 1 2 3 4 5 6 7
12 2 8 5 1 6 4
N=7
8
a[N] = X;
X 15
N ++;
43. Mảng – Chè X vào dãy tăng dầ
Chèn à dã tă dần
Chèn 6 vào (a, 7)
pos
0 1 2 3 4 5 6 7
1 2 4 5 8 12 15
N=7
8
X 6
Vị trí thích hợp: 4
44. Mảng – Chè X vào dãy tăng dầ
Chèn à dã tă dần
//input: dãy (a, N) tăng dần, X
//output: dãy (a, N) đã có X ở đúng vị trí
void Insert(int a[], int &N, int X)
{
int pos;
for (pos = N; (pos>0)&&(a[pos-1]>X); pos --)
(pos>0)&&(a[pos- --)
a[pos] = a[pos – 1];
a[pos] = X;
N ++;
}
45. Mảng – L i bỏ một thành phần dữ liệ
Loại ột thà h hầ liệu
Bài toán: loại bỏ thành phần dữ liệu X ra khỏi
toán:
mảng a đang có N thành phần.
phần.
Hướng giải quyết: xác định vị trí của X, nếu tìm
quyết:
thấy thì dồn các phần tử ở phía sau lên để lấp vào
chỗ trống. 2 trường h :
hỗ trống.
ố ờ hợphợp:
Dãy không có thứ tự: lấp phần tử cuối lên
tự:
Dãy đã thứ tự: dời tất cả các phần tử ở sau ví
tự: ấ ầ
trí của X lên trước 1 vị trí.
trí.
46. Mảng – L i bỏ X ra khỏi dãy tăng
Loại dã tă
Loại 5 khỏi (a, 8)
(a
pos
0 1 2 3 4 5 6 7
1 2 4 5 7 8 8 9
N=8
7 STOP
X 5 Ok, found
Tìm vị trí của 5 Dồn các vị trí 4, 5, 6, 7 lên
47. Mảng – L i bỏ X ra khỏi dãy tăng
Loại dã tă
//input: dãy (a, N), X
//output: dãy (a, N) đã loại bỏ 1 thành phần X
int Remove(int a[], int &N, int X)
{
int pos = Search(a, N, X);
if (pos == -1) //không có X trong dãy
return 0;
N --;
--;
for (; (pos < N); pos ++)
a[pos] = a[pos + 1];
return 1;
}
48. Mảng – Sắ xếp
Sắp ế
Bài toán: Sắp xếp các thành phần của (a, N) để thu
toán: ắ ế ầ ể
được dãy tăng dần
Giải pháp: Tì cách t iệt tiê tất cả các nghịch thế
pháp: Tìm á h triệt tiêu
há ả á hị h
của dãy
Thuật toán sắp xếp Đổi chổ trực tiếp
54. Mảng – Sắp xếp đổi chổ
void Swap(int &x int &y)
&x,
{
int t = x; x = y; y = t;
}
void I t
id InterchangeSort(int a[], int N)
h S t(i t [] i t
{
int i, j;
for (i = 0 ; i<N-1 ; i++)
for (j =i+1; j < N ; j++)
if(a[j]< a[i])
Swap(a[i],a[j]);
}
55. Mả nhiều chiều
Mảng hiề hiề
C khô hỗ t mảng nhiều chiều. T nhiên có thể tiế
không trợ ả hiề chiều. Tuy hiê ó
hiề tiếp
cận theo hướng: Mảng 2 chiều là mảng một chiều mà mỗi
hướng:
thành phần của nó là một mảng một chiều.
chiều.
“rainfall” là mảng gồm 12
float rainfall[12][365]; thành phần, mỗi thành phần là
mảng gồm 365 số float
ồ ố
“exam_marks” là mảng gồm
short exam_marks[500][10];
exam marks[500][10]; 500 thà h phần, mỗi thành
thành hầ ỗi thà h
phần là mảng 10 số short
const int brighton = 7
t i t b i ht 7;
int day_of_year = 238;
rainfall[brighton][day_of_year] = 0.0F;
56. Mả nhiều chiều
Mảng hiề hiề
Khai báo mảng 2 chiều:
chiều:
type name[row_size][column_size];
name[row_size][column_size];
SumSquares 0 1 4
1 2 5
0 1 4 1 2 5
int SumSquares[2][3] = { {0,1,4}, {1,2,5} };
SumSquares[ ][3
int SumSquares[2][3] = { 0,1,4,1,2,5 };
SumSquares[ ][3
int SumSquares[2][3] = { {0,1,4} };
SumSquares[ ][3
int SumSquares[ ][3] = { {0,1,4}, {1,2,5} };
SumSquares[ ][3
int SumSquares[ ][3] = { {0,1, }, {1} };
SumSquares[ ][3
int SumSquares[ ][3];
SumSquares[ ][3
57. Nhập Mả
Nhậ Mảng 2 chiều
hiề
1.
1 #define MAX_STUDENT 5
MAX STUDENT
2. #define MAX_SUBJECT 6
3. int StudentScore[MAX_STUDENT][MAX_SUBJECT];
StudentScore[MAX_STUDENT][MAX_SUBJECT];
4. void read_Score(i S
id read_Score(int Score[MAX_STUDENT][MAX_SUBJECT],
d S [MAX STUDENT][MAX SUBJECT]
int nStudents, int nSubjects)
nStudents, nSubjects)
5. {
6. int i,j;
i,j;
7. for(i
for(i=0; i<nStudents; i++)
nStudents;
8. for(j=0; j<nSubjects; j++)
j<nSubjects;
9. scanf(“%d”, &Score[i
scanf(“%d”, &Score[i][j]);
10.
10 }
58. Hà truy cập, i Mảng 2 chiều
Hàm t ậ in Mả hiề
1.
1 void print_Score(int Score[MAX STUDENT][MAX SUBJECT]
print_Score
print Score( Score[MAX_STUDENT][MAX_SUBJECT],
Score(
int nStudents, int nSubjects)
nStudents, nSubjects)
2. {
3. int i,j;
i,j;
4. for(i
for(i=0; i<nStudents; i++)
nStudents;
5. {
6. for(j=0; j<nSubjects; j++)
j<nSubjects;
7.
7 printf( %2d
printf(“%2dt &Score[i
printf(“%2dt”, &Score[i][j]);
( %2d
8. printf(“
printf(“n”);
9. }
10. }
61. Con trỏ - Pointer
trỏ
Phạm Thế Bảo
Trường Đại học Khoa học Tự nhiên Tp.HCM
Tp HCM
62. Con trỏ Pointer
C t ỏ–P i t
Khai báo
Các toán
Cá t á tử “&” “*” “ ” “+”
”, ”, “=”,
Nhắc lại về truyền tham số địa chỉ
Con trỏ và mảng
Cấp hát ù
Cấ phát vùng nhớ độ
hớ động
63. Con trỏ Một ố d ê ử d
C t ỏ – Mộ số lý do nên sử dụng
Con trỏ là kiểu dữ liệu lưu trữ địa chỉ của các vùng
dữ liệu trong bộ nhớ máy tính
Kiểu con trỏ cho phép:
ể phép:
Truyền tham số kiểu địa chỉ
Biểu diễn các kiểu, cấu trúc dữ liệu động
ể ễ ể ấ
Lưu trữ dữ liệu trong vùng nhớ heap
Con trỏ đã được sử dụng trong hàm scanf
64. Con trỏ Khai báo
C t ỏ – Kh i bá trong C
Kiểu
Kiể con trỏ phải đ
t ỏ hải được đị h nghĩa t ê một kiể cơ sở đã
định hĩ trên ột kiểu ở
được định nghĩa trước đó.
đó.
typedef kiểucơsở *Tênkiểu;
Tênkiểu;
typedef int *PINT;
//PINT
//PINT là kiểu con trỏ - địa chỉ vùng nhớ kiểu int
int x;
PINT p; //
//p, p1: biế kiểu int *
1 biến kiể i t
int *p1;
65. Con trỏ Khai bá t
C t ỏ – Kh i báo trong C
int *pi;
long int *p;
float* pf;
char c, d, *pc; /* c và d kiểu char
pc là con trỏ đến char */
double* pd, e, f; /* pd là con trỏ đến double
e and f are double */
char *start, *end;
66. Con trỏ Toán ử “&
C t ỏ - T á tử “&”
“&”: toán tử lấy địa chỉ của 1 biến
Địa chỉ của tất cả các biến trong chương trình đều đã
được chỉ định từ khi khai báo
char g = 'z';
p c
int main()
{ 0x1132 'a'
char c = 'a'; 0x1132
char *p; g
p
p = &c;
p = &g; 0x91A2 'z'
0x91A2
return 0;
}
67. Con trỏ Toán ử
C t ỏ - T á tử “*”
“*”: toán tử truy xuất giá trị của vùng nhớ được quản lý
bởi con trỏ.
trỏ.
#include <stdio.h> p c
char g = 'z';
0x1132 'a'
int main()
() a 0x1132
{ z
char c = 'a'; p g
char *p;
p;
0x91A2
0 91A2 'z'
' '
p = &c; 0x91A2
printf("%cn", *p);
p = &g; xuất giá trị do p đang
printf("%cn", *p); quản lý
return 0;
}
68. Con trỏ Truyền h
C t ỏ - T ề tham số đị chỉ
ố địa hỉ
#include <stdio.h>
void change(int *v);
int main()
{
int var = 5;
change(&var);
printf("main: var = %in", var);
return 0;
}
void change(int *v)
{
(*v) *= 100;
printf("change: *v = %in", (*v));
}
69. Con t ỏ NULL
C trỏ
Giá trị đặ biệt để chỉ rằng con t ỏ khô quản lý vùng
t ị đặc hỉ ằ trỏ không ả ù
nào.
nào. Giá trị này thường được dùng để chỉ một con trỏ
không hợp lệ.lệ.
#include <stdio.h>
int main()
{
int i = 13;
short *p = NULL;
if (p == NULL)
printf(“Con trỏ không hợp lệ!n");
else
printf(“Giá trị : %hin", *p);
return 0;
;
}
70. Con trỏ T á ử á “ ”
C t ỏ - Toán tử gán “=”
Có sự khá biệt rất quan t
khác ất trọng khi th hiệ các phép gán:
thực hiện á hé gán:
á
p i
int i = 10, j = 14;
int* p = &i; 0x15A0
0 15A0 10 14
0x15A0
int *q = &j;
q j
*p = *q; 0x15A4 14
0x15A4
và:
int i = 10, j = 14; p 0x15A4 i
int *p = &i;
p ; 0x15A0 10
int *q = &j; 0x15A0
q j
p = q; 0x15A4 14
0x15A4
71. Luyện tậ
L ệ tập – Điề vào ô trống
Điền à ố
int main(void) i
{
0x2100
int i = 10, j = 14 k;
10 14,
int *p = &i; j
int *q = &j; 0x2104
k
*p += 1;
0x1208
p = &k;
*p = *q; p
p = q; 0x120B
*p = *q;
q
return 0; 0x1210
}
72. C t ỏ và Mả
Con trỏ à Mảng
Biến kiểu ả
Biế kiể mảng là đị chỉ tĩnh của một vùng nhớ, đ
địa hỉ tĩ h ủ ột ù hớ được xácá
định khi khai báo, không thay đổi trong suốt chu kỳ sống.
sống.
Biến con trỏ là địa chỉ động của một vùng nhớ được xác
nhớ,
định qua phép gán địa chỉ khi chương trình thực thi.
thi.
#include <stdio h>
<stdio.h>
int main()
{
int a[10] = {1 3 4 2 0};
{1, 3, 4, 2,
int *p;
p = a; //a = p: sai
printf(“0x%04X %i 0 %04X %i “
i tf(“0 %04X 0x%04X %in“,
a, a[0], p, *p);
return 0;
}
73. Con trỏ Toán ử “+” ới ố
C t ỏ - T á tử “ ” với số nguyên
ê
0x15A0
#include <stdio.h> a
int main() 1
{ 4
3
short a[10] = {1, 3, 5, 2, 0};
short *p = a; 5
printf( 0x%04X
printf(“0x%04X %i 0x%04X %in“,
%in 2
a, a[0], p, *p); 0
p ++;
…
printf(“0x%04X %i 0 %04X %i “
i tf(“0 %04X 0x%04X %in“,
a, a[0], p, *p);
(*p) ++; 0x16B2
printf(“0x%04X %i 0x%04X %in“, p
a, a[0], p, *p); 0x15A0
0x15A2
return 0;
}
74. Con trỏ Luyện ậ
C t ỏ - L ệ tập
#include <stdio.h>
int main() 2 2
{ 3 1
int a[10] = {2, 3, 5, 1, 4, 7, 0}; 1 9
int *p = a; 1 3
printf( %i %in
printf(“%i %in“, a[0] *p);
a[0],
p ++;
printf(“%i %in“, *p, p[2]);
p ++
++; a[2] = 9
[2] 9;
printf(“%i %in“, p[1], *p);
p -= 2;
printf(“%i %in”, p[3], p[1]);
return 0;
}
75. Con trỏ Cấp há ù hớ độ
C t ỏ - Cấ phát vùng nhớ động
Có thể chỉ đị h vùng mới cho 1 con t ỏ quản lý bằ các
hỉ định ù ới h trỏ ả bằng á
lệnh hàm malloc, calloc hoặc toán tử new của C++
malloc,
Vùng nhớ do lập trình viên chỉ định phải được giải phóng
bằng lệnh free (malloc, calloc) hoặc toán tử delete (new)
#include <stdio.h>
int main()
{
int *p = new int[10];
p[0] = 1;
p[3] = -7;
7;
delete []p;
return 0;
}
76. Cấp hát động malloc() à calloc()
Cấ phát độ : malloc() và calloc()
động: ll ll
Hàm ll
Hà malloc và calloc cho phép cấp phát các vùng nhớ
à ll h hé ấ hát á ù hớ
ngay trong lúc chạy chương trình.
trình.
void *malloc( size_t size);
*malloc(
void *calloc( size_t nItems, size_t size);
*calloc( nItems,
Hàm calloc cấp phát vùng nhớ và kh i tạo tất cả các bi
ll ấ h h khởi ấ bit
trong vùng nhớ mới cấp phát về 0.
Hàm malloc chỉ cấp phát vùng nhớ.
nhớ.
77. Ví d 1 dùng malloc()
dụ 1: dù ll ()
1.
1 #include <stdio.h>
<stdio.
2. #include <string.h>
<string.
3. #include <alloc.h>
<alloc.
4. #include <process.h>
<process.
5. int main(void)
6. { char *str;
*str;
7.
7 /* allocate memory for string */
8. if ((str = (char *) malloc(10)) == NULL)
malloc(10))
9. {
10. printf("Not enough memory to allocate buffern");
buffern");
11. exit(1
exit(1); /* terminate program if out of memory */
12. }
81. Giải phóng vùng nhớ
hó ù hớ
Khi th át khỏi hà , các biế khai bá t
thoát hàm,
hàm á biến kh i báo trong hà sẽ “biế
hàm ẽ biến
mất”.
mất”. Tuy nhiên các vùng nhớ được cấp phát động vẫn còn
tồn tại và được “đánh dấu” là đang “được dùng” bộ nhớ
dấu” dùng”
của máy tính sẽ hết.
hết.
ví dụ:
dụ:
ụ
void aFunction(void)
aFunction(void)
{
int tmpArray,
i *tmpArray, i = 5;
tmpArray = (int *)malloc(i * sizeof(int));
(int *)malloc( sizeof(int));
)malloc
} tmpArray i
82. Giải phóng vùng nhớ: f
hó ù nhớ: free
hớ
Sử d
dụng các cặp hà
á ặ hàm
(malloc, free)
malloc,
(calloc, free)
calloc,
C dùng hàm free để giải phóng vùng nhớ cấp phát động.
động.
void free(void *block);
83. Cấ phát l i vùng nhớ: realloc
Cấp hát lại ù hớ ll
Đôi khi chúng t muốn mở rộng h ặ giảm bớt kích th ớ
hú ta ố ở ộ hoặc iả kí h thước
mảng.
mảng.
C dùng hàm realloc để cấp phát lại vùng nhớ, thực hiện
nhớ,
chép nội dung của vùng nhớ cũ sang vùng nhớ mới.
mới.
void *realloc(void *block, size_t size);
*realloc(void
( , );
ví dụ:
dụ:
int *tmpArray, N=5,i;
tmpArray,
tmpArray = (int *)malloc(N * sizeof(int));
(int *)malloc(N sizeof(int));
for(i
for( 0; <N;
f (i = 0 i<N i++)
(i
tmpArray]
tmpArray]i] = i;
tmpArray = (int *)realloc(tmpArray, 7);
(int *)realloc(tmpArray,
)realloc
84. Ví d realloc()
dụ: ll ()
1.
1 #include <stdio.h>
#i l d <stdio.h>
tdi hh>
2. #include <alloc.h>
<alloc.h>
3. #include <string.h>
#i l d <string.h>
ti h h>
4. int i ( id)
i main(void)
5. {
6. char *str;
h *str;
7. /* allocate memory for string */
8. str = (char *) malloc(10);
malloc(10);
85. Ví d realloc() - tt
dụ: ll ()
9.
9 /* copy "H ll " i t string */
"Hello" into t i
10. strcpy(str, "Hello");
"Hello");
11. printf("String is %sn Address is %pn", str, str);
str);
12. str = ( h *) realloc(str, 20);
(char ll ( 20)
13. printf("String is %sn New address is %pn", str, str);
str);
14. /* free memory */
15. free(str);
free(str);
16. return 0;
17. }
86. Di chuyển con trỏ t
h ể t ỏ trong mảng
ả
int IntArr
i t I tA [5] = {3,4,2,1,0};
IntArr[5] {3 4 2 1 0}
char CharArr[5] = {‘a’,’b’,’c’,’d’,’e’};
CharArr[5] {‘a’,’b’,’c’,’d’,’e’};
int IntPtr IntArr
i t *I tPt = I tA ;
IntArr;
char *charPtr = CharArr;
*charPtr CharArr;
Di chuyển trong mảng 1 chiều:
chiều:
int val_at_0 = * IntPtr;
IntPtr; // = IntArr[0]
IntArr[0]
int l t 3
i t val_at_3 = * (IntPtr+3); // = I tA [3]
(I tPt +3) IntArr[3]
IntArr
IntPtr IntPtr+1 IntPtr+2
87. Phép toán với con trỏ trong
p g
mảng
#define
#d fi ROWS 5
#define COLS 3
int IntArr
i t I tA [ROWS][COLS] = {{3 4 2 1 0}
IntArr[ROWS][COLS] {{3,4,2,1,0},
{5,6,7,8,9},
{10,11,12,13,14}};
{10 11 12 13 14}};
int *IntPtr = IntArr;
IntArr;
Tham chiếu đến phần tử trong mảng 2 chiều:
chiều:
int val_at_00 = * IntPtr;// = IntArr[0][0]
IntPtr;// IntArr[0][0]
int val_at_30 = * (IntPtr+3);// = IntArr[3][0]
IntArr[3][0]
int val_at_32 = * (intPtr+3*5+2);// = IntArr[3][2]
IntArr[3][2]
int val_at_32 = * ( * (IntPtr+3)
88. Phép toán với con trỏ trong
p g
mảng
IntPtr IntPtr+3
3 1
13
IntPtr + 2*5 + 3
89. Ký tự và
Chuỗ
Chu ký
Ch ỗi k tự - S i
String
Phạm Thế Bảo
Trường Đại học Khoa học Tự nhiên Tp.HCM
Tp HCM
90. Ký tự (character)
Kiểu char:
ký tự “in được” gồm: 26 chữ thường (a ) 26 chữ hoa
được” gồm: (a..z),
(A..Z), 10 chữ số (0..9), khoảng trắng, các ký tự:
trắng, tự:
!“#$%&‘()*+,-./:;<=>?@[]^_{|}~
Các ký tự “không in được”: tab, lert (bell), newline,
được”:
formfeed,...
formfeed,...
các ký tự “in được” đặc biệt: ‘’, ‘’’, ‘”’
được” biệt: ‘ ‘ ‘
các ký tự “không in được” đặc biệt:
được” biệt:
n new line
a bell
0 null character
b b k
backspace
t horizontal tab
...
91. Nhập ất
Nhậ xuất Ký tự
t
scanf
char ch;
ch;
scanf(“%c”, &ch);
scanf(“%c”, &ch);
sử dụng các đoạn macro có trong thư viện <stdio.h>
stdio.h>
putchar:
putchar: đưa ký tự ra thiết bị xuất chuNn (stdout)
stdout)
putchar(‘
putchar(‘n’);
getchar:
getchar: lấy ký tự từ thiết bị nhập chuNn (stdin)
stdin)
ch = getchar();
getchar();
g
getch: y ự
getch: lấy trực tiếp ký tự từ bàn phím không hiển thị ra màn hình
p ý ự p g ị
ch = getch();
getch();
getche():
getche(): lấy trực tiếp ký tự từ bàn phím và hiển thị ký tự ra màn hình.
hình.
ch = getche();
getche();
92. getchar
t h
1.
1 #include <stdio h>
<stdio.h
<stdio h>
stdio.h>
2. int main(void)
( )
3. {
4. int c;
5. /* Note that getchar reads from stdin and is line buffered; this means it
will not return until you press ENTER. */
ENTER /
6. while ((c = getchar()) != ''n')
getchar())
7. printf("%c",
printf("%c", c);
8. return 0;
t 0
9. }
93. putchar
1. /* putchar example */
2.
2 #include <stdio h>
<stdio.h
<stdio h>
stdio.h>
3. /* define some box-drawing characters */
box-
4.
4 #define LEFT TOP 0xDA
LEFT_TOP
5. #define RIGHT_TOP 0xBF
6. #define HORIZ 0xC4
7. #define VERT 0xB3
#d fi 0 B3
8. #define LEFT_BOT 0xC0
9. #define RIGHT_BOT 0xD9
10. int main(void)
11. {
12. char i, j;
13. /* draw the top of the box */
14. putchar(LEFT_TOP);
putchar(LEFT_TOP);
15. for (i=0; i<10; i++)
(i
16. putchar(HORIZ);
putchar(HORIZ);
95. Một số hàm khá
ố hà khác
kbhit: kiểm tra ó hí bấm
kbhit: kiể t có phím bấ
1.
1 /* khbit example */
2. #include <conio.h>
<conio.h>
3. int main(void)
4.
4 {
5. cprintf("Press
cprintf("Press any key to continue:");
6. while (!kbhit()) /* do nothing */ ;
hil (!kbhit()) d thi
7. cprintf("
cprintf("rnA key was pressed...rn");
pressed...
8. return 0;
t 0
9. }
96. Chuỗi
Ch ỗi ký t – St i
tự Strings
Một số qui tắc
Nhập
Nhậ / xuất
ất
Con trỏ và chuỗi ký tự
Một số hàm thư viện
97. Chuỗi
Ch ỗi ký t - Mộ số qui tắc
tự Một ố i ắ
Chuỗi ký t là mảng một chiều có mỗi thà h phần là một
Ch ỗi tự ả ột hiề ó ỗi thành hầ ột
số nguyên được kết thúc bởi số 0.
Ký tự kết thúc (0) ở cuối chuỗi ký tự thường được gọi là
ký tự null (không giống con trỏ NULL). Có thể ghi là 0
NULL).
hoặc ‘0’ (không phải chữ o).
ặ ( gp o).
)
Được khai báo và truyền tham số như mảng một chiều.
chiều.
char s[100];
unsigned char s1[1000];
98. Chuỗi
Ch ỗi ký t - Ví d
tự dụ
char first name[5] = { 'J' 'o' 'h' 'n' '0' };
first_name[5] 'J', 'o', 'h', 'n',
char last_name[6] = "Minor";
char other[] = "Tony Blurt";
char characters[8] = "No null";
first_name
first name 'J'
J 'o'
o 'h'
h 'n'
n 0
last_name 'M' 'i' 'n' 'o' 'r' 0
other 'T' 'o' ‘n’ 'y' 32 'B' 'l' 'u' 'r' 't' 0
characters 'N' 'o'
N o 32 'n'
n 'u'
u 'l'
l 'l'
l 0
99. Chuỗi
Ch ỗi ký t - Nhậ / xuất
tự Nhập ấ
Có thể nhập / xuất chuỗi ký tự s bằng cách nhập từng ký
ập ý ự g ập g ý
tự của s
Hoặc sử dụng các hàm scanf và printf với ký tự định
dạng “%s”
char other[] = "Tony Blurt";
printf("%sn", other);
Nhập chuỗi có khoảng trắng dùng hàm gets
char name[100];
printf("Nhap mot chuoi ky tu %s: ");
gets(name);
100. Lưu ý
L ý: kết thú chuỗi
thúc h ỗi
#include <stdio.h>
int main()
{ "Blurt" sẽ không
Blurt
char other[] = "Tony Blurt"; được in ra
printf( %sn
printf("%sn", other);
other[4] = '0';
printf("%sn", other); Tony Blurt
Tony
return 0;
}
other 'T' 'o' ‘n’ 'y' 32 'B' 'l' 'u' 'r' 't' 0
101. Lỗi khi tạo một chuỗi
t ột h ỗi
Chú ý: không có phép gán trong kiểu dữ liệu chuỗi
như thế này là sai
h à i
char ten[10];
ten = “hoahong”;
“hoahong”;
102. Chú ý
Không
Khô :
sử dụng toán tử gán = để chép nội dung của một chuỗi
sang chuỗi khác.
khác.
char a[4]=“hi”;
char b[4];
b = a; //???
Không:
Không:
h
dùng toán tử == để so sánh nội dung hai chuỗi
char a[] = “hi”;
hi ;
char b[] = “there”;
if(a==b) //???
( )
{}
103. Con t ỏ à h ỗi
C trỏ và chuỗi ký t
tự
char * ; // kh i bá chuỗi ký t như một con t ỏ
h *p khai báo h ỗi tự h
*p; ột trỏ
p = new char[30]; //xin cấp phát số lượng ký tự,
char[30] //xin tự,
// giống mảng các ký tự
iố ả á
104. Mảng các chuỗi: char * [ ]
Mả á h ỗi h
char *
h *words[ ] = {“h
*words[
d {“hong” “cuc” “l ” “nhai”,”mo”};
{“h
hong”, cuc”, lan”, nhai”,”mo”}
”, ”, lan”, h i” ” ”};
Words
Words[0] Words[1] Words[2] Words[3] Words[4]
h o n g 0 c u c 0 l a n 0 n h a i 0 m o 0
Hay char **words;
105. Chuỗi
Ch ỗi ký t – Mộ số hà thư viện
tự Một ố hàm h iệ
Lấy độ dài chuỗi
l = strlen(s);
strlen(s);
( )
);
Đổi toàn bộ các ký tự của chuỗi thành IN HOA
strupr(s);
strupr(s);
Đổi toàn bộ các ký tự của chuỗi thành in thường
strlwr(s);
strlwr(s);
t l ( )
106. Chuỗi
Ch ỗi ký t – Mộ số hà thư viện
tự Một ố hàm h iệ
So sánh chuỗi: so sánh theo thứ tự từ điển
chuỗi:
Phân biệt IN HOA – in thường:
thường:
int strcmp(const char *s1, const char *s2);
strcmp(const *s1
s *s2
s
Không phân biệt IN HOA – in thường:
thường:
int stricmp(const char *s1, const char *s2);
stricmp(const *s1 *s2
107. Chuỗi
Ch ỗi ký t – ví dụ strcmp
tự í d
#
#include <stdio.h>
#include <string.h>
Minor < Tony
int main()
{
char s1[] = "Minor";
char s2[] = "Tony";
int cmp = strcmp(s1, s2);
if (cmp < 0)
printf("%s < % " s1, s2);
i f("% %s", 1 2)
else
if (cmp == 0)
printf("%s = %s", s1, s2);
else
p
printf("%s > %s", s1, s2);
( , , )
return 0;
}
108. Chuỗi
Ch ỗi ký t – Mộ số hà thư viện
tự Một ố hàm h iệ
Gán nội dung chuỗi:
chuỗi:
o Chép toàn bộ chuỗi source sang chuỗi dest:
p ộ g dest:
int strcpy(char *dest, const char *src);
strcpy(char *src);
o Chép tối đa n ký tự từ source sang dest:
dest:
int strncpy(char *dest,
strncpy(char
py(
py( ,
const char *src, int n); n);
Tạo chuỗi mới từ chuỗi đã có:
có:
char *strdup(const char *src);
strdup(const *src);
src);
src)
109. Chuỗi
Ch ỗi ký t – ví dụ strcpy
tự í d
#
#include <stdio.h>
#include <string.h>
int main() Tony Blurt
y
{ To123Blurt
char s[] = "Tony Blurt"; Blurt
char s2[100] *s3;
s2[100],
strcpy(s2, s);
printf("%sn", s2);
i f("% " 2)
strncpy(s2 + 2, "12345", 3);
printf("%sn", s2);
s3 = strdup(s + 5);
printf("%sn", s3);
( )
free(s3);
return 0;
}
110. Chuỗi
Ch ỗi ký t – Mộ số hà thư viện
tự Một ố hàm h iệ
Nối chuỗi:
chuỗi:
char *strcat(char *dest,
strcat(char
const char *src);
*src);
Tách chuỗi:
chuỗi:
char *strtok(char *s,
strtok(char
( ,
const char *sep);
*sep);
Trả về địa chỉ của đoạn đầu tiên. Muốn tách đoạn kế tiếp
tiên.
tham số thứ nhất sẽ là NULL
111. Chuỗi
Ch ỗi ký t – ví dụ strtok
tự í d k
#
#include <stdio.h>
#include <string.h> Thu
strtok:
#define SEPARATOR "., "
9
int main() 123
{ 45
char s[]= "Thu strtok: 9,123.45";
char *p;
p = strtok(s, SEPARATOR);
while (p != NULL) {
printf("%sn", p);
p = strtok(NULL, SEPARATOR);
}
return 0;
}
112. Chuỗi
Ch ỗi ký t – Mộ số hà thư viện
tự Một ố hàm h iệ
Tìm một ký tự trên chuỗi:
chuỗi:
char *strchr(const char *s, int c);
strchr(const c);
Tìm một đoạn ký tự trên chuỗi:
chuỗi:
char *strstr(const char *s1,
strstr(const
( *s1
const char *s2);
*s2
113. Chuỗi
Ch ỗi ký t – ví dụ tìm kiếm
tự í d ì kiế
#include <stdio.h>
#include <string.h>
int main()
{
char s[]= "Thu tim kiem chuoi";
[] ;
char *p;
p = strchr(s 'm');
strchr(s, m );
printf("%sn", p); m kiem chuoi
p = strstr(s, "em");
em chuoi
printf("%sn",
printf("%sn" p);
return 0;
}
114. Chuỗi
Ch ỗi ký t – chèn một đ ký tự
tự hè ộ đoạn
#
#include <stdio.h>
#include <string.h>
void StrIns(char *s char *sub)
s, sub)
{
int len = strlen(sub);
memmove(s + len s strlen(s)+1);
len, s,
strncpy(s, sub, len); 123 Thu chen
}
123 Thu 45chen
int main()
i i ()
{
char s[]= “ Thu chen";
StrIns(s, "123"); printf("%sn", s);
StrIns(s + 8, "45");
( , ) p
printf("%sn", p)
( , p);
return 0;
}
115. Chuỗi
Ch ỗi ký t – xóa một đ ký tự
tự ó ộ đoạn
#
#include <stdio.h>
#include <string.h>
void StrDel(char *s int n)
s,
{
memmove(s, s + n, strlen(s+n)+1);
} xoa 12345
int main() xoa 45
{
char s[]= " h xoa 12345"
h [] "Thu 12345";
StrDel(s, 4); printf("%sn", s);
StrDel(s + 4, 3); printf("%sn", s);
return 0;
}
116. Biế đổi chuỗi sang số
Biến h ỗi ố
atoi(), atof(), atol():
atoi(), atof(), atol():
đổi chuỗi ký tự sang số.số.
int atoi(const char *s);
i t atoi(
t i(const h * )
i( t
double atof(const char *s);
atof(const
long atol(const char *s);
atol(const s);
...
float f;
char *str = "12345.67";
*str
f = atof(str);
atof(str);
printf(
printf("string
printf( string = %s float = %fn", str, f);
("string %fn str,
...
117. Cấu trúc - Struct
Phạm Thế Bảo
Trường Đại học Khoa học Tự nhiên Tp.HCM
Tp HCM
118. Kiểu ấ t ú
Kiể cấu trúc
Khái niệm
Khai báo
Truy xuất các thành phần
Cấu trúc & mảng
Con trỏ đến cấu trúc
119. Khái niệm
iệ
Cấu trúc là kiểu dữ liệu gồm một nhóm các
thành phần có kiểu không giống nhau, mỗi
nhau,
thành phần đ
hà h hầ được xác đị h bằ một tên riêng
á định bằng ộ ê iê
biệt (kiểu dữ liệu trừu tượng – Abstract Data
Type – ADT).
ADT).
Kiểu của mỗi thành phần trong cấu trúc là một
kiếu đã được định nghĩa trước, kể cả mảng và
trước,
các cấu trúc khác.
khác.
120. Cấu t ú Khai báo
Cấ trúc – Kh i bá trong C
Một kiểu cấu trúc được định nghĩa với từ khóa struct.
struct.
typedef struct Tênkiểu
{
Kiểuthànhphần
p Tênthànhphần;
Tênthànhphần;
p
Kiểuthànhphần Tênthànhphần;
Tênthànhphần;
Kiểuthànhphần Tênthànhphần;
Tênthànhphần;
Kiểuthànhphần Tênthànhphần;
Tênthànhphần;
...
};
122. Cấu t ú Truy ấ á hà h hầ
Cấ trúc – T xuất các thành phần
Các thà h hầ ủ
Cá thành phần của một biế kiể cấu t ú đ
ột biến kiểu ấ trúc được t
truy xuất
ất
thông qua tên biến, dấu "." và tên thành phần.
phần.
void Print(TStudent m)
{
printf( Name
printf("Name : %s %sn",
%sn
m.firstname, m.lastname);
printf("Student ID : %sn", m.ID);
printf("Date of birth : %hi/%hi/%i"
%hi/%hi/%i",
m.dob.day, m.dob.month, m.dob.year);
printf("Marks : ");
for (i t i 0 i 10 i )
f (int i=0; i<10; i++)
printf("%.2f ", m.marks[i]);
}
123. Cấu t ú Truy ấ á hà h hầ
Cấ trúc – T xuất các thành phần
void ReadInfo(TStudent &m)
{
printf("Type student ID: ");
scanf("%s", m.ID);
printf("Type first name: ");
g
gets(m.firstname);
( );
printf("Type last name: ");
gets(m.lastname);
printf( Date
printf("Date of birth (d m y): ");
);
scanf("%hi %hi %i", &(m.dob.day),
&(m.dob.month), &(m.dob.year));
printf("Marks (10 floats): ");
for (int i=0; i<10; i++)
scanf("%f", &(m.marks[i]));
}
124. Kí h thước của một cấu t ú
Kích th ớ ủ ột ấ trúc
Kích thước kiểu
Kí h th ớ kiể dữ liệ cấu t ú :
liệu ấ trúc
trúc:
sizeof( typename )
sizeof(<<typename>>)
sizeof(<<typename>>)
(
vd:
vd:
SinhVien_t_size = sizeof(SinhVien); // 48
sizeof(SinhVien);
125. Mảng á Cấ t ú
Mả các Cấu trúc
Khai bao biến ả
Kh i b biế mảng các Cấ t ú cũng giống như kh i bá
á Cấu trúc ũ iố h khai báo
biến mảng trên các kiểu dữ liệu cơ bản khác.
khác.
Dùng tên mảng khi truy cập từng phần tử trong mảng các
cấu trúc và toán tử thành viên để truy cập các trường dữ
liệu của từng thành phần cấu trúc.
trúc.
struct SinhVien{
{ SinhVien mang[100];
char hoten[31]; …
int namsinh;
char noisinh[4];
char maso[11]; mang[i].namsinh
}
126. Con trỏ đế Cấu trúc
C t ỏ đến Cấ t ú
Khai báo
Kh i bá con t ỏ đế cấu t ú t
trỏ đến ấ trúc tương t như các kiể dữ
tự h á kiểu
liệu khác.
khác.
SinhVien *SV_ptr
Toán tử truy cập trường thành phần của cấu trúc do con trỏ
chỉ đến: ->
đến:
SV_ptr-
SV_ptr->namsinh
SV_ptr-
SV_ptr
SV t ->noisinh
ii h
127. Union
U i
Khai báo i được dù để kh i bá các biế dù
Kh i bá union đ dùng khai báo á biến dùng
chung bộ nhớ.
nhớ.
union int_or_long {
int i;
long l;
} a_number;
a_number;
Các thành phần của union có thể không có kích thước bằng
nhau.
nhau.
Kích thước bộ nhớ trong khai báo union là kích thước của
kiểu dữ liệu lớn nhất có trong khai báo union.
128. Ví d
dụ
1.
1 union int_or_long {
int or long
2. int i;
3. long l;
4. } a_number;
a_number;
5. a_number.
a_number.i = 5;
6.
6 a_number
a number.l = 100L;
a_number. 100L
7. // anonymous union
8. union {
9. int i;
10. float f;
11. };
12. i = 10;
10;
13. f = 2.2;
129. Kiểu Enum (liệt kê)
Kiể E kê)
Kiểu Enum:
Enum:
Liệt kê toàn bộ giá trị mà biến có thể nhận
Khai báo:
báo:
enum <tên_kiểu_enum>{
tên_kiểu_enum>{
<danh_sách_các_trị>trị>
ị
};
Ví dụ:
dụ:
ụ
enum day{Hai, Ba, Tu, Nam, Sau, Bay, CN};
Ba, Tu, Sau, CN};
day ngay;
ngay;
gay;
gay
ngay = Tu; // 2
Tu;
enum modes{LASTMODE = -1, BW40 = 0}
BW40
130. Tập tin - File
Phạm Thế Bảo
Trường Đại học Khoa học Tự nhiên Tp.HCM
Tp HCM
131. Kiểu ấ t ú
Kiể cấu trúc
Khái niệm
Khai báo
Phân loại
Các thao tác
132. Khái niệm
iệ
Tập tin là kiểu dữ liệu hỗ trợ truy xuất/lưu trữ
xuất/
dữ liệu trên bộ nhớ ngoài.
ngoài.
C hỗ trợ hai kiểu tập tin: văn bản và nhị phân.
ỗ ể tin: phân.
Truy xuất thông qua con trỏ FILE.
FILE.
133. Kiể FILE *
Kiểu
Kiểu
Kiể FILE * (kh i bá t
(khai báo trong stdio.h) cho phép là việc
(kh
khai stdio.h) h hé làm iệ
tdi hh)
với các tập tin (văn bản, nhị phân).
(văn bản, phân).
Khai báo con trỏ tập tin
FILE * fp;
fp;
Chúng ta sử dụng con trỏ tập tin để truy cập (đọc, ghi,
đọc, ghi,
thêm thông tin) các tập tin.
g ) p
134. Mở tập tin
tậ ti
FILE * fopen( const char *FileName, const char *Mode);
fopen( *FileName
FileName, Mode);
Filename: tên tập tin cần mở. Có thể chỉ định một đường
mở.
dẫn đầy đủ chỉ đến vị trí của tập tin.
Mode: chế độ mở tập tin: chỉ đọc, để ghi (tạo mới), ghi
đọc, mới),
thêm.
thêm.
Nếu thao tác mở thành công, fopen trả về con trỏ FILE trỏ
t ao ở t à công, ope t ả co t ỏ
cô g
g, tỏ
đến tập tin FileName.
FileName.
Nếu mở không thành công (FileName không tồn tại, không
tại,
thể tạo mới), fopen trả về giá trị NULL.
mới),
135. Đóng tậ ti
Đó tập tin
int fclose(
i t f l ( FILE *fil t
*filestream );
filestream:
filestream: con t ỏ đế tậ ti đ
fil t trỏ đến tập tin đang mở cần đó .
ở ầ đóng
đóng.
Nếu h á đóng hà h ô fclose trả về 0.
Nế thao tác đó thành công, f l ả ề
Nếu có lỗi (tập tin đang sử dụng), fclose trả về giá trị EOF.
EOF.
136. Ví d : Mở, Đóng tập tin
dụ Mở Đó tậ ti
1.
1 FILE * f ;
fp;
fp
2. // mở VB TXT “chỉ đ ”
ở VB.TXT “chỉ đọc
hỉ đọc”
3. if( (fp = fopen( “C:LTCVB.TXT”, “r” )) == NULL)
(fp fopen( “C: LTC
4. { printf( “Tap tin kh
printf( “T i khong mo d n”);
i ff( duoc
duoc ”)
5. exit(1);
6. }
/
/* ... */
/
7.
7 fclose(
fclose( fp );
137. Tập ti ă bả
Tậ tin văn bản
Tập tin văn bản là kiểu tập tin được lưu trữ các thông tin
ập ập ợ g
dưới dạng kiểu ký tự.
tự.
Truy xuất tập tin văn bản:
y p bản:
theo từng ký tự
theo từng dòng
g g
Chế độ mở trên tập tin văn bản
“r” : đọc (tập tin phải có trên đĩa)
ọ ập p đĩa)
“w” : ghi (ghi đè lên tập tin cũ hoặc tạo mới nếu tập tin
không có trên đĩa)
đĩa)
“a” : ghi nối vào cuối tập tin.
tin.
“r+” : đọc/ghi. Tập tin phải có trên đĩa.
đọc/ghi. p
g p đĩa.
“a+” : đọc, ghi vào cuối tập tin. Tạo mới tập tin nếu tập
đọc, tin.
tin chưa có trên đĩa.
đĩa.
138. getc, putc, f t f t
t t fgetc, fputc
getc:
getc: nhận ký tự từ tập tin
tin.
int getc ( FILE *fp );
*fp
getc trả về ký tự đọc được hoặc
trả về EOF nếu fp không hợp lệ hoặc đọc đến cuối tập tin
tin.
p
putc: g
putc: ghi ký tự ra tập tin.
ý ự ập
int putc ( int Ch, FILE * fp );
putc trả về EOF nếu thao tác ghi có lỗi.
lỗi.
có thể dùng fgetc và fputc.
fputc.
139. Ví d 1 getc() đọc phím đến khi E t
dụ 1: t () đ hí đế Enter
1. #include <stdio.h>
stdio.
2. #include <conio.h>
conio.
3. #include <stdlib.h>
stdlib.
4. void main()
id i ()
5. { FILE * fp;fp;
6. char filename[67], ch;
filename[67], ch;
7. printf ( “Filename: “ );
“Filename:
8. gets (filename);
(filename);
9. if ((fp = fopen (filename, “w” )) == NULL ) // mở tập tin mới để
((fp
ghi
10.
10 { printf ( “Create file error n”); exit (1); }
Create n )
n”);
);
11. while (( ch = getche() ) != ‘r’ ) // đọc cho đến khi gặp ENTER
getche()
12. putc ( fp );
13. fclose ( fp );
14. }
140. Ví dụ 2: p () in nội dung tập tin văn
ụ putc() ộ g ập
bản ra màn hình
1.
1 #include <stdio h>
<stdio.h
<stdio h>
stdio.h>
2. #include <conio.h>
<conio.h>
3. #include <stdlib.h>
<stdlib.h>
4. void main()
5. { FILE * fp;fp;
6. char filename[67], char ch;ch;
7. printf ( “Filename: “ );
8.
8 gets (filename);
9. if ((fp = fopen (filename, “r” )) == NULL ) // mở tập tin mới để đọc
((fp
10. { printf ( “Open file error n”); exit (1); }
p p ); ( );
11. while (( ch = getc ( fp ) ) != EOF ) // đọc cho đến hết tập tin
12. printf ( “%c”, ch );
13. fclose ( fp );
14. }
141. Ví dụ 3: Đếm số từ trong tập tin văn
ụ g ập
bản.
1. #include <stdio.h>
<stdio.
2. #include <conio.h>
<conio.
3. #include <stdlib.h>
<stdlib.
4. void main()
5. { FILE * fp;
fp;
6. char filename[67], char ch;
filename[67], ch;
7.
7 int count = 0, isword = 0;
8. p
printf ( “Filename: “ ); gets (filename);
“Filename: g ( (filename););
)
9. if ((fp = fopen (filename, “r” )) == NULL ) // mở tập tin mới để đọc
10. { printf ( “Open file error n”); exit (1); }
n”);
143. fgets()
f t ()
fgets: đọc chuỗi ký tự từ tập tin.
fgets:
g ý p
char * fgets ( char *Str, int NumOfChar, FILE *fp );
*Str, NumOfChar, *fp
fgets đọc các ký tự trong tập tin cho đến khi gặp một trong
các điều kiện:
kiện:
EOF
gặp dòng mới
đọc được (NumOfChar - 1) ký tự trước khi gặp hai điều
kiện trên.
trên.
fgets trả về chuỗi ký tự đọc được (kết thúc bằng 0) hoặc
trả về con trỏ NULL nếu EOF hoặc có lỗi khi đọc.
đọc.
144. fputs()
f t ()
fputs:
fputs hi h ỗi tự tập tin.
f t : ghi chuỗi ký t ra tậ ti
int fputs ( const char *Str, FILE * fp );
*Str,
Str
fputs trả về EOF nếu thao tác ghi có lỗi.
lỗi.
145. Hàm hé tậ ti ă bả
Hà chép tập tin văn bản
Có t
trong các th viện
á thư iệ
#include <stdio.h>
<stdio.h>
stdio.h
#include <string.h>
<string.h>
/* Viết chương trình chép từ SourceFile sang DestFile và
trả về số ký tự đọc đươc
146. feof(); fscanf(), fprintf(); fflush()
f f() f f() f i tf() ffl h()
feof:
feof: cho biết đã đến cuối tập tin chư a(EOF)
a(EOF).
int feof (FILE *fp );
*fp
fprintf:
fprintf:
int fprintf ( FILE *fp, const char * Format, ... );
*fp,
fscanf:
fscanf:
int fscanf ( FILE *fp, const char * Format, ...);
*fp,
p , );
fflush:
fflush: làm sạch vùng đệm của tập tin
int fflush
i ffl h ( FILE * f )
fp );
147. Tậ ti Nhị phân
Tập tin hâ
Tập tin hị hâ
Tậ ti nhị phân là một chuỗi các ký t , khô phân biệt
ột h ỗi á tự,
tự không hâ
ký tự in được hay không in được.
được.
Tập tin nhị phân thường dùng để lưu trữ các cấu trúc
(struct) hoặc union
struct) union.
Khai báo:
báo:
FILE * fp;
fp;
p
Truy xuất tập tin nhị phân theo khối dữ liệu nhị phân.
y ập ịp ệ ị phân.
p
148. Tậ ti Nhị phân
Tập tin hâ
Các hế
Cá chế độ mở tậ ti nhị phân:
ở tập tin hị phân:
hâ
“rb” : mở chỉ đọc
“wb” hi (ghi
“ b” : ghi ( hi đè lê tậ ti cũ h ặ t mới nếu tậ
lên tập tin ũ hoặc tạo ới ế tập
tin không có trên đĩa)
“ab”
ab : ghi nối vào cuối tập tin.
tin.
“rb+” : đọc/ghi. Tập tin phải có trên đĩa.
đọc/ghi. đĩa.
“wb+”
“ b+” : tạo mới tập tin cho phép đọc ghi.
ghi.
“ab+” : đọc, ghi vào cuối tập tin. Tạo mới tập tin nếu
tin.
tập tin chưa có trên đĩa.
đĩa.
149. Đọc hi tậ tin
Đ ghi tập ti Nhị phân
hâ
fread()
fread() : đọc
size_t fread ( void *Ptr, size_t ItemSize,
*Ptr, ItemSize,
size_t NumItem, FILE * fp );
NumItem,
fread đọc NumItem khối dữ liệu, mỗi khối có kích thước
liệu,
ItemSize từ fp và chứa vào vùng nhớ xác định bởi Ptr.
p g ị Ptr.
fread trả về số khối dữ liệu đọc được.
được.
Nếu có lỗi hoặc EOF thì giá trị trả về nhỏ hơn NumItem
fwrite()
fwrite() : ghi
size_t f it ( const void *Pt , size_t It Si ,
i t fwrite t id *Ptr i t ItemSize
*Pt
Ptr, ItemSize,
size_t NumItem, FILE * fp );
NumItem,
fwrite ghi khối (NumItem x ItemSize) xác dịnh bởi Ptr ra fp.
ItemSize)
150. Chép 3 mục từ tập tin filename vào vùng nhớ trỏ bởi ptr
ptr fp filename
151. Con t ỏ FILE
C trỏ
Một tậ ti sau khi mở đ
tập tin ở được quản lý thô qua một con t ỏ
ả thông ột trỏ
FILE.
FILE.
Khi mở tập tin (wb, rb), con trỏ FILE chỉ đến đầu tập tin.
tin.
Khi mở tập tin (ab), con trỏ FILE chỉ đến cuối tập tin.
tin.
Con trỏ FILE chỉ đến từng byte trong tập tin nhị phân.
phân.
Sau mỗi lần đọc tập tin, con trỏ FILE sẽ di chuyển đi một
số byte bằng kích thước (byte) của khối dữ liệu đọc được.
được.
152. fseek(),
fseek(),
Các hằng dùng trong di chuyển con trỏ FILE
#define SEEK_SET
SEEK SET 0
#define SEEK_CUR 1
#define SEEK_END 2
int fseek( FILE *fp, long int offset, int whence );
fseek( *fp,
fseek di chuyển con trỏ fp đến vị trí offset theo mốc whence
offset: khoảng cách (byte) cần di chuyển tính từ vị trí hiện tại.
tại.
(offset > 0: đi về phía cuối tập tin, offset < 0: ngược về đầu tập
ề ố ề ầ
tin)
whence: SEEK_SET:
SEEK SET: tính từ đầu tập tin
SEEK_CUR: tính từ vị trí hiện hành của con trỏ
SEEK_END: tính từ cuối tập tin
fseek trả về: 0 nếu thành công, <>0 nếu di chuyển có lỗi
về: công,
153. ftell à
ft ll() và rewind()
ftell()
ll() i d()
rewind đặt l i vị t í con t ỏ về đầ tậ ti
i d lại ị trí trỏ ề đầu tập tin.
void rewind ( FILE * fp );
tương đương với fseek ( fp, 0L, SEEK_SET);
fp,
ftell trả về vị trí offset hiện tại của con trỏ
long int ftell ( FILE * fp );
Nếu có lỗi, ftell trả về -1L
lỗi,
154. Ví d xác đị h kí h thước tập tin.
dụ: á định kích h ớ ậ i
...// kh i bá biế cNn thậ
// khai báo biến N thận
1. if ( f = f
fp fopen ( Fil N ame, “rb” ) ) == N ULL )
FileN ame, “rb”
b
2. fprintf( stderr,
fprintf( stderr, “Cannot open %sn”, FileN ame );
%s
3. else
l
4. {
5. fseek fp
f k( f , 0, SEEK_EN D )
fseek( fp,
k( N );
6. FileSize = ftell( fp );
ftell(
7. printf(
printf( “File size : %d bytesn “, FileSize );
bytes
8. fclose(
fclose( fp );
9. }
155. Vị trí con trỏ: fgetpos() và
ị trỏ: fgetpos()
g p
fsetpos()
etpos()
với các tập tin có kích thước cực lớn fseek và ftell sẽ bị
giới hạn bời kích thước của offset.
Dùng
int fgetpos ( FILE *fp, fpos_t *position);
*fp,
int fsetpos ( FILE *fp, const fpos_t *position);
*fp,
156. Xóa à
Xó và đổi tên tập tin
tê tậ ti
Thực hiện á
Th hiệ xoá
int remove(const char *filename);
filename);
đổi tên tập tin
int rename(const char *oldname, const char *newname);
*oldname, *newname);
157. Chú ý khi làm việc với tập tin
là iệ ới tậ ti
Khi mở tậ ti filename, tậ ti này phải nằm cùng th
ở tập tin fil tập tin à hải ằ ù thư
mục của chương trình hoặc
phải cung cấp đầy đủ đường dẫn đến tập tin
vd: C:baitap
vd: C:baitaptaptin.dat
viết như thế nào?
nào?
fp = fopen( “C:baitaptaptin.dat”, “rb” );
fopen( “C:baitap “rb”
SAI RỒI
vì có ký t đặ biệt ‘’ nên viết đú sẽ là:
ì ó tự đặc ê iết đúng ẽ là:
fp = fopen( “C:baitaptaptin.dat”, “rb” );
fopen( “C: baitap “rb”
158. Tham số dòng lệnh chương trình
Khi gọi chạy một chương trình, chúng ta có thể cung cấp các
trình,
tham số tại dòng lệnh gọi chương trình.
ố trình.
ví dụ: dir A:*.c /w
dụ: A:
“copy”, “A:* c” và “/w” là hai tham số điều khiển chương
copy “A:*.c
A:
A: /w
trình.
trình.
command-
command-line arguments.
arguments
Các tham số dòng lệnh được tham chiếu qua hai đối số khai
báo trong hàm main.
main ( int argc, char * argv[ ] )
argc,
g argv[
g
{ ... }
argc:
argc: argument count
argv:
argv: argument vector
159. Th
Tham số dòng lệ h – ví dụ
ố dò lệnh íd
... // addint.c addint.exe
1. void main (int argc, char * argv [ ])
(int argc,
2. {
3. int res = 0;
4.
4 printf (“ Program %sn “, argv[0]);
( %s argv[0]);
5. for ( int i = 1; i < argc; i++ )
argc;
6.
6 res + atoi(argc[i]);
+= atoi(argc[
7. printf (“ %dn”, res );
%d
8.
8 }
G:
G:>addint 3 –2 1 5 6 -2 1
12
160. Đệ quy - Recursion
Phạm Thế Bảo
Trường Đại học Khoa học Tự nhiên Tp.HCM
Tp HCM
161. Thuật toán đệ quy
ậ ệq y
Là mở rộng cơ bản nhất của khái niệm thuật toán.
toán.
Tư tưởng giải bài toán bằng đệ quy là đưa bài toán
hiện tại về một bài toán cùng loại, cùng tính chất
(đồng dạng) nhưng ở cấp độ thấp hơn, quá trình này
hơn,
tiếp tục cho đến khi bài toán được đưa về một cấp độ
mà tại đó có thể giải được. Từ cấp độ này ta lần ngược
được.
để giải các bài toán ở cấp độ cao hơn cho đến khi giải
xong bài toán ban đầu.
đầu.
Ví dụ:
dụ:
định nghĩa giai thừa: n!=n*(n-1)! với 0!=1
thừa: n!=n*(n- !=1
Dãy Fibonacci: f0=1, f1=1 và fn =fn-1+fn-2 ∀n>1
Fibonacci: n>1
Danh sách liên kết.
kết.
ế
... Phạm Thế Bảo
162. Mọi thuật toán đệ quy gồm 02 phần:
phần:
Phần cơ sở:
sở:
Là các trường hợp không cần thực hiện lại thuật toán (không
y
yêu cầu gọi đệ quy). Nếu thuật toán đệ quy không có phần
g q y)
quy). q y g p
này thì sẽ bị lặp vô hạn và sinh lỗi khi thực hiện. Đôi lúc gọi
hiện.
là trường hợp dừng.
dừng.
Phần đệ quy:
ầ quy:
Là phần trong thuật toán có yêu cầu gọi đệ quy, yêu cầu
thực hiệ thuật toán ở một cấp độ thấp h .
h hiện h ậ á ộ ấ hấ hơn
hơn.
Phạm Thế Bảo
163. Các loại đệ quy
ạ ệq y
Có 03 loại đệ quy:
quy:
1. Đệ quy đ i:
đuôi
đuôi:
Là loại đệ quy mà trong một cấp đệ quy chỉ có duy nhất
một lời gọi đệ quy xuống cấp thấ .
ột i ố ấ thấp
thấp.
Ví dụ:
dụ:
i. Tính giai thừa
í h i i hừ
giaiThua(int n){
if(n==0
if(n==0)
giaiThua = 1;
else giaiThua= n*giaiThua(n-1);
n*giaiThua(n-
}
Phạm Thế Bảo
164. ii. Tìm kiếm nhị phân
p
int searchBinary(int left,int right, intx){
if(left<right){
( g ){
int mid=(left+right)/2;
mid=(left+right)/2
if(x==A[i])return i;
( [ ])
if(x<A[i])return searchBinary(left,mid-1,x);
searchBinary(left,mid- ,x);
return searchBinary(mid+1,right,x);
searchBinary(mid
searchBinary(mid+1,right,x);
}
return -1;
}
iii.
iii Phân tích một số nguyên ra thừa số nguyên tố (Bài
tập)
tập)
Phạm Thế Bảo
165. 2. Đệ quy nhánh
Là dạng đệ quy mà trong quá trình đệ quy, lời gọi được thực hiện
nhiều lần.
lần.
Ví dụ:
dụ:
i. Tháp Hà nội.
nội.
ii.
ii Liệt kê tất cả hoán vị của n phần tử khác nhau.
nhau.
Thuật toán:
toán:
Xét tất cả các phần tử ai với i=1..n
i=1..n
Bỏ phần tử ai ra khỏi dã số
hầ dãy ố
Ghi nhận đã lấy ra phần tử ai
Hoán vị (Dãy số)
Đưa hầ
Đ phần tử ai vào lại dã số
à l i dãy ố
Nếu (Dãy số) rỗng thì thứ tự các phần tử được lấy ra chính là
một hoán vị
iii. Bài toán tô mà (floodfill)
màu
Phạm Thế Bảo