Bài giảng Ngôn ngữ lập trình - Bài 2: Các cấu trúc điều khiển, mảng và con trỏ - Lê Nguyễn Tuấn Thành

Câu lệnh phức hợp

 Mỗi nhánh trong if-else ở slide trước chỉ có một câu lệnh

 Để ghép nhiều câu lệnh trong một nhánh, sử dụng { }.

Tập lệnh khi đó được gọi là một khối (block)

 Ví dụ:

if (myScore > yourScore)

{

cout < "i="">

wager = wager + 100;

}

else

{

cout < "i="" wish="" these="" were="" golf="">

wager = 0;

}Một vài lưu ý

 Toán tử “=” khác toán tử “==” như thế nào?

 “=” dùng để gán giá trị cho các biến

 “==” dùng để so sánh hai biểu thức

 Mệnh đề else có bắt buộc không?

 Ví dụ:

if (sales >= minimum)

salary = salary + bonus;

cout < "salary="%" "=""><>

pdf 81 trang kimcuc 7440
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Ngôn ngữ lập trình - Bài 2: Các cấu trúc điều khiển, mảng và con trỏ - Lê Nguyễn Tuấn Thành", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: Bài giảng Ngôn ngữ lập trình - Bài 2: Các cấu trúc điều khiển, mảng và con trỏ - Lê Nguyễn Tuấn Thành

Bài giảng Ngôn ngữ lập trình - Bài 2: Các cấu trúc điều khiển, mảng và con trỏ - Lê Nguyễn Tuấn Thành
Ngôn ngữ lập trình 
Bài 2: 
Các cấu trúc điều khiển, 
mảng và con trỏ 
Giảng viên: Lê Nguyễn Tuấn Thành 
Email: thanhlnt@tlu.edu.vn 
Bộ Môn Công Nghệ Phần Mềm – Khoa CNTT 
Trường Đại Học Thủy Lợi 
Nội dung 
2 
1. Cấu trúc rẽ nhánh 
2. Cấu trúc lặp 
3. Mảng (Array) 
4. Con trỏ (Pointer) 
Bài giảng có sử dụng hình vẽ trong cuốn sách “Absolute C++. W. Savitch, Addison Wesley, 2002” 
1. CẤU TRÚC RẼ NHÁNH 
1.1. Cấu trúc rẽ nhánh với if-else 
4 
 Mục đích 
 Diễn đạt sự lựa chọn một trong nhiều nhánh, phụ thuộc vào 
giá trị của câu điều kiện 
 Cú pháp: 
 if () 
else 
 Ví dụ: 
 if (hrs > 40) 
 grossPay = rate*40 + 1.5*rate*(hrs-40); 
else 
 grossPay = rate*hrs; 
Câu lệnh phức hợp 
5 
 Mỗi nhánh trong if-else ở slide trước chỉ có một câu lệnh 
 Để ghép nhiều câu lệnh trong một nhánh, sử dụng { }. 
Tập lệnh khi đó được gọi là một khối (block) 
 Ví dụ: 
 if (myScore > yourScore) 
{ 
 cout << "I win!\n"; 
 wager = wager + 100; 
} 
else 
{ 
 cout << "I wish these were golf scores.\n"; 
 wager = 0; 
} 
Một vài lưu ý 
6 
 Toán tử “=” khác toán tử “==” như thế nào? 
 “=” dùng để gán giá trị cho các biến 
 “==” dùng để so sánh hai biểu thức 
 Mệnh đề else có bắt buộc không? 
 Ví dụ: 
 if (sales >= minimum) 
 salary = salary + bonus; 
cout << "Salary = %" << salary; 
Câu lệnh lồng nhau (nested) 
7 
 Chúng ta có thể lồng một cặp if-else trong một nhánh 
của cặp if-else khác 
 Ví dụ: 
 if (speed > 55) 
 if (speed > 80) 
 cout << "You’re really speeding!"; 
 else 
 cout << "You’re speeding."; 
Đa rẽ nhánh (if - else if - else) 
8 
Bài tập với cấu trúc rẽ nhánh if-else 
9 
Bài 1: Viết một chương trình C++ để nhắc người dùng 
nhập 3 số nguyên và tìm giá trị lớn nhất. 
Bài 2: Nhập vào một số nguyên tương ứng với một tháng 
trong năm và in ra màn hình số ngày trong tháng đó. 
 ví dụ: 
 input: 1 
 output: tháng 1 có 31 ngày 
