Professional Documents
Culture Documents
Ky-Thuat-Lap-Trinh - Pham-The-Bao - Slide-Ktlt-Pham-The-Bao-Khtn - (Cuuduongthancong - Com) - (Cuuduongthancong - Com)
Ky-Thuat-Lap-Trinh - Pham-The-Bao - Slide-Ktlt-Pham-The-Bao-Khtn - (Cuuduongthancong - Com) - (Cuuduongthancong - Com)
Ph Bả
http://www.math.hcmuns.edu.vn/~ptbao/KTLT/
ptbao@hcmuns.edu.vn
T ờ Đại
Trường Đ i học
h Khoa
Kh hhọc T
Tự nhiên
hiê TTp.HCM
HCM
Ộ DUNG
NỘI
1. Thiết kế chương trình
2. Mả một
Mảng ộ chiều,
hiề hai
h i chiều
hiề vàà nhiều
hiề chiều
hiề
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
Cách tính điểm
y Điểm thực hành 50% tổng điểm
y Điểm lý thuyết 50% tổng điểm
ộ g thêm 10 – 20% tổng
y Điểm cộng g điểm
ệ tham khảo
Tài liệu
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.
N Patt,
Patt Sanjay J.J Patel,
Patel Introduction to
Computing System, from Bits and Gates to C and
Beyond.. McGrawHill, 1999.
4
4. T ầ Đan
Trần Đ Thư,
Th Giáo
Giá trình
t ì h lập
lậ trình
t ì h C (Tậ
(Tập 1 & 2 ).
) NXB
ĐH QG TPHCM –2003.
5. Nguyễn
g y Thanh Thuỷ, ỷ, Nhập
ập môn lập
ập trình ngôn
g ngữg C.
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- 2006.
2006
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).
Website
1. http://www.congdongcviet.com
2
2. htt //
http://www.cprogramming.com/
i /
3. http://www.programmingtutorials.com/c.aspx
4
4. htt //
http://www.codeguru.com/
d /
5. http://www.thecodeproject.com/
6
6. htt // 4 i
http://c4swimmers.net
t
7. http://www.vocw.edu.vn/
8
8. h
http://www.google.com.vn/
// l /
Phạm Thế Bảo
Trường Đại học Khoa học Tự nhiên Tp.HCM
Tp HCM
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
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 hệ thức,
thức, thức định luật,
luật …)) hoặc qua các bước căn bản để có
được lời giải.
• Việc ggiải qquyết
y vấn đề trên máyy tính chỉ là thao tác lậpp trình hayy
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,
sin cos,
cos giải phương trình siêu việt,
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.
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.
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
y 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ấ trúc
Cấu t ú rẽẽ nhánh
há h
1. Rẽ nhánh có điều kiện: if (condition)
y rẽ nhánh đơn: if ()
y rẽẽ nhánh
há h đôi:
đôi if () ... else
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
Phân chia bài toán ban đầu thành những
bài toán nhỏ hơn
y 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.
Biểu diễn tính toán không tường minh bằng đệ quy
y 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
y Sẽ trình
t ì h bày
bà sau này.
à
Phương
gpphápp g
gián tiếp
p
y Được sử dụng khi chưa tìm ra lời giải chính xác của vấn
đề.
đề
y Đây là cách tiếp cận chủ yếu của loài người từ xưa đến
nay.
nay
y Lời giải trực tiếp bao giờ cũng tốt hơn, nhưng không
phải
hải lúc
lú nào
à cũng
ũ có ó
Phân
â lọai
ọa pphương
ươ g ppháp
áp ggián
á ttiếp
ếp
1. Phương pháp thử - sai
1 Thử - saii hệ thống
1. thố
2. Thử - sai phân lớp
3. Thử - saii ngẫu
ẫ nhiên
hiê
2. Phương pháp Heuristic
3. Phương pháp trí tuệ nhân tạo
Ph
Phương há thử - saii
pháp
Thomas Edison – pphát biểu cách tìm một câyy kim trongg một đốngg
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
Phương pháp
há nàyà dự
d trên
t ê 3 nguyên
ê lý:
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ảyy ra và xem xét chúng.
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
lược chọn
h ngẫu ẫ nhiên
hiê vàà một
ột sốố điều
điề kiện
kiệ cụ thể.
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,
hN chọnh ngẫu ẫ nhiên
hiê 5 sản
ả phNm,
hN ...
g y lýý được
Nguyên ợ pphát triên thành pphương
g ppháp
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
hình dạng
dạng" của lời giải, mà phải xây
dựng lời giải dần qua từng bước, giống như tìm được ra khỏi
mê cung.
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 hãy lần lượt rút từng cọng rơm đến khi rút được cây
rơm,
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ó?
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
g ệ p phươngg trình trong
g một
ộ đoạn
ạ
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
Thử
hử - saii phân
hâ lớp
lớ
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,
y 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
ậ A*
Giải thuật
Phương
gpphápp trí tuệệ nhân tạo
ạ
y "Dạy"
Dạy máy tính để có "trí trí thông minh
minh" như con người
bắt chước khả năng "suy luận" của con người.
ví dụ: bài toán đong nước,
nước có 3 bình A,
A B,
B và C có dung
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
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
2. h ê gia
i
3. Máy học
Mảng - Array
int
i a[5]
[5] = { 10
10, 20
20, 30
30, 40
40, 50}
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[];
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
hú 0....size
size-
i -1
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;
}
T ề tham
Truyền th sốố Mảng
Mả cho
h hà
hàm
Th
Tham sốố kiểu
kiể mảng
ả đượcđ t ề cho
truyền h hàm
hà chính
hí h là địa
đị chỉ
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
(vd:: size)
int
t add_e
add elements(int
e e ts( t a[], int
t s
size)
e)
{
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
Mảng – Nhập
Nhậ dữ liệu
liệ
void ReadData(int a[], int size)
{
duyệt qua tất cả các
int i; phần tử
for(i
o ( = 0; i < ssize;
e; i++)
)
{
printf(“Nhap thanh phan %d: ”, i);
scanf(“%d”, &a[i]);
}
}
nhập
ập dữ liệu
ệ cho a[i]
[]
Mảng – X
Xuất
ất dữ liệu
liệ ra màn
à hình
hì h
N=8
7
a[N] = X;
15
NX ++;
Mảng – Chèn
Chè X vào
à dãy
dã tăng
tă dần
dầ
N=8
7
X 6
Bài toán:
toán: loại bỏ thành phần dữ liệu X ra khỏi
mảng a đang có N thành phần.phần.
Hướng giải quyết:
quyết: xác định vị trí của X, nếu tìm
thấy thì dồn các phần tử ở phía sau lên để lấp vào
chỗ
hỗ trống
trống.
ố . 2 trường
ờ hợp h :
hợp:
Dãy không có thứ tự tự:: lấp phần tử cuối lên
Dãy đã thứ tựtự:: dời tất
ấ cả các phầnầ tử ở sau ví
trí của X lên trước 1 vị trí
trí..
Mảng – L
Loạii bỏ X ra khỏi dãy
dã tăng
tă
Loại 5 khỏi (a,
(a 8)
pos
0 1 2 3 4 5 6 7
1 2 4 5 7 8 8 9
N=7
8 STOP
X 5 Ok, found
j
1 2 3 4 5 6 7 8
12
1 2 8 5 1 6 4 15
i
Mảng – Sắp xếp đổi chổ
j
1 2 3 4 5 6 7 8
1 2
12 8 5 2 6 4 15
i
Mảng – Sắp xếp đổi chổ
j
1 2 3 4 5 6 7 8
1 2 12
4 8 5 6 4 15
i
Mảng – Sắp xếp đổi chổ
j
1 2 3 4 5 6 7 8
1 2 4 12
5 8 6 5 15
i
Mảng – Sắp xếp đổi chổ
1 2 3 4 5 6 7 8
1 2 4 5 6 8 12 15
Mảng – Sắp xếp đổi chổ
void Swap(int &x
&x, int &y)
{
int t = x; x = y; y = t;
}
void
id I
InterchangeSort(int
t h S t(i t a[],
[] int
i t N)
{
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]);
}
Mả
Mảng nhiều
hiề chiều
hiề
C không
khô hỗ trợ
t mảngả nhiều
hiề chiều.
chiều
hiề . Tuy
T nhiênhiê cóó thể tiếp
tiế
cận theo hướng:
hướng: Mảng 2 chiều là mảng một chiều mà mỗi
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à
thànhh phần,
hầ mỗiỗi thành
thà h
phần là mảng 10 số short
const
t int
i t brighton
b i ht = 7
7;
int day_of_year = 238;
rainfall[brighton][day_of_year] = 0.0F;
Mả
Mảng nhiều
hiề chiều
hiề
Khai báo mảng 2 chiều:
chiều:
type name[row_size
name[row_size][
][column_size
column_size];
];
SumSquares 0 1 4
1 2 5
0 1 4 1 2 5
int SumSquares
SumSquares[[2][
][33] = { {0,1,4}, {1,2,5} };
int SumSquares
SumSquares[[2][
][33] = { 0,1,4,1,2,5 };
int SumSquares
SumSquares[[2][
][33] = { {0,1,4} };
int SumSquares
SumSquares[[ ][
][33] = { {0,1,4}, {1,2,5} };
int SumSquares
SumSquares[[ ][
][33] = { {0,1, }, {1} };
int SumSquares
SumSquares[[ ][
][33];
Nhậ Mảng
Nhập Mả 2 chiều
hiề
1
1. #define MAX_STUDENT
MAX STUDENT 5
2. #define MAX_SUBJECT 6
3. int StudentScore
StudentScore[MAX_STUDENT][MAX_SUBJECT];
[MAX_STUDENT][MAX_SUBJECT];
4. void
id read_Score
read_Score(
d S (int
i Score[MAX_STUDENT][MAX_SUBJECT],
S [MAX STUDENT][MAX SUBJECT]
int nStudents
nStudents,, int nSubjects
nSubjects))
5. {
6. int i,j
i,j;;
7. for(ii=0; i<nStudents;
for( nStudents; i++)
8. for(j=0; j<j<nSubjects
nSubjects;; j++)
9. scanf(“%d”,
scanf (“%d”, &Score[
&Score[ii][j]);
10
10. }
Hà
Hàm truy
t cập,
ậ iin Mảng
Mả 2 chiều
hiề
1
1. void print_Score(
print Score(
print_Score
Score(int Score[MAX_STUDENT][MAX_SUBJECT],
Score[MAX STUDENT][MAX SUBJECT]
int nStudents
nStudents,, int nSubjects
nSubjects))
2. {
3. int i,j
i,j;;
4. for(ii=0; i<nStudents;
for( nStudents; i++)
5. {
6. for(j=0; j<j<nSubjects
nSubjects;; j++)
7
7. printf(“%2d
printf(
printf (“%2d\
( %2d\
%2d\tt”, &Score[i
&Score[i][j]);
8. printf(“
printf (“\\n”);
9. }
10. }
Ch
Chương ttrình
ì h
1
1. main(void)
2. {
3. int nStudents
nStudents,, nScores
nScores;;
4. scanf(“%d
scanf (“%d %d”, & &nStudents
nStudents,, &
&nScores
nScores);
);
5. if(nStudents
if( nStudents <= MAX_STUDENT &&
nScores
S <= MAX_SCORES)
MAX SCORES)
6. read_Score((StudentScore
read_Score StudentScore,, nStudents,
nStudents, nScores);
nScores);
7
7. print_Score
print Score (StudentScore
StudentScore,, nStudents
nStudents,, nScores
nScores);
);
8. return 0;
9. }
Biểu diễn mảng 2 chiều
StudentScores
Student1 0 1 4 ? ? ?
Student2 1 2 5 ? ? ?
Student3 ? ? ? ? ? ?
Student4 ? ? ? ? ? ?
Student5 ? ? ? ? ? ?
0 1 4 ? ? ? 1 2 5 ? ? ?
Student1 Student2
Con tr
trỏỏ - Pointer
int x;
PINT p; //p,
// p1:
1 biế
biến kiểu
kiể int
i t *
int *p1;
C ttrỏ
Con ỏ – Khai
Kh i báo
bá trong
t C
int *pi;
float* pf;
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;
}
C ttrỏ
Con ỏ - Toán
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;
0 91A2
0x91A2 ' '
'z'
p = &c; 0x91A2
printf("%c\n", *p);
p = &g; xuất giá trị do p đang
printf("%c\n", *p); quản lý
return 0;
}
C ttrỏ
Con ỏ - Truyền
T ề tham
h số
ố đị
địa chỉ
hỉ
#include <stdio.h>
void change(int *v);
int main()
{
int var = 5;
change(&var);
printf("main: var = %i\n", var);
return 0;
}
#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ị : %hi\n", *p);
return 0;
;
}
C ttrỏ
Con ỏ - Toán
T á tử
ử gán
á “=”
“ ”
Có sự khác
khá biệt rất
ất quan trọng
t khi thực
th hiện
hiệ các
á phép
hé gán:
gán
á :
p i
int i = 10, j = 14;
int* p = &i; 0 15A0
0x15A0 10 14
0x15A0
int *q = &j;
q j
*p = *q; 0x15A4 14
0x15A4
và:
int i = 10, j = 14; p 0x15A4 i
int *p
p = &i;
; 0x15A0 10
int *q = &j; 0x15A0
q j
p = q; 0x15A4 14
0x15A4
L ệ tập
Luyện tậ – Điề
Điền vào
à ô trống
ố
int main(void) i
{
0x2100
int i = 10,
10 j = 14
14, k;
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
}
C
Con ttrỏ
ỏ vàà Mả
Mảng
Biế kiểu
Biến kiể mảng
ả là địa
đị chỉ
hỉ tĩnh
tĩ h của
ủ một
ột vùng
ù nhớ,
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ớ,
nhớ được xác
định qua phép gán địa chỉ khi chương trình thực thi.
thi.
#include <stdio
<stdio.h>
h>
int main()
{
int a[10] = {1
{1, 3
3, 4
4, 2
2, 0};
int *p;
p = a; //a = p: sai
printf(“0x%04X
i tf(“0 %04X %i 00x%04X
%04X %i\
%i\n“,
“
a, a[0], p, *p);
return 0;
}
C ttrỏ
Con ỏ - Toán
T á tử
ử “+”
“ ” với
ớ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 %i\n“
%i\n , 2
a, a[0], p, *p); 0
p ++;
…
printf(“0x%04X
i tf(“0 %04X %i 00x%04X
%04X %i\
%i\n“,
“
a, a[0], p, *p);
(*p) ++; 0x16B2
printf(“0x%04X %i 0x%04X %i\n“, p
a, a[0], p, *p); 0x15A0
0x15A2
return 0;
}
C ttrỏ
Con ỏ - Luyện
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
printf( %i %i\n“
%i\n , a[0],
a[0] *p);
p ++;
printf(“%i %i\n“, *p, p[2]);
p ++;
++ a[2]
[2] = 9
9;
printf(“%i %i\n“, p[1], *p);
p -= 2;
printf(“%i %i\n”, p[3], p[1]);
return 0;
}
C ttrỏ
Con ỏ - Cấp
Cấ phát
há vùng
ù nhớ
hớ động
độ
Có thể chỉ
hỉ định
đị h vùng
ù mới ới cho
h 1 con trỏ
t ỏ quản
ả lý bằng
bằ cácá
lệnh hàm malloc
malloc,, calloc hoặc toán tử new của C++
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;
}
Cấ phát
Cấp hát động
độ : malloc()
động: malloc
ll () vàà calloc()
calloc
ll ()
Hà malloc
Hàm ll vàà calloc
ll cho
h phép
hé cấpấ phát
hát các
á vùng
ù nhớ
hớ
ngay trong lúc chạy chương trình
trình..
void **malloc
malloc(( size_t size);
void **calloc
calloc(( size_t nItems
nItems,, size_t size);
Hàm calloc
ll cấp
ấ phát
h vùng nhớh và khởi
kh i tạo tất
ấ cả các bit
bi
trong vùng nhớ mới cấp phát về 0.
5. int main(void)
6. { char *str;
*str;
7
7. /* allocate memory for string */
8. if ((str = (char *) malloc(
malloc(10
10))
)) == NULL)
9. {
10. printf("Not enough memory to allocate buffer\
buffer\n")
n");;
11. exit(1
exit(1); /* terminate program if out of memory */
12. }
Ví d
dụ 11: (tt)
13
13. /* copy "Hello" into string */
14. strcpy(str, "Hello");
"Hello");
4. int main(void)
5. {
6. char *str = NULL
NULL;;
15. return 0;
16
16. }
Giải phóng
hó vùng
ù nhớ
hớ
Khi thoát
th át khỏi hàm
hà , các
hàm, á biến
biế khai
kh i báo
bá trong
t hà sẽẽ “biến
hàm biế
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 dùng”” Æ bộ nhớ
dấu”” là đang “được dùng
của máy tính sẽ hết
hết..
ví dụ:
dụụ:
void aFunction(void)
aFunction(void)
{
i *tmpArray
int tmpArray,, i = 5;
tmpArray = (int
(int *)
*)malloc
)malloc
malloc((i * sizeof
sizeof((int
int));
));
} tmpArray i
Giải phóng
hó vùng
ù nhớ
nhớ:
hớ: free
f
Sử dụng
d các
á cặp
ặ hàm
hà
(malloc
malloc,, free)
(calloc,
calloc, free)
C dùng hàm free để giải phóng vùng nhớ cấp phát động
động..
tmpArray = ((int
int *)malloc
*)malloc(N(N * sizeof(
sizeof(int));
int));
f (i
for(i
for(
(i = 0;
0 i<N;
<N i++)
tmpArray]]i] = i;
tmpArray
tmpArray = ((int
int *)
*)realloc
)realloc
realloc((tmpArray
tmpArray,, 7);
Ví d
dụ: realloc()
ll ()
1
1. #include
#i l d <stdio.h
<stdio.h>
tdi h>
h>
2. #include <
<alloc.h
alloc.h>
>
3. #i l d <string.h
#include <string.h>
t i h>h>
4. i main(void)
int i ( id)
5. {
6. char
h *str
*str;;
16. return 0;
17. }
Di chuyển
h ể con trỏ
t ỏ trong
t mảng
ả
i t IntArr
int I tA [5] = {3,4,2,1,0};
IntArr[5] {3 4 2 1 0}
char CharArr
CharArr[5]
[5] = {‘a’,’b’,’c’,’d’,’e
{‘a’,’b’,’c’,’d’,’e’};
’};
i t *IntPtr
int I tPt = IntArr
I tA ;
IntArr;
char **charPtr
charPtr = CharArr
CharArr;;
IntPtr IntPtr+3
3 1
13
IntPtr + 2*5 + 3
Ký tự và
Ch ỗi ký
Chuỗ
Chu k tự - String
S i
getch:: lấy
getch
g y trực
ự tiếp p ký
ý tự
ự từ bàn p
phím khôngg hiển thịị ra màn hình
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();
();
getchar
t h
1
1. #include <stdio.h
<
<stdio
stdio
stdio.h>
h>
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 *//
8. return
t 0;
0
9. }
putchar
1. /* putchar example */
2
2. #include <stdio.h
<
<stdio
stdio
stdio.h>
h>
h>
26. putchar('
putchar('\\n');
27. }
28. /* draw the bottom */
29. putchar(LEFT_BOT);
putchar (LEFT_BOT);
30. for ((ii=0; i<10; i++)
31
31. putchar(HORIZ);
putchar (HORIZ);
32. putchar(RIGHT_BOT);
putchar (RIGHT_BOT);
33. putchar('
putchar ('\\n');
34. return 0;
35. }
Một sốố hàm
hà khá
khác
kbhit:: kiểm
kbhit kiể tra
t cóó phím
hí bấ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
hil (!kbhit
(!kbhit())
()) /* do
d nothing
thi */ ;
7. cprintf("
cprintf ("\\r\nA key was pressed...\
pressed...\r\n");
8. return
t 0;
0
9. }
Ch ỗi ký ttự – Strings
Chuỗi St i
Một số qui tắc
Nhậ / xuất
Nhập ất
Con trỏ và chuỗi ký tự
Một số hàm thư viện
Ch ỗi ký ttự - Một
Chuỗi Mộ số
ố quii tắc
ắ
Chuỗi
Ch ỗi ký tự
t là mảng
ả một ột chiều
hiề cóó mỗi
ỗi thành
thà h phần
hầ là một
ộ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)
NULL).. Có thể ghi là 0
hoặc
ặ ‘\0’ (không
( g pphải chữ o)
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];
Ch ỗi ký ttự - Ví dụ
Chuỗi d
char first_name[5]
first name[5] = { 'J'
'J', 'o'
'o', 'h'
'h', 'n'
'n', '\0' };
first name
first_name 'J'
J 'o'
o 'h'
h 'n'
n 0
other 'T' 'o' ‘n’ 'y' 32 'B' 'l' 'u' 'r' 't' 0
characters 'N'
N 'o'
o 32 'n'
n 'u'
u 'l'
l 'l'
l 0
Ch ỗi ký ttự - Nhập
Chuỗi Nhậ / xuất
ấ
Có thể nhập
ập / xuất chuỗi kýý tự
ự s bằngg cách nhập
ập từngg kýý
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("%s\n", other);
int main()
{ "Blurt"
Blurt sẽ không
char other[] = "Tony Blurt"; được in ra
printf("%s\n"
printf( %s\n , other);
other[4] = '\0';
other 'T' 'o' ‘n’ 'y' 32 'B' 'l' 'u' 'r' 't' 0
Lỗi khi tạo
t một
ột chuỗi
h ỗi
char ten[10];
ten = “hoahong
“hoahong”;
”;
Chú ý
Khô :
Không
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)
( ) //???
{}
C trỏ
Con t ỏ và
à chuỗi
h ỗi ký tự
t
char
h *p* ; // khai
*p; kh i báo
bá chuỗi
h ỗi ký tự
t như
h một ột con trỏ
tỏ
p = new char[
char[30
30]]; //xin
//xin cấp phát số lượng ký tựtự,,
// giống
iố mảngả cácá ký tự
Mảng
Mả các
á chuỗi:
h ỗi char
h *[]
char
h *words
*
*words[
d [ ] = {“
{“hhong”,
{“hong
h ” “cuc
”, cuc”,
” “lan
”, l ”,
lan”,
” “nhai”,”mo
nhai”,”mo”}
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
So sánh chuỗi
chuỗi:: so sánh theo thứ tự từ điển
strcpy(s2, s);
printf("%s\n",
i f("% \ " s2);
2)
strncpy(s2 + 2, "12345", 3);
printf("%s\n", s2);
s3 = strdup(s + 5);
printf("%s\n", s3);
( )
free(s3);
return 0;
}
Ch ỗi ký ttự – Một
Chuỗi Mộ số
ố hà
hàm thư
h viện
iệ
Nối chuỗi:
chuỗi:
char *strcat
strcat(char
(char *dest,
const char *src)
*src);;
Tách chuỗi:
chuỗi:
char *strtok
strtok(char
(char *s,
( ,
const char *sep)
*sep);;
Trả về địa chỉ của đoạn đầu tiên
tiên.. Muốn tách đoạn kế tiếp
tham số thứ nhất sẽ là NULL
Ch ỗi ký ttự – víí dụ
Chuỗi d strtok
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("%s\n", p);
p = strtok(NULL, SEPARATOR);
}
return 0;
}
Ch ỗi ký ttự – Một
Chuỗi Mộ số
ố hà
hàm thư
h viện
iệ
int main()
{
char s[]=
[] "Thu tim kiem chuoi";
;
char *p;
p = strchr(s,
strchr(s 'm');
m );
printf("%s\n", p); m kiem chuoi
p = strstr(s, "em");
em chuoi
printf("%s\n" p);
printf("%s\n",
return 0;
}
Ch ỗi ký ttự – chèn
Chuỗi hè một
ộ đđoạn ký tự
#
#include <stdio.h>
#include <string.h>
void StrIns(char *s
s, char *sub)
sub)
{
int len = strlen(sub);
memmove(s + len,
len s,
s strlen(s)+1);
strncpy(s, sub, len); 123 Thu chen
}
123 Thu 45chen
i
int main()
i ()
{
char s[]= “ Thu chen";
void StrDel(char *s
s, int n)
{
memmove(s, s + n, strlen(s+n)+1);
} xoa 12345
int main() xoa 45
{
char
h s[]=
[] "
"Thu
h xoa 12345";
12345"
iintt atoi
atoi(const
t i(
i(const
( t char
h *s);
*)
double atof(const
atof(const char *s);
long atol
atol(const
(const char *s);
s);
...
float f;
char **str
str = "12345.67";
f = atof(
atof(str);
str);
printf("string
printf(
printf(("string
string = %s float = %f\
%f\nn", str
str,, f);
...
Cấu trúc - Struct
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
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,
nhau, mỗi
thành
hà h phần
hầ được
đ xác
á định
đị h bằng
bằ mộtộ tên
ê riêng
iê
biệt (kiểu dữ liệu trừu tượng – Abstract Data
Type – ADT)
ADT)..
void Print(TStudent m)
{
printf("Name
printf( Name : %s %s\n"
%s\n ,
m.firstname, m.lastname);
printf("Student ID : %s\n", m.ID);
printf("Date of birth : %hi/%hi/%i"
%hi/%hi/%i",
m.dob.day, m.dob.month, m.dob.year);
printf("Marks : ");
f
for (i
(intt i
i=0;
0 ii<10;
10 ii++))
printf("%.2f ", m.marks[i]);
}
Cấ trúc
Cấu t ú – Truy
T xuất
ấ các
á thành
hà h phần
hầ
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]));
}
Kí
Kích
h thước
th ớ của
ủ một
ột cấu
ấ ttrúc
ú
Kí h thước
Kích th ớ kiểu
kiể dữ liệu
liệ cấu
ấ trúc
tú :
trúc:
sizeof(<<
sizeof(
sizeof((<<typename
typename>>)
typename>>))
vd::
vd
SinhVien_t_size = sizeof
sizeof((SinhVien);
SinhVien); // 48
Mả các
Mảng á Cấu
Cấ trúc
t ú
Kh i bao
Khai b biến
biế mảng
ả cácá Cấu
Cấ trúc
t ú cũng
ũ giống
iố nhưh khai
kh i báo
bá
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..
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->namsinh
SV_ptr-
SV t ->noisinh
SV_ptr-
SV_ptr ii h
U i
Union
Kh i báo
Khai bá union
i được
đ dù để khai
dùng kh i báo
bá các
á biến
biế dùng
dù
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.
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..i = 5;
a_number
6
6. aa_number.
a_number
number.l = 100
100L
L;
7. // anonymous union
8. union {
9. int i;
10. float f;
11. };
12. i = 10
10;;
13. f = 2.2;
Kiể Enum
Kiểu E (liệt kê
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,Ba, TuTu,, Nam, Sau
Sau,, Bay, CN}
CN};;
day ngay
ngay;
gay;;
gay
ngay = TuTu;; // 2
enum modes{LASTMODE = -1, BW BW40 40 = 0}
Tập tin - File
Khái niệm
Khai báo
Phân loại
Các thao tác
Khái niệm
iệ
Tập tin là kiểu dữ liệu hỗ trợ truy xuất/
xuất/lưu trữ
dữ liệu trên bộ nhớ ngoài
ngoài..
C hỗỗ trợ hai kiểu
ể tập tin
tin:: văn bản và nhị phân
phân..
Truy xuất thông qua con trỏ FILE
FILE..
Kiể
Kiểu FILE *
Kiể FILE * (khai
Kiểu ((kh
kh i báo
khai bá trong
t stdio.h)
stdio.h
tdi h)
h) cho
h phép
hé làm
là việc
iệ
với các tập tin ((văn
văn bản
bản,, nhị phân
phân).
).
FILE * fp;
fp;
Nếu tthao
ao tác mởở tthành
à côcông,
công
g, fopen
g, ope trả
t ả về co
con trỏ
t ỏ FILE ttrỏỏ
đến tập tin FileName
FileName..
fil t
filestream:
filestream : con trỏ
t ỏ đến
đế tập
tậ tin
ti đang
đ mở
ở cần
ầ đóng
đó .
đóng.
Nế thao
Nếu h tácá đóng
đó thành
hà h công,
ô fclose
f l trảả vềề 0.
Nếu có lỗi (tập tin đang sử dụng), fclose trả về giá trị EOF
EOF..
Ví d
dụ : Mở,
Mở Đóng
Đó tập
tậ tin
ti
1
1. FILE * fp
f ;
fp;
2. // mởở VB.TXT
VB TXT “chỉ“chỉ
hỉ đọc
đ ”
đọc”
3. if( (fp
(fp = fopen
fopen(( “C:\
“C:\\LTC
LTC\\\VB.TXT”, “r” )) == NULL)
4. { printf(
printf
i f(
f( “Tap
“T tini khong
kh mo duoc
d \n”);
duoc\ ”)
5. exit(1);
6. }
7
7. fclose(( fp );
fclose
Tậ tin
Tập ti văn
ă bản
bả
Tập
ập tin văn bản là kiểu tập ập tin được ợ lưu trữ các thôngg tin
dưới dạng kiểu ký tự tự..
Truyy xuất tậpp tin văn bảnbản::
theo từng ký tự
theo từngg dòngg
Chế độ mở trên tập tin văn bản
“r” : đọcọ (tậpập tin pphải có trên đĩa đĩ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
đọc//gghi
ghi.. Tậpp tin pphải có trên đĩa đĩa..
“a+” : đọc
đọc,, ghi vào cuối tập tin tin.. Tạo mới tập tin nếu tập
tin chưa có trên đĩađĩa..
getc,
t putc,
t ffgetc,
t ffputc
t
getc:: nhận ký tự từ tập tin.
getc tin
8. printf ( “Filename
p “Filename:: “ ); g
gets ((filename)
(filename); );
);
9. if ((fp = fopen (filename, “r” )) == NULL ) // mở tập tin mới để đọc
10. { printf ( “Open file error \n”)
n”);; exit (1); }
11
11. while (( ch = getc ( fp ) ) != EOF ) // đọc cho đến hết tập tin
12. {
13. if (( ch >= ‘a’ && ch <= ‘z’ ) || ( ch >= ‘A’ && ch <= ‘Z’ ))
14. isword =1;
15. if (( ch == ‘ ‘ || ch == ‘\n’ || ch == ‘\t’ ) && isword )
16. { count ++
++;; isword = 0; }
17. }
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..
f t ()
fputs()
f t : ghi
fputs:
fputs hi chuỗi
h ỗi ký tự
t ra tập
tậ tin.
ti
#include <stdio.h
<stdio.h
stdio.h>
>
#include <string.h
<string.h>
>
fprintf:
fprintf:
int fprintf ( FILE **fp
fp,, const char * Format, ... );
fscanf:
fscanf:
int fscanf ( FILE **fp
fp,
p, const char * Format,, ...);
);
Tập tin nhị phân thường dùng để lưu trữ các cấu trúc
(struct
struct)) hoặc union.
union
Khai báo
báo::
FILE * fp;
fpp;
fwrite() : ghi
fwrite()
size_t
i t fwrite
f it ( constt void
id *Ptr
**Pt
Pt , size_t
Ptr, i t ItemSize
It Si ,
ItemSize,
size_t NumItem
NumItem,, FILE * fp );
ptr fpÆfilename
fpÆ
Con
C ttrỏ
ỏ FILE
Một tập
tậ tin
ti sau khi mở
ở được
đ quản
ả lý thông
thô qua một
ột con trỏ
tỏ
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..
fseek(),
fseek (),
Các hằng dùng trong di chuyển con trỏ FILE
#define SEEK SET 0
SEEK_SET
#define SEEK_CUR 1
#define SEEK_END 2
int fseek(
fseek( FILE *fp
*fp,, long int offset, int whence );
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: tính từ đầu tập tin
SEEK_SET:
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ề
về:: 0 nếu thành công
công,, <>0 nếu di chuyển có lỗi
ft
ftell
ftell()
ll() và
ll() à rewind()
i d()
rewind
i d đặt lại
l i vịị trí
t í con trỏ
t ỏ vềề đầu
đầ tập
tậ tin.
ti
Nếu có lỗi,
lỗi, ftell trả về -1L
Ví d
dụ: xác
á định
đị h kí
kích
h thước
h ớ tập
ậ tin.
i
...//
// khai
kh i báo
bá biến
biế cNn
N thận
thậ
1. if ( fp
f = fopen
f ( FileN
Fil N ame,
ame, “rb
“rb”
b” ) ) == N ULL )
2. fprintf(( stderr,
fprintf stderr, “Cannot open %s %s\\n”, FileN ame );
3. else
l
4. {
5. f k(
fseek(
fseek
k( fpf , 0, SEEK_ENN D );
fp, )
6. FileSize = ftell
ftell(( fp );
7. printf(( “File size : %d bytes
printf bytes\\n “, FileSize );
8. fclose(( fp );
fclose
9. }
Vịị trí con trỏ
trỏ:: fgetpos()
fgetpos
g p () và
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
vd: C:
vd: C:\\baitap\
baitap\taptin.dat
viết như thế nào
nào??
fp = fopen
fopen(( “C:\
“C:\baitap\
baitap\taptin.dat”, ““rb
rb”” );
SAI RỒI
vìì cóó ký tự
t đặc
đặ biệt ‘\’ nên
ê viếtiết đúng
đú sẽẽ làlà::
fp = fopen
fopen(( “C:\
“C:\\baitap
baitap\\\taptin.dat”, ““rb
rb”” );
Tham số dòng lệnh chương trình
Khi gọi chạy một chương trình
trình,, chúng ta có thể cung cấp các
tham sốố tại dòng lệnh gọi chương trình
trình..
ví dụ:
dụ: dir A:\
A:\*.c /w
“copy”
copy , “A:\
“A:
A:\*.c
A:\ * c” và “/w”
/w là hai tham số điều khiển chương
trình..
trình
command--line arguments.
command arguments
Các tham số dòng lệnh được tham chiếu qua hai đối số khai
báo trong hàm main.
G:\>addint 3 –2 1 5 6 -2 1
G:\
12
Đệ quy - Recursion
1. Vòng lặp
2. Bằ stackk
Bằng
8. int main(void)
9. { int n;
10. printf(“
printf
printf(
((“Nhap
Nhap n:
n:”);
); scanf
scanf(“%d”,
scanf(
(“%d”,
( %d , &n);
printf(“n!
printf(“n! = %d! = %l\
%l\n”, n, factorial(n));
11. return 0;
12. }
Đệ quy
Một
ộ hàm đượcợ gọgọi là đệệ q
quy
y nếu như trong
gqquá trình xử lý,
ý, hàm này
y có một
ộ lời gọ
gọi
đến
ế chính nó.
nó.
Giải quyết bài toán bằng đệ quy
1. #include <stdio
<stdio.
stdio..h
stdio h>
7. int main(void)
8. { int n;
9. printf(“Nhap
printf( Nhap n:”)
”);
); scanf(
scanf(“%
scanf(“ %d”,
d , &n)
&n);;
10. printf(“n! = %d! = %l\n”, n, factorial(n))
factorial(n));;
11. return 0;
12. }
Lời gọ
gọi hàm đệệ q
quy
y và Điều kiện
ệ
dừng của thuật giải đệ quy
Bài toán
t á giải
iải bằng
bằ thuật
th ật giải
iải đệ quy phải
hải cóó điều
điề kiện
kiệ
dừng..
dừng
Thuật toán đệ quy trên máy tính có thể bị giới hạn bởi
dung lượng bộ nhớ do lời gọi hàm liên tiếp
tiếp..
main
Hãy vẽ sơ đồ tiến trình gọi hàm khi thực hiện tính dãy fibonacci bằng
đệ quy
quy..
Bài ttoán
á Thá
Tháp Hà Nội
Bàn cờ có n hàng được đánh số từ 0 đến n-1, n cột được đánh số từ 0 đến n-1; Bàn cờ có n*2
-1 đường chéo xuôi được đánh số từ 0 đến 2*n -2, 2 *n -1 đường chéo ngược được đánh số từ
2*n -2. Ví dụ: với bàn cờ 8 x 8, chúng ta có 8 hàng được đánh số từ 0 đến 7, 8 cột được đánh
số từ 0 đến 7, 15 đường chéo xuôi, 15 đường chéo ngược được đánh số từ 0 . .15.
Vì trên mỗi hàng chỉ xếp được đúng một quân hậu, nên chúng ta chỉ cần quan tâm đến quân
hậu được xếp ở cột nào. Từ đó dẫn đến việc xác định bộ n thành phần x1, x2, . ., xn,trong đó
xi = j được hiểu là quân hậu tại dòng i xếp vào cột thứ j. Giá trị của i được nhận từ 0 đến n-1;
giá trị của j cũng được nhận từ 0 đến n-1, nhưng thoả mãn điều kiện ô (i,j) chưa bị quân hậu
khác chiếu đến theo cột, đường chéo xuôi, đường chéo ngược.
Việc kiểm soát theo hàng ngang là không cần thiết vì trên mỗi hàng chỉ xếp đúng một quân
hậu. Việc kiểm soát theo cột được ghi nhận nhờ dãy biến logic aj với qui ước aj=1nếu cột j
còn trống, cột aj=0 nếu cột j không còn trống. Để ghi nhận đường chéo xuôi và đường chéo
ngược có chiếu tới ô (i,j) hay không, ta sử dụng phương trình i + j = const và i - j = const,
đường chéo thứ nhất được ghi nhận bởi dãy biến bj, đường chéo thứ 2 được ghi nhận bởi dãy
biến cj với qui ước nếu đường chéo nào còn trống thì giá trị tương ứng của nó là 1 ngược lại
là 0. Như vậy, cột j được chấp nhận khi cả 3 biến aj, bi+j, ci+j đều có giá trị 1. Các biến này
phải được khởi đầu giá trị 1 trước đó, gán lại giá trị 0 khi xếp xong quân hậu thứ i và trả lại
giá trị 1 khi đưa ra kết quả.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#define N 8
#define D (2*N-1)
#define SG (N-1)
#define TRUE 1
#define FALSE 0
void hoanghau(int);
void inloigiai(int loigiai[]);
FILE *fp;
int A[N], B[D], C[D], loigiai[N];
int soloigiai =0;
void hoanghau(int i){
int j;
for (j=0; j<N;j++){
if (A[j] && B[i-j+SG] && C[i+j] ) {
loigiai[i]=j;
A[j]=FALSE;
B[i-j+SG]=FALSE;
C[i+j]=FALSE;
if (i==N-1){
soloigiai++;
inloigiai(loigiai);
delay(500);
}
else
hoanghau(i+1);
A[j]=TRUE;
B[i-j+SG]=TRUE;
C[i+j]=TRUE;
}
}
}
void inloigiai(int *loigiai){
int j;
printf("\n Lời giải %3d:",soloigiai);
fprintf(fp,"\n Lời giải %3d:",soloigiai);
for (j=0;j<N;j++){
printf("%3d",loigiai[j]);
fprintf(fp,"%3d",loigiai[j]);
}
}
void main(void){
int i;
clrscr();
fp=fopen("loigiai.txt","w");
for (i=0;i<N;i++)
A[i]=TRUE;
for(i=0;i<D; i++){
B[i]=TRUE;
C[i]=TRUE;
}
hoanghau(0);
fclose(fp);
}
Bài toán Tháp Hà Nội (Tower of Hanoi)
Truyeàn thuyeát 1: Moät nhaø toaùn hoïc Phaùp sang thaêm Ñoâng Döông ñeán moät ngoâi chuøa coå ôû
Haø Noäi thaáy caùc vò sö ñang chuyeån moät choàng ñóa quùy goàm 64 ñóa vôùi kích thöôùc khaùc
nhau töø coät A sang coät C theo caùch:
- Moãi laàn chæ chuyeån 1 ñóa .
- Khi chuyeån coù theå duøng coät trung gian B .
- Trong suoát quùa trình chuyeån caùc choàng ñóa ôû caùc coät luoân ñöôïc xeáp ñuùng (ñóa coù kích
thöôùc beù ñöôïc ñaët treân ñóa coù kích thöôùc lôùn ) .
Khi ñöôïc hoûi caùc vò sö cho bieát khi chuyeån xong choàng ñóa thì ñeán ngaøy taän theá !
Truyền thuyết 2: Lúc thế giới hình thành, trong ngôi đền thờ Brahma có một chồng 64 cái
đĩa. Mỗi ngày, có một thầy tu di chuyển một đĩa. Đến khi hết đĩa thì đó là ngày tận thế.
Nhö seõ chæ ra sau naøy vôùi choàng goàm n ñóa caàn 2n- 1 laàn chuyeån cô baûn (chuyeån 1 ñóa ). 2n
Giaû söû thôøi gian ñeå chuyeån 1 ñæa laø t giaây thì thôøi gian ñeå chuyeån xong choàng 64 ñóa seõ laø:
T = ( 264-1 ) * t giaây = 11.84*1019*t giaây
Vôùi t = 1/100 giaây thì T =5.8*109 naêm = 5.8 tyû naêm.
Ta coù theå tìm thaáy giaûi thuaät (daõy caùc thao taùc cô baûn ) cho baøi toaùn moät caùch deã daøng
öùng vôùi tröôøng hôïp choàng ñóa goàm 0, 1, 2, 3 ñóa . Vôùi choàng 4 ñóa giaûi thuaät baøi toaùn ñaõ
trôû neân phöùc taïp . Tuy nhieân giaûi thuaät cuûa baøi toaùn laïi ñöôïc tìm thaáy raát deã daøng nhanh
choùng khi ta khaùi quaùt soá ñóa laø n baát kyø vaø nhìn baøi toaùn baèng quan nieäm ñeä quy .
a) Thoâng soá hoùa baøi toaùn .
Xeùt baøi toaùn ôû möùc toång quaùt nhaát : chuyeån n (n>=0) ñóa töø coät X sang coät Z laáy coät Y laøm
trung gian .
Ta goïi giaûi thuaät giaûi baøi toaùn ôû möùc toång quaùt laø thuû tuïc THN(n ,X ,Y,Z) chöùa 4 thoâng soá
n,X,Y,Z ; n thuoäc taäp soá töï nhieân N (kieåu nguyeân khoâng daáu ); X ,Y,Z thuoäc taäp caùc kyù töï
(kieåu kyù töï ).
Baøi toaùn coå ôû treân seû ñöôïc thöïc hieän baèng lôøi goïi THN(64,A,B,C) .
Deã thaáy raèng : trong 4 thoâng soá cuûa baøi toaùn thì thoâng soá n laø thoâng soá quyeát ñònh ñoä phöùc
taïp cuûa baøi toaùn ( n caøng lôùn thì soá thao taùc chuyeån ñæa caøng nhieàu vaø thöù töï thöïc hieän
chuùng caøng khoù hình dung ) , n laø thoâng soá ñieàu khieån .
b) Tröôøng hôïp suy bieán vaø caùch giaûi .
Vôùi n =1 baøi toaùn toång quaùt suy bieán thaønh baøi toaùn ñôn giaûn THN (1,X,Y,Z) : tìm daõy
thao taùc ñeå chuyeån choàng 1 ñóa töø coät X sang coät Z laáy coät Y laøm trung gian . Giaûi thuaät
giaûi baøi toaùn THN (1,X,Y,Z) laø thöïc hieän chæ 1 thao taùc cô baûn : Chuyeån 1 ñóa töø X sang Z
( kyù hieäu laø Move (X , Z) ) . THN(1,X,Y,Z) ≡ { Move( X, Z ) }
Chuù yù : Hoaøn toaøn töông töï ta cuõng coù theå quan nieän tröôøng hôïp suy bieán laø tröôøng hôïp n=
0 töông öùng vôùi baøi toaùn THN(0,X,Y,Z) : chuyeån 0 ñóa töø X sang Z laáy Y laøm trung gian
maø giaûi thuaät töông öùng laø khoâng laøm gì caû ( thöïc hieän thao taùc roãng ) .
THN(0,X,Y,Z) ≡ {φ }
c) Phaân raõ baøi toaùn :
Ta coù theå phaàn raõ baøi toaùn TH N (k,X,Y,Z) : chuyeån k ñóa töø coät X sang coät Z laáy coät Y
laøm trung gian thaønh daõy tuaàn töï 3 coâng vieäc sau :
+ Chuyeån (k -1) ñóa töø coät X sang coät Y laáy coät Z laøm trung gian :
THN (k -1,X,Z,Y) (baøi toaùn THN vôùi n = k-1,X= X , Y = Z , Z = Y )
+ Chuyeån 1 ñóa töø coät X sang coät Z : Move ( X, Z ) (thao taùc cô baûn ).
+ Chuyeån (k - 1 ) ñóa töø coät Y sang coät Z laáy coät X laøm trung gian :
THN( k -1,Y,X,Z) ( baøi toaùn THN vôùi n = k-1 , X = Y , Y = X , Z = Z ) .
Vaäy giaûi thuaät trong tröôøng hôïp toång quaùt (n > 1) laø :
THN(n,X,Y,Z) ≡ {
THN (n -1,X,Z,Y) ;
Move ( X, Z ) ;
THN (n -1,Y,X,Z) ;
}
Vôùi n ñóa thì caàn bao nhieâu böôùc chuyeån 1 ñóa? Thöïc chaát trong thuû tuïc THN caùc leänh goïi
ñeä qui chæ nhaèm saép seáp trình töï caùc thao taùc chuyeån 1 ñóa
Soá laàn chuyeån 1 ñóa ñöôïc thöïc hieän laø ñaëc tröng cho ñoä phöùc taïp cuûa giaûi thuaät .
Vôùi n ñóa , goïi f(n) laø soá caùc thao taùc chuyeån _moät_ñóa .
Ta coù : f(0) = 0 .
f(1) =1 .
f(n) = 2f(n -1) + 1 vôùi n > 0
2 n-1 n
Do ño ù : f(n) = 1+ 2 + 2 + + 2 =2 -1
64 20
Ñeå chuyeån 64 ñóa caàn 2 - 1 böôùc hay xaáp xæ 10 böôùc . Caàn khoaûng 10 trieäu naêm vôùi
moät maùy tính nhanh nhaát hieän nay ñeå laøm vieäc naøy .