Câu hỏi: 
 Nếu có quá nhiều nhánh rẽ thì ngoài sử dụng if-else, 
C++ còn cung cấp cách nào nữa không? 
1.2. Rẽ nhánh với lệnh witch (1/2) 
10 
Rẽ nhánh với lệnh witch (2/2) 
11 
Lệnh switch: câu hỏi 
12 
switch (aChar) 
{ 
 case "A": 
case "a": 
 cout << "Excellent: you got an "A"!\n"; 
 break; 
case "B": 
case "b": 
 cout << "Good: you got a "B"!\n"; 
 break; 
} 
 Nếu giá trị của aChar là “A” hoặc “B” thì kết quả in ra là gì ? 
Toán tử điều kiện 
(Conditional/ternary operator) 
13 
 Thay thế cho mệnh đề if-else đơn giản với hai toán tử 
“?” và “:” 
 Cấu trúc: 
 if (condition) 
 if_true; 
else 
 if_false; 
 Có thể thay bằng một lệnh 
 (condition) ? (if_true) : (if_false) 
Bài tập: viết hàm trả lại số lớn nhất trong hai số 
 #define MAX(a, b) ((a > b) ? a : b) 
 #define MIN(a, b) ((a < b) ? a : b) 
 Giá trị của a trong câu lệnh sau (với x > 0) a = x ? : y; 
2. CẤU TRÚC LẶP 
2. Cấu trúc lặp (loop) 
15 
Các cấu trúc lặp trong C++ 
1. While 
2. do-while 
3. for 
Cấu trúc lặp với while 
16 
int count = 0; // Initialization 
while (++count < 3) // Loop Condition 
{ 
 cout << "Hi "; // Loop Body 
} 
Chuỗi “Hi” sẽ được in ra màn hình bao nhiêu lần? 
Cấu trúc lặp với do-while (1/2) 
17 
Cấu trúc lặp với do-while (2/2) 
18 
 int count = 0; // Initialization 
do 
{ 
 cout << "Hi "; // Loop Body 
} while (++count < 3); // Loop Condition 
Chuỗi “Hi” sẽ được in ra màn hình bao nhiêu lần? 
So sánh while và do-while 
19 
 Khá giống nhau, nhưng một khác biệt quan trọng 
 while: kiểm tra điều kiện logic TRƯỚC KHI thực thi lệnh 
bên trong 
 do-while: kiểm tra điều kiện logic SAU KHI đã thực thi lệnh 
bên trong 
Cấu trúc lặp với for 
20 
 Cú pháp 
for (Init_Action; Bool_Expression; Update_Action) 
 Body_Statement 
 Ví dụ: 
for (count=0; count<3; count++) 
{ 
 cout << "Hi "; // Loop Body 
} 
 Chuỗi “Hi” sẽ được in ra màn hình bao nhiêu lần? 
 Điều gì xảy ra với câu lệnh sau: 
 for ( ; ;) { cout << “Hi”; } 
Một vài chú ý với cấu trúc lặp (1/2) 
21 
 Biểu thức điều kiện của vòng lặp có thể là BẤT KỲ biểu 
thức logic nào 
 Ví dụ: 
 while (count<3 && done!=0) 
{ 
 // Do something 
} 
 ----- 
 for (index=0; index<10 && entry!=99) 
{ 
 // Do something 
} 
Một vài chú ý với cấu trúc lặp (2/2) 
22 
 Vòng lặp vô hạn 
 Ví dụ: 
 while (1) 
{ 
 cout << "Hello "; 
} 
 ---- 
 for ( ; ;) 
 { 
 cout << “Hello”; 
 } 
Lệnh break và continue 
23 
 Lệnh break: ép buộc thoát khỏi vòng lặp ngay lập tức 
 Lệnh continue: bỏ qua phần còn lại trong thân vòng lặp 
(loop body) 
 Hai lệnh này vi phạm luồng chạy tự nhiên => chỉ dùng 
khi thật cần thiết 
Minh họa lệnh continue 
24 
Cấu trúc lặp lồng nhau 
25 
 Nhớ lại: bất kỳ mệnh đề hợp lệ nào trong C++ có thể được 
đặt bên trong vòng lặp 
 Có thể dùng “{ }” hoặc thụt lề (indent) để biểu diễn vòng lặp 
lồng nhau (nested loops) 
 Ví dụ: 
 for (outer=0; outer<5; outer++) 
 for (inner=7; inner>2; inner--) 
 cout << outer << inner; 
 hoặc 
 for (outer=0; outer<5; outer++) 
 { 
 for (inner=7; inner>2; inner--) 
 { 
 cout << outer << inner; 
 } 
 } 
Bài tập với cấu trúc lặp 
26 
 Viết chương trình tìm TẤT CẢ các số nguyên tố nhỏ 
hơn một số nguyên dương nhập vào từ bàn phím 
 Input: N – số nguyên dương 
 Output: in ra tất cả các số nguyên tố nhỏ hơn N 
3. MẢNG 
3. Mảng (Array) 
28 
 Giới thiệu về mảng 
 Mảng khai báo (declaring arrays) và mảng tham chiếu 
(referencing arrays) 
 Vòng lặp for và mảng 
 Mảng trong bộ nhớ 
 Mảng trong hàm 
 Sử dụng mảng như tham số của hàm hoặc giá trị trả lại 
 Lập trình với mảng 
 Tìm kiếm (searching), sắp xếp (sorting) 
 Mảng nhiều chiều (multidimensional arrays) 
3.1. Giới thiệu về mảng 
29 
 Định nghĩa: một tập giá trị có CÙNG KIỂU 
 Mảng là một cơ chế lưu trữ phổ biến 
 Được sử dụng như danh sách các phần tử: 
 Tránh khai báo nhiều biến đơn giản 
 Có thể thao tác danh sách như một thực thể (entity) 
Mảng khai báo 
30 
 Khai báo mảng là cấp phát một dải vùng nhớ (allocate 
memory) 
 Cấu trúc: Kiểu Tên_Mảng[Kích_Thước] 
 Ví dụ: int score[5]; 
 Khai báo một mảng gồm 5 số nguyên tên là “score” 
 Giống như khai báo 5 biến: int score[0], score[1], score[2], score[3], 
score[4]; 
 Số nguyên dương ở giữa hai dấu [ ] được gọi là chỉ số, 
nằm trong khoảng từ 0 đến (size-1) 
 Truy cập các phần tử trong mảng thông qua chỉ số. Ví dụ: 
cout << score[3]; 
Khởi tạo mảng 
31 
 Giống như các biến có thể được khởi tạo lúc khai báo. 
 Ví dụ: int price = 0; // 0 là giá trị khởi tạo 
 Khai báo mảng cũng như thế. 
 Ví dụ: int children[3] = {2, 12, 1}; tương đương 
 int children[3]; 
children[0] = 2; 
children[1] = 12; 
children[2] = 1; 
 Nếu số lượng giá trị nhỏ hơn kích thước mảng thì: 
 Khởi tạo giá trị từ đầu 
 Phần còn lại được gán trị 0 
 Nếu thiếu kích thước mảng (vd: int b[] = {5, 12, 11};) tự động 
khai báo mảng với kích thước dựa trên số lượng giá trị khởi tạo 
Vòng lặp for và mảng 
32 
 Vòng lặp đếm tự nhiên duyệt qua tất cả các phần tử của 
mảng 
 Ví dụ: 
 for(int i = 0; i < 5; i++) 
 cout << a[i] << “\t”; 
Bài tập (1/3) 
33 
 Viết một chương trình chấp nhận một mảng số 
nguyên score có tối đa 10 phần tử. Tìm phần tử lớn 
nhất của mảng và in ra khoảng cách từ mỗi phần tử 
đến phần tử lớn nhất. 
 Input: một mảng N phần tử ( 3 < N <=10) 
 Output: số lớn nhất của mảng này 
Bài tập (2/3) 
34 
Bài tập (3/3) 
35 
Lưu ý 
36 
 Phần tử đầu tiên có chỉ số là 0 
 Lỗi: Out of range, trình biên dịch không báo lỗi nhưng lúc 
chạy có thể sẽ dẫn đến kết quả sai ! 
 Dùng hằng số (constant) để khai báo kích thước mảng. Ví 
dụ: 
 const int NUMBER_OF_STUDENTS = 5; 
int score[NUMBER_OF_STUDENTS]; 
 Trong vòng lặp: 
 for (idx = 0; idx < NUMBER_OF_STUDENTS; idx++) 
{ 
 // Manipulate array 
} 
 lastIndex = (NUMBER_OF_STUDENTS – 1); 
Mảng trong bộ nhớ (1/2) 
37 
 Nhớ lại: các biến được cấp phát bộ nhớ với địa chỉ 
(address) xác định 
 Mảng khai báo cấp phát bộ nhớ cho toàn mảng theo 
kiểu tuần tự (sequentially-allocated) 
Mảng trong bộ nhớ (2/2) 
38 
Sử dụng mảng trong hàm 
39 
 Như tham số của hàm 
 Phần tử của mảng: giống như một biến đơn giản. Ví dụ: void 
myFunction(double par1); 
 int i; double n, a[10]; 
 myFunction(i); // i is converted to double 
myFunction(a[3]); // a[3] is double 
myFunction(n); // n is double 
 Toàn bộ mảng 
 Như giá trị trả lại của hàm (sẽ học sau) 
Truyền toàn bộ mảng vào hàm 
40 
int score[5], numberOfScores = 5; 
fillup(score, numberOfScores); 
Lưu ý: không có [ ] khi gọi hàm 
Mảng như tham số: cách hoạt đông? 
41 
 Điều gì thực sự xảy ra? 
 Xem mảng gồm 3 thành phần: 
 Địa chỉ của phần tử đầu tiên (arrName[0]) 
 Kiểu của các phần tử trong mảng 
 Kích thước của mảng 
 Chỉ thành phần thứ nhất được truyền vào hàm 
 Là địa chỉ của phần tử đầu tiên của mảng 
 Tương tự như truyền tham chiếu (pass-by-reference) 
Lưu ý 
42 
 Phải có tham số là kích thước của mảng 
 Không cần [ ] (brackets) khi gọi hàm 
 Trong hàm có thể thay đổi giá trị của mảng nên đôi khi 
phải bảo vệ tránh sự thay đổi này bằng cách dùng const 
Ứng dụng của mảng 
43 
 Tìm kiếm (searching) 
 Sắp xếp (sorting) 
Bài tập 
44 
 Viết một chương trình chấp nhận một mảng số 
nguyên có tối đa 200 phần tử. 
 Hiển thị các phần tử của mảng, sắp xếp mảng theo 
chiều tăng dần và hiển thị mảng sau khi sắp xếp ra 
màn hình. 
 Input: mảng số nguyên N phần tử 
 Output: in ra mảng này sau khi sắp xếp 
Mảng nhiều chiều 
45 
 Mảng có thể có nhiều hơn 1 chỉ số. 
 Ví dụ: char page[30][100]; 
 Truy cập vào từng phần tử page[i][j] 
Bài tập 
46 
 Bài 1: Cho một mảng hai chiều số nguyên dương với tối 
đa 100 hàng và 100 cột, tính tổng các phần tử chẵn trong 
mảng và hiển thị ra màn hình. 
 Input: ma trận số nguyên dương kích thước tối đa 100x100 
 Output: tổng của các phần tử chẵn trong ma trận 
 Bài 2: Cho một mảng hai chiều số nguyên với đối đa 100 
hàng và 100 cột, xét xem mảng có đối xứng qua đường 
chéo chính hay không ? 
4. CON TRỎ 
4. CON TRỎ (POINTER) 
48 
 Con trỏ 
 Biến con trỏ (pointer variables) 
 Quản lý bộ nhớ 
 Mảng động (dynamic arrays) 
 Tạo và sử dụng mảng động 
 Phép tính với con trỏ (pointer arithmetic) 
Định nghĩa Con trỏ 
49 
 Con trỏ là địa chỉ trong bộ nhớ của một biến 
 Tham số tham chiếu (call-by-reference) của hàm 
chính là con trỏ: địa chỉ của tham số được 
truyền vào trong hàm. 
Biến con trỏ 
50 
 Biến con trỏ là biến kiểu con trỏ (không phải kiểu int, 
double, ) dùng để trỏ đến một vùng nhớ đã được khởi 
tạo. 
 Cú pháp khai báo: Kiểu *Biến_Con_Trỏ; 
 Ví dụ: 
 double *p; // biến p được khai báo là một biến có thể trỏ đến bất kỳ 
một vùng nhớ kiểu double (mà không phải kiểu int hay float) 
 int *p1, *p2, v1, v2; 
Địa chỉ và số 
(Addresses & numbers) 
51 
 Con trỏ là một địa chỉ 
 Địa chỉ (trong vùng nhớ) là một số nguyên 
 NHƯNG: Con trỏ KHÔNG PHẢI là một số nguyên 
!!! 
 C++ ép buộc con trỏ được sử dụng như một địa chỉ 
 Không được dùng như một số nguyên 
 Mặc dù nó giống như một số nguyên 
Toán tử & và * (1/2) 
52 
 Toán tử & 
 Khi đặt trước một biến sẽ trả về địa chỉ của biến đó (cũng 
được xem là một con trỏ trỏ đến biến). 
 Thường được gọi là toán tử địa chỉ ("address of" operator) 
 p = &v; nghĩa là con trỏ p được gán bằng địa chỉ của biến v 
hay con trỏ p trỏ đến biến v 
 Toán tử * 
 Khi đặt trước một biến con trỏ sẽ dùng để chỉ định biến mà 
con trỏ đấy đang trỏ đến. 
 Toán tử * với cách dùng như trên được gọi là toán tử giải 
tham chiếu (dereference operator) 
 *p nghĩa là “lấy dữ liệu mà p đang trỏ tới” 
Toán tử & và * (2/2) 
53 
 Kết quả in ra của chương trình sau?: 
int *p1, v1 = 0; 
p1 = &v1; // biến con trỏ p1 được gán cho địa chỉ vùng nhớ của 
biến v1 
*p1 = 42; // giải tham chiếu p1 và gán 42 
cout << v1 << “\t”; 
cout << *p1 << endl; 
 Có 2 cách để tham chiếu đến biến v1: 
 Sử dụng chính bản thân biến v1 
 Thông qua con trỏ p1 
Gán con trỏ 
(Pointer assignments) 
54 
 int *p1, *p2; 
p2 = p1 khác *p2 = *p1 như thế nào? 
 p2 = p1 
 thay đổi địa chỉ vùng nhớ của con trỏ p2, trỏ tới nơi mà p1 
đang trỏ tới. p2, p1 lúc này trỏ tới cùng 1 địa chỉ. 
 *p2 = *p1 
 gán giá trị của biến mà p2 đang trỏ tới bằng giá trị của biến 
mà p1 đang trỏ tới. p2, p1 vẫn trỏ tới hai địa chỉ khác nhau 
nhưng giá trị tại hai địa chỉ này giờ bằng nhau 
Minh họa gán con trỏ 
55 
Toán tử new 
56 
 Do con trỏ có thể dùng để tham chiếu đến một biến => 
Không cần thiết phải có một định danh (không nhất thiết 
phải có tên) 
 Có thể cấp phát động các biến bằng toán tử new, sẽ tạo ra 
một biến 
 Không có định danh tham chiếu đến nó 
 Chỉ là một con trỏ 
 Ví dụ: int *p; p = new int; 
 Tạo ra một biến mới vô danh (không được đặt tên) và gán con trỏ 
p trỏ tới biến đó 
 Có thể truy cập biến đó thông qua *p và sử dụng như một biến 
thông thường 
 int *n; n = new int(17); //Khởi tạo *n to 17 
57 
M
IN
H
 H
Ọ
A
 T
O
Á
N
 T
Ử
 N
E
W
Chương trình với new (1/2) 
58 
Chương trình với new (2/2) 
59 
Con trỏ và hàm 
60 
 Con trỏ có thể được sử dụng: 
 như tham số của hàm 
 như giá trị trả lại của hàm 
 int* findOtherPointer(int* p); 
 Hàm này khai báo: 
 Một tham số kiểu con trỏ có thể trỏ tới biến kiểu int 
 Giá trị trả lại là một kiểu con trỏ có thể trỏ tới biến kiểu 
int 
Quản lý bộ nhớ 
(Memory management) 
61 
 Heap (đống) 
 Cũng được gọi là “freestore” 
 Được dành riêng cho các biến cấp phát động (dynamically-
allocated) với toán tử new 
 Tất cả các biến được cấp phát động sẽ sử dụng bộ nhớ trong 
freestore (heap) => nếu có quá nhiều biến động, có thể dẫn 
đến hết bộ nhớ freestore 
 Thao tác cấp phát động (với toán tử new) có thể không 
thực hiện được nếu freestore bị đầy 
Kiểm tra kết quả cấp phát bộ nhớ (1/2) 
62 
 Với những trình biên dịch cũ, thực hiện 2 bước 
1. Kiểm tra liệu giá trị null có được trả về sau khi gọi new hay 
không 
 int *p; 
p = new int; 
if (p == NULL) 
{ 
 cout << "Error: Insufficient memory.\n"; 
 exit(1); 
} 
2. Nếu cấp phát thành công thì mới tiếp tục chương trình 
Kiểm tra kết quả cấp phát bộ nhớ (2/2) 
63 
 Với những trình biên dịch mới, nếu hoạt 
động cấp phát với new bị lỗi: 
 Chương trình sẽ tự động ngừng ngay lập tức 
 Thông báo lỗi 
Toán tử delete 
64 
 Toán tử delete: giải phóng (de-allocate) vùng nhớ động đang 
được trỏ bởi một biến con trỏ. 
 Sử dụng khi biến con trỏ không còn cần thiết 
 Trả vùng nhớ này về freestore, để sau đó có thể được dùng để cấp 
phát cho biến khác 
 VD: delete p; // giải phóng vùng nhớ được trỏ bởi con trỏ p 
 int *p; 
p = new int(5); 
 // Một vài xử lý 
delete p; 
Con trỏ treo 
(Dangling pointers) 
65 
 delete p; giải phóng vùng nhớ động nhưng p vẫn trỏ 
tới đó ! 
 Dẫn đến con trỏ treo (dangling pointer) 
 Điều gì xảy ra khi gọi *p sau đó? 
 Tránh con trỏ treo 
 Nên gán con trỏ bằng null sau khi delete p 
 delete p; 
p = NULL; 
Biến động và Biến tự động 
(Dynamic vs automatic variables) 
66 
 Biến động (dynamic variables) 
 Được tạo với toán tử new 
 Được tạo và hủy (destroy) trong lúc chạy chương trình 
 Biến địa phương (local variables) 
 Được khai báo bên trong định nghĩa hàm 
 Không phải là biến động (not dynamic) 
 Được tạo khi hàm được gọi 
 Bị hủy khi lời gọi hàm hoàn tất 
 Thường được gọi là các biến tự động (automatic variables). 
Chương trình sẽ kiểm soát các biến này cho bạn 
Định nghĩa lại tên cho kiểu con trỏ 
67 
 Giúp bạn tránh việc thêm dấu “*” mỗi khi khai báo 
con trỏ 
 typedef int* IntPtr; 
 Định nghĩa một kiểu biệt danh mới (alias) 
 IntPtr p; tương đương với int *p; 
Tham số con trỏ call-by-value (1/3) 
68 
Tham số con trỏ call-by-value (2/3) 
69 
Tham số con trỏ call-by-value (3/3) 
70 
Mảng động 
(Dynamic arrays) 
 Biến kiểu mảng thực sự là một kiểu con trỏ 
 Mảng chuẩn với kích thước cố định 
 Mảng động: 
 Kích thước của mảng không được xác định khi lập trình 
 Được quyết định trong lúc chạy chương trình 
Biến kiểu mảng (1/2) 
(Array variables) 
72 
 Mảng được lưu trữ trong bộ nhớ theo địa chỉ tuần 
tự 
 Biến mảng tham chiếu đến giá trị đầu tiên của mảng 
 Do đó biến mảng cũng là một kiểu con trỏ 
 Ví dụ: 
 int a[10]; 
int * p; 
 a và p đều là con trỏ 
Biến kiểu mảng (2/2) 
(Array variables) 
73 
 a và p đều là con trỏ => có thể thực hiện việc gán 
 p = a; // Hợp lệ. p bây giờ trỏ tới nơi mà a đang trỏ (tới vị 
trí đầu tiên của mảng a) 
 a= p; // KHÔNG HỢP LỆ. Do con trỏ mảng là một CON 
TRỎ HẰNG SỐ (constant pointer) 
 a có kiểu const int* 
 Mảng đã được cấp phát trong bộ nhớ 
 Biến a PHẢI LUÔN trỏ tới đó! Không thể thay đổi! 
 Đối lập với con trỏ bình thường: có thể thay đổi địa 
chỉ trỏ tới 
Mảng động 
74 
 Những hạn chế của mảng chuẩn 
 Phải khai báo kích thước trước, ước lượng kích thước tối đa 
cần thiết 
 Có thể lãng phí bộ nhớ 
 Mảng động 
 Có thể co giãn khi cần thiết 
 Tạo mảng động với toán tử new. Cấp phát động với biến 
con trỏ 
 typedef double * DoublePtr; 
DoublePtr d; 
d = new double[10]; // Tạo một biến mảng d được cấp phát động với 
10 phần tử kiểu double 
Xóa mảng động 
75 
 Được cấp phát động lúc chạy (run-time), vì thế nên 
được hủy lúc chạy 
 d = new double[10]; 
 //Xử lý 
delete [] d; 
 Giải phóng tất cả bộ nhớ của mảng động 
 Dấu ngoặc vuông (brackets) [] ám chỉ đây là một mảng 
 Tuy nhiên d vẫn chỉ tới vùng nhớ vừa được giải phóng => 
nên đặt lại d = NULL; 
Phép tính với con trỏ 
(Pointer arithmetic) 
76 
 Có thể thực hiện phép tính trên con trỏ: tính toán với 
các địa chỉ 
 typedef double* DoublePtr; 
DoublePtr d; 
d = new double[10]; 
 d chứa địa chỉ của d[0] 
 d + 1 là địa chỉ của d[1] 
 d + 2 là địa chỉ của d[2] 
 for (int i = 0; i < arraySize; i++) 
 cout << *(d + i) << " "; 
 Chỉ thực hiện phép + - trên con trỏ (không thực hiện 
các phép tính * / với con trỏ) 
Con trỏ động nhiều chiều 
(Multidimensional dynamic arrays) 
77 
 Nhớ lại: Mảng của Mảng 
 typedef int* IntArrayPtr; 
IntArrayPtr *m = new IntArrayPtr[3]; 
 for (int i = 0; i < 3; i++) 
 m[i] = new int[4]; 
 Tạo mảng của 3 con trỏ 
 Cấp phát cho mỗi con trỏ một mảng 4 phần tử kiểu int 
 Kết quả: một mảng động 3x4 
Tóm tắt (1/3) 
78 
 Mệnh đề rẽ nhánh: if-else, switch 
 Vòng lặp: 
 while, 
 do-while: luôn thực hiện phần thân vòng lặp ít nhất 1 lần 
 for 
 Vòng lặp có thể bị ngắt quãng đột ngột với hai lệnh: 
break, continue 
Tóm tắt (2/3) 
79 
 Mảng là tập hợp của dữ liệu cùng kiểu 
 Phần tử trong mảng được sử dụng như những biến 
đơn giản khác 
 Vòng lặp for là cách tự nhiên để duyệt mảng 
 Chú ý lỗi out-of-range 
 Các phần tử trong mảng được lưu trữ tuần tự 
 Mảng nhiều chiều 
Tóm tắt (3/3) 
80 
 Con trỏ là một địa chỉ trong bộ nhớ. Cung cấp một 
tham chiếu không trực tiếp đến các biến 
 Biến động: được tạo ra và hủy trong lúc chạy 
chương trình 
 Freestore: bộ nhớ dành cho các biến động 
 Mảng cấp phát động: kích thước được quyết định 
khi chạy chương trình 
Tham khảo 
81 
 Giáo trình chính: W. Savitch, Absolute C++, Addison 
Wesley, 2002 
 Tham khảo: 
 A. Ford and T. Teorey, Practical Debugging in C++, Prentice Hall, 
2002 
 Nguyễn Thanh Thủy, Kĩ thuật lập trình C++, NXB Khoa học và 
Kĩ Thuật, 2006 

File đính kèm:

  • pdfbai_giang_ngon_ngu_lap_trinh_bai_2_cac_cau_truc_dieu_khien_m.pdf