1
Ngôn ngữ Lập trình C++
Chương I - Giới thiệu ngôn ngữ C++
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
2
Nội dung chính
•
•
•
•
•
Mã máy, Hợp ngữ, và ngôn ngữ bậc cao
Một số ngôn ngữ lập trình bậc cao
Lịch sử C và C++
Hệ thống và môi trường lập trình C++
Giới thiệu về C++
–
–
–
–
–
ví dụ về chương trình C++ đơn giản
khái niệm biến
vào ra dữ liệu
các phép toán số học
ra quyết định - các phép toán quan hệ
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
3
1.1 Mã máy, Hợp ngữ, và Ngôn ngữ bậc cao
1. Mã máy (machine language)
–
–
–
–
–
–
Là ngôn ngữ duy nhất máy tính trực tiếp hiểu được, là “ngôn
ngữ tự nhiên” của máy tính
Được định nghĩa bởi thiết kế phần cứng, phụ thuộc phần cứng
Gồm các chuỗi số, => chuỗi các số 0 và 1
Dùng để lệnh cho máy tính thực hiện các thao tác cơ bản, mỗi
lần một thao tác
Nặng nề, khó đọc đối với con người
Ví dụ:
+1300042774
+1400593419
+1200274027
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
4
1.1 Mã máy, Hợp ngữ, và Ngôn ngữ bậc cao
2. Hợp ngữ (assembly)
–
–
–
Những từ viết tắt kiểu tiếng Anh, đại diện cho các thao tác
cơ bản của máy tính
Dễ hiểu hơn đối với con người
Máy tính không hiểu
•
–
Cần đến các chương trình dịch hợp ngữ (assembler) để
chuyển từ hợp ngữ sang mã máy
Ví dụ:
LOAD
BASEPAY
ADD
OVERPAY
STORE GROSSPAY
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
5
1.1 Mã máy, Hợp ngữ, và Ngôn ngữ bậc cao
3. Các ngôn ngữ bậc cao (high-level languages)
–
–
–
Tương tự với tiếng Anh, sử dụng các ký hiện toán học thông dụng
Một lệnh thực hiện được một công việc mà hợp ngữ cần nhiều
lệnh để thực hiện được.
Ví dụ:
grossPay = basePay + overTimePay
–
–
Các chương trình dịch (compiler) để chuyển sang mã máy
Các chương trình thông dịch (interpreter program) trực tiếp chạy
các chương trình viết bằng ngôn ngữ bậc cao.
•
•
Chậm hơn
Thuận tiện khi đang phát triển chương trình
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
6
1.2 Một số ngôn ngữ lập trình bậc cao
•
•
•
•
FORTRAN
– FORmula TRANslator (1954-1957: IBM)
– Tính toán toán học phức tạp, thường dùng trong các ứng dụng khoa học và kỹ
thuật
COBOL
– COmmon Business Oriented Language (1959)
– Thao tác chính xác và hiệu quả đối với các khối lượng dữ liệu lớn,
• Các ứng dụng thương mại
Pascal
– Tác giả: Niklaus Wirth
– Dùng trong trường học.
Java
– Tác giả: Sun Microsystems (1991)
– Ngôn ngữ điều khiển theo sự kiện (event-driven), hoàn toàn hướng đối tượng,
tính khả chuyển (portable) rất cao.
– Các trang Web với nội dung tương tác động
– Phát triển các ứng dụng quy mô lớn
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
7
1.2 Một số ngôn ngữ lập trình bậc cao
• BASIC
– Beginner’s All-Purpose Symbolic Instruction Code
– Từ giữa những năm1960
• Visual Basic
– GUI, xử lý sự kiện (event handling), sử dụng Win32 API, lập trình hướng
đối tượng (object-oriented programming), bắt lỗi (error handling)
• Visual C++
– C++ của Microsoft và mở rộng
• Thư viện của Microsoft (Microsoft Foundation Classes -MFC)
• Thư viện chung
– GUI, đồ họa, lập trình mạng, đa luồng (multithreading), …
– Dùng chung giữa Visual Basic, Visual C++, C#
• C#
– Bắt nguồn từ C, C++ và Java
– Ngôn ngữ điều khiển theo sự kiện (event-driven), hoàn toàn hướng đối
tượng, ngôn ngữ lập trình trực quan (visual programming language)
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
8
1.3 Lịch sử ngôn ngữ C và C++
• C
–
–
–
–
–
Dennis Ritchie (Bell Laboratories)
Là ngôn ngữ phát triển của hệ điều hành UNIX
Độc lập phần cứng => có thể viết các chương trình khả chuyển
Chuẩn hóa năm 1990 – ANSI C
Kernighan & Ritchie “The C Programming Language”, 2nd, 1988
• C++
–
–
–
–
Là mở rộng của C
Đầu những năm 1980: Bjarne Stroustrup (phòng thí nghiệm Bell)
Cung cấp khả năng lập trình hướng đối tượng.
Ngôn ngữ lai
• Lập trình cấu trúc kiểu C
• Lập trình hướng đối tượng
• Cả hai
• Có cần biết C trước khi học C++?
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
9
1.4 Hệ thống C++
– Môi trường phát triển chương trình (Program-development
environment)
– Ngôn ngữ
– Thư viện chuẩn (C++ Standard Library)
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
10
1.4 Môi trường cơ bản cho lập trình C++
Các giai đoạn của
chương trình C++:
1. Soạn thảo - Edit
2. Tiền xử lý - Preprocess
3. Biên dịch - Compile
4. Liên kết - Link
Disk
Chương trình được viết
bằng chương trình soạn
thảo và lưu trên đĩa.
Preprocessor
Disk
Chương trình tiền xử lý
thực hiện xử lý mã nguồn
Compiler
Disk
Linker
Disk
Editor
Trình biên dịch tạo object
code và lưu trên đĩa.
Primary
Memory
Trình kết nối kết hợp
objectcode với các thư viện,
tạo file chạy được và lưu
lên đĩa
Loader
Disk
5. Nạp - Load
Trình nạp nạp
trình vào bộ nhớ
chương
..
..
..
Primary
Memory
CPU
CPU nhận từng lệnh, thực
thi lệnh đó, có thể lưu các
giá trị dữ liệu mới khi
chương trình chạy.
6. Chạy - Execute
..
..
..
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
11
1.4 Môi trường cơ bản cho lập trình C++
• Soạn thảo
– File có kiểu mở rộng *.cpp, *cxx, *.cc, *.C
– Unix/Linux:
vi, emacs
– MS.Windows: các môi trường soạn thảo tích hợp: Devcpp, Microssoft Visual C++, Borland C++ Builder, …
• Chú ý mức độ hỗ trợ C++ chuẩn – ANSI/ISO C++
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
12
Ví dụ 1: Hello World!
1
2
3
4
5
6
7
8
9
10
11
12
/* A first program in C++.
Print a line of text to standard output */
#include <iostream>
hàm main trả về một giá trị kiểu số nguyên.
Chú thích
// function main begins program execution
int main()
Định hướng tiền xử lý (preprocessor directive) để khai
{
báo sử dụng thư viện ra/vào chuẩn <iostream>.
std::cout << “Hello World!\n";
return 0;
// indicate that program ended successfully
Viết một dòng ra output
} // end function main
chuẩn (màn hình)
hàm main xuất hiện đúng
một lần trong mỗi chương
trình C++.
Ngoặc trái { bắt đầu thân hàm.
Hello World!
Tương ứng, ngoặc phải }
kết thúc thân hàm.
Các lệnh kết thúc bằng dấu
chấm phảy;
Từ khóa return là một cách
thoát khỏi hàm; giá trị 0 được
trả về có nghĩa chương trình
kết thúc thành công.
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
13
1.5 Các thành phần cơ bản
Chú thích và định hướng tiền xử lý
• Chú thích - comment
// A first program in C++.
–
–
–
–
Làm tài liệu cho các chương trình
Làm chương trình dễ đọc dễ hiểu hơn
được trình biên dịch (compiler) bỏ qua
1 dòng chú thích bắt đầu với //
• Các định hướng tiền xử lý - directive
#include <iostream>
– Được xử lý ngay trước khi biên dịch
– Bắt đầu bằng #
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
14
Ví dụ 1 - mở rộng 1
1
2
3
// Fig. 1.4: fig01_04.cpp
// Printing a line with multiple statements.
#include <iostream>
4
5
6
7
8
9
// function main begins program execution
int main()
{
std::cout << "Welcome ";
std::cout << "to C++!\n";
10
11
12
13
return 0;
fig01_04.cpp
Nhiều dòng lệnh tạo output
trên một dòng.
// indicate that program ended successfully
} // end function main
Welcome to C++!
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
15
Ví dụ 1 - mở rộng 2
1
2
3
// Fig. 1.5: fig01_05.cpp
// Printing multiple lines with a single statement
#include <iostream>
4
5
6
7
8
// function main begins program execution Dùng ký tự dòng mới \n để in
trên nhiều dòng.
int main()
{
std::cout << "Welcome\nto\n\nC++!\n";
9
10
11
12
return 0;
// indicate that program ended successfully
} // end function main
Welcome
to
C++!
©2004 Trần Minh Châu.
FOTECH. VNU.
16
Ví dụ 2:
Chương trình tính tổng hai số nguyên
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Enter first integer
45
Enter second integer
72
Sum is 117
// Fig. 1.6: fig01_06.cpp
// Addition program.
#include <iostream>
// function main begins program execution
int main()
Khai báo các biến nguyên.
{
int integer1; // first number to be input by user
int integer2; // second number to be input by user
Nhập
một
số nguyên
từ input
int sum;
// variable in which
sum
will
be stored
chuẩn,
ghi vào biến integer1
std::cout << "Enter first integer\n";
std::cin >> integer1;
// prompt
endl
// read an integer
cho kết quả là một dòng
trống.
std::cout << "Enter second integer\n"; // prompt
std::cin >> integer2;
integer
Tính toán có //
thểread
đượcan
thực
hiện trong
lệnh output: Thay cho các
dòng 18 và 20:
sum = integer1 + integer2; cout
// assign
result
is " to
<< sum
integer1 + integer2 << endl;
<< "Sum
std::cout << "Sum is " << sum << endl; // print sum
return 0;
// indicate that program ended successfully
} // end function main
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
17
1.5 Các thành phần cơ bản
Biến chương trình
• Biến - variable: Một nơi trong bộ nhớ, có thể lưu các giá trị
thuộc một kiểu nào đó.
• Các kiểu dữ liệu cơ bản
•
•
•
•
int - số nguyên
char – ký tự
double - số chấm động
bool – các giá trị logic true hoặc false
• Các biến phải được khai báo tên và kiểu trước khi sử dụng
int integer1;
int integer2;
int sum;
• Có thể khai báo nhiều biến thuộc cùng một kiểu dữ liệu
trong một dòng khai báo biến.
int integer1, integer2, sum;
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
18
1.5 Biến chương trình
• Quy tắc đặt tên biến
• Chuỗi ký tự (chữ cái a..z, A..Z, chữ số 0..9, dấu gạch dưới _ )
• Không được bắt đầu bằng chữ số
• Phân biệt chữ hoa chữ thường.
Ví dụ:
Tên biến hợp lệ: h678h_m2, _adh2, taxPayment…
Không hợp lệ: áadàn, so chia, 2n, …
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
19
1.5 Biến chương trình
• Các khái niệm về bộ nhớ (memory)
–
–
–
–
Mỗi biến tương ứng với một khu trong bộ nhớ máy tính
Mỗi biến có tên, kiểu, kích thước, và giá trị
Khi biến được gán một giá trị mới, giá trị cũ bị ghi đè
Đọc giá trị của các biến trong bộ nhớ không làm thay đổi các
biến trong bộ nhớ.
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
20
1.5 Biến chương trình
std::cin >> integer1;
integer1
45
integer1
45
integer2
72
integer1
45
integer2
72
– giả sử người dùng nhập 45
std::cin >> integer2;
– giả sử người dùng nhập 72
sum = integer1 + integer2;
sum
117
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
21
1.6 Vào ra dữ liệu
Các đối tượng vào/ra cơ bản
• cin
• dòng dữ liệu vào chuẩn - Standard input stream
• thường là từ bàn phím
• cout
• dòng dữ liệu ra chuẩn - Standard output stream
• thường là màn hình máy tính
• cerr
• dòng báo lỗi chuẩn - Standard error stream
• hiện các thông báo lỗi
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
22
1.6 Vào ra dữ liệu
In dòng văn bản ra màn hình
std::cout << "Enter first integer\n";
•
// prompt
Đối tượng ra chuẩn - Standard output stream object
– std::cout
– “nối” với màn hình
– <<
• toán tử chèn vào dòng dữ liệu ra – stream insert operator
• giá trị bên phải (right operand) được chèn vào dòng dữ liệu ra
•
Không gian tên - Namespace
– std:: có nghĩa là sử dụng tên thuộc “namespace” std
– std:: được bỏ qua nếu dùng các khai báo using
•
Escape characters
\
– đánh dấu các ký tự đặc biệt
• ví dụ \\, \’, \n, \t
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
23
1.6 Vào ra dữ liệu
Các chuỗi escape
Chuỗi Escape
Mô tả
\n
Dòng mới. Đặt con trỏ màn hình tại đầu
dòng tiếp theo.
Tab. Di chuyển con trỏ đến điểm dừng tab
tiếp theo.
Về đầu dòng. Chuyển con trỏ màn hình tới
đầu dòng hiện tại; không xuống dòng mới.
Chuông. Bật chuông hệ thống.
Chéo ngược. Dùng để in một đấu chéo
ngược.
Nháy kép. Dùng để in một dấu nháy kép.
\t
\r
\a
\\
\"
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
24
1.6 Vào ra dữ liệu
Nhập dữ liệu từ thiết bị vào chuẩn
std::cin >> integer1;
// read an integer
• Đối tượng dòng dữ liệu vào - Input stream object
– >> (toán tử đọc từ dòng dữ liệu vào)
• được sử dụng với std::cin
• đợi người dùng nhập giá trị, rồi gõ phím Enter (Return)
• lưu giá trị vào biến ở bên phải toán tử
– đổi giá trị được nhập sang kiểu dữ liệu của biến
• = (toán tử
gán)
– gán giá trị cho biến
– toán tử hai ngôi - Binary operator
– Ví dụ:
sum = variable1 + variable2;
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
25
1.7 Tính toán số học
• Các phép toán số học
– *
– /
Phép nhân
Phép chia
• Phép chia với số nguyên lấy thương là số nguyên và bỏ phần
dư
– 7 / 5 cho kết quả 1
• Phép chia với số thực cho kết quả là số thực
– 7.0 / 5.0 cho kết quả 1.4
– %
Phép lấy số dư
– 7 % 5 cho kết quả 2
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
26
1.7 Tính toán số học
• Các quy tắc ưu tiên - Rules of operator precedence
– Các phép toán trong ngoặc được tính trước
• ngoặc lồng nhau
– các phép toán ở bên trong nhất được tính trước nhất
– tiếp theo là các phép nhân, chia, và phép lấy số dư
• các phép toán được tính từ trái sang phải
– cộng và trừ được tính cuối cùng
• các phép toán được tính từ trái sang phải
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
27
1
2
3
4
// Fig. 1.14: fig01_14.cpp
// Using if statements, relational
// operators, and equality operators.
#include <iostream>
5
6
7
8
using std::cout;
using std::cin;
using std::endl;
9
10
11
12
13
14
// function main begins program execution
int main()
Có thể viết cout và cin mà không cần tiền tố std::
{
int num1; // first number to lệnh
be read
from
if kiểm
tra user
xem các giá trị của
int num2; // second number tonum1
be read
fromcóuser
và num2
bằng nhau không.
// program uses cout
// program uses cin
// program uses endl
fig01_14.cpp
(1 of 2)
khai báo using để sau đó
không cần dùng tiền tố std::
Khai báo biến.
15
16
17
18
cout << "Enter two integers, and I will tell you\n"
<< "the relationships they satisfy: ";
cin >> num1 >> num2;
// read two integers
19
20
21
if ( num1 == num2 )
cout << num1 << " is equal to " << num2 << endl;
Nếu điều kiện là đúng (nghĩa
là hai giá trị bằng nhau) thì
thực hiện lệnh này.
lệnh if kiểm tra xem các giá trị của
num1 và num2 có khác nhau không.
Nếu điều kiện là đúng (nghĩa là hai giá trị
22
23
24
25
if ( num1 != num2 )
khác nhau) thì thực hiện lệnh này.
cout << num1 << " is not equal to " << num2 << endl;
26
27
if ( num1 < num2 )
cout << num1 << " is less than " << num2 << endl;
28
29
30
fig01_14.cpp
if ( num1 > num2 )
Một lệnh có(2
thểofđược
2) tách
cout << num1 << " is greater than " << num2 << endl;
©2004 Trần Minh Châu.
FOTECH. VNU.
thành nhiều dòng.
fig01_14.cpp
output (1 of 2)
31
32
33
34
if ( num1 <= num2 )
cout << num1 << " is less than or equal to "
<< num2 << endl;
35
36
37
38
if ( num1 >= num2 )
cout << num1 << " is greater than or equal to "
<< num2 << endl;
39
40
return 0;
41
42
28
// indicate that program ended successfully
} // end function main
Enter two integers, and I will tell you
the relationships they satisfy: 22 12
22 is not equal to 12
22 is greater than 12
22 is greater than or equal to 12
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
29
Enter two integers, and I will tell you
the relationships they satisfy: 7 7
7 is equal to 7
7 is less than or equal to 7
7 is greater than or equal to 7
fig01_14.cpp
output (2 of 2)
©2004 Trần Minh Châu.
FOTECH. VNU.
30
1.8 Ra quyết định: Các phép toán quan hệ
Ký hiệu toán học
Toán tử của C++
Ví dụ điều kiện C++ Ý nghĩa của điều kiện
>
>
x > y
x lớn hơn y
<
<
x < y
x nhỏ hơn y
≥
>=
x >= y
x lớn hơn hoặc bằng y
≤
<=
x <= y
x nhỏ hơn hoặc bằng y
=
==
x == y
x bằng y
≠
!=
x != y
x khác y
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
31
1.8 Ra quyết định: Các phép toán quan hệ
• cấu trúc if
– Đưa ra quyết định dựa vào kết quả đúng hoặc
sai của điều kiện
• Nếu điều kiện thỏa mãn thì thực hiện tập lệnh S
• nếu không, tập lệnh S không được thực hiện
if ( num1 == num2 )
cout << num1 << " is equal to " << num2 <<
endl;
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 1.
32
1.9 Khai báo using
• Khai báo sử dụng toàn bộ không gian tên
– using namespace std;
– Để không cần tiền tố std:: cho mọi tên trong std
1
2
3
// Fig. 1.4: fig01_04.cpp
// Printing a line with multiple statements.
#include <iostream>
4
5
6
7
8
9
10
using namespace std;
// function main begins program execution
int main()
{
cout << "Welcome ";
std::cout << "to C++!\n";
11
12
13
14
return 0;
} // end function main
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
33
1.9 Khai báo using
• Khai báo sử dụng từng tên
using std::cout; // program uses cout
using std::cin;
// program uses cin
using std::endl; // program uses endl
...
cout << "No need to write std::";
cin >> somevariable;
...
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 1.
https://fb.com/tailieudientucntt
1
Ngôn ngữ lập trình C++
Chương 2 – Các kiểu dữ liệu cơ bản
Các cấu trúc điều khiển
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
2
Tài liệu đọc thêm
• Tài liệu đọc thêm cho chương này:
– Section 2.1. Complete C++ Language Tutorial (CCLT)
– Day 7. Teach Yourself C++ in 21 Days (TY21)
– Namespace (Sec.5-2.CCLT) (Không bắt buộc)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
3
Chương 2 – Kiểu dữ liệu và phép toán cơ bản
Cấu trúc điều khiển và cấu trúc chương trình
Đề mục
2.1
Các kiểu dữ liệu cơ bản
2.2
Các phép gán tắt, phép tăng, phép giảm
2.3
Các phép toán logic
2.4
Thuật toán, mã giả, điều khiển của chương trình, sơ đồ khối
2.5
Sơ lược về các cấu trúc điều khiển
2.6
Cấu trúc lựa chọn if, if/else
2.7
Phép toán lựa chọn 3 ngôi
2.8
Cấu trúc lặp while
2.9
Thiết lập thuật toán
2.10
Điều khiển lặp bằng con đếm và giá trị canh
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
Chương 2 – Kiểu dữ liệu và phép toán cơ bản
Cấu trúc điều khiển và cấu trúc chương trình
4
Đề mục (tiếp theo)
2.11
Các cấu trúc lồng nhau
2.12
Vòng lặp for
2.13
Cấu trúc đa lựa chọn switch
2.14
Vòng lặp do/while
2.15
break và continue
2.16
Sơ lược về lập trình cấu trúc
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
5
2.1 Các kiểu dữ liệu cơ bản
char
ký tự hoặc số nguyên 8 bit
short
số nguyên 16 bit
long
số nguyên 32 bit
int
số nguyên độ dài bằng 1 word (16 bit
hoặc 32 bit)
float
số chấm động 4 byte
double
số chấm động 8 byte
long double số chấm động 10 byte
bool
giá trị Boolean, true hoặc false
wchar_t
ký tự 2 byte, lưu bảng chữ cái quốc tế
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
6
2.2 Các phép toán cơ bản
• phép gán – assignation (=)
x = 5;
//x: lvalue, 5: rvalue
– là biểu thức có giá trị là giá trị được gán
• các phép toán số học - Arithmetic operators
(+, -, *, /, %)
• các phép gán kép - Compound assignation
operators
(+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=)
• phép tăng và phép giảm (++, --)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
7
2.2 Các phép toán cơ bản
• các phép quan hệ - relational operators
( ==, !=, >, <, >=, <= )
• các phép toán logic - Logic operators ( !, &&, || )
• phép điều kiện - Conditional operator ( ? ).
(7 == 5 ? 4 : 3) cho kết quả 3 do 7 khác 5.
• các toán tử bit - Bitwise Operators
( &, |, ^, ~, <<, >> ).
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
8
2.2 Các phép gán tắt
• Các biểu thức gán tắt - Assignment expression
abbreviations
– Phép gán cộng
c = c + 3; viết tắt thành c += 3;
• Các lệnh có dạng
variable = variable operator expression;
có thể được viết lại thành
variable operator= expression;
• Các phép gán khác
d
e
f
g
-=
*=
/=
%=
4
5
3
9
(d
(e
(f
(g
=
=
=
=
d
e
f
g
*
/
%
4)
5)
3)
9)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
9
2.2 Các phép tăng và giảm
• Phép tăng - Increment operator (++)
– có thể được dùng thay cho c += 1
• Phép giảm - Decrement operator (--)
– có thể được dùng thay cho c -= 1
• Tăng/giảm trước – Preincrement/Predecrement
• ++c hoặc --c
• Giá trị của biến bị thay đổi, sau đó biểu thức chứa nó được tính giá trị.
• Biểu thức có giá trị là giá trị của biến sau khi tăng/giảm
• Tăng/giảm sau - Postincrement/Predecrement
• c++ hoặc c-• Biểu thức chứa biến được thực hiện, sau đó biến được thay đổi.
• Biểu thức có giá trị là giá trị của biến trước khi tăng/giảm
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
10
2.2 Các phép tăng và giảm
• Ví dụ: nếu c = 5
– cout << ++c;
• c nhận giá trị 6, rồi được in ra
– cout << c++;
• in giá trị 5 (cout được chạy trước phép tăng).
• sau đó, c nhận giá trị 6
• Khi biến không nằm trong biểu thức
– Tăng trước và tăng sau có kết quả như nhau
++c;
cout << c;
và
c++;
cout << c;
là như nhau
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
1
2
3
4
5
6
7
8
9
10
11
11
// Fig. 2.14: fig02_14.cpp
// Preincrementing and postincrementing.
#include <iostream>
fig02_14.cpp
(1 of 2)
using std::cout;
using std::endl;
// function main begins program execution
int main()
{
int c;
// declare variable
5
5
6
12
13
14
15
16
17
// demonstrate postincrement
c = 5;
//
cout << c << endl;
//
cout << c++ << endl;
//
cout << c << endl << endl; //
assign 5 to c
print 5
print 5 then postincrement
print 6
18
19
20
21
22
23
// demonstrate preincrement
c = 5;
//
cout << c << endl;
//
cout << ++c << endl;
//
cout << c << endl;
//
assign 5 to c
print 5
preincrement then print 6
print 6
24
25
return 0;
26
27
5
6
6
// indicate successful termination
©2004 Trần Minh Châu.
FOTECH. VNU.
} // end function main
12
2.3 Các phép toán logic
• được dùng làm điều kiện trong các vòng lặp và
lệnh if
• && (logical AND)
– true nếu cả hai điều kiện là true
if ( gender == 1 && age >= 65 )
++seniorFemales;
• || (logical OR)
– true nếu ít nhất một trong hai điều kiện là true
if ( semesterAverage >= 90 || finalExam >= 90 )
cout << "Student grade is A" << endl;
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
13
2.3 Các phép toán logic
• ! (logical NOT, phủ định logic – logical negation)
– trả về giá trị true khi điều kiện là false, và ngược lại
if ( !( grade == sentinelValue ) )
cout << "The next grade is " << grade << endl;
tương đương với:
if ( grade != sentinelValue )
cout << "The next grade is " << grade << endl;
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
14
Nhầm lẫn giữa
phép so sánh bằng (==) và phép gán (=)
• Lỗi thường gặp
– Thường không tạo lỗi cú pháp (syntax error)
• Các khía cạnh của vấn đề
– biểu thức có giá trị có thể được dùng làm điều kiện
• bằng không = false, khác không = true
– Các lệnh gán cũng tạo giá trị (giá trị được gán)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
15
Nhầm lẫn giữa
phép so sánh bằng (==) và phép gán (=)
• Ví dụ
if ( 4 == payCode )
cout << "You get a bonus!" << endl;
– Nếu mã tiền lương (paycode) là 4 thì thưởng
• Nếu == bị thay bởi =
if ( payCode = 4 )
cout << "You get a bonus!" << endl;
– Paycode được gán giá trị 4 (không cần biết giá trị của
paycode trước đó)
– lệnh gán cho giá trị true (vì 4 khác 0)
– trường hợp nào cũng được thưởng
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
16
Nhầm lẫn giữa
phép so sánh bằng (==) và phép gán (=)
• Lvalue
– là biểu thức có thể xuất hiện tại vế trái của phép gán
– xác định một vùng nhớ có thể được gán trị (i.e, các biến)
• x = 4;
• Rvalue
– chỉ xuất hiện bên phải phép gán
– hằng, các giá trị (literal)
• không thể viết 4 = x;
• Lvalue có thể được dùng như các rvalue, nhưng
chiều ngược lại là không thể
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
17
Viết chương trình
• Trước khi viết chương trình
– Hiểu kỹ bài toán
– Lập kế hoạch giải quyết bài toán
• Trong khi viết chương trình
– Biết lời giải có sẵn cho các bài toán con
– Sử dụng các nguyên lý lập trình tốt
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
18
Thuật toán - Algorithm
• Các bài toán tin học
– được giải bằng cách thực hiện một chuỗi hành động theo
một thứ tự cụ thể
• Thuật toán: một quy trình quyết định
– Các hành động cần thực hiện
– Thứ tự thực hiện
– Ví dụ: cách nấu một món ăn
• Điều khiển của chương trình – Program Control
– Chỉ ra thứ tự thực hiện các lệnh
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
19
Mã giả - Pseudocode
• Mã giả: ngôn ngữ không chính thức được dùng để
mô tả thuật toán
– tương tự với ngôn ngữ hàng ngày
• Không chạy được trên máy tính
– dùng để mô tả chương trình trước khi viết chương trình
• dễ chuyển thành chương trình C++
– chỉ gồm các lệnh chạy
• không cần khai báo biến
Ví dụ:
tìm số nhỏ hơn trong hai số
1.
nhập 2 số x,y
2.
nếu x>y thì in y ra màn hình
3.
nếu không, in x ra màn hình
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
Các cấu trúc điều khiển - Control Structures
Khái niệm
20
• Thực thi tuần tự - Sequential execution
– Các lệnh được thực hiện theo thứ tự tuần tự
• Chuyển điều khiển - Transfer of control
– Lệnh tiếp theo được thực thi không phải lệnh tiếp theo trong
chuỗi lệnh.
• 3 cấu trúc điều khiển
– Cấu trúc tuần tự - Sequence structure
• theo mặc định, chương trình chạy tuần tự từng lệnh
– Các cấu trúc chọn lựa - Selection structures
• if, if/else, switch
– Các cấu trúc lặp - Repetition structures
• while, do/while, for
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
21
Các cấu trúc điều khiển
• Các từ khóa của C++
– Không thể dùng làm tên biến hoặc tên hàm
C++ Keyw o rd s
Keywords common to the
C and C++ programming
languages
auto
continue
enum
if
short
switch
volatile
C++ only keywords
asm
delete
inline
private
static_cast
try
wchar_t
break
default
extern
int
signed
typedef
while
case
do
float
long
sizeof
union
char
double
for
register
static
unsigned
const
else
goto
return
struct
void
bool
dynamic_cast
mutable
protected
template
typeid
catch
explicit
namespace
public
this
typename
class
false
new
reinterpret_cast
throw
using
const_cast
friend
operator
true
virtual
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
22
Các cấu trúc điều khiển
true
grade >= 60
print “Passed”
false
• Sơ đồ khối - Flowchart
– mô tả thuật toán bằng hình vẽ
– gồm các ký hiệu đặc biệt được nối bằng các mũi tên
(flowlines)
– Hình chữ nhật (ký hiệu hành động)
• kiểu hành động bất kỳ
– ký hiệu oval
• Bắt đầu hoặc kết thúc một chương trình,
hoặc một đoạn mã (hình tròn)
• Các cấu trúc điều khiển có đúng 1 đầu vào, 1 đầu ra
– Kết nối đầu ra của một cấu trúc điều khiển với đầu vào của
cấu trúc tiếp theo
– xếp chồng các cấu trúc điều khiển
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
23
Cấu trúc lựa chọn if
• Cấu trúc lựa chọn - Selection structure
– chọn giữa các tuyến hành động khác nhau
– ví dụ bằng mã giả:
If student’s grade is greater than or equal to 60
Print “Passed”
– Nếu điều kiện thỏa mãn (có giá trị true)
• lệnh Print được thực hiện, chương trình chạy tiếp lệnh tiếp theo
– Nếu điều kiện không thỏa mãn (có giá trị false)
• lệnh Print bị bỏ qua, chương trình chạy tiếp
– Cách viết thụt đầu dòng làm chương trình dễ đọc hơn
• C++ bỏ qua các ký tự trắng (tab, space, etc.)
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
24
Cấu trúc lựa chọn if
• Dịch sang C++
If student’s grade is greater than or equal to 60
Print “Passed”
grade >= 60
if ( grade >= 60 )
cout << "Passed";
true
print “Passed”
false
• ký hiệu hình thoi (ký hiệu quyết định)
– đánh đấu chọn lựa cần thực hiện
– chứa một biểu thức có giá trị true hoặc false
• kiểm tra điều kiện, đi theo đường thích hợp
• cấu trúc if
– Single-entry/single-exit
Một biểu thức bất kỳ đều
có thể được sử dụng làm
điều kiện cho lựa chọn.
bằng 0 - false
khác 0 - true
Ví dụ:
3 - 4 có giá trị true
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
25
Cấu trúc chọn lựa if/else
• if
– Thực hiện hành động nếu điều kiện thỏa mãn
• if/else
– thực hiện những hành động khác nhau tùy theo điều kiện được
thỏa mãn hay không
• mã giả
if student’s grade is greater than or equal to 60
print “Passed”
else
print “Failed”
• mã C++
if ( grade >= 60 )
cout << "Passed";
else
cout << "Failed";
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
26
Cấu trúc chọn lựa if/else
• phép toán điều kiện 3 ngôi (?:)
– ba tham số (điều kiện, giá trị nếu true, giá trị nếu false)
• mã có thể được viết:
cout << ( grade >= 60 ? “Passed” : “Failed” );
Condition
false
print “Failed”
Value if true
grade >= 60
Value if false
true
print “Passed”
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
27
Cấu trúc chọn lựa if/else
• Các cấu trúc if/else lồng nhau
– lệnh này nằm trong lệnh kia, kiểm tra nhiều trường hợp
– Một khi điều kiện thỏa mãn, các lệnh khác bị bỏ qua
if student’s grade is greater than or equal to 90
Print “A”
else
if student’s grade is greater than or equal to 80
Print “B”
else
if student’s grade is greater than or equal to 70
Print “C”
else
if student’s grade is greater than or equal to 60
Print “D”
else
Print “F”
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
28
Cấu trúc chọn lựa if/else
• Ví dụ
if ( grade >= 90 )
cout << "A";
else if ( grade >= 80 )
cout << "B";
else if ( grade >= 70 )
cout << "C";
else if ( grade >= 60 )
cout << "D";
else
cout << "F";
// 90 and above
// 80-89
// 70-79
// 60-69
// less than 60
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
29
Cấu trúc chọn lựa if/else
• lệnh phức – compound statement
– tập lệnh bên trong một cặp ngoặc
if ( grade
cout <<
else {
cout <<
cout <<
>= 60 )
"Passed.\n";
"Failed.\n";
"You must take this course again.\n";
}
– nếu không có ngoặc,
cout << "You must take this course again.\n";
sẽ luôn được thực hiện
• Khối chương trình - Block
– tập lệnh bên trong một cặp ngoặc
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
30
Cấu trúc lặp while
• Cấu trúc lặp - Repetition structure
– hành động được lặp đi lặp lại trong khi một điều kiện nào đó
còn được thỏa mãn
– mã giả
Trong khi vẫn còn tên hàng trong danh sách đi chợ của tôi
Mua mặt hàng tiếp theo và gạch tên nó ra khỏi danh sách
– vòng while lặp đi lặp lại cho đến khi điều kiện không thỏa
mãn
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
31
Cấu trúc lặp while
• Ví dụ
int product = 2;
while ( product <= 1000 )
product = 2 * product;
• Sơ đồ khối của vòng while
true
product <= 1000
product = 2 * product
false
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
32
Thiết lập thuật toán
(Điều khiển lặp bằng con đếm)
• Vòng lặp được điều khiển bằng con đếm (counter)
– Lặp đến khi con đếm đạt đến giá trị nào đó
• Lặp hữu hạn - Definite repetition
– số lần lặp biết trước
• Ví dụ
Một lớp gồm 10 sinh viên làm một bài thi. Cho biết các điểm
thi (số nguyên trong khoảng từ 0 đến 100). Tính trung bình
điểm thi của lớp.
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
33
Thiết lập thuật toán
(Điều khiển lặp bằng con đếm)
• Mã giả cho ví dụ:
Đặt tổng bằng 0
Đặt con đếm bằng 1
Trong khi con đếm nhỏ hơn hoặc bằng 10
Nhập điểm tiếp theo
Cộng điểm đó vào tổng
Thêm 1 vào con đến
Đặt trung bình lớp bằng tổng chia cho 10
In trung bình lớp
• Tiếp theo: Mã C++ cho ví dụ trên
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
1
2
3
// Fig. 2.7: fig02_07.cpp
// Class average program with counter-controlled repetition.
#include <iostream>
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
10
11
12
13
14
15
// function main begins
int main()
{
int total;
//
int gradeCounter; //
int grade;
//
int average;
//
16
17
18
19
34
fig02_07.cpp
(1 of 2)
program execution
sum of grades input by user
number of grade to be entered next
grade value
average of grades
// initialization phase
total = 0;
// initialize total
gradeCounter = 1;
// initialize loop counter
20
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
35
21
22
23
24
25
26
27
// processing phase
while ( gradeCounter <= 10 ) {
cout << "Enter grade: ";
cin >> grade;
total = total + grade;
gradeCounter = gradeCounter + 1;
}
28
29
30
// termination phase
average = total / 10;
31
32
33
// display result
cout << "Class average is " << average << endl;
34
35
return 0;
36
37
//
//
//
//
//
loop 10 times
prompt for input
read grade from user
add grade to total
increment counter
fig02_07.cpp
(2 of 2)
fig02_07.cpp
output (1 of 1)
Con
đếm được division
tăng thêm 1 mỗi lần vòng lặp chạy.
// integer
Cuối cùng, con đếm làm vòng lặp kết thúc.
// indicate program ended successfully
} // end function main
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Class
grade: 98
grade: 76
grade: 71
grade: 87
grade: 83
grade: 90
grade: 57
grade: 79
grade: 82
grade: 94
average is 81
©2004 Trần Minh Châu.
FOTECH. VNU.
36
Thiết lập thuật toán
(Điều khiển lặp bằng lính canh)
• Giả sử bài toán trở thành:
Viết một chương trình tính điểm trung bình của lớp, chương
trình sẽ xử lý một số lượng điểm tùy ý mỗi khi chạy chương
trình.
– Số sinh viên chưa biết
– Chương trình sẽ làm thế nào để biết khi nào thì kết thúc?
• Giá trị canh
– Ký hiệu “Kết thúc của dữ liệu vào”
– Vòng lặp kết thúc khi nhập canh
– Canh được chọn để không bị lẫn với dữ liệu vào thông
thường
• trong trường hợp này là -1
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
37
Thiết lập thuật toán
(Điều khiển lặp bằng lính canh)
• Thiết kế từ trên xuống, làm mịn từng bước
– Bắt đầu bằng mã giả cho mức cao nhất
Tính trung bình điểm thi của lớp
– Chia thành các nhiệm vụ nhỏ hơn, liệt kê theo thứ tự
Khởi tạo các biến
Nhập, tính tổng, và đếm các điểm thi
Tính và in trung bình điểm thi
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
38
Thiết lập thuật toán
(Điều khiển lặp bằng lính canh)
• Nhiều chương trình có 3 pha
– Khởi tạo - Initialization
• Khởi tạo các biến chương trình
– Xử lý - Processing
• Nhập dữ liệu, điều chỉnh các biến trong chương trình
– Kết thúc - Termination
• Tính và in kết quả cuối cùng
– Giúp việc chia nhỏ chương trình để làm mịn từ trên xuống
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
39
Thiết lập thuật toán
(Điều khiển lặp bằng lính canh)
• Làm mịn pha khởi tạo
Khởi tạo các biến
thành
Khởi tạo tổng bằng 0
Khởi tạo biến đếm bằng 0
• Xử lý
Nhập, tính tổng, và đếm các điểm thi
thành
Nhập điểm đầu tiên (có thể là canh)
Trong khi người dùng còn chưa nhập canh
Cộng điểm vừa nhập vào tổng
Cộng thêm 1 vào biến đếm điểm
Nhập điểm tiếp theo (có thể là canh)
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
40
Thiết lập thuật toán
(Điều khiển lặp bằng lính canh)
• Kết thúc
Tính và in trung bình điểm thi
thành
Nếu con đếm khác 0
Đặt trung bình bằng tổng chia cho con đếm
In giá trị trung bình
Nếu không
In “Không nhập điểm nào”
• Tiếp theo: chương trình C++
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using
using
using
using
fig02_09.cpp
(1 of 3)
std::cout;
std::cin;
std::endl;
std::fixed;
#include <iomanip>
// parameterized stream manipulators
using std::setprecision;
// sets numeric output precision
// function main begins program execution
int main()
{
Dữ liệu kiểu double dùng để
int total;
// sum of grades
biểu
diễn sốentered
thập phân.
int gradeCounter; // number of grades
int grade;
// grade value
20
21
double average;
22
23
24
25
// initialization phase
total = 0;
// initialize total
gradeCounter = 0; // initialize loop counter
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
41
// Fig. 2.9: fig02_09.cpp
// Class average program with sentinel-controlled repetition.
#include <iostream>
// number with decimal point for average
©2004 Trần Minh Châu.
FOTECH. VNU.
42
// processing phase
// get first grade from user
cout << "Enter grade, -1 to end: ";
cin >> grade;
// prompt for input
// read grade from user
fig02_09.cpp
(2 of 3)
// loop until sentinel value read from user
while ( grade != -1 ) {
total = total + grade;
// add grade to total
gradeCounter = gradeCounter + 1; // increment counter
cout << "Enter grade, -1 to end: ";
cin >> grade;
// prompt for input
// read next grade
} // end while
// termination phase
// if user entered at least one grade ...
if ( gradeCounter != 0 ) {
// calculate average of all grades entered
average = static_cast< double >( total ) / gradeCounter;
static_cast<double>() coi total như một double tạm thời (casting).
©2004 Trần Minh Châu.
Cần thiết vì phép chia số nguyên bỏ qua phần dư.
gradeCounter là một biến int, nhưng nó được nâng lên kiểu double.FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
49
50
51
43
// display average with two digits of precision
cout << "Class average is " << setprecision( 2 )
<< fixed << average << endl;
52
53
} // end if part of if/else
fig02_09.cpp
(3 of 3)
54
55
56
else // if no grades were entered, output appropriate message
cout << "No grades were entered" << endl;
fig02_09.cpp
output (1 of 1)
57
58
return 0;
59
60
// indicate program ended successfully
} // end function main
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Class
grade, -1 to end:
grade, -1 to end:
grade, -1 to end:
grade, -1 to end:
grade, -1 to end:
grade, -1 to end:
grade, -1 to end:
grade, -1 to end:
grade, -1 to end:
average is 82.50
75
94
97
88
70
64
83
89
-1
fixed làm số liệu ra được in
theo dạng thông thường
(không phải dạng ký hiệu
khoa học); qui định in cả các
chữ số 0 ở sau và in dấu chấm
thập phân.
setprecision(2)in hai
chữ số sau dấu phảy (làm tròn
theo độ chính xác quy định).
Các chương trình dùng hàm
này phải include <iomanip>
Include <iostream>
©2004 Trần Minh Châu.
FOTECH. VNU.
44
Các cấu trúc điều khiển lồng nhau
• Phát biểu bài toán
Một trường có danh sách kết quả thi (1 = đỗ, 2 = trượt) của
10 sinh viên. Viết một chương trình phân tích kết quả thi.
Nếu có nhiều hơn 8 sinh viên đỗ thì in ra màn hình dòng
chữ “Tăng tiền học phí".
• Lưu ý
– Chương trình xử lý 10 kết quả thi
• số lần lặp cố định, sử dụng vòng lặp điều khiển bằng biến đếm
– Có thể sử dụng hai con đếm
• Một con đếm để đếm số lượng đỗ
• Một con đếm khác đếm số lương trượt
– Mỗi kết quả thi chỉ là 1 hoặc 2
• Nếu không phải 1 thì coi là 2
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
45
Các cấu trúc điều khiển lồng nhau
• Phác thảo mức cao nhất - Top level outline
Analyze exam results and decide if tuition should be raised
• Làm mịn lần một - First refinement
Initialize variables
Input the ten quiz grades and count passes and failures
Print a summary of the exam results and decide if tuition
should be raised
• Làm mịn - Refine
Initialize variables
to
Initialize passes to zero
Initialize failures to zero
Initialize student counter to one
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
46
Các cấu trúc điều khiển lồng nhau
• Refine
Input the ten quiz grades and count passes and failures
to
While student counter is less than or equal to ten
Input the next exam result
If the student passed
Add one to passes
Else
Add one to failures
Add one to student counter
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
47
Các cấu trúc điều khiển lồng nhau
• tiếp tục làm mịn
Print a summary of the exam results and decide if tuition should
be raised
to
Print the number of passes
Print the number of failures
If more than eight students passed
Print “Raise tuition”
• Program next
© 2004 Trần Minh Châu. FOTECH. VNU
1
2
3
// Fig. 2.11: fig02_11.cpp
// Analysis of examination results.
#include <iostream>
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
10
11
12
13
14
15
16
// function main begins program execution
int main()
{
// initialize variables in declarations
int passes = 0;
// number of passes
int failures = 0;
// number of failures
int studentCounter = 1;
// student counter
int result;
// one exam result
17
18
19
20
21
22
23
Chương 2.
48
fig02_11.cpp
(1 of 2)
// process 10 students using counter-controlled loop
while ( studentCounter <= 10 ) {
// prompt user for input and obtain value from user
cout << "Enter result (1 = pass, 2 = fail): ";
cin >> result;
24
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
26
27
28
29
30
fig02_11.cpp
(2 of 2)
else // if result not 1, increment failures
failures = failures + 1;
31
32
33
34
35
} // end while
36
37
38
39
// termination phase; display number of passes and failures
cout << "Passed " << passes << endl;
cout << "Failed " << failures << endl;
40
41
42
43
// if more than eight students passed, print "raise tuition"
if ( passes > 8 )
cout << "Raise tuition " << endl;
44
45
return 0;
46
47
49
// if result 1, increment passes; if/else nested in while
if ( result == 1 )
// if/else nested in while
passes = passes + 1;
// increment studentCounter so loop eventually terminates
studentCounter = studentCounter + 1;
// successful termination
} // end function main
©2004 Trần Minh Châu.
FOTECH. VNU.
Enter result
Enter result
Enter result
Enter result
Enter result
Enter result
Enter result
Enter result
Enter result
Enter result
Passed 6
Failed 4
(1
(1
(1
(1
(1
(1
(1
(1
(1
(1
=
=
=
=
=
=
=
=
=
=
pass,
pass,
pass,
pass,
pass,
pass,
pass,
pass,
pass,
pass,
2
2
2
2
2
2
2
2
2
2
=
=
=
=
=
=
=
=
=
=
fail):
fail):
fail):
fail):
fail):
fail):
fail):
fail):
fail):
fail):
1
2
2
1
1
1
2
1
1
2
Enter result (1
Enter result (1
Enter result (1
Enter result (1
Enter result (1
Enter result (1
Enter result (1
Enter result (1
Enter result (1
Enter result (1
Passed 9
Failed 1
Raise tuition
=
=
=
=
=
=
=
=
=
=
pass,
pass,
pass,
pass,
pass,
pass,
pass,
pass,
pass,
pass,
2
2
2
2
2
2
2
2
2
2
=
=
=
=
=
=
=
=
=
=
fail):
fail):
fail):
fail):
fail):
fail):
fail):
fail):
fail):
fail):
1
1
1
1
2
1
1
1
1
1
CuuDuongThanCong.com
50
fig02_11.cpp
output (1 of 1)
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
51
Những điểm quan trọng về
vòng lặp điều khiển bằng con đếm
• vòng lặp điều khiển bằng con đếm đòi hỏi
– Tên của biến điều khiển(control variable) hay biến đếm
(loop counter)
– Giá trị khởi tạo của biến điều khiển
– Điều kiện kiểm tra giá trị cuối cùng
– Tăng/giảm biến đếm khi thực hiện vòng lặp
int counter = 1;
// initialization
while ( counter <= 10 ) {
cout << counter << endl;
++counter;
}
// repetition condition
// display counter
// increment
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
1
2
3
// Fig. 2.16: fig02_16.cpp
// Counter-controlled repetition.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
9
10
11
// function main begins program execution
int main()
{
int counter = 1;
// initialization
12
13
14
15
while ( counter <= 10 ) {
cout << counter << endl;
++counter;
16
17
} // end while
18
19
return 0;
20
21
fig02_16.cpp
(1 of 1)
// repetition condition
// display counter
// increment
// indicate successful termination
} // end function main
52
1
2
3
4
5
6
7
8
9
10
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
53
Cấu trúc vòng lặp for
• Dạng tổng quát của vòng for
for ( khởi_tạo; điều_kiện_lặp; tăng/giảm )
lệnh
• Ví dụ
for( int counter = 1; counter <= 10; counter++ )
cout << counter << endl;
– In các số nguyên từ 1 đến 10
Không có dấu ; ở cuối
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
1
2
3
// Fig. 2.17: fig02_17.cpp
// Counter-controlled repetition with the for structure.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
9
10
11
12
// function main begins program execution
int main()
{
// Initialization, repetition condition and incrementing
// are all included in the for structure header.
fig02_17.cpp
(1 of 1)
13
14
15
for ( int counter = 1; counter <= 10; counter++ )
cout << counter << endl;
16
17
return 0;
18
19
// indicate successful termination
} // end function main
54
1
2
3
4
5
6
7
8
9
10
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
55
Cấu trúc vòng lặp for
• vòng for thường có thể viết được thành vòng
while tương đương
khởi_tạo;
while ( điều_kiện_lặp){
lệnh
tăng/giảm biến đếm;
}
• Khởi tạo và tăng biến đếm
– nếu sử dụng nhiều biến đếm, sử dụng dấu phảy để tách
for (int i = 0, j = 0; j + i <= 10; j++, i++)
cout << j + i << endl;
© 2004 Trần Minh Châu. FOTECH. VNU
1
2
3
// Fig. 2.20: fig02_20.cpp
// Summation with for.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
9
10
11
Chương 2.
56
fig02_20.cpp
(1 of 1)
// function main begins program execution
int main()
{
int sum = 0;
// initialize sum
12
13
14
15
// sum even integers from 2 through 100
for ( int number = 2; number <= 100; number += 2 )
sum += number;
// add number to sum
16
17
18
cout << "Sum is " << sum << endl;
return 0;
19
20
fig02_20.cpp
output (1 of 1)
// output sum
// successful termination
} // end function main
Sum is 2550
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
57
Ví dụ sử dụng vòng for
• Chương trình tính lãi kép (compound interest)
Một người đầu tư $1000.00 vào một tài khoản tiết kiệm với lãi suất
5%. Giả sử tiền lãi được gộp với vốn trong tài khoảng, tính và in ra số
tiền trong tài khoản vào cuối mỗi năm trong vòng 10 năm. Sử dụng
công thức sau để tính các khoản tiền đó:
•
n
a = p(1+r)
p : khoản đầu tư ban đầu (i.e., the principal),
r : lãi suất hàng năm, (interest rate)
n : số năm, và
a : lượng tiền có trong tài khoản (amount on deposit)
vào cuối năm thứ n
•
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
58
1
2
3
// Fig. 2.21: fig02_21.cpp
// Calculating compound interest.
#include <iostream>
4
5
6
7
8
using
using
using
using
9
10
#include <iomanip>
11
12
13
using std::setw;
using std::setprecision;
14
15
#include <cmath>
16
17
18
19
20
21
22
// function main begins program execution
int main()
{
double amount;
// amount on deposit
double principal = 1000.0; // starting principal
double rate = .05;
// interest rate
fig02_21.cpp
(1 of 2)
std::cout;
std::endl;
std::ios;
std::fixed;
<cmath> header cần cho
hàm pow (chương trình sẽ
không dịch nếu không có khai
báo này).
// enables program to use function pow
23
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
24
25
// output table column heads
cout << "Year" << setw( 21 ) << "Amount on deposit" << endl;
26
27
28
// set floating-point number format
cout << fixed << setprecision( 2 );
29
30
31
// calculate amount on deposit for each of ten years
for ( int year = 1; year <= 10; year++ ) {
32
33
34
// calculate new amount for specified year
amount = principal * pow( 1.0 + rate, year );
35
36
37
38
// output one table row
cout << setw( 4 ) << year
<< setw( 21 ) << amount << endl;
Đặt độ rộng của output ít nhất 21 ký
tự. Nếu output ít hơn 21 kýfig02_21.cpp
tự thì căn
(2 of 2)
phải.
pow(x,y) = x mũ y
39
40
} // end for
41
42
return 0;
43
44
59
// indicate successful termination
} // end function main
©2004 Trần Minh Châu.
FOTECH. VNU.
Year
1
2
3
4
5
6
7
8
9
10
60
Amount on deposit
1050.00
1102.50
1157.63
1215.51
1276.28
1340.10
1407.10
1477.46
1551.33
1628.89
fig02_21.cpp
output (1 of 1)
Các số được căn phải do các lệnh
setw (với tham số có giá trị 4 và 21).
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
61
Cấu trúc đa lựa chọn switch
• switch
– Test biến với nhiều giá trị
– chuỗi các nhãn case
– trường hợp default không bắt buộc
switch ( variable ) {
case value1:
statements
break;
case value2:
case value3:
statements
break;
default:
statements
break;
// taken if variable == value1
// necessary to exit switch
// taken if variable == value2 or == value3
// taken if variable matches no other cases
}
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
62
Cấu trúc đa lựa chọn switch
true
case a
case a action(s)
break
case b action(s)
break
case z action(s)
break
false
true
case b
false
.
.
.
true
case z
false
default action(s)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
63
Cấu trúc đa lựa chọn switch
• Ví dụ sắp tới
– Chương trình đọc xếp loại điểm (A-F)
– Hiện số lượng mỗi xếp loại được nhập
• Chi tiết về các ký tự
– Các ký tự đơn thường được lưu bằng kiểu dữ liệu char
• char: số nguyên 1-byte, Æcó thể được lưu dưới dạng các giá trị
int
– Có thể coi ký tự là int hoặc char
• 97 là biểu diễn dạng số của chữ ‘a’ thường (ASCII)
• dùng cặp nháy đơn để lấy biểu diễn chữ của ký tự
cout << "The character (" << 'a' << ") has the value "
<< static_cast< int > ( 'a' ) << endl;
In ra dòng:
The character (a) has the value 97
© 2004 Trần Minh Châu. FOTECH. VNU
1
2
3
// Fig. 2.22: fig02_22.cpp
// Counting letter grades.
#include <iostream>
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
10
11
12
13
14
15
16
17
// function main begins program execution
int main()
{
int grade;
// one grade
int aCount = 0; // number of As
int bCount = 0; // number of Bs
int cCount = 0; // number of Cs
int dCount = 0; // number of Ds
int fCount = 0; // number of Fs
18
19
20
Chương 2.
64
fig02_22.cpp
(1 of 4)
cout << "Enter the letter grades." << endl
<< "Enter the EOF character to end input." << endl;
21
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
22
23
24
25
26
65
// loop until user types end-of-file key sequence
while ( ( grade = cin.get() ) != EOF ) {break kết thúc lệnh switch và chương trình
chạy tiếp tại lệnh đầu tiên sau cấu trúc switch.
fig02_22.cpp
// determine which grade was input
(2 of 4)
switch ( grade ) { // switch structure nested in while
27
28
29
30
31
case 'A':
case 'a':
++aCount;
break;
32
33
34
35
36
case 'B':
case 'b':
++bCount;
break;
37
38
39
40
41
Các
lệnh gán là biểu thức có
// grade was uppercase B
giá trị bằng biến bên trái dấu
// or lowercase b
gán =. Giá trị của lệnh này
// increment bCount
bằng giá trị trả về bởi hàm
// exit switch
cin.get().
case 'C':
case 'c':
++cCount;
break;
// grade was uppercase C
Đặc
điểm này còn được sử
// or
lowercase
dụng
để khởi
tạo nhiềucbiến
//
increment
cCount
một lúc:
//
exit
switch
a = b = c = 0;
//
//
//
//
cin.get() sử dụng dot notation
grade was uppercase A
(ký hiệu kiểu dấu chấm). Hàm này
or lowercase a
đọc một ký tự từ bàn phím (sau khi
increment aCount
nhấn Enter), và gán giá trị đó cho
necessary to exit switch
biến grade.
cin.get() trả về EOF (end-offile), sau khi ký tự EOF được nhập,
để đánh dấu kết thúc của dữ liệu vào.
EOF có thể là ctrl-d hoặc ctrl-z, tùy
theo hệ điều hành. (MS-Windows:
ctrl-z, Unix/Linux: ctrl-d)
42
So sánh grade (một biến int)
với biểu diễn số của A và a.
©2004 Trần Minh Châu.
FOTECH. VNU.
66
43
44
45
46
case 'D':
case 'd':
++dCount;
break;
//
//
//
//
47
48
49
50
51
case 'F':
case 'f':
++fCount;
break;
// exit switch
52
53
54
55
56
case '\n':
case '\t':
case ' ':
break;
57
58
59
60
61
default:
// catch all other characters
cout << "Incorrect letter grade entered."
<< " Enter a new grade." << endl;
break;
// optional; will exit switch anyway
62
63
64
65
grade was uppercase D
or lowercase d
increment dCount
exit switch
fig02_22.cpp
(3 of 4)
Kiểm tra này là cần thiết vì Enter được nhấn sau
// grade was uppercase
F xếp loại được nhập. Việc nhấn Enter
mỗi chữ cái
// or lowercase tạo
f một ký tự xuống dòng cần được loại bỏ. Cũng
// increment fCount
như vậy, ta muốn bỏ qua các ký tự trắng.
//
//
//
//
ignore newlines,
tabs,
and spaces in input
exit switch Lưu ý trường hợp default bao gồm tất
cả các trường hợp còn lại (chưa xét đến).
} // end switch
} // end while
66
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
67
68
69
70
71
72
73
74
// output summary of results
cout << "\n\nTotals for each letter grade are:"
<< "\nA: " << aCount
// display number of
<< "\nB: " << bCount
// display number of
<< "\nC: " << cCount
// display number of
<< "\nD: " << dCount
// display number of
<< "\nF: " << fCount
// display number of
<< endl;
75
76
return 0;
77
78
67
A
B
C
D
F
grades
grades
grades
grades
grades
fig02_22.cpp
(4 of 4)
// indicate successful termination
} // end function main
©2004 Trần Minh Châu.
FOTECH. VNU.
68
Enter the letter grades.
Enter the EOF character to end input.
a
B
c
C
A
d
f
C
E
Incorrect letter grade entered. Enter a new grade.
D
A
b
^Z
fig02_22.cpp
output (1 of 1)
Totals for each letter grade are:
A: 3
B: 2
C: 3
D: 2
F: 1
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
69
Cấu trúc lặp do/while
• Tương tự cấu trúc while
– Kiểm tra điều kiện tiếp tục lặp ở
cuối, không kiểm tra ở đầu
– Thân vòng lặp chạy ít nhất một
lần
action(s)
• Công thức
do {
statements
} while ( condition );
true
condition
false
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
1
2
3
// Fig. 2.24: fig02_24.cpp
// Using the do/while repetition structure.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
9
10
11
70
fig02_24.cpp
(1 of 1)
{
int counter = 1;
// initialize counter
12
13
14
15
do {
cout << counter << " ";
} while ( counter++ <= 10 );
// display counter
// end do/while
16
17
cout << endl;
18
19
return 0;
20
21
1
fig02_24.cpp
output (1 of 1)
Chú ý phép tăng trước (preincrement)
// function main begins program execution
trong
phần kiểm tra điều kiện lặp.
int main()
// indicate successful termination
} // end function main
2
3
4
5
6
7
8
9
10
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
71
Các lệnh break và continue
• break
– Thoát ngay ra khỏi các cấu trúc while, for, do/while,
switch
– Chương trình tiếp tục chạy tại lệnh đầu tiên ngay sau cấu
trúc
• thường được sử dụng để
– Thoát khỏi vòng lặp sớm hơn bình thường
– bỏ qua phần còn lại của switch
© 2004 Trần Minh Châu. FOTECH. VNU
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Chương 2.
72
// Fig. 2.26: fig02_26.cpp
// Using the break statement in a for structure.
#include <iostream>
fig02_26.cpp
using std::cout;
using std::endl;
1 2 3 4
(1 of 2)
Broke out of loop when x became 5
// function main begins program execution
int main()
{
int x;
// x declared here so it can be used after the loop
// loop 10 times
for ( x = 1; x <= 10; x++ ) {
Thoát khỏi vòng for khi
break được thực thi.
// if x is 5, terminate loop
if ( x == 5 )
break;
// break loop only if x is 5
cout << x << " ";
// display value of x
} // end for
cout << "\nBroke out of loop when x became " << x << endl;
return 0;
// indicate successful termination
} // end function main
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
73
Các lệnh break và continue
• continue
– được dùng trong while, for, do/while
– bỏ qua phần còn lại của thân vòng lặp
– chạy tiếp lần lặp tiếp theo
• với các vòng while và do/while
– thực hiện kiểm tra điều kiện lặp ngay sau lệnh continue
• với vòng for
– biểu thức tăng/giảm biến đếm được thực hiện
– sau đó, điều kiện lặp được kiểm tra
© 2004 Trần Minh Châu. FOTECH. VNU
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Chương 2.
74
// Fig. 2.27: fig02_27.cpp
// Using the continue statement in a for structure.
#include <iostream>
fig02_27.cpp
using std::cout;
using std::endl;
1 2 3 4 6 7 8 9 10
(1 of
2) value 5
Used continue to skip printing
the
// function main begins program execution
int main()
Bỏ qua phần còn lại của thân vòng
{
for, nhảy đến lần lặp tiếp theo.
// loop 10 times
for ( int x = 1; x <= 10; x++ ) {
// if x is 5, continue with next iteration of loop
if ( x == 5 )
continue;
// skip remaining code in loop body
cout << x << " ";
// display value of x
} // end for structure
cout << "\nUsed continue to skip printing the value 5"
<< endl;
return 0;
} // end function main
CuuDuongThanCong.com
// indicate successful termination
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
75
Lập trình cấu trúc
Structured-Programming
• Lập trình cấu trúc – Structured programming
– Chương trình dễ hiểu, test, tìm lỗi (debug) và dễ sửa đổi hơn
• Các quy tắc lập trình cấu trúc
– Chỉ sử dụng các cấu trúc điều khiển một đầu vào một đầu ra
– Quy tắc
1) Bắt đầu bằng một sơ đồ khối đơn giản nhất
2) Mỗi hình chữ nhật (hành động) có thể được thay bằng một
chuỗi gồm 2 hình chữ nhật khác
3) Mỗi hình chữ nhật (hành động) có thể được thay bằng một cấu
trúc điều khiển tùy ý (tuần tự, if, if/else, switch, while,
do/while hoặc for)
4) Các quy tắc 2 và 3 có thể được áp dụng nhiều lần và theo thứ
tự tùy ý
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 2.
76
Lập trình cấu trúc
Structured-Programming
Mô tả quy tắc 3 (thay một hình chữ nhật tùy ý bằng một cấu trúc điều khiển)
Qui tắc 3
Qui tắc 3
Qui tắc 3
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 2.
https://fb.com/tailieudientucntt
1
Ngôn ngữ lập trình C++
Chương 3 – Hàm
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
2
Chương 3 - Hàm
Đề mục
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
3.10
3.11
3.12
3.13
3.14
3.15
Giới thiệu
Các thành phần của chương trình C++
Các hàm trong thư viện toán học
Hàm
Định nghĩa hàm (Function Definition)
Nguyên mẫu hàm (Function Prototype)
Header File
Sinh số ngẫu nhiên
Ví dụ: Trò chơi may rủi và Giới thiệu về kiểu enum
Các kiểu lưu trữ (Storage Class)
Các quy tắc phạm vi (Scope Rule)
Đệ quy (Recursion)
Ví dụ sử dụng đệ quy: chuỗi Fibonacci
So sánh Đệ quy và Vòng lặp
Hàm với danh sách đối số rỗng
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
3
Chương 3 - Hàm
Đề mục
3.16
3.17
3.18
3.19
3.20
3.21
Hàm Inline
Tham chiếu và tham số là tham chiếu
Đối số mặc định
Toán tử phạm vi đơn (Unary Scope Resolution Operator)
Chồng hàm (Function Overloading)
Khuôn mẫu hàm (Function Templates)
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
4
3.1 Giới thiệu
• Chia để trị - Divide and conquer
– Xây dựng một chương trình từ các thành phần (component)
nhỏ hơn
– Quản lý từng thành phần dễ quản lý hơn quản lý chương
trình ban đầu
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
5
3.2 Các thành phần của chương trình C++
• Các module: các hàm(function) và lớp(class)
• Các chương trình sử dụng các module mới và đóng gói sẵn
(“prepackaged”)
– Mới: các hàm và lớp do lập trình viên tự định nghĩa
– Đóng gói sẵn: các hàm và lớp từ thư viện chuẩn
• lời gọi hàm - function call
– tên hàm và các thông tin (các đối số - arguments) mà nó cần
• định nghĩa hàm - function definition
– chỉ viết một lần
– được che khỏi các hàm khác
• tương tự
– Một ông chủ (hàm gọi - the calling function or caller) đề nghị một
công nhân (hàm được gọi - the called function) thực hiện một
nhiệm vụ và trả lại (báo cáo lại) kết quả khi nhiệm vụ hoàn thành.
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
6
3.3 Các hàm trong thư viện toán học
• Thực hiện các tính toán toán học thông thường
– Include header file <cmath> (hoặc
<math.h>)
• Cách gọi hàm
– tên_hàm (đối_số); hoặc
– tên_hàm(đối_số_1, đối_số_2, …);
• Ví dụ
cout << sqrt( 900.0 );
– Mọi hàm trong thư viện toán đều trả về giá trị kiểu double
• các đối số (argument) cho hàm có thể là
– hằng - Constants
• sqrt( 4 );
– biến - Variables
• sqrt( x );
– biểu thức - Expressions
• sqrt( sqrt( x ) ) ;
• sqrt( 3 - 6x );
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
7
Me tho d
ceil( x )
De sc rip tio n
làm tròn x tới số nguyên nhỏ
nhất không nhỏ hơn x
cos( x )
cos của x (lượng giác)
(x tính theo đơn vị radian)
hàm mũ: e mũ x
exp( x )
Exa mp le
ceil( 9.2 ) is 10.0
ceil( -9.8 ) is -9.0
cos( 0.0 ) is 1.0
exp( 1.0 ) is 2.71828
exp( 2.0 ) is 7.38906
fabs( x )
giá trị tuyệt đối của x
fabs( 5.1 ) is 5.1
fabs( 0.0 ) is 0.0
fabs( -8.76 ) is 8.76
floor( x )
làm tròn x xuống số nguyên lớn floor( 9.2 ) is 9.0
nhất không lớn hơn x
floor( -9.8 ) is -10.0
fmod( x, y )
phần dư của phép chia x/y , tính fmod( 13.657, 2.333 ) is 1.992
bằng kiểu số thực
log( x )
loga tự nhiên của x (cơ số e)
log( 2.718282 ) is 1.0
log( 7.389056 ) is 2.0
log10( x )
loga cơ số 10 của x
log10( 10.0 ) is 1.0
log10( 100.0 ) is 2.0
pow( x, y )
x mũ y
pow( 2, 7 ) is 128
pow( 9, .5 ) is 3
sin( x )
sin x (lượng giác)
sin( 0.0 ) is 0
(x tính theo radian)
sqrt( x )
căn bậc hai của x
sqrt( 900.0 ) is 30.0
sqrt( 9.0 ) is 3.0
tan( x )
tang x (lượng giác)
tan( 0.0 ) is 0
(x tính theo radian)
Fig . 3.2 Ma th lib ra ry func tio ns.
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
8
3.4 Hàm - function
• Chương trình con
– Module hóa một chương trình
– khả năng tái sử dụng phần mềm – Software reusability
• gọi hàm nhiều lần
• Các biến địa phương – Local variables
– khai báo trong hàm nào thì chỉ được biết đến bên trong hàm
đó
– biến được khai báo bên trong định hàm là biến địa phưnơg
• Các tham số – Parameters
– là các biến địa phương với giá trị được truyền vào hàm khi
hàm được gọi
– cung cấp thông tin về bên ngoài hàm
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
9
// Creating and using a programmer-defined function.
#include <iostream>
Function prototype: chỉ rõ kiểu dữ liệu
của đối số và giá trị trả về. square
cần một số int, và trả về int.
using std::cout;
using std::endl;
int square( int );
fig03_03.cpp
(1 of 2)
// function prototype
int main()
{
// loop 10 times and calculate and output Cặp ngoặc () dùng khi gọi hàm.
Khi chạy xong, hàm trả kết quả.
// square of x each time
for ( int x = 1; x <= 10; x++ )
cout << square( x ) << " "; // function call
cout << endl;
return 0;
// indicates successful termination
1
} // end main
4
9
16
25
36
49
64
81
100
// square function definition returns square of an integer
int square( int y ) // y is a copy of argument to function
{
return y * y;
// returns square of Định
y as nghĩa
an int
hàm square.
} // end function square
y là một bản sao
của đối số được truyền vào. Hàm trả về y *
©2004 Trần Minh Châu.
y, hoặc y bình phương.
FOTECH. VNU.
10
1
2
3
// Fig. 3.4: fig03_04.cpp
// Finding the maximum of three floating-point numbers.
#include <iostream>
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
double maximum( double, double, double ); // function prototype
10
11
12
13
14
15
int main()
{
double number1;
double number2;
double number3;
fig03_04.cpp
(1 of 2)
Hàm maximum lấy 3 tham số
(cả 3 là double) và trả về
một double.
16
17
18
cout << "Enter three floating-point numbers: ";
cin >> number1 >> number2 >> number3;
19
20
21
22
23
// number1, number2 and number3 are arguments to
// the maximum function call
cout << "Maximum is: "
<< maximum( number1, number2, number3 ) << endl;
24
25
return 0;
// indicates successful termination
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
11
} // end main
dấu phảy phân tách các tham số.
// function maximum definition;
// x, y and z are parameters
double maximum( double x, double y, double z )
{
double max = x;
// assume x is largest
if ( y > max )
max = y;
// if y is larger,
// assign y to max
if ( z > max )
max = z;
// if z is larger,
// assign z to max
return max;
// max is largest value
fig03_04.cpp
(2 of 2)
fig03_04.cpp
output (1 of 1)
} // end function maximum
Enter three floating-point numbers: 99.32 37.3 27.1928
Maximum is: 99.32
Enter three floating-point numbers: 1.1 3.333 2.22
Maximum is: 3.333
©2004 Trần Minh Châu.
Enter three floating-point numbers: 27.9 14.31 88.99 FOTECH. VNU.
M i
i
88 99
12
3.4
Hàm
• Nguyên mẫu hàm - Function prototype
– Cho trình biên dịch biết kiểu dữ liệu của đối số và kiểu giá
trị trả về của hàm
int square( int );
• Hàm lấy một giá trị int và trả về một giá trị int
– Sẽ giới thiệu kỹ hơn sau
• Gọi hàm
square(x);
– Cặp ngoặc đơn là toán tử dùng để gọi hàm
• Truyền đối số x
• Hàm nhận được bản sao các đối số cho riêng mình
– Sau khi kết thúc, hàm trả kết quả về cho nơi gọi hàm
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
13
3.5 Định nghĩa hàm – function definition
• định nghĩa hàm
return-value-type function-name( parameter-list )
{
declarations and statements
}
– danh sách tham số – Parameter list
• dấu phảy tách các tham số
– mỗi tham số cần cho biết kiểu dữ liệu của tham số đó
• Nếu không có đối số, sử dụng void hoặc để trống
– giá trị trả về – Return-value-type
• kiểu của giá trị trả về (sử dụng void nếu không trả về giá trị
gì)
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
14
3.5 Định nghĩa hàm
• Từ khóa return
Ví dụ về hàm
int square( int y )
{
return y * y;
– trả dữ liệu về, và trả điều khiển lại cho nơi
gọi (caller)
• nếu không trả về, sử dụng return;
– hàm kết thúc khi chạy đến ngoặc phải ( } )
}
• điều khiển cũng được trả về cho nơi gọi
int main()
{
...
• Không thể định nghĩa một hàm bên
trong một hàm khác
cout << square(x);
...
}
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
15
3.6 Nguyên mẫu hàm - Function Prototype
• Function prototype bao gồm
– Tên hàm
– Các tham số (số lượng và kiểu dữ liệu)
– Kiểu trả về (void nếu không trả về giá trị gì)
• Function prototype chỉ cần đến nếu định nghĩa hàm đặt
sau lời gọi hàm (function call)
• Prototype phải khớp với định nghĩa hàm
– Function prototype
double maximum( double, double, double );
– Function definition
double maximum( double x, double y, double z )
{
…
}
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
16
3.6 Function Prototype
• Chữ ký của hàm - Function signature
– Phần prototype chứa tên và các tham số của hàm
• double maximum( double, double, double );
Function signature
• Ép kiểu đối số – Argument Coercion
– Ép các đối số thành các kiểu dữ liệu thích hợp
• đổi int (4) thành double (4.0)
cout << sqrt(4)
– các quy tắc biến đổi
• các đối số thường được tự động đổi kiểu
• đổi từ double sang int có thể làm tròn dữ liệu
– 3.4 thành 3
– các kiểu hỗn hợp được nâng lên kiểu cao nhất
• int * double
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
17
3.6 Function Prototype
Da ta typ es
long double
double
float
unsigned long int
(synonymous with unsigned long)
(synonymous with long)
long int
unsigned int
(synonymous with unsigned)
int
(synonymous with unsigned short)
unsigned short int
short int
(synonymous with short)
unsigned char
char
bool
(false becomes 0, true becomes 1)
Fig . 3.5 Pro m o tio n hiera rc hy fo r b uilt-in d a ta typ es.
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
18
3.7 Header File
• Các file header chứa
– các function prototype
– định nghĩa của các kiểu dữ liệu và các hằng
• Các file header kết thúc bằng .h
– các file header do lập trình viên định nghĩa
#include “myheader.h”
• Các file header của thư viện
#include <cmath>
– chú ý:
• <cmath> tương đương với <math.h> (kiểu cũ, trước ANSI
C++)
• <iostream> tương đương với <iostream.h> (kiểu cũ, trước
ANSI C++)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
19
3.8 Sinh số ngẫu nhiên
Random Number Generation
• Hàm rand (thuộc <cstdlib>)
– i = rand();
– Sinh một số nguyên không âm trong đoạn từ 0 đến
RAND_MAX (thường là 32767)
• Lấy tỷ lệ và dịch (scaling and shifting)
– phép đồng dư (lấy số dư) – Modulus (remainder) operator: %
• 10 % 3 bằng 1
• x % y nằm giữa 0 và y – 1
– Ví dụ
i = rand() % 6 + 1;
• “Rand() % 6” sinh một số trong khoảng từ 0 đến 5 (lấy tỷ lệ )
• “+ 1” tạo khoảng từ 1 đến 6 (dịch)
– Tiếp theo: chương trình thả súc sắc
© 2004 Trần Minh Châu. FOTECH. VNU
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Chương 3.
20
// Fig. 3.7: fig03_07.cpp
// Shifted, scaled integers produced by 1 + rand() % 6.
#include <iostream>
using std::cout;
using std::endl;
6
5
6
6
#include <iomanip>
6
1
6
2
fig03_07.cpp
(1 of 2)
5
1
2
3
5
5
4
4
6
3
2
1
using std::setw;
#include <cstdlib>
// contains function prototype for rand
int main()
{
// loop 20 times
Kết
for ( int counter = 1; counter <= 20; counter++ ) {
// pick random number from 1 to 6 and output
cout << setw( 10 ) << ( 1 + rand() % 6 );
quả của rand() được
lấy tỷ lệ và dịch thành một số
it trong khoảng từ 1 đến 6.
// if counter divisible by 5, begin new line of output
if ( counter % 5 == 0 )
cout << endl;
} // end for structure
return 0;
// indicates successful termination
} // end main
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
21
3.8 Sinh số ngẫu nhiên
• Tiếp theo
– Chương trình biểu diễn phân bố (distribution) của hàm
rand()
– Giả lập 6000 lần thả súc sắc
– In số lượng các giá trị 1, 2, 3, v.v.... thả được
– số lượng đếm được của mỗi giá trị phải xấp xỉ 1000
© 2004 Trần Minh Châu. FOTECH. VNU
1
2
3
// Fig. 3.8: fig03_08.cpp
// Roll a six-sided die 6000 times.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
9
10
using std::setw;
11
12
#include <cstdlib>
13
14
15
16
17
18
19
20
21
22
int main()
{
int frequency1 = 0;
int frequency2 = 0;
int frequency3 = 0;
int frequency4 = 0;
int frequency5 = 0;
int frequency6 = 0;
int face; // represents one roll of the die
Chương 3.
22
fig03_08.cpp
(1 of 3)
// contains function prototype for rand
23
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// determine face value and increment appropriate counter
switch ( face ) {
fig03_08.cpp
(2 of 3)
case 1:
// rolled 1
++frequency1;
break;
case 2:
// rolled 2
++frequency2;
break;
case 3:
// rolled 3
++frequency3;
break;
case 4:
// rolled 4
++frequency4;
break;
case 5:
// rolled 5
++frequency5;
break;
©2004 Trần Minh Châu.
FOTECH. VNU.
24
case 6:
// rolled 6
++frequency6;
break;
fig03_08.cpp
(3 of 3)
default:
// invalid value
cout << "Program should never get here!";
} // end switch
Trường hợp mặc định được xét đến, ngay
cả khi nó không bao giờ xảy ra. Đây là
một nét của phong cách lập trình tốt
59
60
} // end for
61
62
63
64
65
66
67
68
69
// display results in tabular format
cout << "Face" << setw( 13 ) << "Frequency"
<< "\n
1" << setw( 13 ) << frequency1
<< "\n
2" << setw( 13 ) << frequency2
<< "\n
3" << setw( 13 ) << frequency3
<< "\n
4" << setw( 13 ) << frequency4
<< "\n
5" << setw( 13 ) << frequency5
<< "\n
6" << setw( 13 ) << frequency6 << endl;
70
71
return 0;
72
73
23
// loop 6000 times and summarize results
for ( int roll = 1; roll <= 6000; roll++ ) {
face = 1 + rand() % 6; // random number from 1 to 6
Face
1
2
3
4
5
6
Frequency
1003
1017
983
994
1004
999
// indicates successful termination
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
3.8 Sinh số ngẫu nhiên
• Gọi rand() lặp đi lặp lại
– cho kết quả là cùng một chuỗi số
• Các số giả ngẫu nhiên (pseudorandom numbers)
– chuỗi các số "ngẫu nhiên" được định sẵn
– chương trình chạy lần nào cũng sinh cùng một chuỗi
• Để được các chuỗi ngẫu nhiên khác nhau
– Cung cấp một giá trị hạt giống
• điểm xuất phát cho việc sinh chuỗi ngẫu nhiên
• hạt giống giống nhau sẽ cho cùng một chuỗi ngẫu nhiên
– srand(seed);
• <cstdlib>
• sử dụng trước rand() để đặt hạt giống
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
1
2
3
// Fig. 3.9: fig03_09.cpp
// Randomizing die-rolling program.
#include <iostream>
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
#include <iomanip>
10
11
using std::setw;
12
13
14
// contains prototypes for functions srand and rand
#include <cstdlib>
15
16
17
18
19
// main function begins program execution
int main()
{
unsigned seed;
20
21
22
23
26
fig03_09.cpp
(1 of 2)
Đặt hạt giống bằng
cout << "Enter seed: "; srand().
cin >> seed;
srand( seed ); // seed random number generator
24
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
26
27
28
29
30
31
32
33
// pick random number from 1 to 6 and output it
cout << setw( 10 ) << ( 1 + rand() % 6 );
fig03_09.cpp
(2 of 2)
// if counter divisible by 5, begin new line of output
if ( counter % 5 == 0 )
cout << endl;
fig03_09.cpp
output (1 of 1)
34
35
} // end for
36
37
return 0;
38
39
27
// loop 10 times
for ( int counter = 1; counter <= 10; counter++ ) {
// indicates successful termination
rand() sinh cùng một chuỗi
ngẫu nhiên nếu dùng cùng
một hạt giống
} // end main
Enter seed: 67
6
1
1
6
4
1
6
6
2
4
Enter seed: 432
4
3
6
1
3
5
1
4
6
2
Enter seed: 67
6
1
1
6
4
1
6
6
2
4
©2004 Trần Minh Châu.
FOTECH. VNU.
28
3.8 Sinh số ngẫu nhiên
• Có thể sử dụng thời gian hiện tại để làm hạt giống
– không cần phải đặt hạt giống mỗi lần sinh 1 số ngẫu nhiên
– srand( time( 0 ) );
– time( 0 );
• <ctime>
• trả về thời gian hiện tại, tính bằng giây
• Tổng quát về dịnh và lấy tỷ lệ
– Number = shiftingValue + rand() % scalingFactor
– shiftingValue = số đầu tiên của khoảng mong muốn
– scalingFactor = độ rộng của khoảng mong muốn
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
29
3.9 Ví dụ: Trò chơi may rủi và
Giới thiệu về kiểu enum
• Kiểu liệt kê - Enumeration
– tập hợp các số tự nhiên được đặt tên
enum typeName {constant1, constant2…};
– Các hằng số là các số nguyên bắt đầu từ 0 (mặc định), tăng dần,
mỗi lần thêm 1 đơn vị.
– Các hằng phải có tên riêng
– Không thể gán giá trị kiểu nguyên cho biến kiểu liệt kê
• Phải dùng một giá trị thuộc cùng kiểu liệt kê đã được định nghĩa
• Ví dụ
enum Status {CONTINUE, WON, LOST};
enum Foo {Zero, One, Two};
Status enumVar;
enumVar = WON; // cannot do enumVar = 1 or enumVar=One
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
30
3.9 Ví dụ: Trò chơi may rủi và
Giới thiệu về kiểu enum
• Các hằng kiểu liệt kê có thể có giá trị đặt trước
enum Months { JAN = 1, FEB, MAR, APR, MAY,
JUN, JUL, AUG, SEP, OCT, NOV, DEC};
– bắt đầu tại 1, tăng dần mỗi lần thêm 1
• Tiếp theo: giả lập trò chơi gieo súc sắc
–
–
–
–
Gieo 2 con súc sắc, được kết quả là tổng hai giá trị gieo được
7 hoặc 11 tại lần gieo đầu tiên: người chơi thắng
2, 3, hoặc 12 tại lần gieo đầu tiên: người chơi thua
4, 5, 6, 8, 9, 10
• giá trị gieo được trở thành "điểm" (point) của người chơi
• người chơi phải gieo được số điểm của mình trước khi gieo
được 7 để thắng cuộc
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
31
1
2
3
// Fig. 3.10: fig03_10.cpp
// Craps.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
9
// contains function prototypes for functions srand and rand
Hàm gieo 2 con súc sắc và trả về kết
#include <cstdlib>
10
11
#include <ctime>
12
13
int rollDice( void );
14
15
16
17
18
Kiểu liệt kê để ghi trạng thái
int main()
của ván chơi hiện tại.
{
// enumeration constants represent game status
enum Status { CONTINUE, WON, LOST };
fig03_10.cpp
(1 of 5)
quả là 1 giá trị kiểu int.
// contains prototype for function time
19
20
21
int sum;
int myPoint;
22
23
Status gameStatus;
// function prototype
// can contain CONTINUE, WON or LOST
24
©2004 Trần Minh Châu.
FOTECH. VNU.
25
26
// randomize random number generator using current time
srand( time( 0 ) );
27
28
sum = rollDice();
29
30
31
// determine game status and point based on sum of dice
switch ( sum ) {
32
fig03_10.cpp
(2 of 5)
// first roll of the dice
32
33
34
35
36
37
// win on first roll
case 7:
case 11:
gameStatus = WON;
break;
38
39
40
41
42
43
44
// lose on first roll
case 2:
case 3:
case 12:
gameStatus = LOST;
break;
lệnh switch quyết định kết
cục ván chơi, dựa vào kết quả
gieo súc sắc.
45
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
46
47
48
49
50
51
33
// remember point
default:
gameStatus = CONTINUE;
myPoint = sum;
cout << "Point is " << myPoint << endl;
break;
// optional
fig03_10.cpp
(3 of 5)
52
53
} // end switch
54
55
56
57
// while game not complete ...
while ( gameStatus == CONTINUE ) {
sum = rollDice();
// roll dice again
58
59
60
61
62
63
64
65
66
// determine game status
if ( sum == myPoint )
gameStatus = WON;
else
if ( sum == 7 )
gameStatus = LOST;
// win by making point
// lose by rolling 7
} // end while
67
©2004 Trần Minh Châu.
FOTECH. VNU.
68
69
70
71
72
// display won or lost message
if ( gameStatus == WON )
cout << "Player wins" << endl;
else
cout << "Player loses" << endl;
73
74
return 0;
fig03_10.cpp
(4 of 5)
// indicates successful termination
Hàm rollDice không lấy
đối số, nên nó có từ khóa
void tại danh sách tham số.
75
76
} // end main
77
78
79
80
81
82
83
// roll dice, calculate sum and display results
int rollDice( void )
{
int die1;
int die2;
int workSum;
84
85
86
87
34
die1 = 1 + rand() % 6;
die2 = 1 + rand() % 6;
workSum = die1 + die2;
// pick random die1 value
// pick random die2 value
// sum die1 and die2
88
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
89
90
91
// display results of this roll
cout << "Player rolled " << die1 << " + " << die2
<< " = " << workSum << endl;
92
93
return workSum;
94
95
35
fig03_10.cpp
(5 of 5)
// return sum of dice
} // end function rollDice
fig03_10.cpp
output (1 of 2)
Player rolled 2 + 5 = 7
Player wins
Player rolled 6 + 6 = 12
Player loses
Player rolled
Point is 6
Player rolled
Player rolled
Player rolled
Player rolled
Player wins
3 + 3 = 6
5
4
2
1
+
+
+
+
3
5
1
5
=
=
=
=
8
9
3
6
Player rolled
Point is 4
Player rolled
Player rolled
Player rolled
Player rolled
Player rolled
Player rolled
Player rolled
Player rolled
Player loses
1 + 3 = 4
4
2
6
2
2
1
4
4
+
+
+
+
+
+
+
+
6
4
4
3
4
1
4
3
=
=
=
=
=
=
=
=
10
6
10
5
6
2
8
7
©2004 Trần Minh Châu.
FOTECH. VNU.
36
3.10 Các kiểu lưu trữ – Storage Classes
• biến có các thuộc tính
– đã biết: tên, kiểu, kích thước, giá trị
– kiểu lưu trữ – Storage class
• biến tồn tại bao lâu trong bộ nhớ
– Phạm vi – Scope
• biến có thể được sử dụng tại những nơi nào trong chương trình
– Liên kết – Linkage
• Đối với những chương trình gồm nhiều file (multiple-file
program) – (xem chương 6), những file nào có thể sử dụng
biến đó
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
37
3.10 Các kiểu lưu trữ – Storage Classes
• loại biến tự động – Automatic storage class
– biến được tạo khi chương trình chạy vào một khối chương
trình (block)
– và bị hủy bỏ khi chương trình ra khỏi block
– Chỉ có các biến địa phương của các hàm mới có thể là biến
tự động
• mặc định là tự động
• từ khóa auto dùng để khai báo biến tự động
– từ khóa register
• gợi ý đặt biến vào thanh ghi tốc độ cao
• có lợi cho các biến thường xuyên được sử dụng (con đếm vòng
lặp)
• Thường là không cần thiết, trình biên dịch tự tối ưu hóa
– Chỉ dùng một trong hai từ register hoặc auto.
• register int counter = 1;
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
38
3.10 Các kiểu lưu trữ
• loại biến tĩnh – Static storage class
– Biến tồn tại trong suốt chương trình
– Có thể không phải nơi nào cũng dùng được, do áp dụng quy
tắc phạm vi (scope rules)
• từ khóa static
– dành cho biến địa phương bên trong hàm
– giữ giá trị giữa các lần gọi hàm
– chỉ được biết đến trong hàm của biến đó
• từ khóa extern
– mặc định với các biến/hàm toàn cục (global
variables/functions)
• toàn cục: được định nghĩa bên ngoài các hàm
– được biết đến tại mọi hàm nằm sau biến đó
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
39
3.11 Các quy tắc phạm vi – Scope Rules
• Phạm vi – Scope
– Phạm vi của một định danh (tên) là phần chương trình nơi có
thể sử dụng định danh đó
• Phạm vi file – File scope
– được định nghĩa bên ngoài một hàm và được biết đến tại mọi
hàm trong file
– các biến toàn cục (global variable), định nghĩa và prototype
của các hàm.
• Phạm vi hàm – Function scope
– chỉ có thể được dùng đến bên trong hàm chứa định nghĩa
– Chỉ áp dụng cho các nhãn (label), ví dụ: các định danh đi
kèm một dấu hai chấm (case:)
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
40
3.11 Các quy tắc phạm vi
• Phạm vi khối – Block scope
– Bắt đầu tại nơi khai báo, kết thúc tại ngoặc phải }
• chỉ có thể được dùng trong khoảng này
– Các biến địa phương, các tham số hàm
– các biến static cũng có phạm vi khối
• loại lưu trữ độc lập với phạm vi
• Function-prototype scope
– danh sách tham số của function prototype
– không bắt buộc phải chỉ rõ các tên trong prototype
• Trình biên dịch bỏ qua
– Trong một prototype, mỗi tên chỉ được dùng một lần
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
41
1
2
3
// Fig. 3.12: fig03_12.cpp
// A scoping example.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
9
10
được
khai báo bên
ngoài hàm;
void useLocal( void );
// function
prototype
là
biến
toàn
cục
với
phạm vi file.
void useStaticLocal( void ); // function prototype
void useGlobal( void );
// function prototype
11
12
int x = 1;
13
14
15
16
int main()
{
int x = 5;
17
18
19
20
21
22
23
24
25
26
fig03_12.cpp
(1 of 5)
// global variable
Biến địa phương với phạm vi hàm.
// local variable to main
cout << "local x in main's outer scope is " << x << endl;
{ // start new scope
Tạo một khối, cho x phạm vi
khối. Khi khối kết thúc, x sẽ
bị hủy bỏ.
int x = 7;
cout << "local x in main's inner scope is " << x << endl;
©2004 Trần Minh Châu.
FOTECH. VNU.
} // end new scope
42
27
28
cout << "local x in main's outer scope is " << x << endl;
29
30
31
32
33
34
35
useLocal();
useStaticLocal();
useGlobal();
useLocal();
useStaticLocal();
useGlobal();
36
37
cout << "\nlocal x in main is " << x << endl;
38
39
return 0;
40
41
//
//
//
//
//
//
fig03_12.cpp
(2 of 5)
useLocal has local x
useStaticLocal has static local x
useGlobal uses global x
useLocal reinitializes its local x
static local x retains its prior value
global x also retains its value
// indicates successful termination
} // end main
42
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
43
44
45
46
47
48
49
50
51
52
53
54
43
// useLocal reinitializes local variable x during each call
void useLocal( void )
{
int x = 25; // initialized each time useLocal is called
fig03_12.cpp
(3 of 5)
Biến tự động (biến địa phương của
cout <<
<<
++x;
cout <<
<<
endl << "local x is "
<< x
hàm).
Biến này sẽ bị hủy khi hàm kết
" on entering useLocal"
endl;
thúc, <<
và được
khởi tạo lại khi hàm bắt
đầu.
"local x is " << x
" on exiting useLocal" << endl;
} // end function useLocal
55
©2004 Trần Minh Châu.
FOTECH. VNU.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
44
// useStaticLocal initializes static local variable x only the
// first time the function is called; value of x is saved
// between calls to this function
void useStaticLocal( void )
{
// initialized only first time useStaticLocal is called
static int x = 50;
cout <<
<<
++x;
cout <<
<<
fig03_12.cpp
(4 of 5)
endl << "local static x is " << x
" on entering useStaticLocal" << endl;
"local static x is " << x
" on exiting useStaticLocal" << endl;Biến
} // end function useStaticLocal
tĩnh địa phương của hàm; nó được khởi tạo
đúng một lần và giữ nguyên giá trị giữa các lần gọi
hàm.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
72
73
74
75
76
77
78
79
80
81
45
// useGlobal modifies global variable x during each call
void useGlobal( void )
Hàm này không khai báo biến nào. Nó sử dụng biến toàn
{
cục x đã được khai báo tại đầu chương trình.
fig03_12.cpp
cout << endl << "global x is " << x
(5 of 5)
<< " on entering useGlobal" << endl;
x *= 10;
fig03_12.cpp
cout << "global x is " << x
output (1 of 2)
<< " on exiting useGlobal" << endl;
} // end function useGlobal
local x in main's outer scope is 5
local x in main's inner scope is 7
local x in main's outer scope is 5
local x is 25 on entering useLocal
local x is 26 on exiting useLocal
local static x is 50 on entering useStaticLocal
local static x is 51 on exiting useStaticLocal
global x is 1 on entering useGlobal
global x is 10 on exiting useGlobal
©2004 Trần Minh Châu.
FOTECH. VNU.
46
local x is 25 on entering useLocal
local x is 26 on exiting useLocal
fig03_12.cpp
output (2 of 2)
local static x is 51 on entering useStaticLocal
local static x is 52 on exiting useStaticLocal
global x is 10 on entering useGlobal
global x is 100 on exiting useGlobal
local x in main is 5
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
47
3.12 Đệ quy – Recursion
• Các hàm đệ quy – Recursive functions
– các hàm tự gọi chính mình
– chỉ giải quyết một trường hợp cơ bản (base case)
• Nếu không phải trường hợp cơ bản
– Chia bài toán thành các bài toán nhỏ hơn
– Gọi bản sao mới của hàm để giải quyết vấn đề nhỏ hơn (gọi
đệ quy (recursive call) hoặc bước đệ quy(recursive step))
• hội tụ dần dần về trường hợp cơ bản
• hàm gọi chính nó tại lệnh return
– Cuối cùng, trường hợp cơ bản được giải quyết
• câu trả lời đi ngược lên, giải quyết toàn bộ bài toán
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
48
3.12 Đệ quy
• Ví dụ: tính giai thừa (factorial)
n! = n * ( n – 1 ) * ( n – 2 ) * … * 1
– Quan hệ đệ quy ( n! = n * ( n – 1 )! )
5! = 5 * 4!
4! = 4 * 3!…
– Trường hợp cơ bản (1! = 0! = 1)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
49
1
2
3
// Fig. 3.14: fig03_14.cpp
// Recursive factorial function.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
9
10
using std::setw;
11
12
unsigned long factorial( unsigned long ); // function prototype
13
14
15
16
17
18
19
20
int main()
{
// Loop 10 times. During each iteration, calculate
// factorial( i ) and display result.
for ( int i = 0; i <= 10; i++ )
cout << setw( 2 ) << i << "! = "
<< factorial( i ) << endl;
21
22
23
24
return 0;
fig03_14.cpp
(1 of 2)
Kiểu dữ liệu unsigned
long có thể lưu số nguyên
trong khoảng từ 0 đến 4 tỷ.
// indicates successful termination
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
25
26
27
28
29
30
31
32
33
34
35
36
37
0!
1!
2!
3!
4!
5!
6!
7!
8!
9!
10!
50
// recursive definition of function factorial
unsigned long factorial( unsigned long number )
{
Trường hợp cơ bản xảy ra khi
// base case
ta có 0! hoặc 1!.
if ( number <= 1 )
Mọi trường hợp khác phải
return 1;
fig03_14.cpp
(2 of 2)
fig03_14.cpp
output (1 of 1)
được chia nhỏ (bước đệ qui).
// recursive step
else
return number * factorial( number - 1 );
} // end function factorial
=
=
=
=
=
=
=
=
=
=
=
1
1
2
6
24
120
720
5040
40320
362880
3628800
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
51
3.13 Ví dụ sử dụng đệ quy: chuỗi Fibonacci
• Chuỗi Fibonacci: 0, 1, 1, 2, 3, 5, 8...
– Mỗi số là tổng của hai số đứng liền trước
– Ví dụ một công thức đệ quy:
• fib(n) = fib(n-1) + fib(n-2)
• Mã C++ cho hàm Fibonacci
long fibonacci( long n )
{
if ( n == 0 || n == 1 ) // base case
return n;
else
return fibonacci( n - 1 ) +
fibonacci( n – 2 );
}
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
52
3.13 Ví dụ sử dụng đệ quy: chuỗi Fibonacci
f( 3 )
return f( 2 )
return f( 1 )
return 1
+
+
f( 0 )
f( 1 )
return 1
return 0
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
53
3.13 Ví dụ sử dụng đệ quy: chuỗi Fibonacci
• Thứ tự thực hiện
– return fibonacci( n - 1 ) + fibonacci( n - 2 );
• Không xác định hàm nào được thực hiện trước
– C++ không qui định
– Chỉ có các phép &&, || và ?: đảm bảo thứ tự thực hiện từ
trái sang phải
• Các lời gọi hàm đệ quy
– Mỗi tầng đệ quy nhân đôi số lần gọi hàm
• số thứ 30 cần 2^30 ~ 4 tỷ lời gọi hàm
– Độ phức tạp lũy thừa (Exponential complexity)
© 2004 Trần Minh Châu. FOTECH. VNU
1
2
3
// Fig. 3.15: fig03_15.cpp
// Recursive fibonacci function.
#include <iostream>
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
Chương 3.
54
8
9
fig03_15.cpp
(1 of 2)
Các số Fibonacci tăng rất nhanh
và đều là số không âm.
Do đó, ta dùng kiểu
unsigned
long.
unsigned long fibonacci( unsigned long ); // function
prototype
10
11
12
13
int main()
{
unsigned long result, number;
14
15
16
17
// obtain integer from user
cout << "Enter an integer: ";
cin >> number;
18
19
20
// calculate fibonacci value for number input by user
result = fibonacci( number );
21
22
23
// display result
cout << "Fibonacci(" << number << ") = " << result << endl;
24
25
return 0;
// indicates successful termination
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
55
} // end main
fig03_15.cpp
(2 of 2)
// recursive definition of function fibonacci
unsigned long fibonacci( unsigned long n )
{
// base case
if ( n == 0 || n == 1 )
return n;
fig03_15.cpp
output (1 of 2)
// recursive step
else
return fibonacci( n - 1 ) + fibonacci( n - 2 );
} // end function fibonacci
Enter an integer: 0
Fibonacci(0) = 0
Enter an integer: 1
Fibonacci(1) = 1
Enter an integer: 2
Fibonacci(2) = 1
Enter an integer: 3
Fibonacci(3) = 2
©2004 Trần Minh Châu.
FOTECH. VNU.
56
Enter an integer: 4
Fibonacci(4) = 3
Enter an integer: 5
Fibonacci(5) = 5
fig03_15.cpp
output (2 of 2)
Enter an integer: 6
Fibonacci(6) = 8
Enter an integer: 10
Fibonacci(10) = 55
Enter an integer: 20
Fibonacci(20) = 6765
Enter an integer: 30
Fibonacci(30) = 832040
Enter an integer: 35
Fibonacci(35) = 9227465
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
57
3.14 So sánh Đệ quy và Vòng lặp
• Lặp
– Vòng lặp (Iteration): lặp tường minh
– Đệ quy: các lời gọi hàm được lặp đi lặp lại
• Kết thúc
– Vòng lặp: điều kiện lặp thất bại
– Đệ quy: gặp trường hợp cơ bản
• Cả hai đều có thể lặp vô tận
• Cân đối giữa hiệu quả chương trình (vòng lặp) và
công nghệ phần mềm tốt (đệ quy)
– vòng lặp chạy nhanh hơn
– đệ quy trong sáng hơn
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
58
3.15 Hàm với danh sách tham số rỗng
• Danh sách tham số rỗng
– dùng từ khóa void hoặc để danh sách rỗng
– dành cho hàm không lấy đối số
– thí dụ: hàm print không lấy đối số và không trả về giá trị
nào
• void print();
• void print( void );
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
59
1
2
3
// Fig. 3.18: fig03_18.cpp
// Functions that take no arguments.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
9
void function1();
void function2( void );
10
11
12
13
14
int main()
{
function1();
function2();
// call function1 with no arguments
// call function2 with no arguments
15
16
return 0;
// indicates successful termination
17
18
fig03_18.cpp
(1 of 2)
// function prototype
// function prototype
} // end main
19
©2004 Trần Minh Châu.
FOTECH. VNU.
20
21
22
23
24
// function1 uses an empty parameter list to specify that
// the function receives no arguments
void function1()
{
cout << "function1 takes no arguments" << endl;
25
26
} // end function1
27
28
29
30
31
32
// function2 uses a void parameter list to specify that
// the function receives no arguments
void function2( void )
{
cout << "function2 also takes no arguments" << endl;
33
34
} // end function2
60
fig03_18.cpp
(2 of 2)
fig03_18.cpp
output (1 of 1)
function1 takes no arguments
function2 also takes no arguments
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
61
3.16 Hàm Inline
• Hàm inline
– Từ khóa inline đặt trước hàm
– Yêu cầu trình biên dịch sao chép mã vào chương trình thay
cho việc tạo lời gọi hàm
• Giảm chi phí gọi hàm (function-call overhead)
• Trình biên dịch có thể bỏ qua inline
– Tốt đối với các hàm nhỏ, hay dùng
• Ví dụ
inline double cube( const double s )
{ return s * s * s; }
– const cho trình biên dịch biết rằng hàm không sửa đổi s
• được nói đến trong các chương 6-7
© 2004 Trần Minh Châu. FOTECH. VNU
1
2
3
4
// Fig. 3.19: fig03_19.cpp
// Using an inline function to calculate.
// the volume of a cube.
#include <iostream>
5
6
7
8
using std::cout;
using std::cin;
using std::endl;
9
10
11
12
13
14
15
16
17
18
Chương 3.
62
fig03_19.cpp
(1 of 2)
// Definition of inline function cube. Definition of function
// appears before function is called, so a function prototype
// is not required. First line of function definition acts as
// the prototype.
inline double cube( const double side )
{
return side * side * side; // calculate cube
} // end function cube
19
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
20
21
22
63
int main()
{
cout << "Enter the side length of your cube: ";
fig03_19.cpp
(2 of 2)
23
24
double sideValue;
25
26
cin >> sideValue;
27
28
29
30
// calculate cube of sideValue and display result
cout << "Volume of cube with side "
<< sideValue << " is " << cube( sideValue ) << endl;
31
32
return 0;
33
34
fig03_19.cpp
output (1 of 1)
// indicates successful termination
} // end main
Enter the side length of your cube: 3.5
Volume of cube with side 3.5 is 42.875
©2004 Trần Minh Châu.
FOTECH. VNU.
64
3.17 Tham chiếu và Tham số là tham chiếu
• Các tham chiếu là các biệt danh (alias) của các
biến khác
– chỉ tới cùng một biến
– có thể được dùng bên trong một hàm
int count = 1; // khai báo biến nguyên count
int &cRef = count; // tạo cRef là một biệt danh của count
++cRef; // tăng count (sử dụng biệt danh của count)
• Các tham chiếu phải được khởi tạo khi khai báo
– Nếu không, trình biên dịch báo lỗi
– Tham chiếu lạc (Dangling reference)
• tham chiếu tới biến không xác định
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
1
2
3
// Fig. 3.21: fig03_21.cpp
// References must be initialized.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
9
10
65
fig03_21.cpp
(1 of 1)
fig03_21.cpp
output (1 of 1)
int main()
{
int x = 3;
y được khai báo là một tham chiếu tới x.
11
12
13
// y refers to (is an alias for) x
int &y = x;
14
15
16
17
cout << "x = " << x << endl << "y = " << y << endl;
y = 7;
cout << "x = " << x << endl << "y = " << y << endl;
18
19
return 0;
20
21
// indicates successful termination
} // end main
x
y
x
y
=
=
=
=
3
3
7
7
©2004 Trần Minh Châu.
FOTECH. VNU.
1
2
3
// Fig. 3.22: fig03_22.cpp
// References must be initialized.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
9
10
11
int main()
{
int x = 3;
int &y;
66
fig03_22.cpp
(1 of 1)
fig03_22.cpp
output
Lỗi biên dịch – tham chiếu không được khởi
tạo. (1 of 1)
// Error: y must be initialized
12
13
14
15
cout << "x = " << x << endl << "y = " << y << endl;
y = 7;
cout << "x = " << x << endl << "y = " << y << endl;
16
17
return 0;
18
19
// indicates successful termination
} // end main
Borland C++ command-line compiler error message:
Error E2304 Fig03_22.cpp 11: Reference variable 'y' must be
initialized- in function main()
Microsoft Visual C++ compiler error message:
D:\cpphtp4_examples\ch03\Fig03_22.cpp(11) : error C2530: 'y' :
references must be initialized
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
67
3.17 Tham chiếu và Tham số là tham chiếu
• Gọi bằng giá trị - Call by value
– Bản sao của dữ liệu được truyền cho hàm
– Thay đổi đối với bản sao không ảnh hưởng tới dữ liệu gốc
– Ngăn chặn các hiệu ứng phụ không mong muốn
• Gọi bằng tham chiếu - Call by reference
– Hàm có thể truy nhập trực tiếp tới dữ liệu gốc
– Các thay đổi thể hiện tại dữ liệu gốc
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
68
3.17 Tham chiếu và Tham số là tham chiếu
• Tham số tham chiếu - Reference parameter
– Ý nghĩa: Là biệt danh (alias) của biến được truyền vào lời
gọi hàm
• 'truyền tham số bằng tham chiếu' hay 'truyền tham chiếu'
– Cú pháp: Đặt ký hiệu & sau kiểu dữ liệu tại prototype của
hàm
• void myFunction( int &data )
• có nghĩa “data là một tham chiếu tới một biến kiểu int”
– dạng của lời gọi hàm không thay đổi
• tuy nhiên dữ liệu gốc khi được truyền bằng tham chiếu có thể
bị sửa đổi
• Con trỏ (chương 5)
– Một cách truyền tham chiếu khác
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
1
2
3
4
// Fig. 3.20: fig03_20.cpp
// Comparing pass-by-value and pass-by-reference
// with references.
#include <iostream>
5
6
7
using std::cout;
using std::endl;
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int squareByValue( int );
void squareByReference( int & );
69
fig03_20.cpp
(1 of 2)
Lưu ý ký hiệu & có nghĩa
truyền tham chiếu (pass-byreference).
// function
prototype
// function prototype
int main()
{
int x = 2;
int z = 4;
// demonstrate squareByValue
cout << "x = " << x << " before squareByValue\n";
cout << "Value returned by squareByValue: "
<< squareByValue( x ) << endl;
cout << "x = " << x << " after squareByValue\n" << endl;
22
©2004 Trần Minh Châu.
FOTECH. VNU.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
70
// demonstrate squareByReference
cout << "z = " << z << " before squareByReference" << endl;
squareByReference( z );
cout << "z = " << z << " after squareByReference" << endl;
fig03_20.cpp
(2 of 2)
return 0; // indicates successful termination
thay đổi number, nhưng đối số gốc
} // end main
(x) không bị thay đổi.
// squareByValue multiplies number by itself, stores the
// result in number and returns the new value of number
int squareByValue( int number )
{
return number *= number; // caller's argument not modified
} // end function squareByValue
thay đổi numberRef, một biệt danh
của đối số gốc. Do đó, z bị thay đổi.
// squareByReference multiplies numberRef by itself and
// stores the result in the variable to which numberRef
// refers in function main
void squareByReference( int &numberRef )
{
numberRef *= numberRef;
// caller's argument modified
} // end function squareByReference
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
71
x = 2 before squareByValue
Value returned by squareByValue: 4
x = 2 after squareByValue
fig03_20.cpp
output (1 of 1)
z = 4 before squareByReference
z = 16 after squareByReference
©2004 Trần Minh Châu.
FOTECH. VNU.
72
3.18 Các đối số mặc định
• Lời gọi hàm với các tham số được bỏ qua
– Nếu không đủ số tham số, các vị trí ở bên phải nhất sẽ được
nhận giá trị mặc định của chúng
– Các giá trị mặc định
• Có thể là hằng, biến toàn cục, hoặc các lời gọi hàm
• Đặt các giá trị mặc định tại function prototype
int myFunction( int x = 1, int y = 2, int z = 3 );
– myFunction(3)
• x = 3, y và z nhận giá trị mặc định (bên phải nhất)
– myFunction(3, 5)
• x = 3, y = 5 còn z nhận giá trị mặc định
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
73
1
2
3
// Fig. 3.23: fig03_23.cpp
// Using default arguments.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
9
// function prototype that specifies default arguments
int boxVolume( int length = 1, int width = 1, int height = 1 );
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fig03_23.cpp
(1 of 2)
Các giá trị mặc định được đặt
trong function prototype.
Các lời gọi hàm thiếu một
int main()
số đối số – Các đối số bên
{
phải nhất nhận giá trị mặc
// no arguments--use default values for all dimensions định.
cout << "The default box volume is: " << boxVolume();
// specify length; default width and height
cout << "\n\nThe volume of a box with length 10,\n"
<< "width 1 and height 1 is: " << boxVolume( 10 );
// specify length and width; default height
cout << "\n\nThe volume of a box with length 10,\n"
<< "width 5 and height 1 is: " << boxVolume( 10, 5 );
©2004 Trần Minh Châu.
FOTECH. VNU.
24
25
26
27
// specify all arguments
cout << "\n\nThe volume of a box with length 10,\n"
<< "width 5 and height 2 is: " << boxVolume( 10, 5, 2 )
<< endl;
28
29
return 0;
30
31
32
33
34
35
36
37
38
74
fig03_23.cpp
(2 of 2)
// indicates successful termination
fig03_23.cpp
output (1 of 1)
} // end main
// function boxVolume calculates the volume of a box
int boxVolume( int length, int width, int height )
{
return length * width * height;
} // end function boxVolume
The default box volume is: 1
The volume of a box with length 10,
width 1 and height 1 is: 10
The volume of a box with length 10,
width 5 and height 1 is: 50
The volume of a box with length 10,
width 5 and height 2 is: 100
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
75
3.19 Toán tử phạm vi đơn
• Toán tử phạm vi đơn (::)
Unitary Scope Resolution Operator
– Dùng để truy nhập biến toàn cục nếu biến địa phương có
cùng tên
– Không cần thiết nếu các tên biến khác nhau
– Cách dùng ::tên_biến
y = ::x + 3;
– Nên tránh dùng các tên giống nhau cho các biến địa phương
và toàn cục
© 2004 Trần Minh Châu. FOTECH. VNU
1
2
3
// Fig. 3.24: fig03_24.cpp
// Using the unary scope resolution operator.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
9
10
using std::setprecision;
11
12
13
// define global constant PI
const double PI = 3.14159265358979;
14
15
16
17
18
int main()
{
// define local constant PI
const float PI = static_cast< float >( ::PI );
Chương 3.
76
fig03_24.cpp
(1 of 2)
Truy nhập PI toàn cục với
::PI.
Chuyển đổi PI toàn cục
thành một giá trị float
cho PI địa phương. Ví dụ
này cho thấy sự khác nhau
giữa float và double.
19
20
21
22
23
// display values of local and global PI constants
cout << setprecision( 20 )
<< " Local float value of PI = " << PI
<< "\nGlobal double value of PI = " << ::PI << endl;
24
25
return 0;
// indicates successful termination
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
26
27
77
} // end main
fig03_24.cpp
(2 of 2)
Borland C++ command-line compiler output:
Local float value of PI = 3.141592741012573242
Global double value of PI = 3.141592653589790007
fig03_24.cpp
output (1 of 1)
Microsoft Visual C++ compiler output:
Local float value of PI = 3.1415927410125732
Global double value of PI = 3.14159265358979
©2004 Trần Minh Châu.
FOTECH. VNU.
78
3.20 Chồng hàm
• Chồng hàm - Function overloading
– Các hàm có cùng tên nhưng khác nhau về tham số
– Nên thực hiện các nhiệm vụ tương tự
• ví dụ, hàm tính bình phương cho int và hàm tính bình
phương cho float
int square( int x) {return x * x;}
float square(float x) { return x * x; }
• Các hàm chồng phân biệt nhau bởi chữ ký
– Dựa vào tên và kiểu tham số (xét cả thứ tự)
– Trình biên dịch đảm bảo gọi đúng hàm chồng được yêu cầu
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
1
2
3
// Fig. 3.25: fig03_25.cpp
// Using overloaded functions.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
79
fig03_25.cpp
(1 of 2)
Các hàm chồng có cùng tên
nhưng có tham số khác nhau
// function square for int values
int square( int x )
{
cout << "Called square with int argument: " << x << endl;
return x * x;
} // end int version of function square
// function square for double values
double square( double y )
{
cout << "Called square with double argument: " << y << endl;
return y * y;
} // end double version of function square
23
©2004 Trần Minh Châu.
FOTECH. VNU.
24
25
26
27
int main()
{
int intResult = square( 7 );
// calls int version
double doubleResult = square( 7.5 ); // calls double version
28
29
30
31
cout << "\nThe square of integer 7 is " << intResult
<< "\nThe square of double 7.5 is " << doubleResult
<< endl;
32
33
return 0;
34
35
80
fig03_25.cpp
(2 of 2)
fig03_25.cpp
output (1 of 1)
// indicates successful termination
} // end main
Tùy theo đối số được truyền vào (int
hoặc double) để gọi hàm thích hợp.
Called square with int argument: 7
Called square with double argument: 7.5
The square of integer 7 is 49
The square of double 7.5 is 56.25
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
81
3.21 Khuôn mẫu hàm - Function Template
• Cách ngắn gọn để tạo các hàm chồng
– Sinh các hàm riêng biệt cho các kiểu dữ liệu khác nhau
• Cú pháp
– Bắt đầu bằng từ khóa template
– các tham số kiểu hình thức trong cặp ngoặc <>
• typename hoặc class (đồng nghĩa) đặt trước mỗi tham số
kiểu
• là đại diện cho các kiểu cài sẵn (ví dụ int) hoặc các kiểu dữ
liệu người dùng
• chỉ ra các kiểu dữ liệu cho đối số hàm, giá trị trả về, biến địa
phương
– Hàm được định nghĩa như bình thường, ngoại trừ việc sử
dụng các kiểu hình thức
© 2004 Trần Minh Châu. FOTECH. VNU
Chương 3.
82
3.21 Khuôn mẫu hàm
• Ví dụ
template < class T > // or template< typename T >
T square( T value1 )
{
return value1 * value1;
}
– T là một kiểu hình thức, được dùng làm tham số kiểu
• hàm trên trả về giá trị thuộc cùng kiểu với tham số
– Tại lời gọi hàm, T được thay bằng kiểu dữ liệu thực
• Nếu là int, mọi T trở thành int
int x;
int y = square(x);
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 3.
https://fb.com/tailieudientucntt
1
2
3
// Fig. 3.27: fig03_27.cpp
// Using a function template.
#include <iostream>
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
83
fig03_27.cpp
(1 of 3)
Tham số kiểu hình thức T là đại
diện của kiểu dữ liệu được kiểm
tra trong hàm maximum.
// definition of function template maximum
template < class T > // or template < typename T >
T maximum( T value1, T value2, T value3 )
{
T max = value1;
if ( value2 > max )
max = value2;
maximum mong đợi mọi
tham số đều thuộc cùng một
kiểu dữ liệu.
if ( value3 > max )
max = value3;
return max;
} // end function template maximum
24
©2004 Trần Minh Châu.
FOTECH. VNU.
25
26
27
28
84
int main()
{
// demonstrate maximum with int values
int int1, int2, int3;
29
30
31
cout << "Input three integer values: ";
cin >> int1 >> int2 >> int3;
32
33
34
35
// invoke int version of maximum
cout << "The maximum integer value is: "
<< maximum( int1, int2, int3 );
36
37
38
// demonstrate maximum with double values
double double1, double2, double3;
39
40
41
cout << "\n\nInput three double values: ";
cin >> double1 >> double2 >> double3;
42
43
44
45
// invoke double version of maximum
cout << "The maximum double value is: "
<< maximum( double1, double2, double3 );
fig03_27.cpp
(2 of 3)
maximum được gọi với nhiều
kiểu dữ liệu.
46
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
85
47
48
// demonstrate maximum with char values
char char1, char2, char3;
49
50
51
cout << "\n\nInput three characters: ";
cin >> char1 >> char2 >> char3;
fig03_27.cpp
(3 of 3)
52
53
54
55
56
// invoke char version of maximum
cout << "The maximum character value is: "
<< maximum( char1, char2, char3 )
<< endl;
fig03_27.cpp
output (1 of 1)
57
58
return 0;
59
60
// indicates successful termination
} // end main
Input three integer values: 1 2 3
The maximum integer value is: 3
Input three double values: 3.3 2.2 1.1
The maximum double value is: 3.3
Input three characters: A C B
The maximum character value is: C
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
Ngôn ngữ lập trình C++
Chương 4 – Mảng
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
2
Chương 4 – Mảng
Đề mục
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8
4.9
Giới thiệu
Mảng
Khai báo mảng
Ví dụ về sử dụng mảng
Truyền tham số cho hàm
Sắp xếp mảng
Ví dụ: Dùng mảng tính Mean, Median và Mode
Tìm kiếm trên mảng: Tìm kiếm Tuyến tính và tìm kiếm Nhị phân
Mảng nhiều chiều
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
3
4.1
Giới thiệu
• Mảng (array)
– Cấu trúc của những phần tử dữ liệu có liên quan
– Thực thể tĩnh (giữ nguyên kích thước trong suốt chương
trình)
• Một vài loại mảng
– mảng dựa vào con trỏ (Pointer-based arrays) (C-like)
– mảng là đối tượng (Arrays as objects) (C++)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
4
4.2
Mảng
• Mảng
– Tập hợp các vùng nhớ liên tiếp
– Cùng tên, cùng kiểu (int, char, ...)
• Truy nhập đến 1 phần tử
– Chỉ ra tên mảng và vị trí - position (chỉ số - index)
– Cú pháp: tên_mảng[ chỉ_số ]
– Phần tử đầu tiên ở vị trí 0
• Mảng c có n phần tử
c[ 0 ], c[ 1 ] … c[ n - 1 ]
– Phần tử thứ N ở vị trí thứ N-1
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
5
4.2
Mảng
• Phần tử của mảng cũng như các biến khác
– Gán giá trị và in mảng số nguyên c
c[ 0 ] = 3;
cout << c[ 0 ];
• Có thể sử dụng các phép toán trong cặp ngoặc vuông
c[ 5 – 2 ] cũng giống c[3]
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
6
Tên mảng
(Lưu ý rằng mọi phần tử
của mảng này đều có cùng
tên, c)
c[0]
-45
c[1]
6
c[2]
0
c[3]
72
c[4]
1543
c[5]
-89
c[6]
0
c[7]
62
c[8]
-3
c[9]
1
c[10]
6453
c[11]
78
Chỉ số của phần tử
trong mảng c
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
7
4.3
Khai báo mảng
• Khi khai báo mảng, chỉ rõ
– Tên
– Kiểu của mảng
• Bất cứ kiểu dữ liệu nào
– Số phần tử
– type arrayName[ arraySize ];
int c[ 10 ]; // mảng của 10 số nguyên
float d[ 3284 ]; // mảng của 3284 số thực
• Khai báo nhiều mảng cùng kiểu
– Sử dụng dấu phẩy như với các biến bình thường
int b[ 100 ], x[ 27 ];
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
8
4.4
Ví dụ về sử dụng mảng
• Khởi tạo mảng
– Dùng vòng lặp khởi tạo từng phần tử
– Khởi tạo cả danh sách
• Chỉ rõ từng phần tử khi khai báo mảng
int n[ 5 ] = { 1, 2, 3, 4, 5 };
• Nếu trong danh sách không có đủ số giá trị khởi tạo, các phần tử ở
bên phải nhất sẽ nhận giá trị 0
• Nếu danh sách thừa sẽ gây lỗi cú pháp
– Khởi tạo giá trị bằng 0 cho tất cả các phần tử
int n[ 5 ] = { 0 };
– Nếu không khai báo kích thước mảng, kích thước của danh sách
các giá trị khởi tạo sẽ quyết định kích thước mảng
int n[] = { 1, 2, 3, 4, 5 };
• Có 5 giá trị khởi tạo, do đó mảng có 5 phần tử
• Nếu không khai báo kích thước mảng thì phải khởi tạo khi khai báo
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
1
2
3
fig04_03.cpp
(1 of 2)
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
9
10
using std::setw;
11
12
13
14
9
// Fig. 4.3: fig04_03.cpp
// Initializing an array.
#include <iostream>
Khai báo mảng 10 phần tử số nguyên.
int main()
{
int n[ 10 ];
// n is an array of 10 integers
Khởi tạo mảng bằng vòng lặp for.
Chú ý rằng mảng gồm các phẩn tử
từ n[0] đến n[9].
15
16
17
18
// initialize elements of array n to 0
for ( int i = 0; i < 10; i++ )
n[ i ] = 0;
// set element at location i to 0
19
20
cout << "Element" << setw( 13 ) << "Value" << endl;
21
22
23
24
// output contents of array n in tabular format
for ( int j = 0; j < 10; j++ )
cout << setw( 7 ) << j << setw( 13 ) << n[ j ] << endl;
25
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
28
return 0;
10
// indicates successful termination
} // end main
fig04_03.cpp
(2 of 2)
Element
0
1
2
3
4
5
6
7
8
9
Value
0
0
0
0
0
0
0
0
0
0
fig04_03.cpp
output (1 of 1)
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
fig04_04.cpp
(1 of 1)
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
9
10
using std::setw;
11
12
13
14
15
16
17
11
// Fig. 4.4: fig04_04.cpp
// Initializing an array with a declaration.
#include <iostream>
Lưu ý cách dùng danh sách
khởi tạo cho mảng.
int main()
{
// use initializer list to initialize array n
int n[ 10 ] = { 32, 27, 64, 18, 95, 14, 90, 70, 60, 37 };
cout << "Element" << setw( 13 ) << "Value" << endl;
18
19
20
21
// output contents of array n in tabular format
for ( int i = 0; i < 10; i++ )
cout << setw( 7 ) << i << setw( 13 ) << n[ i ] << endl;
22
23
return 0;
24
25
// indicates successful termination
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
Element
0
1
2
3
4
5
6
7
8
9
12
Value
32
27
64
18
95
14
90
70
60
37
fig04_04.cpp
output (1 of 1)
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
13
4.4
Ví dụ về sử dụng mảng
• Kích thước của mảng
– Có thể được xác định bằng hằng số (const)
• const int size = 20;
– Hằng số không thể thay đổi
– Hằng phải được khởi tạo khi khai báo
– Còn được gọi là “named constant” (giá trị được đặt tên) hoặc
“read-only variable” (biến chỉ đọc)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
1
2
3
fig04_05.cpp
(1 of 2)
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
9
10
using std::setw;
11
12
13
14
15
16
17
18
19
20
21
22
23
14
// Fig. 4.5: fig04_05.cpp
// Initialize array s to the even integers from 2 to 20.
#include <iostream>
int main()
{
// constant variable can be used
const int arraySize = 10;
int s[ arraySize ];
Chú ý từ khoá const. Chỉ có
các biến const được dùng
để khai
báo kích
thướcsize
mảng.
to
specify
array
// array s has 10 elements
Chương trình dễ thay đổi hơn khi ta
dùng
hằng
(const) cho kích thước của
for ( int i = 0; i < arraySize; i++ ) // set
the
values
mảng.
s[ i ] = 2 + 2 * i;
Ta có thể thay đổi arraySize, và tất
cả các vòng lặp vẫn hoạt động bình
cout << "Element" << setw( 13 ) << "Value" << endl;
thường (nếu không, ta phải sửa mọi
vòng lặp trong chương trình).
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
24
25
26
27
28
29
30
15
// output contents of array s in tabular format
for ( int j = 0; j < arraySize; j++ )
cout << setw( 7 ) << j << setw( 13 ) << s[ j ] << endl;
return 0;
// indicates successful termination
fig04_05.cpp
output (1 of 1)
} // end main
Element
0
1
2
3
4
5
6
7
8
9
fig04_05.cpp
(2 of 2)
Value
2
4
6
8
10
12
14
16
18
20
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
4
5
6
7
8
9
10
fig04_06.cpp
(1 of 1)
using std::cout;
using std::endl;
Khởi tạo hằng
int main()
{
const int x = 7;
fig04_06.cpp
output (1 of 1)
// initialized constant variable
11
12
13
cout << "The value of constant variable x is: "
<< x << endl;
14
15
return 0;
16
17
16
// Fig. 4.6: fig04_06.cpp
// Using a properly initialized constant variable.
#include <iostream>
// indicates successful termination
} // end main
The value of constant variable x is: 7
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
// Fig. 4.7: fig04_07.cpp
// A const object must be initialized.
3
4
5
6
int main()
{
const int x;
Lỗi cú pháp do không khởi tạo hằng.
Sửa giá trị của hằng cũng là một lỗi.
// Error: x must be initialized
7
8
x = 7;
// Error: cannot modify a const variable
9
10
return 0;
// indicates successful termination
11
12
17
fig04_07.cpp
(1 of 1)
fig04_07.cpp
output (1 of 1)
} // end main
d:\cpphtp4_examples\ch04\Fig04_07.cpp(6) : error C2734: 'x' :
const object must be initialized if not extern
d:\cpphtp4_examples\ch04\Fig04_07.cpp(8) : error C2166:
l-value specifies const object
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
4
5
6
7
8
9
10
18
// Fig. 4.8: fig04_08.cpp
// Compute the sum of the elements of the array.
#include <iostream>
fig04_08.cpp
(1 of 1)
using std::cout;
using std::endl;
fig04_08.cpp
output (1 of 1)
int main()
{
const int arraySize = 10;
11
12
int a[ arraySize ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
13
14
int total = 0;
15
16
17
18
19
20
21
22
23
24
// sum contents of array a
for ( int i = 0; i < arraySize; i++ )
total += a[ i ];
cout << "Total of array element values is " << total << endl;
return 0;
} // end main
// indicates successful termination
Total of array element values is 55
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Fig. 4.9: fig04_09.cpp
// Histogram printing program.
Element
#include <iostream>
0
1
using std::cout;
2
using std::endl;
3
4
#include <iomanip>
5
6
using std::setw;
7
8
int main()
9
{
fig04_09.cpp
(1 of 2)
Value
19
3
15
7
11
9
13
5
17
1
Histogram
*******************
***
***************
*******
***********
*********
*************
*****
*****************
*
const int arraySize = 10;
int n[ arraySize ] = { 19, 3, 15, 7, 11, 9, 13, 5, 17, 1 };
cout << "Element" << setw( 13 ) << "Value"
<< setw( 17 ) << "Histogram" << endl;
19
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
20
21
22
23
// for each element of array n, output a bar in histogram
for ( int i = 0; i < arraySize; i++ ) {
cout << setw( 7 ) << i << setw( 13 )
In số dấu saofig04_09.cpp
(*) tương ứng
<< n[ i ] << setw( 9 );
với giá trị của
(2 phần
of 2) tử n[i].
24
25
26
for ( int j = 0; j < n[ i ]; j++ )
cout << '*';
27
28
cout << endl;
} // end outer for structure
31
32
return 0;
} // end main
// print one bar
fig04_09.cpp
output (1 of 1)
// start next line of output
29
30
33
34
20
// indicates successful termination
Element
0
1
2
3
4
5
6
7
8
9
Value
19
3
15
7
11
9
13
5
17
1
Histogram
*******************
***
***************
*******
***********
*********
*************
*****
*****************
*
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
21
// Fig. 4.10: fig04_10.cpp
// Roll a six-sided die 6000 times.
#include <iostream>
fig04_10.cpp
(1 of 2)
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
9
10
using std::setw;
11
12
13
#include <cstdlib>
#include <ctime>
14
15
16
17
18
int main()
{
const int arraySize = 7;
int frequency[ arraySize ] = { 0 };
Viết lại một chương trình cũ. Một
mảng được sử dụng thay cho 6
biến thường, và các phần tử dễ
dàng cập nhật hơn (không cần sử
dụng switch).
Dòng lệnh này tạo ra một số trong
khoảng 1 đến 6 và tăng phần tử
// seed random-number generator
frequency[] có chỉ số đó.
19
20
srand( time( 0 ) );
21
22
23
24
25
// roll die 6000 times
for ( int roll = 1; roll <= 6000; roll++ )
++frequency[ 1 + rand() % 6 ]; // replaces 20-line switch
// of Fig. 3.8
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
22
26
27
cout << "Face" << setw( 13 ) << "Frequency" << endl;
28
29
30
31
32
// output frequency elements 1-6 in tabular format
for ( int face = 1; face < arraySize; face++ )
cout << setw( 4 ) << face
<< setw( 13 ) << frequency[ face ] << endl;
33
34
return 0;
35
36
fig04_10.cpp
(2 of 2)
fig04_10.cpp
output (1 of 1)
// indicates successful termination
} // end main
Face
1
2
3
4
5
6
Frequency
1003
1004
999
980
1013
1001
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
23
// Fig. 4.11: fig04_11.cpp
***modified***
// Student mark statistic program.
#include <iostream>
fig04_11.cpp
(1 of 2)
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
9
10
using std::setw;
11
12
13
14
15
16
int main()
{
// define array sizes
const int markSize = 40;
// size of array of marks
const int frequencySize = 11; // size of array frequency
17
18
19
20
21
// place student marks in array of marks
int marks[ markSize ] = { 1, 2, 6, 4, 8, 5, 9, 7, 8,
10, 1, 6, 3, 8, 6, 10, 3, 8, 2, 7, 6, 5, 7, 6, 8, 6, 7,
5, 6, 6, 5, 6, 7, 5, 6, 4, 8, 6, 8, 10 };
22
23
24
// initialize frequency counters to 0
int frequency[ frequencySize ] = { 0 };
25
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
28
29
30
// for each student's mark, select value of an element of array
// responses and use that value as subscript in array
// frequency to determine element to increment
fig04_11.cpp
for ( int student = 0; student < markSize; student++ )
(2 of 2)
++frequency[ marks[student] ];
31
32
33
// display results
cout << "Rating" << setw( 17 ) << "Frequency" << endl;
34
35
36
37
38
// output frequencies in tabular format
for ( int rating = 1; rating < frequencySize; rating++ )
cout << setw( 6 ) << rating
<< setw( 17 ) << frequency[ rating ] << endl;
39
40
return 0;
41
42
} // end main
// indicates successful termination
marks[student] là điểm (từ 1 đến 10).
Giá trị này quyết định chỉ số của phần tử
frequency[] cần tăng.
CuuDuongThanCong.com
Rating
1
2
3
4
5
6
7
8
9
10
Frequency
2
2
2
2
5
11
5
7
1
©2004 Trần Minh Châu.
3
FOTECH. VNU.
https://fb.com/tailieudientucntt
24
25
4.4
Ví dụ về sử dụng mảng
• Xâu - string (xem thêm ở chương 5)
– Mảng của các ký tự
– Mọi xâu đều kết thúc với ký tự null ('\0')
– Ví dụ
• char string1[] = "hello";
– Ký tự null tự động được thêm vào, xâu có 6 phần tử
• char string1[] = { 'h', 'e', 'l', 'l',
'o', '\0’ };
– Chỉ số cũng giống như đối với mảng
String1[ 0 ] bằng 'h'
string1[ 2 ] bằng 'l'
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
26
4.4
Ví dụ về sử dụng mảng
• Nhập từ bàn phím bằng cin
char string2[ 10 ];
cin >> string2;
– Ghi dữ liệu vào của người dùng vào xâu
• Dừng lại ở ký tự trắng đầu tiên (tab, newline, blank…)
• Thêm vào ký tự null
– Nếu nhập quá nhiều, dữ liệu sẽ tràn mảng
• Ta cần phải tránh điều này (mục 5.12 sẽ giải thích phương
pháp)
• In xâu
– cout << string2 << endl;
• Không sử dụng được với các mảng có kiểu dữ liệu khác
– In các ký tự cho đến khi gặp null
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
1
2
3
27
// Fig. 4_12: fig04_12.cpp
// Treating character arrays as strings.
#include <iostream>
fig04_12.cpp
(1 of 2)
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
10
11
12
int main()
{
char string1[ 20 ],
// reserves 20 characters
char string2[] = "string literal"; // reserves 15 characters
13
14
15
16
// read string from user into array string2
cout << "Enter the string \"hello there\": ";
cin >> string1; // reads "hello" [space terminates input]
17
18
19
20
// output strings
cout << "string1 is: " << string1
<< "\nstring2 is: " << string2;
21
22
cout << "\nstring1 with spaces between characters is:\n";
Hai cách khác nhau để khai báo
xâu. string2 được khởi tạo và
kích thước được xác định tự động.
Ví dụ về đọc xâu từ bàn phím và in ra.
23
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
28
24
25
26
// output characters until null character is reached
for ( int i = 0; string1[ i ] != '\0'; i++ )
cout << string1[ i ] << ' ';
27
28
29
Có thể truy nhập xâu
giống
fig04_12.cpp
như đối với mảng. Vòng
lặp
(2 of 2)
cin >> string1; // reads "there"
kết thúc khi gặp ký tự null.
cout << "\nstring1 is: " << string1 << endl;
fig04_12.cpp
output (1 of 1)
return 0; // indicates successful termination
30
31
32
33
} // end main
Enter the string "hello there": hello there
string1 is: hello
string2 is: string literal
string1 with spaces between characters is:
h e l l o
string1 is: there
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
29
4.4
Ví dụ về sử dụng mảng
• Kiểu lưu trữ tĩnh – static storage (chương 3)
– Nếu là static, các biến địa phương lưu lại giá trị giữa các
lần gọi hàm
– chỉ được nhìn thấy trong thân hàm
– Có thể khai báo mảng địa phương là static
• được khởi tạo về 0
static int array[3];
• Nếu không phải static
– Được tạo (và huỷ) tại mỗi lần gọi hàm
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
1
2
3
fig04_13.cpp
(1 of 3)
4
5
6
using std::cout;
using std::endl;
7
8
9
void staticArrayInit( void );
void automaticArrayInit( void );
10
11
12
13
14
15
int main()
{
cout << "First call to each function:\n";
staticArrayInit();
automaticArrayInit();
// function prototype
// function prototype
16
17
18
19
20
cout << "\n\nSecond call to each function:\n";
staticArrayInit();
automaticArrayInit();
cout << endl;
21
22
return 0;
23
24
30
// Fig. 4.13: fig04_13.cpp
// Static arrays are initialized to zero.
#include <iostream>
// indicates successful termination
} // end main
25
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
28
29
30
// function to demonstrate a static local array
void staticArrayInit( void )
Mảng static, khởi tạo về 0 tại
{
lần gọi hàm đầu tiên.
// initializes elements to 0 first time function is called
static int array1[ 3 ];
31
32
cout << "\nValues on entering staticArrayInit:\n";
33
34
35
36
// output contents of array1
for ( int i = 0; i < 3; i++ )
cout << "array1[" << i << "] = " << array1[ i ] << "
37
38
cout << "\nValues on exiting staticArrayInit:\n";
39
40
41
42
43
// modify and output
for ( int j = 0; j <
cout << "array1["
<< ( array1[
44
45
contents of array1
3; j++ )
<< j << "] = "
j ] += 5 ) << " ";
31
fig04_13.cpp
(2 of 3)
";
Dữ liệu trong mảng bị thay đổi,
các thay đổi được bảo toàn.
} // end function staticArrayInit
46
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
47
48
49
50
51
// function to demonstrate an automatic local array
void automaticArrayInit( void )
Mảng automatic, được tạo lại
{
tại mỗi lần gọi hàm.
fig04_13.cpp
// initializes elements each time function is called
(3 of 3)
int array2[ 3 ] = { 1, 2, 3 };
52
53
cout << "\n\nValues on entering automaticArrayInit:\n";
54
55
56
57
// output contents of array2
for ( int i = 0; i < 3; i++ )
cout << "array2[" << i << "] = " << array2[ i ] << "
58
59
cout << "\nValues on exiting automaticArrayInit:\n";
60
61
62
63
64
// modify and output
for ( int j = 0; j <
cout << "array2["
<< ( array2[
65
66
contents of array2
3; j++ )
<< j << "] = "
j ] += 5 ) << " ";
";
Tuy mảng bị thay đổi, nó sẽ
bị huỷ khi hàm kết thúc và
thayt đổi trong dữ liệu sẽ bị
mất.
} // end function automaticArrayInit
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
32
33
First call to each function:
Values on
array1[0]
Values on
array1[0]
entering staticArrayInit:
= 0 array1[1] = 0 array1[2] = 0
exiting staticArrayInit:
= 5 array1[1] = 5 array1[2] = 5
Values on
array2[0]
Values on
array2[0]
entering automaticArrayInit:
= 1 array2[1] = 2 array2[2] = 3
exiting automaticArrayInit:
= 6 array2[1] = 7 array2[2] = 8
fig04_13.cpp
output (1 of 1)
Second call to each function:
Values on
array1[0]
Values on
array1[0]
entering staticArrayInit:
= 5 array1[1] = 5 array1[2] = 5
exiting staticArrayInit:
= 10 array1[1] = 10 array1[2] = 10
Values on
array2[0]
Values on
array2[0]
entering automaticArrayInit:
= 1 array2[1] = 2 array2[2] = 3
exiting automaticArrayInit:
= 6 array2[1] = 7 array2[2] = 8
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
34
4.5
Truyền tham số cho hàm
• Dùng tên mảng, bỏ cặp ngoặc vuông
– Truyền mảng myArray cho hàm myFunction
int myArray[ 24 ];
myFunction( myArray, 24 );
– Kích thước mảng thường được truyền, nhưng không nhất thiết
• Có ích khi dùng để duyệt tất cả các phần tử
• Mảng được truyền bằng tham chiếu (passed-by-reference)
– Hàm có thể thay đổi dữ liệu gốc của mảng
– Tên mảng có giá trị bằng địa chỉ của phần tử đầu tiên
• Hàm biết mảng được lưu ở đâu.
• Hàm có thể sửa đổi dữ liệu ghi trong mảng
• Các phần tử mảng được truyền bằng giá trị (passed-byvalue)
– Như các biến thông thường
– square( myArray[3] );
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
35
4.5
Truyền tham số cho hàm
• Các hàm dùng mảng làm đối số
– Function prototype
• void modifyArray( int b[], int arraySize );
• void modifyArray( int [], int );
– Trong prototype, tên không bắt buộc
• cả hai hàm lấy đối số là một mảng số nguyên và 1 số nguyên
– Không ghi cần kích thước mảng trong cặp ngoặc
• Trình biên dịch bỏ qua
– Nếu khai báo 1 tham số là const
• đối số đó sẽ không thể bị thay đổi (chương trình dịch báo lỗi)
• void doNotModify( const int [] );
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
1
2
3
36
// Fig. 4.14: fig04_14.cpp
// Passing arrays and individual array elements to functions.
#include <iostream>
fig04_14.cpp
(1 of 3)
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
Cú pháp cho mảng trong danh
sách tham số
9
10
using std::setw;
11
12
13
void modifyArray( int [], int );
void modifyElement( int );
14
15
16
17
18
int main()
{
const int arraySize = 5;
int a[ arraySize ] = { 0, 1, 2, 3, 4 };
// appears strange
// size of array a
// initialize a
19
20
21
cout << "Effects of passing entire array by reference:"
<< "\n\nThe values of the original array are:\n";
22
23
24
25
// output original array
for ( int i = 0; i < arraySize; i++ )
cout << setw( 3 ) << a[ i ];
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
27
28
29
30
31
32
Truyền tên mảng (a) và kích thước cho
hàm. Mảng truyền bằng tham chiếu
cout << endl;
// pass array a to modifyArray by reference
modifyArray( a, arraySize );
cout << "The values of the modified array are:\n";
33
34
35
36
// output modified array
for ( int j = 0; j < arraySize; j++ )
cout << setw( 3 ) << a[ j ];
37
38
39
40
41
// output value of a[ 3 ]
cout << "\n\n\n"
<< "Effects of passing array element by value:"
<< "\n\nThe value of a[3] is " << a[ 3 ] << '\n';
1 phần tử mảng được truyền bằng giá trị;
giá trị phần tử gốc không thể bị thay đổi.
42
43
44
// pass array element a[ 3 ] by value
modifyElement( a[ 3 ] );
45
46
47
// output value of a[ 3 ]
cout << "The value of a[3] is " << a[ 3 ] << endl;
48
49
return 0;
50
51
fig04_14.cpp
(2 of 3)
// indicates successful termination
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
37
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
Tuy đặt tên là b, khi được gọi, mảng chỉ
// in function modifyArray, "b" points to
đến mảng a, nên hàm có thể thay đổi dữ
// the original array "a" in memory
liệu của a.
fig04_14.cpp
void modifyArray( int b[], int sizeOfArray )
(3 of 3)
{
// multiply each array element by 2
for ( int k = 0; k < sizeOfArray; k++ )
b[ k ] *= 2;
} // end function modifyArray
// in function modifyElement, "e" is a local copy of
// array element a[ 3 ] passed from main
Các phần tử đơn lẻ của mảng được
void modifyElement( int e )
truyền bằng giá trị, và các giá trị gốc
{
không thể bị thay đổi.
// multiply parameter by 2
cout << "Value in modifyElement is "
<< ( e *= 2 ) << endl;
} // end function modifyElement
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
38
39
Effects of passing entire array by reference:
The values of
0 1 2 3
The values of
0 2 4 6
the original array are:
4
the modified array are:
8
fig04_14.cpp
output (1 of 1)
Effects of passing array element by value:
The value of a[3] is 6
Value in modifyElement is 12
The value of a[3] is 6
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
40
1
2
3
// Fig. 4.15: fig04_15.cpp
// Demonstrating the const type qualifier.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
void tryToModifyArray( const int [] );
9
10
11
12
int main()
{
int a[] = { 10, 20, 30 };
13
14
tryToModifyArray( a );
15
16
cout << a[ 0 ] << ' ' << a[ 1 ] << ' ' << a[ 2 ] << '\n';
17
18
return 0;
19
20
Tham số mảng được khai báo
là const. Mảng không thểfig04_15.cpp
bị
sửa đổi, kể cả khi nó được (1 of 2)
truyền bằng tham chiếu.
// function prototype
// indicates successful termination
} // end main
21
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
22
23
24
25
26
27
28
29
30
// In function tryToModifyArray, "b" cannot be used
// to modify the original array "a" in main.
void tryToModifyArray( const int b[] )
{
b[ 0 ] /= 2;
// error
b[ 1 ] /= 2;
// error
b[ 2 ] /= 2;
// error
41
fig04_15.cpp
(2 of 2)
} // end function tryToModifyArray
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
42
4.6
Sắp xếp mảng
• Sắp xếp dữ liệu
– Là một ứng dụng quan trọng
– Hầu hết mọi cơ quan/tổ chức đều phải sắp xếp dữ liệu
• Một khối lượng khổng lồ dữ liệu cần được sắp xếp
• Xếp nổi bọt (Bubble sort)
– Duyệt mảng vài lần
– So sánh cặp phần tử liên tiếp
• Nếu thứ tự tăng (hoặc bằng nhau), không thay đổi gì
• Nếu thứ tự giảm, tráo đổi hai phần tử
– Lặp lại các bước trên cho mọi phần tử
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
43
4.6
Sắp xếp mảng
• Ví dụ:
– Đi từ trái sang phải, và tráo các phần tử khi cần thiết
• Một lần duyệt cho mỗi phần tử
–
–
–
–
–
–
–
Dãy gốc:
3 4 2 7 6
Lần duyệt 1:
3 2 4 6 7 (tráo đổi phần tử)
Lần duyệt 2:
2 3 4 6 7
Lần duyệt 3:
2 3 4 6 7 (không cần thay đổi)
Lần duyệt 4:
2 3 4 6 7
Lần duyệt 5:
2 3 4 6 7
Phần tử nhỏ “nổi" lên trên (như số 2 trong ví dụ)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
44
4.6
Sắp xếp mảng
• Tráo đổi các biến
int x = 3, y = 4;
y = x;
x = y;
• Cái gì xảy ra?
– Cả x và y đều là 3!
– Cần có biến tạm
• Giải pháp
int x = 3,
temp = x;
x = y;
y = temp;
y = 4, temp = 0;
// temp là 3
// x là 4
// y là 3
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
1
2
3
45
// Fig. 4.16: fig04_16.cpp
// This program sorts an array's values into ascending order.
#include <iostream>
fig04_16.cpp
(1 of 3)
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
9
10
using std::setw;
11
12
13
14
15
16
int main()
{
const int arraySize = 10; // size of array a
int a[ arraySize ] = { 2, 6, 4, 8, 10, 12, 89, 68, 45, 37 };
int hold; // temporary location used to swap array elements
17
18
cout << "Data items in original order\n";
19
20
21
22
// output original array
for ( int i = 0; i < arraySize; i++ )
cout << setw( 4 ) << a[ i ];
23
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Duyệt 1 lần cho mỗi phần tử
// bubble sort
của mảng.
// loop to control number of passes
for ( int pass = 0; pass < arraySize - 1; pass++ )
// loop to control number of comparisons per pass
for ( int j = 0; j < arraySize - 1; j++ )
fig04_16.cpp
(2 of 3)
// compare side-by-side elements and swap them if
// first element is greater than second element
if ( a[ j ] > a[ j + 1 ] ) {
Nếu phần tử bên trái (chỉ số j)
hold = a[ j ];
lớn hơn phần tử bên phải (chỉ số
a[ j ] = a[ j + 1 ];
j + 1), thì ta tráo đổi chúng.
a[ j + 1 ] = hold;
Nhớ sử dụng biến tạm.
} // end if
39
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
46
47
40
cout << "\nData items in ascending order\n";
41
42
43
44
// output sorted array
for ( int k = 0; k < arraySize; k++ )
cout << setw( 4 ) << a[ k ];
fig04_16.cpp
(3 of 3)
45
46
cout << endl;
47
48
fig04_16.cpp
output (1 of 1)
return 0;
49
50
// indicates successful termination
} // end main
Data items in original order
2
6
4
8 10 12 89 68
Data items in ascending order
2
4
6
8 10 12 37 45
45
37
68
89
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
4.7
Ví dụ: sử dụng mảng để tính
Mean, Median và Mode
48
• Mean
– Giá trị trung bình (tổng/số phần tử)
• Median
– Giá trị ở giữa dãy đã được sắp xếp
– 1, 2, 3, 4, 5 (3 là median)
– Nếu số phần tử là số chẵn, lấy trung bình của 2 số giữa
• Mode
– Giá trị xuất hiện nhiều nhất
– 1, 1, 1, 2, 3, 3, 4, 5 (1 là mode)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
1
2
3
4
// Fig. 4.17: fig04_17.cpp
// This program introduces the topic of survey data analysis.
// It computes the mean, median, and mode of the data.
#include <iostream>
5
6
7
8
9
using
using
using
using
10
11
#include <iomanip>
12
13
14
using std::setw;
using std::setprecision;
15
16
17
18
19
20
void
void
void
void
void
21
22
23
24
int main()
{
const int responseSize = 99;
49
fig04_17.cpp
(1 of 8)
std::cout;
std::endl;
std::fixed;
std::showpoint;
mean( const int [], int );
median( int [], int );
mode( int [], int [], int );
bubbleSort( int[], int );
printArray( const int[], int );
25
// size of array responses
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
int frequency[ 10 ] = { 0 };
27
28
29
30
31
32
33
34
35
36
37
38
39
// initialize array responses
int response[ responseSize ] =
{ 6, 7, 8, 9, 8, 7, 8, 9,
7, 8, 9, 5, 9, 8, 7, 8,
6, 7, 8, 9, 3, 9, 8, 7,
7, 8, 9, 8, 9, 8, 9, 7,
6, 7, 8, 7, 8, 7, 9, 8,
7, 8, 9, 8, 9, 8, 9, 7,
5, 6, 7, 2, 5, 3, 9, 4,
7, 8, 9, 6, 8, 7, 8, 9,
7, 4, 4, 2, 5, 3, 8, 7,
4, 5, 6, 1, 6, 5, 7, 8,
40
41
42
43
44
// process responses
mean( response, responseSize );
median( response, responseSize );
mode( frequency, response, responseSize );
45
46
return 0;
47
48
50
// initialize array frequency
8, 9,
7, 8,
8, 7,
8, 9,
9, 2,
5, 3,
6, 4,
7, 8,
5, 6,
7 };
fig04_17.cpp
(2 of 8)
// indicates successful termination
} // end main
49
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
50
51
52
53
54
55
cout << "********\n
56
57
58
59
// total response values
for ( int i = 0; i < arraySize; i++ )
total += answer[ i ];
60
61
62
// format and output results
cout << fixed << setprecision( 4 );
63
64
65
66
67
68
69
70
71
cout <<
<<
<<
<<
<<
<<
<<
<<
72
73
51
// calculate average of all response values
void mean( const int answer[], int arraySize )
{
int total = 0;
Mean\n********\n";
fig04_17.cpp
(3 of 8)
"The mean is the average value of the data\n"
"items. The mean is equal to the total of\n"
"all the data items divided by the number\n"
"of data items (" << arraySize
Đổi sang double để được giá trị
"). The mean value for\nthis run is: " trung bình bằng số thực (thay vì giá trị
total << " / " << arraySize << " = "
nguyên).
static_cast< double >( total ) / arraySize
"\n\n";
} // end function mean
74
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
52
// sort array and determine median element's value
void median( int answer[], int size )
{
cout << "\n********\n Median\n********\n"
<< "The unsorted array of responses is";
printArray( answer, size );
bubbleSort( answer, size );
fig04_17.cpp
(4 of 8)
Sắp xếp mảng bằng cách
// output unsorted array
// sort array
truyền nó cho một hàm.
Bảo vệ tính modun của
chương trình
cout << "\n\nThe sorted array is";
printArray( answer, size ); // output sorted array
// display median element
cout << "\n\nThe median is element " << size / 2
<< " of\nthe sorted " << size
<< " element array.\nFor this run the median is "
<< answer[ size / 2 ] << "\n\n";
} // end function median
95
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
96 // determine most frequent response
97 void mode( int freq[], int answer[], int size )
98 {
99
int largest = 0;
// represents largest frequency
100
int modeValue = 0; // represents most frequent response
101
102
cout << "\n********\n
103
104
105
106
// initialize frequencies to 0
for ( int i = 1; i <= 9; i++ )
freq[ i ] = 0;
107
108
109
110
// summarize frequencies
for ( int j = 0; j < size; j++ )
++freq[ answer[ j ] ];
111
112
113
114
115
116
// output headers for result columns
cout << "Response" << setw( 11 ) << "Frequency"
<< setw( 19 ) << "Histogram\n\n" << setw( 55 )
<< "1
1
2
2\n" << setw( 56 )
<< "5
0
5
0
5\n\n";
53
fig04_17.cpp
(5 of 8)
Mode\n********\n";
117
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
118
119
120
121
122
123
124
125
126
127
128
54
// output results
for ( int rating = 1; rating <= 9; rating++ ) {
cout << setw( 8 ) << rating << setw( 11 )
<< freq[ rating ] << "
";
fig04_17.cpp
(6 of 8)
// keep track of mode value and largest fequency value
if ( freq[ rating ] > largest ) {
mode là giá trị xuất hiện
largest = freq[ rating ];
nhiều nhất (có giá trị cao nhất
modeValue = rating;
trong mảng freq).
} // end if
129
130
131
132
// output histogram bar representing frequency value
for ( int k = 1; k <= freq[ rating ]; k++ )
cout << '*';
133
134
cout << '\n';
135
136
} // end outer for
137
138
139
140
141
// display the mode value
cout << "The mode is the most frequent value.\n"
<< "For this run the mode is " << modeValue
<< " which occurred " << largest << " times." << endl;
// begin new line of output
142
143 } // end function mode
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
144
145 // function that sorts an array with bubble sort algorithm
146 void bubbleSort( int a[], int size )
147 {
148
int hold; // temporary location used to swap elements
149
150
151
152
153
154
55
fig04_17.cpp
(7 of 8)
// loop to control number of passes
for ( int pass = 1; pass < size; pass++ )
// loop to control number of comparisons per pass
for ( int j = 0; j < size - 1; j++ )
155
156
157
158
159
160
// swap elements if out of order
if ( a[ j ] > a[ j + 1 ] ) {
hold = a[ j ];
a[ j ] = a[ j + 1 ];
a[ j + 1 ] = hold;
161
162
} // end if
163
164 } // end function bubbleSort
165
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
56
166 // output array contents (20 values per row)
167 void printArray( const int a[], int size )
168 {
169
for ( int i = 0; i < size; i++ ) {
170
171
172
if ( i % 20 == 0 )
cout << endl;
173
174
cout << setw( 2 ) << a[ i ];
175
176
fig04_17.cpp
(8 of 8)
// begin new line every 20 values
} // end for
177
178 } // end function printArray
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
********
Mean
********
The mean is the average value of the data
items. The mean is equal to the total of
all the data items divided by the number
of data items (99). The mean value for
this run is: 681 / 99 = 6.8788
********
Median
********
The unsorted array of responses is
6 7 8 9 8 7 8 9 8 9 7 8 9 5 9 8 7 8 7 8
6 7 8 9 3 9 8 7 8 7 7 8 9 8 9 8 9 7 8 9
6 7 8 7 8 7 9 8 9 2 7 8 9 8 9 8 9 7 5 3
5 6 7 2 5 3 9 4 6 4 7 8 9 6 8 7 8 9 7 8
7 4 4 2 5 3 8 7 5 6 4 5 6 1 6 5 7 8 7
The sorted
1 2 2 2 3
5 6 6 6 6
7 7 7 7 7
8 8 8 8 8
9 9 9 9 9
array
3 3 3
6 6 6
7 7 7
8 8 8
9 9 9
is
4 4
6 6
7 7
8 8
9 9
4
7
7
8
9
4
7
7
8
9
4
7
7
8
9
5
7
8
8
9
5
7
8
8
9
5
7
8
8
9
5
7
8
8
9
5
7
8
8
9
5
7
8
8
9
57
fig04_17.cpp
output (1 of 2)
5
7
8
8
The median is element 49 of
the sorted 99 element array.
For this run the median is 7
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
********
Mode
********
Response
58
Frequency
Histogram
5
1
0
1
5
2
0
2
5
fig04_17.cpp
output (2 of 2)
1
1
*
2
3
***
3
4
****
4
5
*****
5
8
********
6
9
*********
7
23
***********************
8
27
***************************
9
19
*******************
The mode is the most frequent value.
For this run the mode is 8 which occurred 27 times.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
59
4.8 Tìm kiếm trên mảng:
Tìm kiếm Tuyến tính và tìm kiếm Nhị phân
• Tìm một giá trị khoá (key value) trên mảng
• Tìm kiếm tuyến tính
– So sánh từng phần tử của mảng với key
• Bắt đầu từ một đầu, đi đến đầu kia của mảng
– Hữu dụng cho mảng nhỏ và chưa sắp xếp
• Không hiệu quả
• Nếu giá trị cần tìm không có trong mảng thì phải kiểm tra tất
cả các phần tử
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
60
4.8
Tìm kiếm trên mảng: Tìm kiếm Tuyến
tính và tìm kiếm Nhị phân
• Tìm kiếm nhị phân
– Chỉ sử dụng cho mảng đã sắp xếp
– So sánh phần tử ở giữa (middle) với key
• Nếu bằng, tìm thấy
• Nếu key < middle
– Lặp lại ở nửa đầu của mảng
• Nếu key > middle
– Lặp lại ở nửa cuối
– Rất nhanh
• Nhiều nhất là N bước với 2 N > số phần tử của mảng
• mảng 30 phần tử cần nhiều nhất 5 bước
5
2 > 30
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
1
2
3
61
// Fig. 4.19: fig04_19.cpp
// Linear search of an array.
#include <iostream>
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
int linearSearch( const int [], int, int );
10
11
12
13
14
15
int main()
{
const int arraySize = 100;
int a[ arraySize ];
int searchKey;
Lấy đối số là một mảng, khoá
cần tìm, và kích thước mảng.
// prototype
// size of array a
// create array a
// value to locate in a
16
17
18
for ( int i = 0; i < arraySize; i++ )
a[ i ] = 2 * i;
19
20
21
cout << "Enter integer search key: ";
cin >> searchKey;
22
23
24
// attempt to locate searchKey in array a
int element = linearSearch( a, searchKey, arraySize );
25
fig04_19.cpp
(1 of 2)
// create some data
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
28
29
30
// display results
if ( element != -1 )
cout << "Found value in element " << element << endl;
else
cout << "Value not found" << endl;
31
32
return 0;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
62
fig04_19.cpp
(2 of 2)
Enter integer search key: 36
Found value in element 18
// indicates successful termination
Enter integer search key: 37
Value not found
} // end main
// compare key to every element of array until location is
// found or until end of array is reached; return subscript of
// element if key or -1 if key not found
int linearSearch( const int array[], int key, int sizeOfArray )
{
for ( int j = 0; j < sizeOfArray; j++ )
if ( array[ j ] == key )
return j;
return -1;
// if found,
// return location of key
// key not found
} // end function linearSearch
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
63
// Fig. 4.20: fig04_20.cpp
// Binary search of an array.
#include <iostream>
fig04_20.cpp
(1 of 6)
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
#include <iomanip>
10
11
using std::setw;
12
13
14
15
16
// function prototypes
int binarySearch( const int [], int, int, int, int );
void printHeader( int );
void printRow( const int [], int, int, int, int );
17
18
19
20
21
22
int main()
{
const int arraySize = 15;
int a[ arraySize ];
int key;
23
24
25
// size of array a
// create array a
// value to locate in a
for ( int i = 0; i < arraySize; i++ )
a[ i ] = 2 * i;
26
CuuDuongThanCong.com
// create some data
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
64
27
28
cout << "Enter a number between 0 and 28: ";
cin >> key;
29
30
printHeader( arraySize );
31
32
33
34
// search for key in array a
int result =
binarySearch( a, key, 0, arraySize - 1, arraySize );
35
36
37
38
39
40
41
// display results
if ( result != -1 )
cout << '\n' << key << " found in array element "
<< result << endl;
else
cout << '\n' << key << " not found" << endl;
42
43
return 0;
44
45
fig04_20.cpp
(2 of 6)
// indicates successful termination
} // end main
46
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
47
48
49
50
51
52
53
54
65
// function to perform binary search of an array
int binarySearch( const int b[], int searchKey, int low,
int high, int size )
{
int middle;
fig04_20.cpp
(3 of 6)
// loop until low subscript is greater than high subscript
while ( low <= high ) {
Xác định phần tử ở giữa
55
56
57
// determine middle element of subarray being searched
middle = ( low + high ) / 2;
58
59
60
// display subarray used in this loop iteration
printRow( b, low, middle, high, size );
61
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
62
63
64
// if searchKey matches middle element, return middle
if ( searchKey == b[ middle ] ) // match
return middle;
65
66
else
67
68
69
70
71
Sử dụng tìm Nhị phân:
fig04_20.cpp
Nếu key bằng middle,
(4 oftìm
6) thấy
Nếu nhỏ hơn, tìm nửa thấp
// if searchKey less than middle element,
// set new high element
Nếu lớn hơn, tìm nửa cao
if ( searchKey < b[ middle ] )
high = middle - 1; // search low end of array
72
73
74
75
76
77
}
78
79
return -1;
80
81
66
// if searchKey greater than middle element,
// set new low element
Vòng lặp tạo low, middle và high tự động. Nếu tìm
else
nửa cao, thì phần tử low mới sẽ cao hơn middle.
low = middle + 1;
// search high end of array
// searchKey not found
} // end function binarySearch
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
82
83
84
85
86
67
// print header for output
void printHeader( int size )
{
cout << "\nSubscripts:\n";
87
88
89
90
// output column heads
for ( int j = 0; j < size; j++ )
cout << setw( 3 ) << j << ' ';
91
92
cout << '\n';
93
94
95
96
// output line of - characters
for ( int k = 1; k <= 4 * size; k++ )
cout << '-';
97
98
cout << endl;
fig04_20.cpp
(5 of 6)
// start new line of output
// start new line of output
99
100 } // end function printHeader
101
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
102
103
104
105
106
107
108
// print one row of output showing the current
// part of the array being processed
void printRow( const int b[], int low, int mid,
int high, int size )
{
// loop through entire array
for ( int m = 0; m < size; m++ )
109
110
111
112
// display spaces if outside current subarray range
if ( m < low || m > high )
cout << "
";
113
114
115
// display middle element marked with a *
else
116
117
118
if ( m == mid )
// mark middle value
cout << setw( 3 ) << b[ m ] << '*';
119
120
121
122
// display other elements in subarray
else
cout << setw( 3 ) << b[ m ] << ' ';
123
124
cout << endl;
68
fig04_20.cpp
(6 of 6)
// start new line of output
125
126 } // end function printRow
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
69
Enter a number between 0 and 28: 6
Subscripts:
0
1
2
3
4
5
6
7
8
9 10 11 12 13 14
-----------------------------------------------------------0
2
4
6
8 10 12 14* 16 18 20 22 24 26 28
0
2
4
6* 8 10 12
fig04_20.cpp
output (1 of 2)
6 found in array element 3
Enter a number between 0 and 28: 25
Subscripts:
0
1
2
3
4
5
6
7
8
9 10 11 12 13 14
-----------------------------------------------------------0
2
4
6
8 10 12 14* 16 18 20 22 24 26 28
16 18 20 22* 24 26 28
24 26* 28
24*
25 not found
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
70
Enter a number between 0 and 28: 8
Subscripts:
0
1
2
3
4
5
6
7
8
9 10 11 12 13 14
-----------------------------------------------------------0
2
4
6
8 10 12 14* 16 18 20 22 24 26 28
0
2
4
6* 8 10 12
8 10* 12
8*
fig04_20.cpp
output (2 of 2)
8 found in array element 4
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
71
4.9
Mảng nhiều chiều
• Đa chỉ số
– int a[ 3 ][ 4 ];
– a[ i ][ j ]
– Các bảng có dòng và cột
– Dòng trước, cột sau
– “Mảng của mảng”
• a[0] là một mảng 4 phần tử
• a[0][0] là phần tử đầu tiên của mảng
Row 0
Column 0
a[ 0 ][ 0 ]
Column 1
a[ 0 ][ 1 ]
Column 2
a[ 0 ][ 2 ]
Column 3
a[ 0 ][ 3 ]
Row 1
a[ 1 ][ 0 ]
a[ 1 ][ 1 ]
a[ 1 ][ 2 ]
a[ 1 ][ 3 ]
Row 2
a[ 2 ][ 0 ]
a[ 2 ][ 1 ]
a[ 2 ][ 2 ]
a[ 2 ][ 3 ]
Column subscript
(chỉ số cột)
Array name
Row subscript
(chỉ số dòng)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
72
4.9
Mảng nhiều chiều
• Khởi tạo
– Mặc định là 0
– Khởi tạo, mỗi dòng trong 1 cặp ngoặc
int b[ 2 ][ 2 ] = { { 1, 2 }, { 3, 4 } };
Row 0
Row 1
int b[ 2 ][ 2 ] = { { 1 }, { 3, 4 } };
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
1
2
3
4
1
0
3
4
Chương 4.
https://fb.com/tailieudientucntt
73
4.9
Mảng nhiều chiều
• Truy nhập đến như bình thường
cout << b[ 0 ][ 1 ];
– In ra 0
1
0
3
4
– Không sử dụng dấu phẩy (,)
cout << b[ 0, 1 ];
• Lỗi cú pháp
• Function prototype
– Phải chỉ rõ kích thước của các chỉ số
• Không đòi hỏi kích thước cho chỉ số đầu tiên, cũng như mảng
1 chiều
– void printArray( int [][ 3 ] );
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
1
2
3
74
// Fig. 4.22: fig04_22.cpp
// Initializing multidimensional arrays.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
void printArray( int [][ 3 ] );
9
10
11
12
13
14
int main()
{
int array1[ 2 ][ 3 ] = { { 1, 2, 3 }, { 4, 5, 6 } };
int array2[ 2 ][ 3 ] = { 1, 2, 3, 4, 5};
int array3[ 2 ][ 3 ] = { { 1, 2 }, { 4 } };
Chú ý cấu trúc của prototype.
Chú ý nhiều cách khởi tạo.
Các phần tử trong array2
được gán từ dòng thứ nhất
rồi đến dòng thứ hai.
15
16
17
cout << "Values in array1 by row are:" << endl;
printArray( array1 );
18
19
20
cout << "Values in array2 by row are:" << endl;
printArray( array2 );
21
22
23
cout << "Values in array3 by row are:" << endl;
printArray( array3 );
24
25
26
return 0; // indicates successful termination
} // end main
CuuDuongThanCong.com
fig04_22.cpp
(1 of 2)
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
28
29
30
31
32
33
34
35
36
37
38
39
40
41
75
// function to output array with two rows and three columns
void printArray( int a[][ 3 ] )
Vòng lặp for thường được
fig04_22.cpp
{
dùng để quét qua
mảng. Sử
of 2)
for ( int i = 0; i < 2; i++ ) {
// for each row dụng vòng lặp(2
lồng
nhau cho
for ( int j = 0; j < 3; j++ )
cout << a[ i ][ j ] << ' ';
cout << endl;
mảng nhiều chiều.
fig04_22.cpp
// output column values
output (1 of 1)
// start new line of output
} // end outer for structure
} // end function printArray
Values in array1 by row are:
1 2 3
4 5 6
Values in array2 by row are:
1 2 3
4 5 0
Values in array3 by row are:
1 2 0
4 0 0
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
76
4.9
Mảng nhiều chiều
• Tiếp theo: chương trình ví dụ về khởi tạo mảng
–
–
–
–
Chương trình lưu trữ điểm của sinh viên
Mảng nhiều chiều (bảng)
Dòng là sinh viên
Cột là điểm
Quiz1
Quiz2
Student0
95
85
Student1
89
80
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 4.
https://fb.com/tailieudientucntt
1
2
3
4
5
6
7
8
using
using
using
using
9
10
#include <iomanip>
11
12
13
using std::setw;
using std::setprecision;
14
15
16
const int students = 3;
const int exams = 4;
17
18
19
20
21
22
23
77
// Fig. 4.23: fig04_23.cpp
// Double-subscripted array example.
#include <iostream>
fig04_23.cpp
(1 of 6)
std::cout;
std::endl;
std::fixed;
std::left;
// number of students
// number of exams
// function prototypes
int minimum( int [][ exams ], int, int );
int maximum( int [][ exams ], int, int );
double average( int [], int );
void printArray( int [][ exams ], int, int );
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
24
25
26
27
28
29
30
78
int main()
{
// initialize student grades for three students (rows)
int studentGrades[ students ][ exams ] =
{ { 77, 68, 86, 73 },
{ 96, 87, 89, 78 },
{ 70, 90, 86, 81 } };
fig04_23.cpp
(2 of 6)
31
32
33
34
// output array studentGrades
cout << "The array is:\n";
printArray( studentGrades, students, exams );
35
36
37
38
39
40
// determine smallest and largest grade values
cout << "\n\nLowest grade: "
<< minimum( studentGrades, students, exams )
<< "\nHighest grade: "
<< maximum( studentGrades, students, exams ) << '\n';
41
42
cout << fixed << setprecision( 2 );
43
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
44
45
46
47
48
49
// calculate average grade for each student
for ( int person = 0; person < students; person++ )
cout << "The average grade for student " << person
<< " is "
<< average( studentGrades[ person ], exams )
<< endl;
50
51
return 0;
// indicates successful termination
79
fig04_23.cpp
(3 of 6)
Tính điểm trung bình cho sinh
viên. Ta truyền dòng chứa điểm
của sinh viên vào hàm. Chú ý:
studentGrades[0] cũng là
một mảng.
52
53
} // end main
54
55
56
57
58
// find minimum grade
int minimum( int grades[][ exams ], int pupils, int tests )
{
int lowGrade = 100; // initialize to highest possible grade
59
60
61
62
63
64
65
66
67
68
69
for ( int i = 0; i < pupils; i++ )
for ( int j = 0; j < tests; j++ )
if ( grades[ i ][ j ] < lowGrade )
lowGrade = grades[ i ][ j ];
return lowGrade;
} // end function minimum
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
80
// find maximum grade
int maximum( int grades[][ exams ], int pupils, int tests )
{
int highGrade = 0; // initialize to lowest possible grade
fig04_23.cpp
(4 of 6)
for ( int i = 0; i < pupils; i++ )
for ( int j = 0; j < tests; j++ )
if ( grades[ i ][ j ] > highGrade )
highGrade = grades[ i ][ j ];
return highGrade;
} // end function maximum
86
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
87
88
89
90
91
92
93
94
95
96
97
98
81
// determine average grade for particular student
double average( int setOfGrades[], int tests )
{
int total = 0;
fig04_23.cpp
(5 of 6)
// total all grades for one student
for ( int i = 0; i < tests; i++ )
total += setOfGrades[ i ];
return static_cast< double >( total ) / tests;
// average
} // end function maximum
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
99
100 // Print the array
101 void printArray( int grades[][ exams ], int pupils, int tests )
102 {
103
// set left justification and output column heads
104
cout << left << "
[0] [1] [2] [3]";
105
106
107
fig04_23.cpp
(6 of 6)
// output grades in tabular format
for ( int i = 0; i < pupils; i++ ) {
108
109
110
// output label for row
cout << "\nstudentGrades[" << i << "] ";
111
112
113
114
// output one grades for one student
for ( int j = 0; j < tests; j++ )
cout << setw( 5 ) << grades[ i ][ j ];
115
116
82
} // end outer for
117
118 } // end function printArray
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
83
The array is:
[0]
studentGrades[0] 77
studentGrades[1] 96
studentGrades[2] 70
[1]
68
87
90
[2]
86
89
86
[3]
73
78
81
fig04_23.cpp
output (1 of 1)
Lowest grade: 68
Highest grade: 96
The average grade for student 0 is 76.00
The average grade for student 1 is 87.50
The average grade for student 2 is 81.75
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
Ngôn ngữ lập trình C++
Chương 5 – Con trỏ và Xâu ký tự
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
2
Chương 5 – Con trỏ và Xâu ký tự
Đề mục
5.1
5.2
5.3
5.4
5.5
5.6
5.7
5.8
5.9
5.10
5.11
5.12
Giới thiệu
Khai báo và khởi tạo biến con trỏ
Các thao tác trên con trỏ
Gọi hàm bằng tham chiếu
Sử dụng const với con trỏ
Sắp xếp nổi bọt sử dụng Pass-by-Reference
Các phép toán trên con trỏ
Quan hệ giữa con trỏ và mảng
Mảng con trỏ
Ví dụ: giả lập tráo và chia bài
Con trỏ tới hàm
Giới thiệu về xử lý ký tự và xâu
5.12.1
Tổng quát về ký tự và xâu
5.12.2 Các hàm xử lý xâu
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
3
5.1
Giới thiệu
• Con trỏ (Pointer)
– Mạnh, nhưng khó làm chủ
– Có tác dụng như truyền tham chiếu (pass-by-reference)
– Có liên quan chặt chẽ đến mảng và xâu
• Biến con trỏ (Pointer variable)
– Chứa địa chỉ vùng nhớ thay vì chứa giá trị
– Thông thường, biến chứa giá trị (tham chiếu trực tiếp)
– Con trỏ chứa địa chỉ của biến mang giá trị
countPtr
cụ thể (tham chiếu gián tiếp)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
count
7
count
7
Chương 5.
https://fb.com/tailieudientucntt
4
5.2
Khai báo và khởi tạo biến con trỏ
• Khai báo con trỏ
– * cho biết biến là con trỏ
int *myPtr;
dữ liệu kiểu int có địa chỉ là myPtr, con trỏ kiểu int *
– Mỗi con trỏ cần một dấu sao
int *myPtr1, *myPtr2;
– Có thể khai báo con trỏ tới bất cứ kiểu dữ liệu nào
• Khởi tạo con trỏ (Pointer initialization)
– Khởi tạo về 0, NULL, hoặc địa chỉ
• 0 hoặc NULL không trỏ đến đâu cả
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
5
Các thao tác đối với con trỏ
5.3
• & Toán tử địa chỉ (address operator)
– Trả về địa chỉ vùng nhớ của toán hạng
– Ví dụ
int y = 5;
int *yPtr;
yPtr = &y;
– yPtr “trỏ đến” y
yPtr
y
5
// yPtr chứa địa chỉ của y
y
yptr
12FEA8
12FED4
12FED4
5
địa chỉ của y là
giá trị của yptr
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
6
5.3
Các thao tác đối với con trỏ
• * phép thâm nhập (indirection/dereferencing)
– Trả về đối tượng mà con trỏ trỏ tới
– *yPtr trả về y (vì yPtr trỏ đến y).
– con trỏ khi bị thâm nhập (dereferenced) là giá trị trái (lvalue)
*yptr = 9;
// assigns 9 to y
• * và & ngược nhau
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
fig05_04.cpp
(1 of 2)
4
5
6
using std::cout;
using std::endl;
7
8
9
10
11
int main()
{
int a;
int *aPtr;
12
13
14
a = 7;
aPtr = &a;
15
16
17
cout << "The address of a is " << &a
<< "\nThe value of aPtr is " << aPtr;
18
19
20
cout << "\n\nThe value of a is " << a
<< "\nThe value of *aPtr is " << *aPtr;
21
22
23
24
25
7
// Fig. 5.4: fig05_04.cpp
// Using the & and * operators.
#include <iostream>
// a is an integer
// aPtr is a pointer to an integer
// aPtr assigned address of a
* và & ngược nhau
cout << "\n\nShowing that * and & are inverses of "
<< "each other.\n&*aPtr = " << &*aPtr
<< "\n*&aPtr = " << *&aPtr << endl;
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
28
return 0;
8
// indicates successful termination
} // end main
fig05_04.cpp
(2 of 2)
The address of a is 0012FED4
The value of aPtr is 0012FED4
fig05_04.cpp
output (1 of 1)
The value of a is 7
The value of *aPtr is 7
Showing that * and & are inverses of each other.
&*aPtr = 0012FED4
* và & ngược nhau; cùng kết quả khi
*&aPtr = 0012FED4
cùng sử dụng cả 2 với aPtr
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
9
5.4
Gọi hàm bằng tham chiếu
• 3 cách truyền tham số cho hàm
– Truyền giá trị (Pass-by-value)
– Truyền tham chiếu với đối số là
reference with reference arguments)
– Truyền tham chiếu
pointer arguments)
tham chiếu (Pass-by-
với đối số là con trỏ (Pass-by-reference with
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
10
5.4
Gọi hàm bằng tham chiếu
• Truyền tham chiếu với đối số là tham chiếu
– Thay đổi giá trị gốc của tham số
– hàm có thể “trả về” nhiều hơn một giá trị
• Truyền tham chiếu bằng đối số là con trỏ
– Tương tự pass-by-reference
• Sử dụng con trỏ và toán tử *
– Truyền địa chỉ của đối số bằng toán tử &
– Truyền mảng không cần toán tử & vì tên mảng chính là con trỏ
– Toán tử thâm nhập * được dùng cùng con trỏ để tạo một tên khác cho
biến được truyền vào
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
fig05_06.cpp
(1 of 2)
4
5
6
using std::cout;
using std::endl;
7
8
int cubeByValue( int );
9
10
11
12
int main()
{
int number = 5;
13
14
11
// Fig. 5.6: fig05_06.cpp
// Cube a variable using pass-by-value.
#include <iostream>
// prototype
cout << "The original value of number is " Truyền
<< number;
number bằng giá trị;
kết quả được trả về bởi
cubeByValue
15
16
17
// pass number by value to cubeByValue
number = cubeByValue( number );
18
19
cout << "\nThe new value of number is " << number << endl;
20
21
return 0;
22
23
24
// indicates successful termination
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
26
27
28
29
30
// calculate and return cube of integer argument
int cubeByValue( int n )
{
cubeByValue nhận tham
return n * n * n; // cube local variable n and return result
số passed-by-value
} // end function cubeByValue
Tính lập phương và trả về biến
địa phương (local variable) n
12
fig05_06.cpp
(2 of 2)
fig05_06.cpp
output (1 of 1)
The original value of number is 5
The new value of number is 125
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
4
// Fig. 5.7: fig05_07.cpp
// Cube a variable using pass-by-reference
// with a pointer argument.
#include <iostream>
5
6
7
using std::cout;
using std::endl;
8
9
void cubeByReference( int * );
10
11
12
13
int main()
{
int number = 5;
13
fig05_07.cpp
(1 of 2)
Prototype cho biết tham số là
con trỏ trỏ đến dữ liệu kiểu int
// prototype
Dùng toán tử địa chỉ & để
truyền địa chỉ của number tới
cubeByReference
14
15
cout << "The original value of number is " << number;
16
17
18
// pass address of number to cubeByReference
cubeByReference( &number );
19
20
cout << "\nThe new value of number is " << number << endl;
21
22
return 0;
23
24
25
// indicates successful termination
cubeByReference
thay đổi biến number
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
28
29
30
31
14
// calculate cube of *nPtr; modifies variable number in main
void cubeByReference( int *nPtr )
{
*nPtr = *nPtr * *nPtr * *nPtr; // cube *nPtr
} // end function cubeByReference
The original value of number is 5
The new value of number is 125
fig05_07.cpp
cubeByReference nhận địa chỉ
(2 of 2)
của biến kiểu int,
tức là con trỏ trỏ đến một số int
fig05_07.cpp
output (1 of 1)
Thay đổi và truy nhập biến
kiểu int sử dụng toán tử
thâm nhập *
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
15
5.5
Sử dụng const với con trỏ
• Tính chất của const
– Giá trị của biến không thay đổi
– const được sử dụng cho một biến khi hàm không cần thay
đổi biến đó.
• Nguyên tắc quyền ưu tiên tối thiểu
– Chỉ cho hàm đủ quyền truy nhập để thực hiện nhiệm vụ của
mình, không cho nhiều quyền hơn.
• Bốn cách truyền con trỏ cho hàm
– Con trỏ thường trỏ đến dữ liệu thường
• Khả năng truy cập cao nhất
– Con trỏ thường trỏ đến hằng dữ liệu
– Hằng con trỏ trỏ đến dữ liệu thường
– Hằng con trỏ trỏ đến hằng dữ liệu
• Ít quyền truy cập nhất
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
4
// Fig. 5.10: fig05_10.cpp
// Converting lowercase letters to uppercase letters
// using a non-constant pointer to non-constant data.
#include <iostream>
5
6
7
using std::cout;
using std::endl;
8
9
#include <cctype>
10
11
void convertToUppercase( char * );
12
13
14
15
int main()
{
char phrase[] = "characters and $32.98";
fig05_10.cpp
(1 of 2)
Con trỏ thường
đến dữ liệu thường
// prototypes for islower and toupper
convertToUppercase
thay đổi biến phrase
16
17
18
19
20
cout << "The phrase before conversion is: " << phrase;
convertToUppercase( phrase );
cout << "\nThe phrase after conversion is: "
<< phrase << endl;
21
22
return 0;
23
24
25
16
// indicates successful termination
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
28
29
30
31
32
33
34
35
36
37
38
// convert string to uppercase letters
void convertToUppercase( char *sPtr )
{
sPtr là con trỏ thường trỏ
fig05_10.cpp
while ( *sPtr != '\0' ) {
// current character
'\0'
đếnis
dữ not
liệu thường
17
(2 of 2)
if ( islower( *sPtr ) ) // if character is lowercase,
*sPtr = toupper( *sPtr ); // convert to uppercase
++sPtr;
Hàm islower trả về true
nếu ký tự là chữ thường
fig05_10.cpp
output (1 of 1)
// move sPtr to next character in string
Hàm toupper trả về chữ hoa nếu ký tự ban đầu là chữ
thường; nếu không toupper trả về ký tự đó (chữ hoa)
} // end while
} // end function convertToUppercase
Khi dùng toán tử ++ cho con trỏ trỏ đến mảng, địa
chỉ vùng nhớ lưu trong con trỏ sẽ được sửa để con
trỏ trỏ đến phần tử tiếp theo của mảng.
The phrase before conversion is: characters and $32.98
The phrase after conversion is: CHARACTERS AND $32.98
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
4
// Fig. 5.11: fig05_11.cpp
// Printing a string one character at a time using
// a non-constant pointer to constant data.
#include <iostream>
5
6
7
using std::cout;
using std::endl;
8
9
void printCharacters( const char * );
10
11
12
13
int main()
{
char phrase[] = "print characters of a string";
fig05_11.cpp
(1 of 2)
Tham số là con trỏ thường trỏ
đến hằng dữ liệu
14
15
16
17
cout << "The string is:\n";
printCharacters( phrase );
cout << endl;
18
19
return 0;
20
21
22
18
Truyền con trỏ phrase cho
hàm printCharacters.
// indicates successful termination
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
23
24
25
26
27
28
29
30
19
// sPtr cannot modify the character to which it points,
// i.e., sPtr is a "read-only" pointer
void printCharacters( const char *sPtr )
fig05_11.cpp
{
(2 of 2)
for ( ; *sPtr != '\0'; sPtr++ )
// no initialization
cout << *sPtr;
sPtr là con trỏ thường trỏ đến hằng
} // end function printCharacters
fig05_11.cpp
dữ liệu; không thể thay
đổi ký tự mà
output
(1 of 1)
sPtr trỏ đến.
Tăng sPtr để trỏ đến ký tự
tiếp theo.
The string is:
print characters of a string
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
20
// Fig. 5.12: fig05_12.cpp
// Attempting to modify data through a
// non-constant pointer to constant data.
4
5
void f( const int * );
6
7
8
9
int main()
{
int y;
fig05_12.cpp
(1 of 1)
// prototype
Tham số là con trỏ thường trỏ
đến hằng dữ liệu.
10
11
f( &y );
// f attempts illegal modification
12
13
return 0;
// indicates successful termination
fig05_12.cpp
output (1 of 1)
Truyền địa chỉ của biến y để thử thay đổi một cách
không hợp lệ.
14
15
} // end main
16
17
18
19
20
21
// xPtr cannot modify the value of the variable
// to which it points
Cố thay đổi đối tượng hằng (const object)
void f( const int *xPtr )
mà xPtr trỏ đến.
{
*xPtr = 100; // error: cannot modify a const object
22
23
} // end function f
Lỗi sinh ra khi biên dịch.
d:\cpphtp4_examples\ch05\Fig05_12.cpp(21) : error C2166:
l-value specifies const object
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
21
5.5
Sử dụng const với con trỏ
• const pointers - hằng con trỏ
– Luôn trỏ đến vùng nhớ cố định
– là mặc định cho tên mảng
– Phải được khởi tạo khi khai báo
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
4
5
6
7
22
// Fig. 5.13: fig05_13.cpp
// Attempting to modify a constant pointer to
// non-constant data.
fig05_13.cpp
(1 of 1)
int main()
{
int x, y;
fig05_13.cpp
output (1 of 1)
ptr là hằng con trỏ trỏ tới số nguyên.
8
9
10
11
12
// ptr is a constant pointer to an integer that can
Có thể thay đổi x (trỏ bởi
// be modified throughptr)
ptr,
but
ptrphải
always
points to the
vì x
không
là hằng
// same memory location.
Không thể cho ptr trỏ đến
int * const ptr = &x;
13
14
15
*ptr = 7;
ptr = &y;
// allowed: *ptr is not const
// error: ptr is const; cannot assign new address
16
17
return 0;
// indicates successful termination
18
19
địa chỉ mới vì ptr là hằng
Dòng 15 sinh ra lỗi biên dịch
vì thay đổi địa chỉ mới cho
constant pointer.
} // end main
d:\cpphtp4_examples\ch05\Fig05_13.cpp(15) : error C2166:
l-value specifies const object
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
4
5
6
using std::cout;
using std::endl;
7
8
9
10
int main()
{
int x = 5, y;
11
12
13
14
15
16
17
23
// Fig. 5.14: fig05_14.cpp
// Attempting to modify a constant pointer to constant data.
#include <iostream>
fig05_14.cpp
(1 of 1)
ptr là hằng con trỏ trỏ tới hằng số nguyên.
// ptr is a constant pointer to a constant integer.
// ptr always points to the same location; the integer
// at that location cannot be modified.
Không thể thay đổi x (trỏ bởi ptr) vì
const int *const ptr = &x;
khai báo *ptr là hằng.
cout << *ptr << endl;
Không thể cho ptr trỏ đến địa chỉ
mới vì ptr được khai báo là hằng.
18
19
20
*ptr = 7;
ptr = &y;
// error: *ptr is const; cannot assign new value
// error: ptr is const; cannot assign new address
21
22
return 0;
// indicates successful termination
23
24
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
24
5.6 Sắp xếp nổi bọt
sử dụng truyền tham chiếu
• bubbleSort dùng con trỏ
– Hàm swap truy nhập các phần tử của mảng
• Các phần tử đơn của mảng: dữ liệu vô hướng (scalars)
– Mặc định là pass by value
• Truyền tham chiếu bằng toán tử địa chỉ &
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
4
// Fig. 5.15: fig05_15.cpp
// This program puts values into an array, sorts the values into
// ascending order, and prints the resulting array.
#include <iostream>
5
6
7
using std::cout;
using std::endl;
8
9
#include <iomanip>
10
11
using std::setw;
12
13
14
void bubbleSort( int *, const int );
void swap( int * const, int * const );
15
16
17
18
19
int main()
{
const int arraySize = 10;
int a[ arraySize ] = { 2, 6, 4, 8, 10, 12, 89, 68, 45, 37 };
20
21
22
23
24
25
25
fig05_15.cpp
(1 of 3)
// prototype
// prototype
cout << "Data items in original order\n";
for ( int i = 0; i < arraySize; i++ )
cout << setw( 4 ) << a[ i ];
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
bubbleSort( a, arraySize );
27
28
cout << "\nData items in ascending order\n";
26
// sort the array
29
30
31
for ( int j = 0; j < arraySize; j++ )
cout << setw( 4 ) << a[ j ];
32
33
cout << endl;
34
35
return 0;
fig05_15.cpp
(2 of 3)
Khai báo là int *array (thay vì
int array[]) để cho hàm
bubbleSort nhận mảng 1 chiều.
// indicates successful termination
Hai cách khai báo này là như nhau.
36
37
} // end main
40
41
42
43
void bubbleSort( int *array, const int size )
{
// loop to control passes
for ( int pass = 0; pass < size - 1; pass++ )
Nhận tham số kích thước của mảng;
38
khai báo là const để chắc chắn
39 // sort an array of integers using bubble sort algorithm
rằng size sẽ không bị thay đổi.
44
45
46
47
48
49
50
// loop to control comparisons during each pass
for ( int k = 0; k < size - 1; k++ )
// swap adjacent elements if they are out of order
if ( array[ k ] > array[ k + 1 ] )
swap( &array[ k ], &array[ k + 1 ] );
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
51
52
53
54
55
56
57
58
59
60
61
62
27
} // end function bubbleSort
fig05_15.cpp
// swap values at memory locations to which
(3 of 3)
// element1Ptr and element2Ptr point
void swap( int * const element1Ptr, int * const element2Ptr )
fig05_15.cpp
{
output (1 of 1)
int hold = *element1Ptr;
*element1Ptr = *element2Ptr;
Truyền tham chiếu, cho phép
*element2Ptr = hold;
hàm tráo giá trị tại vùng nhớ.
} // end function swap
Data items in original order
2
6
4
8 10 12 89 68
Data items in ascending order
2
4
6
8 10 12 37 45
45
37
68
89
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
28
5.6 Sắp xếp nổi bọt
sử dụng truyền tham chiếu
• sizeof
– Toán tử trả về kích thước byte của toán hạng
– Với mảng, sizeof trả về giá trị
( kích thước 1 phần tử ) * ( số phần tử )
– Nếu sizeof( int ) = 4, thì
int myArray[10];
cout << sizeof(myArray);
sẽ in ra 40
• sizeof có thể dùng với
– Tên biến
cout << "sizeof c = " << sizeof c
– Tên kiểu dữ liệu
cout << sizeof( char )
– Hằng số
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
4
// Fig. 5.16: fig05_16.cpp
// Sizeof operator when used on an array name
// returns the number of bytes in the array.
#include <iostream>
5
6
7
using std::cout;
using std::endl;
8
9
size_t getSize( double * );
10
11
12
13
int main()
{
double array[ 20 ];
29
fig05_16.cpp
(1 of 2)
// prototype
sizeof trả về tổng số byte
của mảng.
14
15
16
cout << "The number of bytes in the array is "
<< sizeof( array );
17
18
19
cout << "\nThe number of bytes returned by getSize is "
<< getSize( array ) << endl;
20
21
return 0;
22
23
24
// indicates successful termination
Hàm getSize trả về số byte
được dùng để lưu địa chỉ
mảng array.
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
26
27
28
// return size of ptr
size_t getSize( double *ptr )
{
return sizeof( ptr );
29
30
} // end function getSize
30
fig05_16.cpp
(2 of 2)
sizeof trả về số byte
của con trỏ.
fig05_16.cpp
output (1 of 1)
The number of bytes in the array is 160
The number of bytes returned by getSize is 4
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
31
5.7
Các phép toán đối với con trỏ
• Các phép toán con trỏ
– Tăng/giảm con trỏ (++ hoặc --)
– Cộng/trừ 1 số nguyên với 1 con trỏ ( + hoặc += , - hoặc -=)
– Con trỏ có thể trừ lẫn nhau
– Cộng trừ với con trỏ là vô nghĩa trừ khi dùng cho con trỏ mảng
• Ví dụ: Mảng 5 phần tử int trên máy dùng kiểu int 4 byte
– vPtr trỏ đến phần tử thứ nhất v[ 0 ], tại địa chỉ 3000
vPtr = 3000
– vPtr += 2; trỏ vPtr tới 3008
vùng nhớ
3000
3004
3008
3012
3016
vPtr trỏ tới v[ 2 ]
v[0]
v[1]
v[2]
v[3]
v[4]
biến con trỏ vPtr
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
32
5.7
Các phép toán đối với con trỏ
• Trừ con trỏ (Subtracting pointers)
– Trả về số phần tử giữa 2 địa chỉ
vPtr2 = v[ 2 ];
vPtr = v[ 0 ];
vPtr2 - vPtr == 2
• Gán con trỏ (Pointer assignment)
– Một con trỏ có thể được gán cho con trỏ khác nếu cả hai
cùng kiểu
– Nếu không cùng kiểu thì phải đổi kiểu (cast)
– Ngoại lệ: con trỏ tới void (kiểu void *)
• con trỏ tổng quát, đại diện cho kiểu bất kỳ
• không cần đổi kiểu để chuyển sang con trỏ sang dạng void
pointer
• Không thể (dùng *) lấy dữ liệu của con trỏ kiểu void
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
33
5.7
Các phép toán đối với con trỏ
• So sánh con trỏ (Pointer comparison)
– Sử dụng các toán tử quan hệ để so sánh địa chỉ chứa trong
con trỏ
– Ví dụ: có hai con trỏ trỏ đến hai phần tử của một mảng, chỉ
ra con trỏ trỏ đến phần tử được đánh số thứ tự cao
– So sánh là vô nghĩa trừ khi các con trỏ trỏ đến các phần tử
của cùng một mảng
– Thường dùng để xác định khi con trỏ có giá trị bằng 0 (null)
(không trỏ đến đâu cả)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
34
5.8
Quan hệ giữa Con trỏ và Mảng
• Mảng và con trỏ có quan hệ chặt chẽ
– Tên mảng cũng như hằng con trỏ (constant pointer)
– Có thể dùng chỉ số đối với các con trỏ
• Dùng con trỏ để truy nhập các phần tử mảng
– Phần tử b[ n ] có thể truy nhập bởi *( bPtr + n )
• ký hiệu pointer/offset
– Địa chỉ
• &b[ 3 ] tương đương bPtr + 3
– Tên mảng có thể coi như con trỏ
• b[ 3 ] tương đương *( b + 3 )
– Con trỏ có thể viết với cặp ngoặc vuông (ký hiệu
pointer/subscript)
• bPtr[ 3 ] tương đương b[ 3 ]
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
// Fig. 5.20: fig05_20.cpp
// Using subscripting and pointer notations with arrays.
3
4
#include <iostream>
5
6
7
using std::cout;
using std::endl;
8
9
10
11
12
int main()
{
int b[] = { 10, 20, 30, 40 };
int *bPtr = b;
// set bPtr to point to array b
13
14
15
16
// output array b using array subscript notation
cout << "Array b printed with:\n"
<< "Array subscript notation\n";
17
18
19
for ( int i = 0; i < 4; i++ )
cout << "b[" << i << "] = " << b[ i ] << '\n';
20
21
22
23
24
25
35
fig05_20.cpp
(1 of 2)
Sử dụng ký hiệu chỉ số mảng.
// output array b using the array name and
// pointer/offset notation
cout << "\nPointer/offset notation where "
<< "the pointer is the array name\n";
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
28
36
for ( int offset1 = 0; offset1 < 4; offset1++ )
cout << "*(b + " << offset1 << ") = "
<< *( b + offset1 ) << '\n';
fig05_20.cpp
(2 of 2)
29
30
31
// output array b using bPtr and array subscript notation
cout << "\nPointer subscript notation\n"; Sử dụng tên mảng và ký hiệu pointer/offset.
32
33
34
for ( int j = 0; j < 4; j++ )
cout << "bPtr[" << j << "] = " << bPtr[ j ] << '\n';
35
36
cout << "\nPointer/offset notation\n";
37
38
39
40
41
// output array b using bPtr and pointer/offset notation
for ( int offset2 = 0; offset2 < 4; offset2++ )
cout << "*(bPtr + " << offset2 << ") = "
<< *( bPtr + offset2 ) << '\n';
42
43
return 0;
44
45
Sử dụng ký hiệu chỉ số
cho con trỏ.
// indicates successful termination
Sử dụng bPtr và ký hiệu pointer/offset.
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
37
Array b printed with:
Array subscript notation
b[0] = 10
b[1] = 20
b[2] = 30
b[3] = 40
fig05_20.cpp
output (1 of 1)
Pointer/offset notation where the pointer is the array name
*(b + 0) = 10
*(b + 1) = 20
*(b + 2) = 30
*(b + 3) = 40
Pointer
bPtr[0]
bPtr[1]
bPtr[2]
bPtr[3]
subscript notation
= 10
= 20
= 30
= 40
Pointer/offset notation
*(bPtr + 0) = 10
*(bPtr + 1) = 20
*(bPtr + 2) = 30
*(bPtr + 3) = 40
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
1
2
3
4
// Fig. 5.21: fig05_21.cpp
// Copying a string using array notation
// and pointer notation.
#include <iostream>
5
6
7
using std::cout;
using std::endl;
8
9
10
void copy1( char *, const char * );
void copy2( char *, const char * );
11
12
13
14
15
16
17
int main()
{
char string1[ 10 ];
char *string2 = "Hello";
char string3[ 10 ];
char string4[] = "Good Bye";
fig05_21.cpp
(1 of 2)
// prototype
// prototype
18
19
20
copy1( string1, string2 );
cout << "string1 = " << string1 << endl;
21
22
23
copy2( string3, string4 );
cout << "string3 = " << string3 << endl;
24
25
return 0;
// indicates successful termination
CuuDuongThanCong.com
38
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
39
26
27
} // end main
28
29
30
31
32
33
// copy s2 to s1 using array notation
void copy1( char *s1, const char *s2 )
{
for ( int i = 0; ( s1[ i ] = s2[ i ] ) != '\0'; i++ )
;
// do nothing in body
34
35
} // end function copy1
36
37
38
39
40
41
// copy s2 to s1 using pointer notation Sử dụng ký hiệu con trỏ để copy xâu
void copy2( char *s1, const char *s2 )
tại s2 vào mảng ký tự s1.
{
for ( ; ( *s1 = *s2 ) != '\0'; s1++, s2++ )
;
// do nothing in body
42
43
} // end function copy2
Sử dụng chỉ số mảng để copy
xâu tại s2 vào mảng ký tự s1.
fig05_21.cpp
(2 of 2)
string1 = Hello
string3 = Good Bye
fig05_21.cpp
output (1 of 1)
Tăng cả hai con trỏ để trỏ đến
phần tử tiếp theo trong mảng
tương ứng.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
40
5.9
Mảng con trỏ
• Mảng chứa con trỏ
– Thường dùng để lưu mảng của xâu
char *suit[ 4 ] = {"Hearts", "Diamonds",
"Clubs", "Spades" };
– Mỗi phần tử của suit trỏ đến char * (1 xâu)
– Mảng không chứa xâu, chỉ trỏ đến xâu
suit[0]
’H’
’e’
’a’
’r’
’t’
’s’
’\0’
suit[1]
’D’
’i’
’a’
’m’
’o’
’n’
’d’
suit[2]
’C’
’l’
’u’
’b’
’s’
’\0’
suit[3]
’S’
’p’
’a’
’d’
’e’
’s’
’s’
’\0’
’\0’
– Mảng suit có kích thước cố định, nhưng xâu thì không
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
41
5.10 Ví dụ:
Giả lập tráo bài và chia bài Tú-lơ-khơ
• Chương trình tráo bài (Card shuffling program)
– Dùng một mảng gồm các con trỏ trỏ đến xâu để lưu trữ tên
các chất (suit), i.e. cơ (hearts), rô (diamonds), pích (spades), tép (clubs)
– Sử dụng một mảng hai chiều (hàng: chất, cột: giá trị)
Ace
0
Hearts
0
Diamonds
1
Clubs
2
Spades
3
Two
1
Three Four
2
3
Five
4
Six
5
Seven Eight Nine
6
7
8
Ten
9
Jack
10
Queen King
11
12
deck[2][12] biểu diễn K-tép
Clubs
King
– Ghi các số từ 1-52 vào mảng để làm thứ tự chia các con bài
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
42
5.10 Ví dụ:
Giả lập tráo bài và chia bài Tú-lơ-khơ
Làm mịn lần hai
• Thuật toán tráo (shuffle) và
chia (deal) bài
Ban đầu
Initialize the suit array
Initialize the face array
Initialize the deck array
Shuffle the deck
(tráo bài)
Deal 52 cards
(chia bài)
Làm mịn
Choose slot of deck randomly
While chosen slot of deck has been
previously chosen (Trong khi ô
vừa chọn đã bị chọn từ trước)
For each of the 52 cards
Place card number in randomly
selected unoccupied slot of deck
(Đặt chỉ số quân bài vào một ô
ngẫu nhiên còn trống trong desk)
Choose slot of deck randomly
(chọn ngẫu nhiên một ô)
Place card number in chosen slot
of deck (đặt chỉ số quân bài vào ô
được chọn)
For each of the 52 cards
For each slot of the deck array
Find card number in deck array
and print face and suit of card
(Tìm chỉ số quân bài trong mảng
desk và in ra số hiệu và chất của
quân bài)
If slot contains card number
Print the face and suit of the
card
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
43
// Fig. 5.24: fig05_24.cpp
// Card shuffling dealing program.
#include <iostream>
fig05_24.cpp
(1 of 4)
4
5
6
7
using std::cout;
using std::left;
using std::right;
8
9
#include <iomanip>
10
11
using std::setw;
12
13
14
#include <cstdlib>
#include <ctime>
15
16
17
18
// prototypes
void shuffle( int [][ 13 ] );
void deal( const int [][ 13 ], const char *[], const char *[] );
19
20
21
22
23
24
25
// prototypes for rand and srand
// prototype for time
mảng suit chứa các con trỏ
int main()
trỏ đến các mảng char.
{
// initialize suit array
const char *suit[ 4 ] =
{ "Hearts", "Diamonds", "Clubs", "Spades" };
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
28
29
30
// initialize face array
const char *face[ 13 ] =
{ "Ace", "Deuce", "Three", "Four",
"Five", "Six", "Seven", "Eight",
"Nine", "Ten", "Jack", "Queen", "King" };
31
32
33
// initialize deck array
int deck[ 4 ][ 13 ] = { 0 };
34
35
srand( time( 0 ) );
36
37
38
shuffle( deck );
deal( deck, face, suit );
39
40
return 0;
41
42
44
fig05_24.cpp
(2 of 4)
mảng face chứa các con trỏ
trỏ đến các mảng char.
// seed random number generator
// indicates successful termination
} // end main
43
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
44
45
46
47
48
49
50
51
45
// shuffle cards in deck
void shuffle( int wDeck[][ 13 ] )
{
int row;
int column;
fig05_24.cpp
(3 of 4)
// for each of the 52 cards, choose slot of deck randomly
for ( int card = 1; card <= 52; card++ ) {
52
53
54
55
56
57
// choose new random location until unoccupied slot found
do {
Vị trí hiện tại có dòng và cột được chọn
row = rand() % 4;
ngẫu nhiên.
column = rand() % 13;
} while ( wDeck[ row ][ column ] != 0 ); // end do/while
58
59
60
// place card number in chosen slot of deck
wDeck[ row ][ column ] = card;
61
62
63
64
} // end for
} // end function shuffle
65
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
66
67
68
69
70
71
72
73
74
75
76
77
46
// deal cards in deck
void deal( const int wDeck[][ 13 ], const char *wFace[],
const char *wSuit[] )
{
// for each of the 52 cards
for ( int card = 1; card <= 52; card++ )
// loop through rows of wDeck
for ( int row = 0; row <= 3; row++ )
fig05_24.cpp
(4 of 4)
Căn lề phải trong một vùng
gồm 5 ký tự.
// loop through columns of wDeck for current rowCăn lề trái trong một vùng gồm
for ( int column = 0; column <= 12; column++ ) 8 ký tự.
78
79
80
81
82
83
84
// if slot contains current card, display card
if ( wDeck[ row ][ column ] == card ) {
cout << setw( 5 ) << right << wFace[ column ]
<< " of " << setw( 8 ) << left
<< wSuit[ row ]
<< ( card % 2 == 0 ? '\n' : '\t' );
85
86
} // end if
87
88
} // end function deal
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
Nine
Five
Queen
Jack
Jack
Three
Ten
Ace
Seven
Six
Ace
Nine
Six
Ten
Four
Ten
Eight
Jack
Four
Seven
Queen
Nine
Deuce
King
Queen
Five
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
Spades
Spades
Diamonds
Spades
Diamonds
Clubs
Clubs
Hearts
Spades
Hearts
Clubs
Hearts
Spades
Spades
Clubs
Hearts
Hearts
Hearts
Diamonds
Hearts
Spades
Clubs
Hearts
Clubs
Clubs
Hearts
Seven
Eight
Three
Five
Three
Six
Nine
Queen
Deuce
Deuce
Deuce
Seven
Eight
King
Ace
Four
Eight
Ten
King
King
Four
Six
Jack
Three
Five
Ace
CuuDuongThanCong.com
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
Clubs
Clubs
Hearts
Diamonds
Diamonds
Clubs
Diamonds
Hearts
Spades
Clubs
Diamonds
Diamonds
Diamonds
Hearts
Spades
Spades
Spades
Diamonds
Diamonds
Spades
Hearts
Diamonds
Clubs
Spades
Clubs
Diamonds
47
fig05_24.cpp
output (1 of 1)
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
48
5.11 Con trỏ tới hàm (Function Pointer)
• Con trỏ tới hàm
– chứa địa chỉ của hàm
– Tên mảng có giá trị là địa chỉ của phần tử đầu tiên của mảng
– Tương tự, tên hàm có giá trị là địa chỉ bắt đầu của đoạn mã
định nghĩa hàm
• Các con trỏ tới hàm có thể
–
–
–
–
được truyền vào trong hàm
được trả về từ hàm
được lưu trong mảng
được gán cho các con trỏ hàm khác
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
49
5.11 Con trỏ tới hàm
• Gọi hàm bằng con trỏ tới hàm
– giả sử compare được khai báo là con trỏ tới hàm có kiểu
tham số và kiểu trả về như sau:
• bool ( *compare ) ( int, int )
– gọi hàm bằng một trong hai cách
• ( *compare ) ( int1, int2 )
– thâm nhập con trỏ để chạy hàm được con trỏ trỏ tới
HOẶC
• compare( int1, int2 )
– dễ nhầm lẫn
• người dùng có thể tưởng compare là tên của hàm
thực trong chương trình
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
fig05_25.cpp
(1 of 5)
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
#include <iomanip>
10
11
using std::setw;
12
13
14
15
16
17
// prototypes
void bubble( int [], const int, bool (*)( int, int ) );
void swap( int * const, int * const );
bool ascending( int, int );
bool descending( int, int );
18
19
20
21
22
23
24
};
25
50
// Fig. 5.25: fig05_25.cpp
// Multipurpose sorting program using function pointers.
#include <iostream>
Tham số thứ ba là con trỏ tới
một hàm nhận 2 tham số int
và trả về kết quả kiểu bool.
int main()
{
const int arraySize = 10;
int order;
int counter;
int a[ arraySize ] = { 2, 6, 4, 8, 10, 12, 89, 68, 45, 37
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
28
29
30
31
32
33
51
cout << "Enter 1 to sort in ascending order,\n"
<< "Enter 2 to sort in descending order: ";
cin >> order;
cout << "\nData items in original order\n";
fig05_25.cpp
(2 of 5)
// output original array
for ( counter = 0; counter < arraySize; counter++ )
cout << setw( 4 ) << a[ counter ];
34
35
36
37
38
39
40
// sort array in ascending order; pass function ascending
// as an argument to specify ascending sorting order
if ( order == 1 ) {
bubble( a, arraySize, ascending );
cout << "\nData items in ascending order\n";
}
41
42
43
44
45
46
47
// sort array in descending order; pass function descending
// as an agrument to specify descending sorting order
else {
bubble( a, arraySize, descending );
cout << "\nData items in descending order\n";
}
48
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
52
49
50
51
// output sorted array
for ( counter = 0; counter < arraySize; counter++ )
cout << setw( 4 ) << a[ counter ];
52
53
fig05_25.cpp
cout << endl;
(3 of 5)
compare là con trỏ tới một hàm nhận
return 0; // indicates successful termination
2 tham số kiểu int và trả về giá trị kiểu
bool.
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
} // end main
// multipurpose bubble sort; parameter compare is a pointer to
// the comparison function that determines sorting order
void bubble( int work[], const int size,
bool (*compare)( int, int ) )
{
Dùng ngoặc để chỉ rõ đây là con trỏ tới hàm
// loop to control passes
for ( int pass = 1; pass < size; pass++ ) gọi hàm compare được truyền vào;
thâm nhập con trỏ để chạy hàm.
// loop to control number of comparisons per pass
for ( int count = 0; count < size - 1; count++ )
// if adjacent elements are out of order, swap them
if ( (*compare)( work[ count ], work[ count + 1 ] ) )
swap( &work[ count ], &work[ count + 1 ] );
} // end function bubble
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
53
75
76
77
78
79
80
81
82
// swap values at memory locations to which
// element1Ptr and element2Ptr point
fig05_25.cpp
void swap( int * const element1Ptr, int * const element2Ptr )
(4 of 5)
{
Enter 1 to sort in ascending order,
int hold = *element1Ptr;
Enter 2 to sort in descending order: 1
*element1Ptr = *element2Ptr;
Data items in original order
*element2Ptr = hold;
83
84
} // end function swap
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
2
6
4
8 10 12 89 68
Data items in ascending order
2
4
6
8 10 12 37 45
45
37
68
89
// determine whether elements are out of order
// for an ascending order sort
Enter 1 to sort in ascending order,
bool ascending( int a, int b )
Enter 2 to sort in descending order: 2
{
return b < a;// swap if b is less than a Data items in original order
} // end function ascending
2
6
4
8 10 12 89 68
Data items in descending order
89 68 45 37 12 10
8
6
45
37
4
2
// determine whether elements are out of order
// for a descending order sort
bool descending( int a, int b )
{
return b > a;
// swap if b is greater than a
} // end function descending
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
54
5.11 Con trỏ tới hàm
• Mảng gồm các con trỏ hàm
– Thường dùng cho các hệ thống điều khiển bằng thực đơn
(menu-driven system)
– Các con trỏ đến từng hàm được lưu trong mảng con trỏ hàm
• các hàm đều phải có kiểu dữ liệu trả về giống nhau, và kiểu dữ
liệu của tham số như nhau
– Ánh xạ
(lựa chọn thực đơn Æ chỉ số trong mảng con trỏ tới hàm)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
55
// Fig. 5.26: fig05_26.cpp
// Demonstrating an array of pointers to functions.
#include <iostream>
fig05_26.cpp
(1 of 3)
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
10
11
12
// function prototypes
void function1( int );
void function2( int );
void function3( int );
13
14
15
16
17
18
int main()
{
// initialize array of 3 pointers to functions that each
// take an int argument and return void
void (*f[ 3 ])( int ) = { function1, function2, function3 };
19
20
21
22
23
24
Mảng được khởi tạo với tên của ba hàm,
tên của hàm chính là con trỏ.
int choice;
cout << "Enter a number between 0 and 2, 3 to end: ";
cin >> choice;
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
26
56
// process user's choice
while ( choice >= 0 && choice < 3 ) {
27
28
29
30
// invoke function at location choice in array f
// and pass choice as an argument
(*f[ choice ])( choice );
31
32
33
34
}
35
36
cout << "Program execution completed." << endl;
37
38
return 0;
cout << "Enter a number between 0 and 2, 3 to end: ";
cin >> choice;
Gọi hàm được chọn bằng cách thâm nhập vào
(dereferencing) phần tử tương ứng trong mảng.
// indicates successful termination
39
40
} // end main
41
42
43
44
45
void function1( int a )
{
cout << "You entered " << a
<< " so function1 was called\n\n";
46
47
48
fig05_26.cpp
(2 of 3)
} // end function1
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
49
50
51
52
void function2( int b )
{
cout << "You entered " << b
<< " so function2 was called\n\n";
53
54
} // end function2
55
56
57
58
59
void function3( int c )
{
cout << "You entered " << c
<< " so function3 was called\n\n";
60
61
} // end function3
57
fig05_26.cpp
(3 of 3)
fig05_26.cpp
output (1 of 1)
Enter a number between 0 and 2, 3 to end: 0
You entered 0 so function1 was called
Enter a number between 0 and 2, 3 to end: 1
You entered 1 so function2 was called
Enter a number between 0 and 2, 3 to end: 2
You entered 2 so function3 was called
Enter a number between 0 and 2, 3 to end: 3
Program execution completed.
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
58
5.12.1 Tổng kết về ký tự và xâu ký tự
• Hằng ký tự - Character constant
– Giá trị nguyên biểu diễn dưới dạng một ký tự viết trong 2 dấu nháy
– 'z' là giá trị nguyên của ký tự z
• Mã 122 trong bảng mã ASCII
• Xâu ký tự - String
– Chuỗi các ký tự được coi như là một single unit
– Có thể bao gồm chữ cái, chữ số, ký tự đặc biệt +, -, * ...
– Hằng xâu ký tự - String literal (string constants)
• Viết trong cặp nháy kép, ví dụ: "I like C++"
– Mảng của các ký tự, kết thúc với ký tự rỗng (null character) '\0'
– Xâu là một hằng con trỏ (constant pointer)
• Trỏ đến ký tự đầu tiên của xâu
– Giống như với mảng
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
59
5.12.1 Tổng kết về ký tự và xâu ký tự
• Gán giá trị cho xâu - String assignment
– Mảng của ký tự
• char color[] = "blue";
– Tạo mảng color 5 phần tử kiểu char
• phần tử cuối cùng là '\0'
– Biến kiểu char *
• char *colorPtr = "blue";
– Tạo con trỏ colorPtr trỏ đến chữ b trong xâu "blue"
• "blue" ở đâu đó trong bộ nhớ
– Một cách khác cho mảng ký tự
• char color[] = { 'b', 'l', 'u', 'e', '\0' };
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
60
5.12.1 Tổng kết về ký tự và xâu ký tự
• Đọc xâu
– Đọc dữ liệu cho mảng ký tự word[ 20 ]
cin >> word
• Đọc các ký tự cho đến khi gặp ký tự trắng hoặc EOF
• Xâu có thể vượt quá kích thước mảng
cin >> setw( 20 ) >> word;
• Đọc 19 ký tự (để lại chỗ cho '\0')
• cin.getline
– Đọc 1 dòng văn bản
– cin.getline( array, size, delimiter );
– Lưu input vào mảng array đến khi xảy ra một trong hai trường hợp
• Kích thước dữ liệu đạt đến size – 1
• Ký tự delimiter được nhập vào
– Ví dụ
char sentence[ 80 ];
cin.getline( sentence, 80, '\n' );
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
61
5.12.2 Các hàm xử lý xâu ký tự
• Thư viện xử lý xâu <cstring> cung cấp các hàm
–
–
–
–
thao tác với dữ liệu kiểu xâu
so sánh xâu
tìm kiếm trên xâu các ký tự hoặc xâu khác
chia xâu thành các từ tố (tokenize strings)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
62
5.12.2 Các hàm xử lý xâu ký tự
char *strcpy( char *s1, const
char *s2 );
Copy xâu s2 vào xâu s1. Trả về giá trị của
s1.
char *strncpy( char *s1, const
char *s2, size_t n );
Copy nhiều nhất n ký tự của xâu s2 vào xâu
s1. Trả về giá trị của s1.
char *strcat( char *s1, const
char *s2 );
Thêm xâu s2 vào sau xâu s1. Ký tự đầu tiên
của s2 ghi đè lên ký tự null của s1. Trả về giá
trị của s1.
char *strncat( char *s1, const
char *s2, size_t n );
Thêm xâu nhiều nhất là n ký tự của s2 vào
sau xâu s1. Ký tự đầu tiên của s2 ghi đè lên
ký tự null của s1. Trả về giá trị của s1.
int strcmp( const char *s1,
const char *s2 );
So sánh xâu s1 và xâu s2. Hàm trả về giá trị
0, nhỏ hơn 0, hoặc lớn hơn 0 nếu s1 bằng, nhỏ
hơn hoặc lớn hơn s2.
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
63
5.12.2 Các hàm xử lý xâu ký tự
int strncmp( const char *s1, const
char *s2, size_t n );
So sánh n ký tự xâu s1 và xâu s2. Hàm
trả về giá trị 0, nhỏ hơn 0 hoặc lớn hơn 0
nếu s1 bằng, nhỏ hơn hoặc lớn hơn s2.
char *strtok( char *s1, const char
*s2 );
Một chuỗi lời gọi đến strtok chia xâu
s1 thành các “tokens”—từ tố, chẳng hạn
các từ trong một dòng văn bản—phân tách
nhau bởi các ký tự chứa trong xâu s2.
Lời gọi đầu tiên lấy s1 làm tham số thứ
nhất, các lời gọi tiếp sau (với NULL là tham
số thứ nhất) tiếp tục lấy các từ tố từ chính
xâu đó.
Mỗi lời gọi trả về một con trỏ tới từ tố vừa
nhận được. Nếu không còn từ tố nào, hàm
sẽ trả về giá trị NULL.
size_t strlen( const char *s );
Xác định độ dài của xâu s. Trả về số ký tự
của xâu (không tính ký tự null).
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
64
5.12.2 Các hàm xử lý xâu ký tự
• Copy xâu
– char *strcpy( char *s1, const char *s2 )
• Copy tham số thứ hai vào tham số thứ nhất
– Tham số thứ nhất phải có kích thước đủ lớn để chứa xâu
và ký tự null
– char *strncpy( char *s1, const char *s2,
size_t n )
• Xác định rõ số ký tự được copy từ xâu vào mảng
• Không nhất thiết copy ký tự null
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
65
// Fig. 5.28: fig05_28.cpp
// Using strcpy and strncpy.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
#include <cstring>
9
10
11
12
13
14
int main()
{
char x[] = "Happy Birthday to You";
char y[ 25 ];
Copy toàn bộ xâu trong mảng
char z[ 15 ];
x vào mảng y.
15
16
17
18
19
20
21
22
23
24
25
<cstring> chứa prototype
cho strcpy và strncpy.
strcpy( y, x );
fig05_28.cpp
(1 of 2)
// prototypes for strcpy and strncpy
// copy contents of x into y
Copy 14 ký tự đầu tiên của mảng
x vào mảng y. Chú ý rằng lệnh
này không viết ký tự null.
cout << "The string in array x is: " << x
<< "\nThe string in array y is: " << y << '\n';
// copy first 14 characters of x into z
strncpy( z, x, 14 ); // does not copy null character
z[ 14 ] = '\0';
// append '\0' to z's contents
cout << "The string in array z is: " << z << endl;
CuuDuongThanCong.com
Thêm ký tự null.
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
26
27
28
29
66
return 0;
// indicates successful termination
} // end main
fig05_28.cpp
(2 of 2)
Xâu gốc.
The string in array x is: Happy Birthday to You
The string in array y is: Happy Birthday to You
The string in array z is: Happy Birthday
fig05_28.cpp
output (1 of 1)
Copy xâu bằng strcpy.
Copy 14 ký tự đầu tiên
bằng strncpy.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
67
5.12.2 Các hàm xử lý xâu ký tự
• Nối xâu - Concatenating strings
– char *strcat( char *s1, const char *s2 )
• Nối xâu thứ hai vào sau xâu thứ nhất
• Ký tự đầu tiên của tham số thứ hai thay thế ký tự null của tham
số thứ nhất
• Phải chắc chắn rằng tham số thứ nhất có kích thước đủ lớn để
chứa thêm phần nối vào và ký tự null kết thúc xâu.
– char *strncat( char *s1, const char *s2,
size_t n )
• Thêm n ký tự của tham số thứ hai vào sau tham số thứ nhất
• Thêm ký tự null vào kết quả
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
68
// Fig. 5.29: fig05_29.cpp
// Using strcat and strncat.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
#include <cstring>
9
10
11
12
13
14
int main()
{
char s1[ 20 ] = "Happy ";
char s2[] = "New Year ";
char s3[ 40 ] = "";
fig05_29.cpp
(1 of 2)
<cstring> chứa prototype
cho strcat và strncat.
// prototypes for strcat and strncat
Thêm s2 vào sau s1.
15
16
cout << "s1 = " << s1 << "\ns2 = " << s2;
17
18
strcat( s1, s2 );
19
20
21
cout << "\n\nAfter strcat(s1, s2):\ns1 = " << s1
<< "\ns2 = " << s2;
Thêm 6 ký tự đầu tiên của s1 vào sau s3.
22
23
24
25
// concatenate s2 to s1
// concatenate first 6 characters of s1 to s3
strncat( s3, s1, 6 ); // places '\0' after last character
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
cout << "\n\nAfter strncat(s3, s1, 6):\ns1 = " << s1
<< "\ns3 = " << s3;
Thêm s1 vào sau s3.
28
29
30
31
strcat( s3, s1 ); // concatenate s1 to s3
cout << "\n\nAfter strcat(s3, s1):\ns1 = " << s1
<< "\ns3 = " << s3 << endl;
32
33
34
35
return 0;
// indicates successful termination
69
fig05_29.cpp
(2 of 2)
fig05_29.cpp
output (1 of 1)
} // end main
s1 = Happy
s2 = New Year
After strcat(s1, s2):
s1 = Happy New Year
s2 = New Year
After strncat(s3, s1, 6):
s1 = Happy New Year
s3 = Happy
After strcat(s3, s1):
s1 = Happy New Year
s3 = Happy Happy New Year
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
70
5.12.2 Các hàm xử lý xâu ký tự
• So sánh xâu - Comparing strings
– Các ký tự được biểu diễn bằng mã dạng số (numeric code)
• các mã đó được dùng để so sánh các xâu ký tự
– Các bộ mã ký tự (Character codes / character sets)
• ASCII “American Standard Code for Information Interchage”
• EBCDIC “Extended Binary Coded Decimal Interchange Code”
• Các hàm so sánh xâu
– int strcmp( const char *s1, const char *s2 )
• So sánh từng ký tự một, theo thứ tự từ điển
• Trả về
– 0 nếu xâu bằng nhau
– Giá trị âm nếu xâu thứ nhất nhỏ hơn xâu thứ hai
– Giá trị dương nếu xâu thứ nhất lớn hơn xâu thứ hai
– int strncmp( const char *s1,
const char *s2, size_t n )
• So sánh n ký tự đầu tiên
• Dừng so sánh nếu gặp ký tự null của 1 trong 2 tham số
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
fig05_30.cpp
(1 of 2)
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
<cstring> chứa prototype
cho strcmp và strncmp.
9
10
using std::setw;
11
12
#include <cstring>
13
14
15
16
17
18
19
20
21
22
23
24
25
71
// Fig. 5.30: fig05_30.cpp
// Using strcmp and strncmp.
#include <iostream>
// prototypes for strcmp and strncmp
int main()
{
char *s1 = "Happy New Year";
char *s2 = "Happy New Year";
char *s3 = "Happy Holidays";
cout <<
<<
<<
<<
<<
<<
So sánh s1 với s2.
So sánh s1 với s3.
"s1 = " << s1 << "\ns2 = " << s2
"\ns3 = " << s3 << "\n\nstrcmp(s1, s2) = "
setw( 2 ) << strcmp( s1, s2 )
So sánh s3 với s1.
"\nstrcmp(s1, s3) = " << setw( 2 )
strcmp( s1, s3 ) << "\nstrcmp(s3, s1) = "
setw( 2 ) << strcmp( s3, s1 );
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
72
So sánh 6 ký tự đầu tiên của
s1 với s3.
26
27
28
29
30
31
cout <<
<<
<<
<<
<<
32
33
return 0;
34
35
"\n\nstrncmp(s1, s3, 6) = " << setw( 2 )
strncmp( s1, s3, 6 ) << "\nstrncmp(s1, s3, 7) = "
setw( 2 ) << strncmp( s1, s3, 7 )
"\nstrncmp(s3, s1, 7) = "
setw( 2 ) << strncmp( s3, s1, 7 ) << endl;
fig05_30.cpp
(2 of 2)
fig05_30.cpp
So sánh 7 kýoutput
tự đầu (1 of 1)
// indicates successful termination
} // end main
tiên của s1 với s3.
So sánh 7 ký tự đầu tiên của
s3 với s1.
s1 = Happy New Year
s2 = Happy New Year
s3 = Happy Holidays
strcmp(s1, s2) = 0
strcmp(s1, s3) = 1
strcmp(s3, s1) = -1
strncmp(s1, s3, 6) = 0
strncmp(s1, s3, 7) = 1
strncmp(s3, s1, 7) = -1
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
73
5.12.2 Các hàm xử lý xâu ký tự
• Phân tích từ tố - Tokenizing
– Chia xâu thành các từ tố, phân tách bởi các ký tự ngăn cách
(delimiting character)
– Các từ tố thường là các đơn vị logic (logical units), chẳng
hạn các từ (tách nhau bởi các dấu trống)
– "This is my string" có 4 từ tố (tách nhau bởi các
dấu trống)
– char *strtok( char *s1, const char *s2 )
• Cần gọi nhiều lần
– Lần gọi đầu cần 2 tham số, xâu cần phân tích từ tố và xâu
chứa các ký tự ngăn cách
• Tìm ký tự ngăn cách tiếp theo và thay bằng ký tự null
– Những lời gọi tiếp theo tiếp tục phân tích từ tố trên xâu đó
• Gọi hàm với tham số thứ nhất là NULL
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
74
// Fig. 5.31: fig05_31.cpp
// Using strtok.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
#include <cstring>
9
10
11
12
13
int main()
{
char sentence[] = "This is a sentence with 7 tokens";
char *tokenPtr;
14
15
16
17
18
19
fig05_31.cpp
(1 of 2)
<cstring> chứa prototype
cho strtok.
// prototype for strtok
cout << "The string to be tokenized is:\n" << sentence
<< "\n\nThe tokens are:\n\n";
Lời gọi strtok đầu tiên
khởi đầu việc phân tích từ tố.
// begin tokenization of sentence
tokenPtr = strtok( sentence, " " );
20
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
21
22
23
24
// continue tokenizing sentence until tokenPtr becomes NULL
while ( tokenPtr != NULL ) {
cout << tokenPtr << '\n';
tokenPtr = strtok( NULL, " " ); // get next token
25
26
} // end while
27
28
cout << "\nAfter strtok, sentence = " << sentence << endl;
29
30
return 0;
31
32
75
fig05_31.cpp
(2 of 2)
// indicates successful termination
Các lời gọi strtok tiếp sau với
NULL là tham số đầu để tiếp tục việc
phân tích từ tố trên xâu sentence.
} // end main
The string to be tokenized is:
This is a sentence with 7 tokens
The tokens are:
This
is
a
sentence
with
7
tokens
After strtok, sentence = This
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
76
5.12.2 Các hàm xử lý xâu ký tự
• Xác định độ dài xâu
– size_t strlen( const char *s )
• Trả về số ký tự của xâu
– Không tính đến ký tự null
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 5.
https://fb.com/tailieudientucntt
1
2
3
77
// Fig. 5.32: fig05_32.cpp
// Using strlen.
#include <iostream>
4
5
6
using std::cout;
using std::endl;
7
8
#include <cstring>
9
10
11
12
13
14
int main()
{
char *string1 = "abcdefghijklmnopqrstuvwxyz";
char *string2 = "four";
char *string3 = "Boston";
15
16
17
18
19
20
21
cout <<
<<
<<
<<
<<
<<
22
23
return 0;
24
25
fig05_32.cpp
(1 of 1)
<cstring> chứa prototype
cho strlen.
// prototype for strlen
"The length of \"" << string1
"\" is " << strlen( string1 )
"\nThe length of \"" << string2
"\" is " << strlen( string2 )
"\nThe length of \"" << string3
"\" is " << strlen( string3 ) << endl;
Sử dụng strlen để xác định
độ dài xâu.
// indicates successful
The termination
length of "abcdefghijklmnopqrstuvwxyz" is 26
The length of "four" is 4
The length of "Boston" is 6
} // end main
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
1
Ngôn ngữ lập trình C++
Chương 6 – Cấu trúc dữ liệu trừu tượng
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
2
Chương 6: Cấu trúc dữ liệu trừu tượng
Đề mục
6.1
6.2
6.3
6.4
6.5
6.6
6.7
6.8
6.9
6.10
6.11
6.12
6.13
6.14
6.15
Giới thiệu
Cấu trúc - struct
Truy nhập các thành viên của struct
Cài đặt kiểu dữ liệu người dùng Time bằng struct
Cài đặt một kiểu dữ liệu trừu tượng Time bằng một lớp - class
Phạm vi lớp và truy nhập các thành viên của lớp
Tách giao diện ra khỏi cài đặt
Quản lý quyền truy nhập thành viên
Các hàm truy nhập và các hàm tiện ích
Khởi tạo các đối tượng: Constructor
Sử dụng các đối số mặc định cho Constructor
Destructor - hàm hủy
Khi nào Constructor và Destructor được gọi
Sử dụng các hàm Set và Get
Phép gán đối tượng mặc định
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
3
Tài liệu đọc thêm
• Day 6. TY21 (lập trình cơ bản)
• Chap 4,5. Introduction to OOP Using C++ (IOOP)
(khái niệm hướng đối tượng)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
4
6.1 Giới thiệu
• các kiểu dữ liệu phức hợp cấu tạo từ các thành
phần thuộc các kiểu dữ liệu khác
– tạo kiểu dữ liệu mới - kiểu dữ liệu người dùng tự định
nghĩa (user-defined data type)
• bản ghi
– gồm nhiều trường, mỗi trường lưu trữ một thành viên
dữ liệu thuộc một kiểu dữ liệu cài sẵn hoặc một kiểu dữ
liệu người dùng khác.
• ví dụ
– Thời gian(giờ, phút, giây)
– Họ tên (họ, đệm, tên)
17:10:02, 04:23:12,...
(Nguyễn, Văn, An), (Lê, Thị, Bình),...
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
5
6.1 Giới thiệu
• C++:
– struct và class - kiểu bản ghi
– đối tượng (một thể hiện của một kiểu struct hay class
nào đó) - bản ghi
– thành viên dữ liệu - trường
– hàm thành viên/phương thức - thao tác trên các thành
viên dữ liệu
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
6
6.2 Cấu trúc - struct
• struct definition
struct Time {
int hour;
int minute;
int second;
};
Structure tag
Structure members
• quy tắc đặt tên cho các thành viên của cấu trúc
– trong cùng struct: không thể trùng tên
– trong các struct khác nhau: có thể trùng tên
• định nghĩa struct phải kết thúc bằng dấu chấm phảy.
– Các biến kiểu cấu trúc được khai báo như các biến thuộc các
loại khác
– Ví dụ: khai báo biến đơn, mảng, con trỏ, tham chiếu...
•
•
•
•
Time
Time
Time
Time
timeObject;
timeArray[ 10 ];
*timePtr;
&timeRef = timeObject;
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
7
6.2 Cấu trúc - struct
• Self-referential structure - cấu trúc đệ quy
– thành viên của một cấu trúc không thể thuộc kiểu cấu trúc đó
– thành viên của một cấu trúc có thể là con trỏ đến kiểu cấu trúc đó
(self-referential structure - cấu trúc đệ quy)
• sử dụng cho danh sách liên kết (linked list), hàng đợi (queue),
ngăn xếp (stack), và cây (tree)
struct Node {
int data;
Node* next;
};
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
8
6.3 Truy nhập các thành viên của struct
• các toán tử truy nhập thành viên (member access
operator)
– Toán tử dấu chấm (.) truy nhập trực tiếp đến các thành viên
của cấu trúc/lớp
– Toán tử mũi tên (->) truy nhập các thành viên qua con trỏ
đến đối tượng
– Ví dụ: in thành viên hour của đối tượng timeObject:
cout << timeObject.hour;
hoặc
timePtr = &timeObject;
cout << timePtr->hour;
– timePtr->hour tương đương ( *timePtr ).hour
• Cần có cặp ngoặc do * không được ưu tiên bằng .
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
1
2
3
fig06_01.cpp
(1 of 3)
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
9
10
11
using std::setfill;
using std::setw;
12
13
14
15
16
17
18
19
20
21
22
23
9
// Fig. 6.1: fig06_01.cpp
// Create a structure, set its members, and print it.
#include <iostream>
Định nghĩa kiểu cấu trúc Time
với 3 thành viên là số nguyên.
// structure definition
struct Time {
int hour;
// 0-23 (24-hour clock format)
int minute;
// 0-59
int second;
// 0-59
Truyền tham chiếu tới hằng Time
để tránh sao chép tham số.
}; // end struct Time
void printUniversal( const Time & );
void printStandard( const Time & );
// prototype
// prototype
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
24
25
26
int main()
{
Time dinnerTime;
10
dụng
ký hiệu
dấu chấm để
// variable ofSử
new
type
Time
khởi tạo các thành viên cấu trúc.fig06_01.cpp
(2 of 3)
// set hour member of dinnerTime
27
28
29
30
dinnerTime.hour = 18;
dinnerTime.minute = 30;
dinnerTime.second = 0;
31
32
33
34
35
36
cout << "Dinner will be held at ";
printUniversal( dinnerTime );
cout << " universal time,\nwhich is ";
printStandard( dinnerTime );
cout << " standard time.\n";
37
38
39
40
41
42
43
44
45
46
47
48
dinnerTime.hour = 29;
dinnerTime.minute = 73;
// set minute member of dinnerTime
// set second member of dinnerTime
Quyền truy nhập trực tiếp tới dữ liệu
cho phép gán các giá trị không hợp lệ.
// set hour to invalid value
// set minute to invalid value
cout << "\nTime with invalid values: ";
printUniversal( dinnerTime );
cout << endl;
return 0;
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
49
50
51
52
53
54
// print time in universal-time format
void printUniversal( const Time &t )
{
cout << setfill( '0' ) << setw( 2 ) << t.hour << ":"
<< setw( 2 ) << t.minute << ":"
<< setw( 2 ) << t.second;
11
fig06_01.cpp
(3 of 3)
fig06_01.cpp
Sử dụng manipulator
setfill.
output (1
of 1)
55
56
} // end function printUniversal
57
58
59
60
61
62
63
64
65
// print time in standard-time format
Dùng dấu chấm để truy nhập
void printStandard( const Time &t )
các thành viên dữ liệu.
{
cout << ( ( t.hour == 0 || t.hour == 12 ) ?
12 : t.hour % 12 ) << ":" << setfill( '0' )
<< setw( 2 ) << t.minute << ":"
<< setw( 2 ) << t.second
<< ( t.hour < 12 ? " AM" : " PM" );
66
67
} // end function printStandard
Dinner will be held at 18:30:00 universal time,
which is 6:30:00 PM standard time.
Time with invalid values: 29:73:00
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
6.4 Cài đặt kiểu dữ liệu người dùng Time
bằng struct
12
• Truyền tham số:
– Mặc định struct được truyền bằng giá trị
– Nên truyền struct bằng tham chiếu để tránh được
việc phải sao chép cấu trúc
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
13
6.4 Cài đặt kiểu dữ liệu người dùng Time
bằng struct
• struct kiểu C
– không có giao diện giữa bên trong và bên ngoài cấu trúc
• Nếu cài đặt thay đổi, mọi chương trình sử dụng struct đó phải
được sửa đổi theo
– không thể in ra như là một biến đơn
• Phải in/định dạng cho từng thành viên
– không thể so sánh hai struct theo kiểu thông thường
• Phải so sánh từng thành viên
• struct kiểu C++
– C++ mở rộng: struct có chức năng như class
– thông lệ: struct chỉ được dùng cho các cấu trúc chỉ gồm dữ liệu;
class dùng cho các lớp có cả dữ liệu và hàm thành viên.
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
6.5 Cài đặt một kiểu dữ liệu trừu tượng Time
bằng một lớp - class
14
• Các lớp - Classes
– mô hình các đối tượng
• Thuộc tính - Attributes (data members)
• Hành vi - Behaviors (member functions)
– từ khoá class
– các hàm thành viên – member functions
• còn được gọi là các phương thức - method
• được gọi để trả lời các thông điệp
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
Class definition bắt đầu bằng
từ khoá class.
15
Class body bắt đầu bằng
ngoặc mở.
Class Time
definition
(1 of 1)
Function prototype
cho các public
member function.
1
class Time {
2
3
4
5
6
7
public:
Time();
// constructor
void setTime( int, int, int ); // set hour, minute, second
void printUniversal();
// print universal-time format
void printStandard();
// print standard-time format
8
9
10
11
12
private:
int hour;
int minute;
int second;
13
14
}; // end class Time
Constructor: thành viên trùng tên
với tên class, Time, và không có
giá trị trả về.
Nhãn quyền truy nhập
// 0 - 23 (24-hour clock format)
// 0 - 59
// 0 - 59
Class body kết
thúc bằng ngoặc
đóng.
CuuDuongThanCong.com
private data member chỉ
có thể được truy nhập từ các
member function.
Definition kết thúc bằng dấu
chấm phảy.
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
6.5 Cài đặt một kiểu dữ liệu trừu tượng Time
bằng một lớp - class
• Nhãn quyền truy nhập – Member access specifiers
16
– quy định quyền truy nhập các thành viên của lớp từ các đoạn
trình bên ngoài định nghĩa lớp
– public:
• thành viên có thể được truy nhập từ trong toàn bộ phạm vi của đối
tượng
– private:
• thành viên chỉ có thể được truy nhập từ các hàm thành viên của
chính lớp đó
– protected:
• dùng cho quan hệ thừa kế
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
6.5 Cài đặt một kiểu dữ liệu trừu tượng Time
bằng một lớp - class
• Constructor – phương thức khởi tạo
17
– hàm thành viên đặc biệt
• khởi tạo các thành viên dữ liệu
• trùng tên với tên lớp
– được gọi khi đối tượng được tạo, ví dụ khi biến được khai báo
– có thể có vài constructor
• hoạt động theo nguyên tắc hàm gọi chồng
– không có giá trị trả về và không có kiểu giá trị trả về
class Time {
public:
Time();
…
};
…
Time::Time()
{
hour = minute = second = 0;
} // end Time constructor
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
6.5 Cài đặt một kiểu dữ liệu trừu tượng Time
bằng một lớp - class
• Destructor – phương thức hủy
18
– trùng tên với tên lớp
• bắt đầu bằng dấu (~)
– không có tham số
– tối đa 1 destructor, không thể bị gọi chồng
– dành cho việc dọn dẹp, chẳng hạn bộ nhớ
class Time {
public:
Time();
~Time();
…
};
…
Time::~Time()
{
//empty
} // end Time destructor
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
6.5 Cài đặt một kiểu dữ liệu trừu tượng Time
bằng một lớp - class
19
• các đối tượng của một lớp
– Kể từ sau class definition
• tên lớp trở thành tên kiểu mới - type specifier
– C++ là ngôn ngữ mở rộng được
• có thể khai báo đối tượng, mảng đối tượng, con trỏ và tham chiếu
tới đối tượng
– Ví dụ:
Tên lớp trở thành tên kiểu dữ liệu mới.
Time
Time
Time
Time
sunset;
arrayOfTimes[ 5 ];
*pointerToTime;
&dinnerTime = sunset;
//
//
//
//
object of type Time
array of Time objects
pointer to a Time object
reference to a Time object
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
6.5 Cài đặt một kiểu dữ liệu trừu tượng Time
bằng một lớp - class
20
• Các hàm thành viên được định nghĩa bên ngoài
lớp
– toán tử phạm vi (::)
• gắn tên thành viên với tên lớp
• xác định duy nhất các hàm của một lớp nào đó
• các lớp khác nhau có thể có các hàm thành viên trùng tên
– Công thức định nghĩa hàm thành viên
ReturnType ClassName::MemberFunctionName( )
{
…
}
– như nhau đối với hàm public hay private
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
6.5 Cài đặt một kiểu dữ liệu trừu tượng Time
bằng một lớp - class
21
• Các hàm thành viên được định nghĩa bên trong lớp
– Không cần toán tử phạm vi (::) và tên lớp
– Trình biên dịch sẽ chuyển thành hàm inline nếu
có thể
• Bên ngoài lớp, các hàm inline cần từ khoá inline
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
1
2
3
fig06_03.cpp
(1 of 5)
4
5
6
using std::cout;
using std::endl;
7
8
#include <iomanip>
9
10
11
using std::setfill;
using std::setw;
12
13
14
15
16
17
18
19
20
21
22
// Fig. 6.3: fig06_03.cpp
// Time class.
#include <iostream>
// Time abstract data type (ADT) definition
class Time {
Định nghĩa lớp Time.
public:
Time();
// constructor
void setTime( int, int, int ); // set hour, minute, second
void printUniversal();
// print universal-time format
void printStandard();
// print standard-time format
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
private:
int hour;
int minute;
int second;
23
// 0 - 23 (24-hour clock format)
// 0 - 59
// 0 - 59
fig06_03.cpp
(2 of 5)
}; // end class Time
// Time constructor initializes each data member to zero and
// ensures all Time objects start in a consistent state
Time::Time()
Constructor khởi tạo các thành
{
viên dữ liệu private về 0.
hour = minute = second = 0;
} // end Time constructor
// set new Time value using universal time, perform validity
// checks on the data values and set invalid values to zero
void Time::setTime( int h, int m, int s )
{
hour = ( h >= 0 && h < 24 ) ? h : 0;
minute = ( m >= 0 && m < 60 ) ? m : 0;
second = ( s >= 0 && s < 60 ) ? s : 0;
Hàm thành viên
public kiểm tra tính
hợp lệ của giá trị các
đối số trước khi gán
trị cho các thành viên
dữ liệu private
} // end function setTime
46
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
24
47
48
49
50
51
52
// print Time in universal format
void Time::printUniversal()
{
cout << setfill( '0' ) << setw( 2 ) << hour << ":"
<< setw( 2 ) << minute << ":"
<< setw( 2 ) << second;
53
54
} // end function printUniversal
55
56
57
58
59
60
61
62
// print Time in standard format
void Time::printStandard()
{
cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 )
<< ":" << setfill( '0' ) << setw( 2 ) << minute
<< ":" << setw( 2 ) << second
<< ( hour < 12 ? " AM" : " PM" );
63
64
} // end function printStandard
65
66
67
68
int main()
{
Time t;
fig06_03.cpp
(3 of 5)
Không có tham số (ngầm hiểu mục
đích là in các thành viên dữ liệu);
lời gọi hàm thành viên ngắn gọn hơn
lời gọi hàm thường.
Khai báo biến t là đối tượng
thuộc lớp Time.
// instantiate object t of class Time
69
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
70
71
72
// output Time object t's initial values
cout << "The initial universal time is ";
t.printUniversal();
// 00:00:00
73
74
75
fig06_03.cpp
(4 of 5) để in
cout << "\nThe initial standard time is "; Gọi các hàm thành viên public
thời gian.
t.printStandard();
// 12:00:00 AM
76
77
t.setTime( 13, 27, 6 );
78
79
80
81
// output Time object t's new values
cout << "\n\nUniversal time after setTime is ";
Thử gán các giá trị không hợp lệ cho các thành viên
t.printUniversal();
// 13:27:06
// change time
Dùng hàm thành viên public để gán
trị cho các thành viên dữ liệu.
dữ liệu bằng cách sử dụng hàm thành viên public
82
83
84
cout << "\nStandard time after setTime is ";
t.printStandard();
// 1:27:06 PM
85
86
t.setTime( 99, 99, 99 );
87
88
89
90
91
// output t's values after specifying invalid values
cout << "\n\nAfter attempting invalid settings:"
<< "\nUniversal time: ";
t.printUniversal();
// 00:00:00
// attempt invalid settings
92
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
93
94
95
96
97
98
99
26
cout << "\nStandard time: ";
t.printStandard();
// 12:00:00 AM
cout << endl;
fig06_03.cpp
(5 of 5)
return 0;
fig06_03.cpp
output (1 of 1)
} // end main
The initial universal time is 00:00:00
The initial standard time is 12:00:00 AM
Universal time after setTime is 13:27:06
Standard time after setTime is 1:27:06 PM
After attempting invalid settings:
Universal time: 00:00:00
Standard time: 12:00:00 AM
Các thành viên dữ liệu được
gán về 0 sau khi thử các giá
trị không hợp lệ.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
6.5 Cài đặt một kiểu dữ liệu trừu tượng Time
bằng một lớp - class
27
• lợi ích khi dùng lớp
– đơn giản hóa việc lập trình
– các giao diện – Interfaces
• che dấu phần cài đặt – Hide implementation
– tái sử dụng phần mềm – Software reuse
• khả năng tích hợp – Composition (aggregation)
– các thành viên của một lớp có thể là đối tượng thuộc lớp
khác
• thừa kế - Inheritance
– các lớp mới được tạo từ lớp cũ
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
28
6.6 Phạm vi lớp và
truy nhập các thành viên của lớp
• phạm vi lớp – Class scope
– gồm thành viên dữ liệu và hàm thành viên của lớp
– bên trong phạm vi lớp
• Các thành viên của lớp
– có thể được truy nhập thẳng từ mọi hàm thành viên
– gọi bằng tên
– bên ngoài phạm vi lớp
• được gọi đến bằng tên đối tượng, tham chiếu/con trỏ tới đối
tượng
– objectTime.printStandard()
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
29
6.6 Phạm vi lớp và
truy nhập các thành viên của lớp
• Phạm vi file - File scope
– áp dụng cho các hàm không phải thành viên
• Phạm vi hàm – Function scope
–
–
–
–
Gồm các biến được khai báo trong hàm thành viên
chỉ được biết đến trong hàm đó
bị hủy khi hàm kết thúc
các biến trùng tên với biến thuộc phạm vi lớp
• biến thuộc phạm vi lớp (class-scope variable) bị che (“hidden”)
– truy nhập bằng toán tử phạm vi (::)
ClassName::classVariableName
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
30
6.6 Phạm vi lớp và
truy nhập các thành viên của lớp
• Các toán tử để truy nhập các thành viên của đối
tượng
– giống các toán tử dành cho struct
– toán tử (.) dùng cho
• đối tượng
• tham chiếu đến đối tượng
– toán tử (->) dùng cho
• các con trỏ tới đối tượng
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
1
2
3
4
5
// Fig. 6.4: fig06_04.cpp
// Demonstrating the class member access operators . and ->
//
// CAUTION: IN FUTURE EXAMPLES WE AVOID PUBLIC DATA!
#include <iostream>
6
7
8
using std::cout;
using std::endl;
9
10
11
// class Count definition
class Count {
12
13
14
public:
int x;
15
16
17
18
19
20
21
31
fig06_04.cpp
(1 of 2)
Thành viên dữ liệu public x
minh họa các toán tử truy nhập;
thông thường các thành viên dữ liệu
đều là private.
void print()
{
cout << x << endl;
}
}; // end class Count
22
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
23
24
25
26
27
int main()
{
Count counter;
Count *counterPtr = &counter;
Count &counterRef = counter;
32
// create counter object
Sử dụng
dấupointer
chấm cho to
đối counter
tượng
//
create
counter.
//
create reference to counter
fig06_04.cpp
(2 of 2)
28
29
30
31
fig06_04.cpp
cout << "Assign 1 to x and print using the object's name: ";
output (1 of 1)
counter.x = 1;
// assign 1 to data member x
Sử dụng dấu chấm cho counterRef là
counter.print();
// call member function print
32
33
34
35
cout << "Assign 2 to x and print using a reference: ";
counterRef.x = 2;
// assignSử2 dụng
to data
member
x
mũi tên
cho counterPtr
counterRef.print(); // call member
print
là con trỏfunction
tới đối tượng.
36
37
38
39
cout << "Assign 3 to x and print using a pointer: ";
counterPtr->x = 3;
// assign 3 to data member x
counterPtr->print(); // call member function print
40
41
return 0;
42
43
tham chiếu đến đối tượng.
} // end main
Assign 1 to x and print using the object's name: 1
Assign 2 to x and print using a reference: 2
Assign 3 to x and print using a pointer: 3
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
33
6.7 Tách giao diện ra khỏi cài đặt
• Tách giao diện khỏi cài đặt
– ích lợi
• dễ sửa đổi chương trình
– bất lợi
• phải tạo các file header gồm
– một phần của cài đặt
• Inline member functions – các hàm inline
– gợi ý về phần khác của cài đặt
• private members
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
34
6.7 Tách giao diện ra khỏi cài đặt
• Các file header
– chứa các định nghĩa lớp và các nguyên mẫu hàm
– được include trong mỗi file sử dụng lớp đó
• #include
– mở rộng của file .h
• Các file mã nguồn – Source-code files
– chứa định nghĩa của các hàm thành viên
– trùng tên file với file header tương ứng (không kể phần mở
rộng)
• đây chỉ là thông lệ, không bắt buộc
– được biên dịch và liên kết với file chương trình chính
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
1
2
3
35
Mã tiền xử lý để tránh việc file bị
// Fig. 6.5: time1.h
// Declaration of class Time. include nhiều lần.
// Member functions are defined in time1.cpp
time1.h (1 of 1)
“If not defined”
4
5
6
7
// prevent multiple inclusions of header file
#ifndef TIME1_H
#define TIME1_H
8
9
10
// Time abstract data type definition
include nến tên TIME1_H đã được định nghĩa.
class Time {
11
12
13
14
15
16
public:
Time();
// constructor
void setTime( int, int, int ); // set hour, minute, second
void printUniversal();
// print universal-time format
void printStandard();
// print standard-time format
17
18
19
20
21
private:
int hour;
int minute;
int second;
22
23
}; // end class Time
24
25
#endif
Mã giữa hai định hướng này không được
Định hướng tiền xử lý định nghĩa tên
TIME1_H.
// 0 - 23 (24-hour clock format)
// 0 - 59
// 0 - 59
Thông lệ đặt tên: tên header file với dấu gạch
dưới thay cho dấu chấm.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
36
// Fig. 6.6: time1.cpp
// Member-function definitions for class Time.
#include <iostream>
time1.cpp (1 of 3)
4
5
using std::cout;
6
7
#include <iomanip>
8
9
10
using std::setfill;
using std::setw;
11
12
13
// include definition of class Time from time1.h
#include "time1.h"
14
15
16
17
18
19
// Time constructor initializes each data member to zero.
// Ensures all Time objects start in a consistent state.
Time::Time()
Tên của header file đặt trong ngoặc kép;
{
cặp ngoặc nhọn làm trình biên dịch cho
hour = minute = second = 0;
20
21
} // end Time constructor
Include header file
time1.h.
rằng đó là một phần của thư viện chuẩn
C++ (C++ Standard Library).
22
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
23
24
25
26
27
28
29
// Set new Time value using universal time. Perform validity
// checks on the data values. Set invalid values to zero.
void Time::setTime( int h, int m, int s )
{
hour = ( h >= 0 && h < 24 ) ? h : 0;
minute = ( m >= 0 && m < 60 ) ? m : 0;
second = ( s >= 0 && s < 60 ) ? s : 0;
30
31
} // end function setTime
32
33
34
35
36
37
38
// print Time in universal format
void Time::printUniversal()
{
cout << setfill( '0' ) << setw( 2 ) << hour << ":"
<< setw( 2 ) << minute << ":"
<< setw( 2 ) << second;
39
40
} // end function printUniversal
37
time1.cpp (2 of 3)
41
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
42
43
44
45
46
47
48
// print Time in standard format
void Time::printStandard()
{
cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 )
<< ":" << setfill( '0' ) << setw( 2 ) << minute
<< ":" << setw( 2 ) << second
<< ( hour < 12 ? " AM" : " PM" );
49
50
} // end function printStandard
38
time1.cpp (3 of 3)
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
4
// Fig. 6.7: fig06_07.cpp
// Program to test class Time.
// NOTE: This file must be compiled with time1.cpp.
#include <iostream>
5
6
7
using std::cout;
using std::endl;
8
9
10
11
12
13
14
39
fig06_07.cpp
(1 of 2)
Include time1.h để đảm bảo tạo đúng và để
tính kích thước đối tượng thuộc lớp Time.
// include definition of class Time from time1.h
#include "time1.h"
int main()
{
Time t;
// instantiate object t of class Time
15
16
17
18
19
20
// output Time object t's initial values
cout << "The initial universal time is ";
t.printUniversal();
// 00:00:00
cout << "\nThe initial standard time is ";
t.printStandard();
// 12:00:00 AM
21
22
t.setTime( 13, 27, 6 );
// change time
23
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
24
25
26
27
28
// output Time object t's new values
cout << "\n\nUniversal time after setTime is ";
t.printUniversal();
// 13:27:06
cout << "\nStandard time after setTime is ";
t.printStandard();
// 1:27:06 PM
29
30
t.setTime( 99, 99, 99 );
31
32
33
34
35
36
37
38
// output t's values after specifying invalid values
cout << "\n\nAfter attempting invalid settings:"
<< "\nUniversal time: ";
t.printUniversal();
// 00:00:00
cout << "\nStandard time: ";
t.printStandard();
// 12:00:00 AM
cout << endl;
39
40
return 0;
41
42
40
fig06_07.cpp
(2 of 2)
fig06_07.cpp
output (1 of 1)
// attempt invalid settings
The initial universal time is 00:00:00
The initial standard time is 12:00:00 AM
} // end main
Universal time after setTime is 13:27:06
Standard time after setTime is 1:27:06 PM
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
41
6.8 Quản lý quyền truy nhập thành viên
• các kiểu truy nhập – Access
– private
• kiểu mặc định - Default access mode
• chỉ có các hàm thành viên và các hàm friend là có thể truy
nhập các thành viên private
– public
• truy nhập được từ mọi hàm trong chương trình.
– protected
• dành cho quan hệ thừa kế, hiện tại chưa nói đến
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
1
2
3
4
// Fig. 6.8: fig06_08.cpp
// Demonstrate errors resulting from attempts
// to access private class members.
#include <iostream>
5
6
using std::cout;
7
8
9
// include definition of class Time from time1.h
#include "time1.h"
10
11
12
13
int main()
{
Time t;
// create Time object
fig06_08.cpp
(1 of 1)
hour là thành viên private;
truy nhập các thành viên private sẽ gây lỗi.
14
15
16
t.hour = 7;
17
18
19
// error: 'Time::minute' is not accessible
cout << "minute = " << t.minute;
20
21
return 0;
22
23
42
// error: 'Time::hour' is not accessible
minute cũng là private;
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
43
6.8 Quản lý quyền truy nhập thành viên
• quyền truy nhập các thành viên của class
– mặc định private
– phải đặt tường minh public, protected
• quyền truy nhập các thành viên của struct
– mặc định public
– phải đặt tường minh private, protected
• truy nhập dữ liệu private của lớp
– các hàm truy nhập (accessor method)
• Get function – hàm đọc dữ liệu
– đọc dữ liệu private
• Set function – hàm ghi dữ liệu
– ghi dữ liệu private
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
44
6.9 Các hàm truy nhập và các hàm tiện ích
• Các hàm truy nhập – Access functions
– public
– các hàm đọc và hiển thị dữ liệu
– các hàm ghi dữ liệu (kèm kiểm tra tính hợp lệ)
– các hàm mệnh đề – Predicate functions
• kiểm tra các điều kiện
• Các hàm tiện ích – Utility functions
– private
– chỉ hỗ trợ hoạt động của các hàm thành viên kiểu public
– không nhằm mục đích để cho client trực tiếp sử dụng
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
1
2
3
4
5
// Fig. 6.9: salesp.h
// SalesPerson class definition.
// Member functions defined in salesp.cpp.
#ifndef SALESP_H
#define SALESP_H
6
7
class SalesPerson {
8
9
10
11
12
13
14
15
16
17
public:
SalesPerson();
//
void getSalesFromUser();
//
void setSales( int, double ); //
void printAnnualSales();
//
private:
double totalAnnualSales();
double sales[ 12 ];
18
19
}; // end class SalesPerson
20
21
#endif
45
salesp.h (1 of 1)
hàm ghi dữ liệu thực hiện việc
kiểm tra tính hợp lệ của dữ liệu
(validity checks).
constructor
input sales from keyboard
set sales for a month
summarize and print sales
hàm tiện ích private
// utility function
// 12 monthly sales figures
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
46
// Fig. 6.10: salesp.cpp
// Member functions for class SalesPerson.
#include <iostream>
salesp.cpp (1 of 3)
4
5
6
7
8
using
using
using
using
9
10
#include <iomanip>
11
12
using std::setprecision;
13
14
15
// include SalesPerson class definition from salesp.h
#include "salesp.h"
16
17
18
19
20
21
// initialize elements of array sales to 0.0
SalesPerson::SalesPerson()
{
for ( int i = 0; i < 12; i++ )
sales[ i ] = 0.0;
22
23
} // end SalesPerson constructor
std::cout;
std::cin;
std::endl;
std::fixed;
24
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
26
27
28
47
// get 12 sales figures from the user at the keyboard
void SalesPerson::getSalesFromUser()
{
double salesFigure;
salesp.cpp (2 of 3)
29
30
31
32
33
for ( int i = 1; i <= 12; i++ ) {
cout << "Enter sales amount for month " << i << ": ";
cin >> salesFigure;
setSales( i, salesFigure );
34
35
} // end for
hàm ghi dữ liệu thực hiện
việc kiểm tra tính hợp lệ của
dữ liệu (validity checks).
36
37
} // end function getSalesFromUser
38
39
40
41
42
43
44
45
// set one of the 12 monthly sales figures; function subtracts
// one from month value for proper subscript in sales array
void SalesPerson::setSales( int month, double amount )
{
// test for valid month and amount values
if ( month >= 1 && month <= 12 && amount > 0 )
sales[ month - 1 ] = amount; // adjust for subscripts 0-11
46
47
48
else // invalid month or amount value
cout << "Invalid month or sales figure" << endl;
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
48
49
50
} // end function setSales
51
52
53
54
55
56
57
// print total annual sales (with help of utility function)
void SalesPerson::printAnnualSales()
{
cout << setprecision( 2 ) << fixed
<< "\nThe total annual sales are: $"
<< totalAnnualSales() << endl; // call utility function
58
59
} // end function printAnnualSales
salesp.cpp (3 of 3)
Hàm tiện ích private
phục vụ hàm printAnnualSales;
60
61 // private utility function to total annual sales đóng gói thao tác trên mảng sales.
62
63
64
65
66
67
68
69
70
71
double SalesPerson::totalAnnualSales()
{
double total = 0.0;
// initialize total
for ( int i = 0; i < 12; i++ )
total += sales[ i ];
// summarize sales results
return total;
} // end function totalAnnualSales
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
49
// Fig. 6.11: fig06_11.cpp
// Demonstrating a utility function.
// Compile this program with salesp.cpp
fig06_11.cpp
(1 of 1)
// include SalesPerson class definition from salesp.h
#include "salesp.h"
int main()
{
SalesPerson s;
s.getSalesFromUser();
s.printAnnualSales();
Chuỗi gọi hàm đơn giản;
logic chương trình được đóng gói trong các
hàm thành viên.
// create SalesPerson object s
// note simple sequential code; no
// control structures in main
return 0;
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Enter
Enter
sales
sales
sales
sales
sales
sales
sales
sales
sales
sales
sales
sales
amount
amount
amount
amount
amount
amount
amount
amount
amount
amount
amount
amount
for
for
for
for
for
for
for
for
for
for
for
for
month
month
month
month
month
month
month
month
month
month
month
month
1: 5314.76
2: 4292.38
3: 4589.83
4: 5534.03
5: 4376.34
6: 5698.45
7: 4439.22
8: 5893.57
9: 4909.67
10: 5123.45
11: 4024.97
12: 5923.92
50
fig06_11.cpp
output (1 of 1)
The total annual sales are: $60120.59
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
51
6.10 Khởi tạo các đối tượng: Constructor
• Constructors
– khởi tạo các thành viên dữ liệu
• hoặc có thể gán trị cho các thành viên dữ liệu sau
– trùng tên với tên lớp
– không có kiểu trả về
• Các giá trị khởi tạo – Initializers
– được truyền dưới dạng đối số
cho constructor
– khi khai báo biến: đặt trong cặp
ngoặc đơn trước dấu chấm phảy
class Time {
public:
Time( int, int, int);
...
}; // end class Time
...
int main()
{
Time t( 27, 74, 99 );
...
Class-type ObjectName( value1,value2,…);
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
52
6.11 Sử dụng các đối số mặc định với
constructor
• có thể chỉ định các đối số mặc định
– tương tự đối số mặc định của hàm thông thường
• constructor mặc định:
– có thể gọi không cần tham số
• Time t;
– Tất cả các đối số là mặc định HOẶC thực sự không nhận tham
số
• Time(int = 0, int = 0, int = 0);
hoặc
• Time();
– mỗi lớp chỉ được có tối đa một constructor mặc định
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
1
2
3
53
// Fig. 6.12: time2.h
// Declaration of class Time.
// Member functions defined in time2.cpp.
time2.h (1 of 1)
4
5
6
7
// prevent multiple inclusions of header file
#ifndef TIME2_H
#define TIME2_H
8
9
10
// Time abstract data type definition
class Time {
11
12
13
14
15
16
public:
Time( int = 0, int = 0, int = 0); // default constructor
void setTime( int, int, int ); // set hour, minute, second
void printUniversal();
// print universal-time format
void printStandard();
// print standard-time format
17
18
19
20
21
private:
int hour;
int minute;
int second;
22
23
}; // end class Time
24
25
#endif
Default constructor chỉ định giá
trị mặc định cho mọi đối số.
// 0 - 23 (24-hour clock format)
// 0 - 59
// 0 - 59
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
time2.cpp (1 of 2)
4
5
using std::cout;
6
7
#include <iomanip>
8
9
10
using std::setfill;
using std::setw;
11
12
13
// include definition of class Time from time2.h
#include "time2.h"
14
15
16
17
18
19
20
21
54
// Fig. 6.13: time2.cpp
// Member-function definitions for class Time.
#include <iostream>
// Time constructor initializes each data member to zero;
// ensures all Time objects start in a consistent state
Constructor gọi setTime để kiểm tra các
Time::Time( int hr, int min, int sec )
giá trị được truyền vào (hoặc mặc định).
{
setTime( hr, min, sec ); // validate and set time
} // end Time constructor
22
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
23
24
25
26
27
28
29
// set new Time value using universal time, perform validity
// checks on the data values and set invalid values to zero
void Time::setTime( int h, int m, int s )
{
hour = ( h >= 0 && h < 24 ) ? h : 0;
minute = ( m >= 0 && m < 60 ) ? m : 0;
second = ( s >= 0 && s < 60 ) ? s : 0;
30
31
} // end function setTime
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
55
time2.cpp (2 of 2)
// print Time in universal format
void Time::printUniversal()
{
cout << setfill( '0' ) << setw( 2 ) << hour << ":"
<< setw( 2 ) << minute << ":"
<< setw( 2 ) << second;
} // end function printUniversal
// print Time in standard format
void Time::printStandard()
{
cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 )
<< ":" << setfill( '0' ) << setw( 2 ) << minute
<< ":" << setw( 2 ) << second
<< ( hour < 12 ? " AM" : " PM" );
} // end function printStandard
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
1
2
3
fig06_14.cpp
(1 of 2)
4
5
6
using std::cout;
using std::endl;
7
8
9
// include definition of class Time from time2.h
#include "time2.h"
10
11
12
13
14
15
16
17
int main()
{
Time t1;
Time t2(
Time t3(
Time t4(
Time t5(
18
19
20
21
22
23
56
// Fig. 6.14: fig06_14.cpp
// Demonstrating a default constructor for class Time.
#include <iostream>
Khởi tạo các đối tượng Time sử
dụng các tham số mặc định.
//
2 );
//
21, 34 );
//
12, 25, 42 ); //
27, 74, 99 ); //
all arguments defaulted
minute and second defaulted
second defaulted
all values specified
all bad values specified
cout << "Constructed with:\n\n"
<< "all default arguments:\n ";
t1.printUniversal(); // 00:00:00
cout << "\n ";
t1.printStandard();
// 12:00:00 AM
Khởi tạo đối tượng Time với
các giá trị không hợp lệ;
khâu kiểm tra tính hợp lệ sẽ
gán các giá trị về 0.
24
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
26
27
28
cout << "\n\nhour specified; default minute and second:\n
t2.printUniversal(); // 02:00:00
cout << "\n ";
t2.printStandard();
// 2:00:00 AM
";
29
30
31
32
33
cout << "\n\nhour and minute specified; default second:\n
t3.printUniversal(); // 21:34:00
cout << "\n ";
t3.printStandard();
// 9:34:00 PM
";
34
35
36
37
38
cout << "\n\nhour, minute, and second specified:\n
t4.printUniversal(); // 12:25:42
cout << "\n ";
t4.printStandard();
// 12:25:42 PM
39
40
41
42
43
44
cout << "\n\nall invalid values specified:\n
t5.printUniversal(); // 00:00:00
cout << "\n ";
t5.printStandard();
// 12:00:00 AM
cout << endl;
45
46
return 0;
47
48
57
fig06_14.cpp
(2 of 2)
";
"; t5 được xây dựng bằng các
đối số không hợp lệ, các giá
trị được gán về 0.
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
58
6.12 Destructor – hàm hủy
• Destructor – hàm thành viên tự hủy của đối tượng
– hàm thành viên đặc biệt
– trùng tên với tên lớp
• bắt đầu bằng dấu ngã (~)
–
–
–
–
không nhận đối số
không có giá trị trả về
không thể bị gọi chồng
thực hiện việc dọn dẹp
• trước khi hệ thống lấy lại phần bộ nhớ của đối tượng
– tái sử dụng cho đối tượng mới
– nếu không có destructor được định nghĩa tường minh
• trình biên dịch tự tạo destructor "rỗng" – không làm gì hết
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
59
6.13 Khi nào Constructor và Destructor
được gọi
• các constructor và destructor
– được gọi ngầm bởi trình biên dịch
• thứ tự gọi hàm
– phụ thuộc vào thứ tự thực thi chương trình
• khi chương trình vào và ra khỏi phạm vi của các đối tượng
– các đối tượng cũng là các biến thông thường,
• biến được khởi tạo – constructor được gọi – tại thời điểm bắt
đầu tồn tại / phạm vi
• biến bị hủy – destructor được gọi – khi kết thúc sự tồn tại / ra
khỏi phạm vi
– thông thường, các lời gọi destructor theo thứ tự ngược lại với
thứ tự gọi các constructor
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
60
6.13 Khi nào Constructor và Destructor
được gọi
• Thứ tự các lời gọi constructor, destructor
– đối với các đối tượng/biến phạm vi toàn cục (global
scope objects)
• Constructor
– được gọi trước mọi hàm khác (kể cả main)
• Destructor
– được gọi khi main kết thúc (hoặc khi hàm exit được
gọi)
– không được gọi nếu chương trình kết thúc bằng hàm
abort
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
61
6.13 Khi nào Constructor và Destructor
được gọi
• Thứ tự các lời gọi constructor, destructor
– đối với các đối tượng/biến địa phương (automatic local
objects)
• Constructor
– được gọi khi đối tượng được định nghĩa
• mỗi khi chương trình vào phạm vi của đối tượng
• Destructor
– được gọi khi đối tượng ra khỏi phạm vi
• chương trình ra khỏi khối nơi đối tượng được định
nghĩa
– không được gọi nếu chương trình kết thúc bằng exit hay
abort
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
62
6.13 Khi nào Constructor và Destructor
được gọi
• Thứ tự các lời gọi constructor, destructor
– các đối tượng tĩnh địa phương (static local objects)
• Constructor
– đúng một lần
– khi chương trình chạy đến chỗ đối tượng được định nghĩa
• Destructor
– khi hàm main kết thúc hoặc khi hàm exit được gọi
– không được gọi nếu chương trình kết thúc bằng hàm
abort
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
1
2
3
4
5
// Fig. 6.15: create.h
// Definition of class CreateAndDestroy.
// Member functions defined in create.cpp.
#ifndef CREATE_H
#define CREATE_H
6
7
class CreateAndDestroy {
8
9
10
11
public:
CreateAndDestroy( int, char * );
~CreateAndDestroy();
12
13
14
15
private:
int objectID;
char *message;
16
17
}; // end class CreateAndDestroy
18
19
#endif
63
create.h (1 of 1)
Các hàm thành viên
constructor và destructor
// constructor
// destructor
Các thành viên private
để minh họa thứ tự các lời gọi
constructor và destructor
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
64
// Fig. 6.16: create.cpp
// Member-function definitions for class CreateAndDestroy
#include <iostream>
create.cpp (1 of 2)
4
5
6
using std::cout;
using std::endl;
7
8
9
// include CreateAndDestroy class definition from create.h
#include "create.h"
10
11
12
13
14
15
16
17
18
19
20
21
// constructor
CreateAndDestroy::CreateAndDestroy(
int objectNumber, char *messagePtr )
{
objectID = objectNumber;
message = messagePtr;
cout << "Object " << objectID << "
<< message << endl;
Output message để thể hiện
thời gian của các lời gọi hàm
constructor.
constructor runs
"
} // end CreateAndDestroy constructor
22
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
23
24
25
26
27
28
29
30
31
32
65
Output message để thể hiện thời gian
// destructor
của các lời gọi hàm destructor
CreateAndDestroy::~CreateAndDestroy()
{
create.cpp (2 of 2)
// the following line is for pedagogic purposes only
cout << ( objectID == 1 || objectID == 6 ? "\n" : "" );
cout << "Object " << objectID << "
<< message << endl;
destructor runs
"
} // end ~CreateAndDestroy destructor
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
66
1
2
3
4
// Fig. 6.17: fig06_17.cpp
// Demonstrating the order in which constructors and
// destructors are called.
#include <iostream>
5
6
7
using std::cout;
using std::endl;
8
9
10
// include CreateAndDestroy class definition from create.h
#include "create.h"
11
12
void create( void );
13
14
15
// global object
CreateAndDestroy first( 1, "(global before main)" );
16
17
18
19
int main()
Tạo đối tượng tự động địa phương.
{
cout << "\nMAIN FUNCTION: EXECUTION BEGINS" << endl;
20
21
22
23
24
25
fig06_17.cpp
(1 of 2)
tạo đối tượng có phạm vi toàn cục
// prototype
Tạo đối tượng địa phương static.
CreateAndDestroy second( 2, "(local automatic in main)" );
static CreateAndDestroy third( 3, "(local static in main)" );
Tạo các đối tượng tự động địa phương.
create();
// call function to create objects
26
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
28
29
30
31
32
33
34
67
cout << "\nMAIN FUNCTION: EXECUTION RESUMES" << endl;
CreateAndDestroy fourth( 4, "(local automatic in main)" );
fig06_17.cpp
(2 of 2)
cout << "\nMAIN FUNCTION: EXECUTION ENDS" << endl;
Tạo đối tượng tự động địa phương.
return 0;
35
36
} // end main
37
38
39
40
41
// function to create objects
void create( void )
Tạo đối tượng tự động địa phương bên trong hàm.
{
cout << "\nCREATE FUNCTION: EXECUTION BEGINS" << endl;
Tạo đối tượng địa phương static bên trong hàm.
42
43
CreateAndDestroy fifth( 5, "(local automatic in create)" );
44
45
46
static CreateAndDestroy sixth(
6, "(local static in create)" );
47
48
49
CreateAndDestroy seventh(
7, "(local automatic in create)" );
50
51
cout << "\nCREATE FUNCTION: EXECUTION ENDS\" << endl;
52
53
} // end function create
CuuDuongThanCong.com
Tạo đối tượng tự động địa
phương bên trong hàm.
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
Object 1
constructor runs
MAIN FUNCTION: EXECUTION BEGINS
Object 2
constructor runs
(local automatic in main)
Object 3
constructor runs
(local static in main)
CREATE
Object
Object
Object
FUNCTION: EXECUTION BEGINS
5
constructor runs
(local automatic in create)
6
constructor runs
(local static in create)
7
constructor runs
(local automatic in create)
CREATE FUNCTION: EXECUTION ENDS
Object 7
destructor runs
(local automatic in create)
Object 5
destructor runs
(local automatic in create)
MAIN FUNCTION: EXECUTION RESUMES
Object 4
constructor runs
(local automatic in main)
MAIN FUNCTION: EXECUTION ENDS
Object 4
destructor runs
Object 2
destructor runs
Object 6
destructor runs
Object 3
destructor runs
(local
(local
(local
(local
Object 1
(global before main)
destructor runs
68
(global before main)
automatic
automatic
static in
static in
fig06_17.cpp
output (1 of 1)
đối
static
địađối
các tượng
destructor
cho các
đối tượng
toàn
cụcphương
được
tạo
phương
tại địa
cho
đến khi
tượng
tựtồn
động
trước
khi
main
bắt
đầu
các đối
tượng
tự động
địavà bị
chương
trình
kết
thúc
trong
hàm
main
được
đối tượng
static
địa gọi
phương
bị
hủy
sauvới
khicác
hàm
hủy
cuối
cùng.
theo
thứđược
tự
ngược
phương
tạo
tại
lời
gọivới
kết
thúc
theo
thứ
tự
ngược
constructor.
hàm
thứ tựđầu
tạo.tiên và hủy sau khi
hàm main kết thúc.
in main)
in main)
create)
main)
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
69
6.14 Sử dụng các hàm truy nhập
• Set functions – các hàm ghi
– kiểm tra tính hợp lệ trước khi sửa đổi dữ liệu private
– thông báo nếu các giá trị là không hợp lệ
– thông báo qua các giá trị trả về
• Get functions – các hàm đọc
– các hàm truy vấn – “Query” functions
– quản lý định dạng của dữ liệu trả về
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
1
2
3
70
// Fig. 6.18: time3.h
// Declaration of class Time.
// Member functions defined in time3.cpp
time3.h (1 of 2)
4
5
6
7
// prevent multiple inclusions of header file
#ifndef TIME3_H
#define TIME3_H
8
9
class Time {
10
11
12
public:
Time( int = 0, int = 0, int = 0 );
// default constructor
13
14
15
16
17
18
Các hàm ghi
// set functions
void setTime( int, int, int ); // set hour, minute, second
void setHour( int );
// set hour
void setMinute( int ); // set minute
void setSecond( int ); // set second
19
20
21
22
23
// get functions
int getHour();
int getMinute();
int getSecond();
các hàm đọc
// return hour
// return minute
// return second
24
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
26
71
void printUniversal(); // output universal-time format
void printStandard(); // output standard-time format
27
28
29
30
31
private:
int hour;
int minute;
int second;
32
33
}; // end clas Time
34
35
#endif
time3.h (2 of 2)
// 0 - 23 (24-hour clock format)
// 0 - 59
// 0 - 59
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
72
// Fig. 6.19: time3.cpp
// Member-function definitions for Time class.
#include <iostream>
time3.cpp (1 of 4)
4
5
using std::cout;
6
7
#include <iomanip>
8
9
10
using std::setfill;
using std::setw;
11
12
13
// include definition of class Time from time3.h
#include "time3.h"
14
15
16
17
18
19
20
// constructor function to initialize private data;
// calls member function setTime to set variables;
// default values are 0 (see class definition)
Time::Time( int hr, int min, int sec )
{
setTime( hr, min, sec );
21
22
} // end Time constructor
23
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
73
// set hour, minute and second values
void Time::setTime( int h, int m, int s )
{
setHour( h );
setMinute( m );
setSecond( s );
} // end function setTime
time3.cpp (2 of 4)
Gọi các hàm set dể kiểm tra
tính hợp lệ.
// set hour value
void Time::setHour( int h )
{
hour = ( h >= 0 && h < 24 ) ? h : 0;
} // end function setHour
Các hàm set kiểm tra tính hợp
lệ trước khi sửa đổi dữ liệu.
// set minute value
void Time::setMinute( int m )
{
minute = ( m >= 0 && m < 60 ) ? m : 0;
} // end function setMinute
46
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
74
Các hàm set kiểm tra tính hợp
// set second value
lệ trước khi sửa đổi dữ liệu.
void Time::setSecond( int s )
{
second = ( s >= 0 && s < 60 ) ? s : 0;
time3.cpp (3 of 4)
} // end function setSecond
// return hour value
int Time::getHour()
{
return hour;
} // end function getHour
Các hàm get cho client đọc dữ
liệu
// return minute value
int Time::getMinute()
{
return minute;
} // end function getMinute
67
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
68
69
70
71
72
73
75
// return second value
int Time::getSecond()
{
return second;
time3.cpp (4 of 4)
Hàm get cho client đọc dữ liệu
} // end function getSecond
74
75
76
77
78
79
80
// print Time in universal format
void Time::printUniversal()
{
cout << setfill( '0' ) << setw( 2 ) << hour << ":"
<< setw( 2 ) << minute << ":"
<< setw( 2 ) << second;
81
82
} // end function printUniversal
83
84
85
86
87
88
89
90
// print Time in standard format
void Time::printStandard()
{
cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 )
<< ":" << setfill( '0' ) << setw( 2 ) << minute
<< ":" << setw( 2 ) << second
<< ( hour < 12 ? " AM" : " PM" );
91
92
} // end function printStandard
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
1
2
3
fig06_20.cpp
(1 of 3)
4
5
6
using std::cout;
using std::endl;
7
8
9
// include definition of class Time from time3.h
#include "time3.h"
10
11
void incrementMinutes( Time &, const int );
12
13
14
15
int main()
{
Time t;
16
17
18
19
20
76
// Fig. 6.20: fig06_20.cpp
// Demonstrating the Time class set and get functions
#include <iostream>
// prototype
// create Time object
Gọi các hàm set để gán các
giá trị hợp lệ.
// set time using individual set functions
t.setHour( 17 );
// set hour to valid value
t.setMinute( 34 );
// set minute to valid value
t.setSecond( 25 );
// set second to valid value
21
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
22
23
24
25
26
27
28
29
30
31
// use get functions to obtain hour, minute and second
cout << "Result of setting all valid values:\n"
<< " Hour: " << t.getHour()
fig06_20.cpp
<< " Minute: " << t.getMinute()
(2 of 3)
<< " Second: " << t.getSecond();
Cố dùng các hàm set để gán
các giá trị không hợp lệ.
// set time using individual set functions
t.setHour( 234 );
// invalid hour set to 0
t.setMinute( 43 );
// set minute to valid value
t.setSecond( 6373 ); // invalid second set to 0
các giá trị không hợp lệ làm
các data member bị gán về 0.
32
33
34
35
36
37
38
// display hour, minute and second after setting
// invalid hour and second values
cout << "\n\nResult of attempting to set invalid hour and"
<< " second:\n Hour: " << t.getHour()
Sửa đổi data member bằng
<< " Minute: " << t.getMinute()
<< " Second: " << t.getSecond() << "\n\n"; hàm setTime.
39
40
41
t.setTime( 11, 58, 0 );
incrementMinutes( t, 3 );
42
43
return 0;
44
45
// set time
// increment t's minute by 3
} // end main
46
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
77
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// add specified number of minutes to a Time object
void incrementMinutes( Time &tt, const int count )
{
fig06_20.cpp
cout << "Incrementing minute " << count
(3 of 3)
<< " times:\nStart time: ";
tt.printStandard();
Dùng các hàm get để đọc và
for ( int i = 0; i < count; i++ ) {
tt.setMinute( ( tt.getMinute() + 1 ) % 60 );
các hàm set để sửa dữ liệu.
if ( tt.getMinute() == 0 )
tt.setHour( ( tt.getHour() + 1 ) % 24);
62
63
cout << "\nminute + 1: ";
tt.printStandard();
Result of setting all valid values:
Hour: 17 Minute: 34 Second: 25
} // end for
64
65
cout << endl;
66
67
78
Result of attempting to set invalid hour and second:
Hour: 0 Minute: 43 Second: 0
} // end function incrementMinutes
Incrementing minute 3 times:
Start time: 11:58:00 AM
minute + 1: 11:59:00 AM
minute + 1: 12:00:00 PM
minute + 1: 12:01:00 PM
CuuDuongThanCong.com
Cố gắng gán các giá trị không
hợp lệ cho các thành viên dữ
liệu, kết©2004
quả là
thông
báo lỗi
Trần
Minh Châu.
và các thành
viên
bị gán về 0.
FOTECH.
VNU.
https://fb.com/tailieudientucntt
79
6.15 Phép gán mặc định
• Gán đối tượng cho đối tượng
– Phép gán (=)
• có thể gán một đối tượng cho một đối tượng khác thuộc cùng kiểu
• Mặc định: gán theo từng thành viên (memberwise assignment)
– Mỗi thành viên của đối tượng vế phải được gán cho thành viên
tương ứng tại vế trái
• được ngầm thực hiện khi
– truyền tham số là đối tượng
– trả về đối tượng
• Đối tượng có thể được truyền làm tham số cho hàm
– Đối tượng có thể được hàm trả về
– Mặc định: pass-by-value
• Bản sao của đối tượng được truyền, trả về
– sử dụng 'copy constructor'
• sao chép các giá trị gốc vào đối tượng mới
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 6.
https://fb.com/tailieudientucntt
80
1
2
3
4
// Fig. 6.24: fig06_24.cpp
// Demonstrating that class objects can be assigned
// to each other using default memberwise assignment.
#include <iostream>
5
6
7
using std::cout;
using std::endl;
8
9
10
// class Date definition
class Date {
11
12
13
14
public:
Date( int = 1, int = 1, int = 1990 ); // default constructor
void print();
15
16
17
18
19
private:
int month;
int day;
int year;
20
21
22
fig06_24.cpp
(1 of 3)
}; // end class Date
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
23
24
25
26
27
28
// Date constructor with no range checking
Date::Date( int m, int d, int y )
{
month = m;
day = d;
year = y;
29
30
} // end Date constructor
31
32
33
34
35
// print Date in the format mm-dd-yyyy
void Date::print()
{
cout << month << '-' << day << '-' << year;
36
37
} // end function print
38
39
40
41
42
int main()
{
Date date1( 7, 4, 2002 );
Date date2; // date2 defaults to 1/1/1990
81
fig06_24.cpp
(2 of 3)
43
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
44
45
46
47
cout << "date1 = ";
date1.print();
cout << "\ndate2 = ";
date2.print();
48
49
date2 = date1;
82
phép gán mặc định gán từng
thành viên của date1 cho
thành viên tương ứng của
date2.
fig06_24.cpp
(3 of 3)
// default memberwise assignment
50
51
52
53
cout << "\n\nAfter default memberwise assignment, date2 = ";
date2.print();
cout << endl;
54
55
return 0;
56
57
fig06_24.cpp
output (1 of 1)
} // end main
date1 = 7-4-2002
date2 = 1-1-1990
After default memberwise assignment, date2 = 7-4-2002
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
Ngôn ngữ lập trình C++
Chương 7 – Ra vào dữ liệu
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
2
Chương 7 : Ra vào dữ liệu
Đề mục
7.1
Giới thiệu
7.2
Dòng – Stream
7.2.2
Các file header thư viện iostream
7.2.3
Các đối tượng và các lớp I/O
7.3
Xuất theo dòng
7.3.1
Xuất các biến kiểu char*.
7.4
Nhập theo dòng
7.4.1
Các thành viên get và getline
7.4.2
Các thành viên peek, putback, và ignore
7.5
I/O không định dạng sử dụng read, write, và gcount
7.6
Giới thiệu về các stream manipulator
7.7
Các trạng thái lỗi của dòng
7.8
Đồng bộ một dòng ra và một dòng vào
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
3
Chương 7 : Ra vào dữ liệu
Đề mục (tiếp)
7.9
File và dòng (stream)
7.10
File truy nhập tuần tự
7.11
Các hàm định vị cho file truy nhập tuần tự
7.12
Các rắc rối khi cập nhật file truy nhập tuần tự
7.13
File truy nhập ngẫu nhiên
7.13.1
Dữ liệu thô và dữ liệu định dạng
7.13.2
Ghi file truy nhập ngẫu nhiên
7.13.3
Ghi dữ liệu vào vị trí tùy ý trong file truy nhập ngẫu nhiên
7.13.4
Đọc tuần tự dữ liệu từ file truy nhập ngẫu nhiên
7.14
Ví dụ: Chương trình quản lý giao dịch
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
4
7.1
Giới thiệu
• C++ I/O
– Hướng đối tượng
• sử dụng tham chiếu, chồng hàm, chồng toán tử
– An toàn về các kiểu dữ liệu
• nhạy cảm với kiểu dữ liệu
• báo lỗi nếu kiểu không khớp
– có thể dùng cho cả kiểu người dùng tự định nghĩa và các
kiểu chuẩn
• làm cho C++ có khả năng mở rộng
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
5
7.2
Dòng - Stream
• Stream – dòng:
–
–
–
–
chuỗi byte, kết thúc bởi ký hiệu end_of_file
Input: từ bàn phím, đĩa... vào bộ nhớ
Output: từ bộ nhớ ra màn hình, máy in...
file cũng được coi là một dòng
• Các dòng cổ điển
– vào/ra char (1 byte)
– các ký tự giới hạn bảng mã ASCII
• Các thư viện dòng chuẩn
– Một số ngôn ngữ cần các bảng chữ cái đặc biệt
– Unicode
• kiểu ký tự wchar_t
– Có thể thực hiện I/O với các ký tự Unicode
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
6
7.2.2 Các file header thư viện iostream
• thư viện iostream
– có các header file với hàng trăm chức năng vào/ra
– <iostream.h>
•
•
•
•
vào chuẩn – Standard input (cin)
ra chuẩn – Standard output (cout)
dòng báo lỗi không có bộ nhớ đệm – Unbuffered error (cerr)
dòng báo lỗi có dùng bộ nhớ đệm – Buffered error (clog)
– <iomanip.h>
• các stream manipulator (có tham số) để định dạng I/O
– <fstream.h>
• các thao tác xử lý file
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
7
7.2.3 Các đối tượng và các lớp I/O
• << và >>
– các toán tử chèn và tách dòng
• cin
– đối tượng istream
– nối với input chuẩn (thường là bàn phím)
– cin >> grade;
• trình biên dịch tự xác định kiểu của grade
• gọi toán tử thích hợp (đã được định nghĩa chồng)
• không cần thông tin thêm về kiểu dữ liệu
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
8
7.2.3 Các đối tượng và các lớp I/O
• cout
– đối tượng ostream
– nối với output chuẩn (thường là màn hình)
– cin << grade;
• cũng như với cin, không cần thêm thông tin về kiểu
• cerr, clog
– các đối tượng ostream
– nối với thiết bị báo lỗi chuẩn
– cerr xuất ngay lập tức
– clog sử dụng bộ nhớ đệm trước khi xuất
• xuất khi bộ nhớ đệm đầy hoặc khi được xả (flushed)
• ưu điểm hiệu năng (giải thích tại môn Hệ điều hành)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
9
7.2.3 Các đối tượng và các lớp I/O
• C++ xử lý file tương tự
– Các kiểu đối tượng dành cho xuất nhập char
• ifstream (file input)
• ofstream (file output)
• fstream (file I/O)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
10
7.2.3 Các đối tượng và các lớp I/O
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
11
7.3
Xuất theo dòng
• Output
– sử dụng ostream
– định dạng và không định dạng dữ liệu xuất
– dành cho các kiểu dữ liệu chuẩn (<<)
• các ký tự (hàm put)
• các kiểu số nguyên (thập phân, bát phân, cơ số 16)
• các số chấm động
– quy định độ chính xác, vị trí dấu chấm, ký hiệu khoa học
– dữ liệu được căn lề, chèn ký tự trống
– điều khiển chữ hoa/chữ thường
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
12
7.3.1 Xuất các biến kiểu char *
• C++ tự động xác định kiểu dữ liệu
– in giá trị của một char *
• địa chỉ bộ nhớ của ký tự đầu tiên
• Rắc rối
– toán tử << được định nghĩa chồng để in xâu kết thúc bằng
null
– cách giải quyết: đổi thành void *
• sử dụng khi in giá trị của một con trỏ
• in dưới dạng một số cơ số 16
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
2
3
4
5
6
7
8
9
10
13
// Fig. 12.3: fig12_03.cpp
// Printing the address stored in a char * variable.
#include <iostream>
fig12_03.cpp
(1 of 1)
using std::cout;
using std::endl;
int main()
{
char *word = "test";
fig12_03.cpp
output (1 of 1)
Để in giá trị của con trỏ, ta
phải đổi sang kiểu void *.
Nếu không, chương trình sẽ
in xâu ký tự.
11
12
13
14
15
16
// display value of char *, then display value of char *
// static_cast to void *
cout << "Value of word is: " << word << endl
<< "Value of static_cast< void * >( word ) is: "
<< static_cast< void * >( word ) << endl;
17
18
return 0;
19
20
} // end main
Value of word is: test
Value of static_cast< void *>( word ) is: 0046C070
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
14
7.3.2 Xuất ký tự bằng hàm thành viên put
• hàm put
– in các ký tự
• cout.put( 'A' );
– Có thể gọi liền
• cout.put( 'A' ).put( '\n' );
• Toán tử dấu chấm (.) được tính từ trái sang phải
– Có thể sử dụng giá trị bằng số (mã ASCII)
• cout.put( 65 );
• in ký tự 'A'
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
15
7.4
Nhập theo dòng
• dữ liệu vào có định dạng và không định dạng
– istream
• toán tử >>
– Thường bỏ qua các ký tự trắng (blank, tab, newline)
• Có thể thay đổi
– Trả về 0 khi gặp EOF
• nếu không, trả về tham chiếu tới istream
• cin >> grade
– các bit trạng thái được bật nếu xảy ra lỗi
• chi tiết sẽ nói đến sau
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
16
7.4.1 Các hàm thành viên get và getline
• hàm get
– cin.get()
– trả về một ký tự từ dòng (kể cả ký tự trắng)
• trả về EOF nếu gặp end-of-file
• End-of-file
– đánh dấu kết thúc dữ liệu vào
• ctrl-z tại DOS/Windows
• ctrl-d tại UNIX và Mac
– cin.eof()
• trả về 1 (true) nếu đã gặp EOF
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
2
3
17
// Fig. 12.4: fig12_04.cpp
// Using member functions get, put and eof.
#include <iostream>
fig12_04.cpp
(1 of 2)
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
10
11
int main()
{
int character; // use int, because char cannot represent EOF
12
13
14
15
// prompt user to enter line of text
cout << "Before input, cin.eof() is " << cin.eof() << endl
<< "Enter a sentence followed by end-of-file:" << endl;
16
17
18
19
// use get to read each character; use put to display it
while ( ( character = cin.get() ) != EOF )
cout.put( character );
20
21
22
23
// display end-of-file character
cout << "\nEOF in this system is: " << character << endl;
cout << "After input, cin.eof() is " << cin.eof() << endl;
24
25
return 0;
Hàm get (không có đối số) trả
về đúng một ký tự nhập vào,
trừ khi gặp EOF.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
18
} // end main
Before input, cin.eof() is 0
Enter a sentence followed by end-of-file:
Testing the get and put member functions
Testing the get and put member functions
^Z
fig12_04.cpp
(2 of 2)
fig12_04.cpp
output (1 of 1)
EOF in this system is: -1
After input cin.eof() is 1
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
19
7.4.1 Các hàm thành viên get và getline
• get(charRef)
– đối số là tham chiếu ký tự
– đọc một ký tự, lưu vào charRef
• trả về tham chiếu tới istream
• nếu hết file, trả về -1
• get(charArray, size, delimiter)
– đọc cho đến khi được size-1 ký tự, hoặc đến khi gặp ký tự
phân cách
• phân cách mặc định '\n'
• ký tự phân cách được để lại dòng nhập
– có thể loại bỏ bằng cin.get() hoặc cin.ignore()
– tự động thêm null vào cuối để kết thúc mảng
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
2
3
fig12_05.cpp
(1 of 2)
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
10
11
12
13
14
int main()
{
// create two char arrays, each with 80 elements
const int SIZE = 80;
char buffer1[ SIZE ];
cin sẽ chỉ đọc cho đến ký tự
char buffer2[ SIZE ];
trắng đầu tiên.
15
16
17
18
19
20
21
22
23
24
25
20
// Fig. 12.5: fig12_05.cpp
// Contrasting input of a string via cin and cin.get.
#include <iostream>
// use cin to input characters into buffer1
cout << "Enter a sentence:" << endl;
cin >> buffer1;
Không chỉ ra ký tự phân cách, do đó
sẽ sử dụng phân cách mặc định (\n).
// display buffer1 contents
cout << "\nThe string read with cin was:" << endl
<< buffer1 << endl << endl;
// use cin.get to input characters into buffer2
cin.get( buffer2, SIZE );
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
21
26
27
28
29
// display buffer2 contents
cout << "The string read with cin.get was:" << endl
<< buffer2 << endl;
30
31
return 0;
32
33
fig12_05.cpp
(2 of 2)
fig12_05.cpp
output (1 of 1)
} // end main
Enter a sentence:
Contrasting string input with cin and cin.get
The string read with cin was:
Contrasting
The string read with cin.get was:
string input with cin and cin.get
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
22
7.4.1 Các hàm thành viên get và getline
• getline(array, size, delimiter)
– như phiên bản 3 tham số của get
– đọc size-1 ký tự, hoặc cho đến khi thấy ký tự phân cách
• mặc định \n
– loại bỏ ký tự phân cách khỏi dòng vào
– đặt ký tự null vào cuối mảng
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
2
3
23
// Fig. 12.6: fig12_06.cpp
// Inputting characters using cin member function getline.
#include <iostream>
fig12_06.cpp
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
10
11
12
int main()
{
const int SIZE = 80;
char buffer[ SIZE ]; // create array of 80 characters
Enter a sentence:
(1 of 1)
Using the getline member function
The sentence entered is:
Using the getline member function
13
14
15
16
// input characters in buffer via cin function getline
cout << "Enter a sentence:" << endl;
cin.getline( buffer, SIZE );
17
18
19
// display buffer contents
cout << "\nThe sentence entered is:" << endl << buffer << endl;
20
21
return 0;
22
23
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
24
7.4.2 Các hàm thành viên
peek, putback và ignore của istream
• ignore()
– lấy các ký tự khỏi dòng (mặc định là 1 ký tự)
– dừng khi gặp ký tự phân cách
• phân cách mặc định là EOF
• putback()
– đẩy ký tự vừa đọc được bằng get() trở lại dòng
• peek()
– trả về ký tự tiếp theo trong dòng nhưng không lấy ra khỏi
dòng
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
7.5
I/O không định dạng sử dụng
read, write và gcount
25
• I/O không định dạng
– read (hàm thành viên của istream)
• đọc các byte thô vào mảng char
• nếu đọc được không đủ số ký tự, đặt failbit
• gcount() trả về số ký tự đã đọc được tại lần gọi gần nhất
– write (hàm thành viên của ostream)
• xuất các byte từ mảng char
– dừng khi gặp ký tự null
char buffer[] = "HAPPY BIRTHDAY";
cout.write( buffer, 10 );
– xuất 10 char đầu tiên
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
2
3
fig12_07.cpp
(1 of 1)
4
5
6
7
using std::cout;
using std::cin;
using std::endl;
8
9
10
11
12
int main()
{
const int SIZE = 80;
char buffer[ SIZE ]; // create array of 80 characters
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Fig. 12.7: fig12_07.cpp
// Unformatted I/O using read, gcount and write.
#include <iostream>
đọc 20 ký tự từ dòng vào.
Hiển
thị sốbuffer
ký tự đọc được,
// use function read to input characters
into
cout << "Enter a sentence:" << endl; sử dụng write và gcount.
cin.read( buffer, 20 );
// use functions write and gcount to display buffer characters
cout << endl << "The sentence entered was:" << endl;
cout.write( buffer, cin.gcount() );
cout << endl;
Enter a sentence:
Using the read, write, and gcount member functions
return 0;
The sentence entered was:
Using the read, writ
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
27
7.6
Giới thiệu về các Stream Manipulator
• Stream manipulator thực hiện việc định dạng
–
–
–
–
–
–
–
–
–
đổi hệ cơ số (hex, oct, dec, setbase)
độ rộng (ký tự) in ra dành cho dữ liệu xuất (setw)
đặt số chữ số sau dấu phảy (setprecision)
in/không in phần sau dấu phảy của số nguyên
(showpoint/noshowpoint)
căn trái/phải/giữa (left/right/internal)
ký tự chèn vào các vị trí còn trống (setfill)
định dạng khoa học/dấu chấm động (scientific/fixed)
in các giá trị bool dạng chữ(true,false)/số
(boolalpha/noboolalpha)
...
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
28
7.7
Các trạng thái lỗi của dòng
• Kiểm tra trạng thái dòng bằng qua các bit trạng
thái
– eofbit được bật khi gặp EOF
• hàm eof trả về true nếu eofbit được bật
• cin.eof()
– failbit được bật khi dòng xảy ra lỗi
• dữ liệu không mất, lỗi có thể khôi phục được
• hàm fail trả về true nếu bit được bật
– badbit được bật khi mất dữ liệu
• thường là không khôi phục được
• hàm bad
– goodbit bật khi badbit, failbit và eofbit tắt
• hàm good
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
29
7.7
Các trạng thái lỗi của dòng
• Các hàm thành viên
– rdstate()
• trả về trạng thái lỗi của dòng
• có thể dùng để kiểm tra goodbit, badbit, v.v...
• sử dụng good(), bad() thì hơn
– clear()
• đối số mặc định là goodbit
• đặt dòng trở về trạng thái tốt để có thể tiếp tục I/O
• có thể truyền các giá trị khác
– cin.clear( ios::failbit )
– bật failbit
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
2
3
fig12_22.cpp
(1 of 2)
4
5
6
7
using std::cout;
using std::endl;
using std::cin;
8
9
10
11
int main()
{
int integerValue;
12
13
14
15
16
17
18
19
20
21
22
23
24
30
// Fig. 12.22: fig12_22.cpp
// Testing error states.
#include <iostream>
in trạng thái ban đầu, sử dụng
các hàm thành viên
// display results of cin functions
cout << "Before a bad input operation:"
<< "\ncin.rdstate(): " << cin.rdstate()
<< "\n
cin.eof(): " << cin.eof()
<< "\n
cin.fail(): " << cin.fail()
<< "\n
cin.bad(): " << cin.bad()
<< "\n
cin.good(): " << cin.good()
<< "\n\nExpects an integer, but enter a character: ";
cin >> integerValue; // enter character value
cout << endl;
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
26
27
28
29
30
31
// display results of cin functions after bad input
cout << "After a bad input operation:"
<< "\ncin.rdstate(): " << cin.rdstate()
<< "\n
cin.eof(): " << cin.eof()
<< "\n
cin.fail(): " << cin.fail()
<< "\n
cin.bad(): " << cin.bad()
<< "\n
cin.good(): " << cin.good() << endl << endl;
fig12_22.cpp
(2 of 2)
Gọi hàm clear.
32
33
cin.clear(); // clear stream
34
35
36
37
38
// display results of cin functions after clearing cin
cout << "After cin.clear()"
<< "\ncin.fail(): " << cin.fail()
<< "\ncin.good(): " << cin.good() << endl;
39
40
return 0;
41
42
31
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
Before a bad input operation:
cin.rdstate(): 0
cin.eof(): 0
cin.fail(): 0
cin.bad(): 0
cin.good(): 1
32
fig12_22.cpp
output (1 of 1)
Expects an integer, but enter a character: A
After a bad input operation:
cin.rdstate(): 2
cin.eof(): 0
cin.fail(): 1
cin.bad(): 0
cin.good(): 0
After cin.clear()
cin.fail(): 0
cin.good(): 1
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
33
7.8
Đồng bộ một dòng ra và một dòng vào
• Rắc rối với output có bộ nhớ đệm
– chương trình tương tác (hỏi người sử dụng, người sử dụng
trả lời)
– lời yêu cầu cần hiện ra trước khi nhập
• output trong bộ nhớ đệm chỉ hiện ra khi bộ nhớ đệm đầy hoặc
được xả (flushed)
• hàm thành viên tie
– đồng bộ hóa các dòng
– Output hiện ra trước các input tiếp theo
– được thực hiện tự động với cin và cout, nhưng có thể viết
• cin.tie( &cout )
– cần thực hiện tường minh đối với các cặp I/O khác
– để bỏ đồng bộ
• inputStream.tie( 0 )
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
34
7.9
File và dòng
• Lưu trữ dữ liệu
– Mảng, biến là dạng lưu trữ tạm thời
– File là dạng lưu trữ bền vững
• đĩa từ - magnetic disk, đĩa quang - optical disk, băng từ - tape
• trong chương này
– tạo, cập nhật, xử lý file
– truy nhập tuần tự (sequential access) và truy nhập ngẫu
nhiên (random access)
– xử lý có định dạng và xử lý thô (formatted and raw
processing)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
35
7.9 File và dòng
• Từ nhỏ nhất tới lớn nhất
– Bit (binary digit)
– Byte: 8 bits
• Có thể lưu trữ 1 ký tự (char)
• còn dùng để lưu Unicode dành cho bộ ký tự lớn hơn (wchar_t)
– Trường - Field: nhóm ký tự có nghĩa
• tên
– Bản ghi - Record: nhóm các trường có liên quan
•
•
•
•
struct hoặc class trong C++
trong hệ thống trả lương (payroll system): tên, mã, địa chỉ, lương
mỗi trường liên quan đến cùng một nhân viên.
Khóa của bản ghi - Record key: trường dùng để xác định duy nhất bản
ghi
– File: nhóm các bản ghi có liên quan
• danh sách lương cho cả công ty
– Cơ sở dữ liệu - Database: nhóm các file có liên quan
• danh sách lương, các tài khoản, …
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
36
7.9
File và dòng
• C++ coi file là một chuỗi byte - stream
– Kết thúc bằng ký hiệu end-of-file
0
1
2
3
4
5
6
7
8
9
...
...
n-1
end-of-file marker
• Khi file mở
– một đối tượng được tạo và kết nối với một dòng
– tạo "đường liên lạc" từ đối tượng tới file
– cin, cout, v.v... được tạo khi <iostream> được include
• liên lạc giữa chương trình và file/thiết bị
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
37
7.10 File truy nhập tuần tự
(sequential-access file)
• C++ không quy định cấu trúc file
– Khái niệm "bản ghi" phải được cài đặt bởi lập trình viên
• Mở file
– tạo đối tượng từ các lớp
• ifstream (input only - chỉ đọc)
• ofstream (output only - chỉ ghi)
• fstream (I/O – file vừa đọc vừa ghi)
– Constructor lấy tên file và kiểu mở file
ofstream outClientFile( "filename", fileOpenMode );
– Hoặc, tạo object trước rồi gắn với một file sau
ofstream outClientFile;
outClientFile.open( "filename", fileOpenMode);
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
38
7.10 File truy nhập tuần tự
• Các kiểu mở file - File-open modes
Mode
Description
ios::app
Viết tiếp output vào cuối file.
ios::ate
Mở một file để ghi và di chuyển đến cuối file
(thường dùng để nối dữ liệu vào file). Dữ liệu có
thể được viết vào vị trí tùy ý trong file.
Mở file để đọc
Mở file để ghi.
Loại bỏ nội dung file nếu nó tồn tại (mặc định
đối với ios::out)
ios::in
ios::out
ios::trunc
ios::binary
Mở file nhị phân (i.e., không phải file text) để
đọc hoặc ghi.
– theo mặc định, ofstream mở để ghi
• ofstream outClientFile( "clients.dat", ios::out );
• ofstream outClientFile( "clients.dat");
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
39
7.10 File truy nhập tuần tự
• Các phép toán
– Overloaded operator!
• !outClientFile
hoặc
!inClientfile
• Trả về nonzero (true) nếu badbit hoặc failbit bật
– mở file không tồn tại để đọc, không có quyền mở
– Overloaded operator void*
• chuyển đổi đối tượng dòng thành con trỏ
• 0 khi failbit hoặc badbit được bật, nếu không: nonzero
– failbit bật khi gặp EOF
• while ( inClientFile >> myVariable )
– lặp cho đến khi gặp EOF
– Ghi/đoc file (như cout, cin)
• outClientFile << myVariable
• inClientFile >> myVariable
– Đóng file
• outClientFile.close()
• đóng tự động khi destructor được gọi
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
2
3
40
// Fig. 14.4: fig14_04.cpp
// Create a sequential file.
#include <iostream>
fig14_04.cpp
(1 of 2)
...................
7
using std::ios;
8
using std::cerr;
9
using std::endl;
10
11
#include <fstream>
12
13
using std::ofstream;
14
15
#include <cstdlib>
16
17
18
19
20
int main()
{
// ofstream constructor opens file
ofstream outClientFile( "clients.dat", ios::out );
Lưu ý các header file cần cho file I/O.
// exit prototype
ofstream object được tạo và
dùng để mở file clients.dat".
Nếu file chưa tồn tại, nó sẽ được
tạo.
21
22
23
24
25
// exit program if unable to create file
if ( !outClientFile ) { // overloaded ! operator
cerr << "File could not be opened" << endl;
exit( 1 );
26
27
} // end if
! operator dùng để kiểm tra xem
có xảy ra lỗi khi mở file không.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
28
29
30
41
cout << "Enter the account, name, and balance." << endl
<< "Enter end-of-file to end input.\n? ";
fig14_04.cpp
(2 of 2)
cin được ngầm đổi thành 1
pointer.
Khi gặp EOF, nó trả về 0 và
vòng lặp dừng.
31
32
33
34
int account;
char name[ 30 ];
double balance;
35
36
37
38
39
40
// read account, name and balance from cin, then place in file
while ( cin >> account >> name >> balance ) {
outClientFile << account << ' ' << name << ' ' << balance
<< endl;
cout << "? ";
41
42
} // end while
43
44
return 0;
45
46
Ghi dữ liệu ra file như ghi ra
một dòng chuẩn.
// ofstream destructor closes file
} // end main
Enter
Enter
? 100
? 200
? 300
? 400
? 500
? ^Z
the account, name, and balance.
end-of-file to end input.
Jones 24.98
Doe 345.67
White 0.00
Stone -42.16
Rich 224.62
CuuDuongThanCong.com
File đóng khi destructor của
object được gọi.
Có thể đóng một cách tường minh
bằng cách gọi close().
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
1
2
3
4
5
6
7
8
9
10
11
12
13
using
using
using
using
using
using
using
using
using
14
15
#include <fstream>
16
17
using std::ifstream;
18
19
#include <iomanip>
20
21
22
23
24
25
26
27
42
// Fig. 14.7: fig14_07.cpp
// Reading and printing a sequential file.
#include <iostream>
std::cout;
std::cin;
std::ios;
std::cerr;
std::endl;
std::left;
std::right;
std::fixed;
std::showpoint;
fig14_07.cpp
(1 of 3)
using std::setw;
using std::setprecision;
#include <cstdlib> // exit prototype
void outputLine( int, const char * const, double );
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
28
29
30
31
int main()
{
// ifstream constructor opens the file
mở file để đọc và kiểm tra.
fig14_07.cpp
ifstream inClientFile( "clients.dat", ios::in );
(2 of 3)
32
33
34
35
36
// exit program if ifstream could not open file
if ( !inClientFile ) {
cerr << "File could not be opened" << endl;
exit( 1 );
37
38
} // end if
39
40
41
42
int account;
char name[ 30 ];
double balance;
43
44
45
cout << left << setw( 10 ) << "Account" << setw( 13 )
<< "Name" << "Balance" << endl << fixed << showpoint;
46
47
48
49
// display each record in file
while ( inClientFile >> account >> name >> balance )
outputLine( account, name, balance );
50
51
return 0; // ifstream destructor closes the file
52
53
Đọc từ file đến khi gặp
EOF.
©2004 Trần Minh Châu.
FOTECH. VNU.
} // end main
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
43
44
54
55
56
57
58
59
60
61
// display single record from file
void outputLine( int account, const char * const name,
double balance )
{
cout << left << setw( 10 ) << account << setw( 13 ) << name
<< setw( 7 ) << setprecision( 2 ) << right << balance
<< endl;
62
63
} // end function outputLine
Account
100
200
300
400
500
Name
Jones
Doe
White
Stone
Rich
fig14_07.cpp
(3 of 3)
fig14_07.cpp
output (1 of 1)
Balance
24.98
345.67
0.00
-42.16
224.62
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
45
7.11 Các hàm định vị cho file tuần tự
• con trỏ vị trí ghi số thứ tự của byte tiếp theo để
đọc/ghi
• các hàm đặt lại vị trí của con trỏ:
– seekg (đặt vị trí đọc cho lớp istream)
– seekp (đặt vị trí ghi cho ostream)
– seekg và seekp lấy các đối số là offset và mốc
• Offset: số byte tương đối kể từ mốc
• Mốc (ios::beg mặc định)
– ios::beg - đầu file
– ios::cur - vị trí hiện tại
– ios::end - cuối file
• các hàm lấy vị trí hiện tại của con trỏ:
– tellg và tellp
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
46
7.11 Các hàm định vị cho file tuần tự
• Ví dụ
– fileObject.seekg(0)
• đến đầu file (vị trí 0), mặc định đối số thứ hai là ios::beg
– fileObject.seekg(n)
• đến byte thứ n kể từ đầu file
– fileObject.seekg(n, ios::cur)
• tiến n byte
– fileObject.seekg(y, ios::end)
• lùi y byte kể từ cuối file
– fileObject.seekg(0, ios::cur)
• đến cuối file
– seekp tương tự
– location = fileObject.tellg()
• lấy vị trí đọc hiện tại của fileObject
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
47
7.11 Các hàm định vị cho file tuần tự
•
Ví dụ:
– chương trình quản lý tài khoản ngân hàng - Credit manager
program
– dữ liệu: file clients.dat
– các chức năng:
1. in danh sách các tài khoản rỗng (account with zero balance)
2. in danh sách các tài khoản âm (account with credit)
3. in danh sách các tài khoản dương (account with debit)
– hoạt động của chương trình
1. menu cho phép người dùng chọn một chức năng hoặc chọn
dừng chương trình
2. thực hiện chức năng đã chọn và in kết quả
3. quay lại menu
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
2
3
4
5
6
7
8
9
10
11
12
13
using
using
using
using
using
using
using
using
using
14
15
#include <fstream>
16
17
using std::ifstream;
18
19
#include <iomanip>
20
21
22
using std::setw;
using std::setprecision;
23
24
25
48
// Fig. 14.8: fig14_08.cpp
// Credit-inquiry program.
#include <iostream>
std::cout;
std::cin;
std::ios;
std::cerr;
std::endl;
std::fixed;
std::showpoint;
std::left;
std::right;
fig14_08.cpp
(1 of 6)
#include <cstdlib>
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
26
27
28
29
30
enum RequestType { ZERO_BALANCE = 1, CREDIT_BALANCE,
DEBIT_BALANCE, END };
int getRequest();
bool shouldDisplay( int, double );
void outputLine( int, const char * const, double );
31
32
33
34
35
int main()
{
// ifstream constructor opens the file
ifstream inClientFile( "clients.dat", ios::in );
36
37
38
39
40
// exit program if ifstream could not open file
if ( !inClientFile ) {
cerr << "File could not be opened" << endl;
exit( 1 );
41
42
} // end if
43
44
45
46
47
int request;
int account;
char name[ 30 ];
double balance;
49
fig14_08.cpp
(2 of 6)
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
49
50
// get user's request (e.g., zero, credit or debit balance)
request = getRequest();
51
52
53
// process user's request
while ( request != END ) {
54
55
switch ( request ) {
56
57
58
59
case ZERO_BALANCE:
cout << "\nAccounts with zero balances:\n";
break;
60
61
62
63
case CREDIT_BALANCE:
cout << "\nAccounts with credit balances:\n";
break;
64
65
66
67
case DEBIT_BALANCE:
cout << "\nAccounts with debit balances:\n";
break;
68
69
50
fig14_08.cpp
(3 of 6)
} // end switch
70
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
71
72
// read account, name and balance from file
inClientFile >> account >> name >> balance;
73
74
75
// display file contents (until eof)
while ( !inClientFile.eof() ) {
fig14_08.cpp
(4 of 6)
76
77
78
79
// display record
if ( shouldDisplay( request, balance ) )
outputLine( account, name, balance );
80
81
82
// read account, name and balance from file
inClientFile >> account >> name >> balance;
83
84
85
86
87
88
} // end inner while
Dùng clear để bỏ cờ eof. Dùng seekg
để đặt con trỏ định vị file về đầu file.
inClientFile.clear();
// reset eof for next input
inClientFile.seekg( 0 ); // move to beginning of file
request = getRequest(); // get additional request from user
89
90
} // end outer while
91
92
cout << "End of run." << endl;
93
94
return 0; // ifstream destructor closes the file
95
96
51
©2004 Trần Minh Châu.
FOTECH. VNU.
} // end main
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
52
97
98 // obtain request from user
99 int getRequest()
100 {
101
int request;
fig14_08.cpp
(5 of 6)
102
103
104
105
106
107
108
// display request options
cout << "\nEnter request" << endl
<< " 1 - List accounts with zero balances" << endl
<< " 2 - List accounts with credit balances" << endl
<< " 3 - List accounts with debit balances" << endl
<< " 4 - End of run" << fixed << showpoint;
109
110
111
112
113
// input user request
do {
cout << "\n? ";
cin >> request;
114
115
} while ( request < ZERO_BALANCE && request > END );
116
117
return request;
118
119 } // end function getRequest
120
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// determine whether to display given record
bool shouldDisplay( int type, double balance )
{
// determine whether to display credit balances
if ( type == CREDIT_BALANCE && balance < 0 )
return true;
53
fig14_08.cpp
(6 of 6)
// determine whether to display debit balances
if ( type == DEBIT_BALANCE && balance > 0 )
return true;
// determine whether to display zero balances
if ( type == ZERO_BALANCE && balance == 0 )
return true;
return false;
} // end function shouldDisplay
// display single record from file
void outputLine( int account, const char * const name,
double balance )
{
cout << left << setw( 10 ) << account << setw( 13 ) << name
<< setw( 7 ) << setprecision( 2 ) << right << balance
<< endl;
} // end function outputLine
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
54
Enter request
1 - List accounts with zero balances
2 - List accounts with credit balances
3 - List accounts with debit balances
4 - End of run
? 1
Accounts with zero balances:
300
White
0.00
Enter request
1 - List accounts with zero balances
2 - List accounts with credit balances
3 - List accounts with debit balances
4 - End of run
? 2
Accounts with credit balances:
400
Stone
-42.16
fig14_08.cpp
output (1 of 2)
Enter request
1 - List accounts with zero balances
2 - List accounts with credit balances
3 - List accounts with debit balances
4 - End of run
? 3
Accounts with debit balances:
100
Jones
24.98
200
Doe
345.67
500
Rich
224.62
Enter request
1 - List accounts with zero balances
2 - List accounts with credit balances
3 - List accounts with debit balances
4 - End of run
? 4
End of run.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
Enter request
1 - List accounts with zero balances
2 - List accounts with credit balances
3 - List accounts with debit balances
4 - End of run
? 3
55
fig14_08.cpp
output (2 of 2)
Accounts with debit balances:
100
Jones
24.98
200
Doe
345.67
500
Rich
224.62
Enter request
1 - List accounts with zero balances
2 - List accounts with credit balances
3 - List accounts with debit balances
4 - End of run
? 4
End of run.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
56
7.12 Các rắc rối khi cập nhật
file truy nhập tuần tự
• cập nhật các file truy nhập tuần tự
– Rủi ro: ghi đè các dữ liệu khác
– Ví dụ: đổi tên từ "White" thành "Worthington"
• Dữ liệu cũ
300 White 0.00 400 Jones 32.87
• Chèn dữ liệu mới
300 Worthington 0.00
300 White 0.00 400 Jones 32.87
Dữ liệu bị ghi đè
300 Worthington 0.00ones 32.87
– Định dạng bị rối loạn
– Vấn đề có thể tránh được, nhưng biện pháp không hay.
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
57
7.13 Random-Access Files
(các file truy nhập ngẫu nhiên)
• Truy nhập tức thời - Instant access
– muốn định vị bản ghi một cách nhanh chóng
• các hệ thống đặt vé máy bay (airline reservations), máy rút tiền
tự động (ATM)
– các file tuần tự phải duyệt qua từng bản ghi một
• Giải pháp: các file truy nhập ngẫu nhiên
– khả năng truy nhập tức thời
– chèn bản ghi mà không phá các dữ liệu khác
– cập nhật/xóa một phần tử dữ liệu mà không làm thay đổi các
dữ liệu khác
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
58
7.13 File truy nhập ngẫu nhiên
(random-access file)
• C++ không quy định quy cách file
– lập trình viên phải tự tạo quy cách cho các file truy nhập
ngẫu nhiên
– cách đơn giản nhất: các bản ghi độ dài cố định
• tính toán được vị trí trong file từ kích thước bản ghi và khóa
0
100
200
300
400
500
}
byte offsets
}
}
}
}
}
}
100
100
100
100
100
100
bytes
bytes
bytes
bytes
bytes
bytes
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
59
7.13.1 Dữ liệu thô và dữ liệu định dạng
• Ví dụ: "1234567" (char *) và 1234567 (int)
– định dạng: char * cần 8 byte (1 byte cho mỗi ký tự + null)
– thô: int lấy một số cố định byte (có thể là 4)
• 123 có cùng kích thước theo byte với 1234567
• các phép toán << và >> dành cho dữ liệu định dạng
– outFile << number
• ghi number (int) dưới dạng char *
• số lượng byte không cố định
• hàm write()và read() dành cho dữ liệu thô
– outFile.write( const char *, size );
• ghi ra các byte dạng thô
• lấy tham số là con trỏ tới địa chỉ bộ nhớ, số byte cần ghi
– sao chép dữ liệu trực tiếp từ bộ nhớ sang file
– Không đổi thành char *
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
60
7.13.2 Ghi file truy nhập nhẫu nhiên
• Ví dụ hàm write()
outFile.write( reinterpret_cast<const char *>(&number),
sizeof( number ) );
– &number là int *
• đổi thành const char * bằng reinterpret_cast
– sizeof(number)
• kích thước của number (một số int) tính theo byte
– tương tự đối với hàm read (more later)
– Chú ý:
• chỉ dùng write/read giữa các máy tương thích
– mở file kiểu ios::binary để đọc/ghi thô
• thường dùng để ghi toàn bộ một struct hoặc
một đối tượng ra file
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
61
7.13.2 Ghi file truy nhập ngẫu nhiên
• Bài toán
– chương trình quản lý tài khoản
– Lưu trữ tối đa 100 bản ghi kích thước cố định
– Bản ghi
• Mã tài khoản - Account number (khóa)
• Họ và tên - First and last name
• Số tiền hiện có trong tài khoản - Balance
– Các thao tác:
• cập nhật, tạo mới, xóa, liệt kê tất cả các tài khoản ra một file
• Tiếp theo: chương trình tạo file chứa 100 bản ghi
rỗng
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
2
3
4
// Fig. 14.10: clientData.h
// Class ClientData definition used in Fig. 14.12–Fig. 14.15.
#ifndef CLIENTDATA_H
#define CLIENTDATA_H
5
6
#include <iostream>
7
8
using std::string;
9
10
class ClientData {
11
12
public:
62
clientData.h
(1 of 2)
Class ClientData lưu
thông tin về từng người.
100 đối tượng ClientData
rỗng sẽ được ghi ra 1 file.
13
14
15
// default ClientData constructor
ClientData( int = 0, string = "", string = "", double = 0.0 );
16
17
18
19
// accessor functions for accountNumber
void setAccountNumber( int );
int getAccountNumber() const;
20
21
22
23
// accessor functions for lastName
void setLastName( string );
string getLastName() const;
24
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
25
26
27
28
29
30
31
63
// accessor functions for firstName
void setFirstName( string );
string getFirstName() const;
// accessor functions for balance
void setBalance( double );
double getBalance() const;
32
33
34
35
36
37
private:
int accountNumber;
char lastName[ 15 ];
char firstName[ 10 ];
double balance;
38
39
}; // end class ClientData
40
41
#endif
clientData.h
(2 of 2)
Đặt giới hạn kích thước tên và họ.
accountNumber (một số int)
và balance (double) đã có kích
thước cố định.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
64
// Fig. 14.11: ClientData.cpp
// Class ClientData stores customer's credit information.
#include <iostream>
ClientData.cpp
(1 of 4)
using std::string;
#include <cstring>
#include "clientData.h"
// default ClientData constructor
ClientData::ClientData( int accountNumberValue,
string lastNameValue, string firstNameValue,
double balanceValue )
{
setAccountNumber( accountNumberValue );
setLastName( lastNameValue );
setFirstName( firstNameValue );
setBalance( balanceValue );
} // end ClientData constructor
// get account-number value
int ClientData::getAccountNumber() const
{
return accountNumber;
} // end function getAccountNumber
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
65
28
29
30
31
32
// set account-number value
void ClientData::setAccountNumber( int accountNumberValue )
{
accountNumber = accountNumberValue;
33
34
} // end function setAccountNumber
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
ClientData.cpp
(2 of 4)
// get last-name value
string ClientData::getLastName() const
{
return lastName;
} // end function getLastName
// set last-name value
void ClientData::setLastName( string lastNameString )
{
// copy at most 15 characters from string to lastName
const char *lastNameValue = lastNameString.data();
int length = strlen( lastNameValue );
length = ( length < 15 ? length : 14 );
strncpy( lastName, lastNameValue, length );
// append null character to lastName
lastName[ length ] = '\0';
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
66
54
55
} // end function setLastName
56
57
58
59
60
// get first-name value
string ClientData::getFirstName() const
{
return firstName;
61
62
} // end function getFirstName
63
64
65
66
67
68
69
70
71
// set first-name value
void ClientData::setFirstName( string firstNameString )
{
// copy at most 10 characters from string to firstName
const char *firstNameValue = firstNameString.data();
int length = strlen( firstNameValue );
length = ( length < 10 ? length : 9 );
strncpy( firstName, firstNameValue, length );
72
73
74
75
76
ClientData.cpp
(3 of 4)
// append new-line character to firstName
firstName[ length ] = '\0';
} // end function setFirstName
77
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
78
79
80
81
// get balance value
double ClientData::getBalance() const
{
return balance;
82
83
} // end function getBalance
84
85
86
87
88
// set balance value
void ClientData::setBalance( double balanceValue )
{
balance = balanceValue;
89
90
} // end function setBalance
67
ClientData.cpp
(4 of 4)
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
1
2
3
68
// Fig. 14.12: fig14_12.cpp
// Creating a randomly accessed file.
#include <iostream>
fig14_12.cpp
(1 of 2)
4
5
6
7
using std::cerr;
using std::endl;
using std::ios;
8
9
#include <fstream>
10
11
using std::ofstream;
12
13
14
#include <cstdlib>
#include "clientData.h"
15
16
17
18
int main()
{
ofstream outCredit( "credit.dat", ios::binary );
// ClientData class definition
19
20
21
22
23
// exit program if ofstream could not open file
if ( !outCredit ) {
cerr << "File could not be opened." << endl;
exit( 1 );
24
25
} // end if
Mở 1 file để ghi thô,
sử dụng một đối tượng ofstream
và ios::binary.
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
69
26
27
28
// create ClientData with no information
Tạo một đối tượng rỗng.
ClientData blankClient;
29
30
31
32
33
34
// output 100 blank records to file
for ( int i = 0; i < 100; i++ )
outCredit.write(
reinterpret_cast< const char * >( &blankClient ),
sizeof( ClientData ) );
35
36
return 0;
37
38
Dùng write để ghi dữ liệu fig14_12.cpp
thô ra 1 file (truyền tham số (2 of 2)
là địa chỉ đối tượng và kích
thước đối tượng).
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
70
7.13.3 Ghi dữ liệu vào vị trí tùy ý
trong file truy nhập ngẫu nhiên
• Dùng seekp để ghi vào vị trí chính xác trong file
– Bản ghi đầu tiên bắt đầu từ đâu?
• Byte 0
– Bản ghi thứ hai?
• Byte 0 + sizeof(object)
– Bản ghi bất kỳ?
• (Recordnum - 1) * sizeof(object)
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
2
3
......
19 #include <cstdlib>
20 #include "clientData.h"
21
22
23
24
25
26
27
71
// Fig. 14.13: fig14_13.cpp
// Writing to a random access file.
#include <iostream>
int main()
{
int accountNumber;
char lastName[ 15 ];
char firstName[ 10 ];
double balance;
fig14_13.cpp
(1 of 3)
// ClientData class definition
Mở file để ghi thô (binary
writing).
28
29
ofstream outCredit( "credit.dat", ios::binary );
30
31
32
33
34
// exit program if ofstream cannot open file
if ( !outCredit ) {
cerr << "File could not be opened." << endl;
exit( 1 );
35
36
} // end if
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
38
39
40
41
42
43
44
45
46
47
48
cout << "Enter account number "
<< "(1 to 100, 0 to end input)\n? ";Nhập account number, ghi vào đối
tượng. Nó chưa được viểt ra file.
fig14_13.cpp
// require user to specify account number
(2 of 3)
ClientData client;
cin >> accountNumber;
client.setAccountNumber( accountNumber );
// user enters information, which is copied into file
while ( client.getAccountNumber() > 0 &&
client.getAccountNumber() <= 100 ) {
49
50
51
52
53
54
// user enters last name, first name and balance
cout << "Enter lastname, firstname, balance\n? ";
cin >> setw( 15 ) >> lastName;
cin >> setw( 10 ) >> firstName;
cin >> balance;
55
56
57
58
59
// set record lastName, firstName and balance values
client.setLastName( lastName );
client.setFirstName( firstName );
client.setBalance( balance );
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
72
73
60
61
62
63
Đặt outCredit vào vị trí thích hợp trong
file (dựa vào account number).
fig14_13.cpp
(3 of 3)
// seek position in file of user-specified record
outCredit.seekp( ( client.getAccountNumber() - 1 ) *
sizeof( ClientData ) );
Ghi đối tượng ClientData vào
file tại vị trí đó.
64
65
66
67
68
// write user-specified information in file
outCredit.write(
reinterpret_cast< const char * >( &client ),
sizeof( ClientData ) );
69
70
71
72
73
// enable user to specify another account number
cout << "Enter account number\n? ";
cin >> accountNumber;
client.setAccountNumber( accountNumber );
74
75
} // end while
76
77
return 0;
78
79
} // end main
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
Enter account number (1 to
? 37
Enter lastname, firstname,
? Barker Doug 0.00
Enter account number
? 29
Enter lastname, firstname,
? Brown Nancy -24.54
Enter account number
? 96
Enter lastname, firstname,
? Stone Sam 34.98
Enter account number
? 88
Enter lastname, firstname,
? Smith Dave 258.34
Enter account number
? 33
Enter lastname, firstname,
? Dunn Stacey 314.33
Enter account number
? 0
74
100, 0 to end input)
balance
Lưu ý các account có thể
được tạo theo thứ tự tùy ý.
fig14_13.cpp
output (1 of 1)
balance
balance
balance
balance
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
7.13.4 Đọc tuần tự dữ liệu
từ file truy nhập ngẫu nhiên
75
• read - tương tự write
– Đọc các byte thô từ file vào bộ nhớ
– inFile.read( reinterpret_cast<char *>( &number ),
sizeof( int ) );
• &number: địa chỉ để lưu dữ liệu
• sizeof(int): số byte cần đọc
– Không dùng inFile >> number cho dữ liệu thô - nhị
phân
• >> nhận char *
• Chương trình tiếp theo
– lấy dữ liệu từ một file random-access
– duyệt tuần tự qua từng bản ghi
• If no data (accountNumber == 0) then skip
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
// Fig. 14.14: fig14_14.cpp
2
// Reading a random access file.
......
25 #include "clientData.h" // ClientData class definition
26
27 void outputLine( ostream&, const ClientData & );
28
29 int main()
30 {
31
ifstream inCredit( "credit.dat", ios::in );
32
33
// exit program if ifstream cannot open file
34
if ( !inCredit ) {
35
cerr << "File could not be opened." << endl;
36
exit( 1 );
37
38
} // end if
39
40
41
42
cout << left << setw( 10 ) << "Account" << setw( 16 )
<< "Last Name" << setw( 11 ) << "First Name" << left
<< setw( 10 ) << right << "Balance" << endl;
43
44
ClientData client; // create record
45
46
47
48
// read first record from file
inCredit.read( reinterpret_cast< char * >( &client ),
sizeof( ClientData ) );
CuuDuongThanCong.com
76
fig14_14.cpp
(1 of 2)
Đọc sizeof(ClientData) byte và ghi vào đối
tượng client. Đây có thể là một bản ghi rỗng.
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
77
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// read all records from file
while ( inCredit && !inCredit.eof() ) {
// display record
if ( client.getAccountNumber() != 0 )
outputLine( cout, client );
fig14_14.cpp
Vòng lặp dừng khi có
lỗi đọc
of 2)gặp EOF
(inCredit == 0)(2hoặc
(inCredit.eof() == 1)
// read next from file
inCredit.read( reinterpret_cast< char * >( &client ),
sizeof( ClientData ) );
Output non-empty accounts.
Lưu ý outputLine lấy 1
tham số kiểu ostream. Ta
có thể dễ dàng output ra một
file khác (mở bằngmột
ofstream object, là dẫn
xuất của ostream).
} // end while
return 0;
} // end main
// display single record
void outputLine( ostream &output, const ClientData &record )
{
output << left << setw( 10 ) << record.getAccountNumber()
<< setw( 16 ) << record.getLastName().data()
<< setw( 11 ) << record.getFirstName().data()
<< setw( 10 ) << setprecision( 2 ) << right << fixed
<< showpoint << record.getBalance() << endl;
} // end outputLine
CuuDuongThanCong.com
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt
Account
29
33
37
88
96
Last Name
Brown
Dunn
Barker
Smith
Stone
First Name
Nancy
Stacey
Doug
Dave
Sam
Balance
-24.54
314.33
0.00
258.34
34.98
78
fig14_14.cpp
output (1 of 1)
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
79
7.14 Ví dụ: Chương trình xử lý giao dịch
• Bài toán:
– chương trình quản lý các tài khoản ngân hàng, cho phép truy nhập
trực tiếp từng tài khoản
– dữ liệu: file truy nhập ngẫu nhiên credit.dat
• Các chức năng cho người dùng (các lựa chọn cho menu)
– Lựa chọn 1: ghi các account ra file print.txt
Account
29
33
37
88
96
Last Name
Brown
Dunn
Barker
Smith
Stone
First Name
Nancy
Stacey
Doug
Dave
Sam
Balance
-24.54
314.33
0.00
258.34
34.98
– Lựa chọn 2: cập nhật bản ghi
Enter account to update (1 - 100): 37
37
Barker
Doug
Enter charge (+) or payment (-): +87.99
37
Barker
Doug
0.00
87.99
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
80
7.14 Ví dụ: Chương trình xử lý giao dịch
• Các chức năng (tiếp)
– Lựa chọn 3: thêm bản ghi
Enter new account number (1 - 100): 22
Enter lastname, firstname, balance
? Johnston Sarah 247.45
– Lựa chọn 4: xóa bản ghi
Enter account to delete (1 - 100): 29
Account #29 deleted.
• Mở file vừa đọc vừa ghi
– Dùng fstream object
– nhiều file-open mode cùng lúc
fstream inOutCredit( "credit.dat", ios::in | ios::out );
© 2004 Trần Minh Châu. FOTECH. VNU
CuuDuongThanCong.com
Chương 7.
https://fb.com/tailieudientucntt
1
2
3
4
5
// Fig. 14.15: fig14_15.cpp
// This program reads a random access file sequentially, updates
// data previously written to the file, creates data to be placed
// in the file, and deletes data previously in the file.
#include <iostream>
6
7
using std::cout;
...
15
using std::showpoint;
16
17
#include <fstream>
18
19
20
21
using std::ofstream;
using std::ostream;
using std::fstream;
22
23
#include <iomanip>
24
25
26
using std::setw;
using std::setprecision;
27
28
29
#include <cstdlib>
#include "clientData.h"
81
fig14_15.cpp
(1 of 14)
// exit prototype
// ClientData class definition
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
82
30
31
32
33
34
35
36
37
int enterChoice();
void printRecord( fstream& );
void updateRecord( fstream& );
void newRecord( fstream& );
void deleteRecord( fstream& );
void outputLine( ostream&, const ClientData & );
int getAccount( const char * const );
38
39
enum Choices { PRINT = 1, UPDATE, NEW, DELETE, END };
40
41
42
43
44
Mở file để đọc và ghi (cần
int main()
fstream object).
{
// open file for reading and writing
fstream inOutCredit( "credit.dat", ios::in | ios::out );
45
46
47
48
49
50
51
52
fig14_15.cpp
(2 of 14)
// exit program if fstream cannot open file
if ( !inOutCredit ) {
cerr << "File could not be opened." << endl;
exit ( 1 );
} // end if
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
83
int choice;
// enable user to specify action
while ( ( choice = enterChoice() ) != END ) {
switch ( choice ) {
fig14_15.cpp
(4 of 14)
Hiện menu và trả về lựa chọn
người dùng.
// create text file from record file
case PRINT:
printRecord( inOutCredit );
break;
// update record
case UPDATE:
updateRecord( inOutCredit );
break;
// create record
case NEW:
newRecord( inOutCredit );
break;
// delete existing record
case DELETE:
deleteRecord( inOutCredit );
break;
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
80
81
82
83
// display error if user does not select valid choice
default:
cerr << "Incorrect choice" << endl;
break;
84
85
} // end switch
86
87
inOutCredit.clear(); // reset end-of-file indicator
88
89
} // end while
90
91
return 0;
92
93
84
fig14_15.cpp
(5 of 14)
} // end main
94
95 // enable user to input menu choice
96 int enterChoice()
97 {
98
// display available options
99
cout << "\nEnter your choice" << endl
100
<< "1 - store a formatted text file of accounts" << endl
101
<< "
called \"print.txt\" for printing" << endl
102
<< "2 - update an account" << endl
103
<< "3 - add a new account" << endl
104
<< "4 - delete an account" << endl
©2004 Trần Minh Châu.
FOTECH.
VNU.
105
<< "5 - end program\n? ";
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
106
107
108
109
110
85
int menuChoice;
cin >> menuChoice; // receive choice from user
fig14_15.cpp
(6 of 14)
return menuChoice;
111
112 } // end function enterChoice
113
114 // create formatted text file for printing
In ra print.txt. Trước
115 void printRecord( fstream &readFromFile )
tiên, in header của bảng.
116 {
117
// create text file
118
ofstream outPrintFile( "print.txt", ios::out );
119
120
121
122
123
// exit program if ofstream cannot create file
if ( !outPrintFile ) {
cerr << "File could not be created." << endl;
exit( 1 );
124
125
} // end if
126
127
128
129
outPrintFile << left << setw( 10 ) << "Account" << setw( 16 )
<< "Last Name" << setw( 11 ) << "First Name" << right
<< setw( 10 ) << "Balance" << endl;
130
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
86
131
132
// set file-position pointer to beginning of record file
readFromFile.seekg( 0 );
133
134
135
136
137
fig14_15.cpp
// read first record from record file
Đến đầu
file,
(7 of
14)đọc dữ liệu
ClientData client;
readFromFile.read( reinterpret_cast< char * >( &client ), về tài khoản, và in bản
ghi nếu nó không rỗng.
sizeof( ClientData ) );
138
139
140
// copy all records from record file into text file
while ( !readFromFile.eof() ) {
Lưu ý outputLine
lấy đối số là đối tượng
ostream object (lớp cơ
sở của ofstream). Nó
có thể ghi ra file (như
trong trường hợp này)
hoặc cout.
141
142
143
144
// write single record to text file
if ( client.getAccountNumber() != 0 )
outputLine( outPrintFile, client );
145
146
147
148
// read next record from record file
readFromFile.read( reinterpret_cast< char * >( &client ),
sizeof( ClientData ) );
149
150
} // end while
151
152 } // end function printRecord
153
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
154 // update balance in record
155 void updateRecord( fstream &updateFile )
156 {
157
// obtain number of account to update
158
int accountNumber = getAccount( "Enter account to update" );
87
fig14_15.cpp
(8 of 14)
159
160
161
162
// move file-position pointer to correct record in file
updateFile.seekg(
( accountNumber - 1 ) * sizeof( ClientData ) );
163
164
165
166
167
// read first record from file
cập nhật nó, và ghi balance mới.
ClientData client;
updateFile.read( reinterpret_cast< char * >( &client ),
sizeof( ClientData ) );
168
169
170
171
// update record
if ( client.getAccountNumber() != 0 ) {
outputLine( cout, client );
172
173
174
175
176
Đây là fstream (I/O) vì ta phải đọc balance cũ,
// request user to specify transaction
cout << "\nEnter charge (+) or payment (-): ";
double transaction; // charge or payment
cin >> transaction;
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
88
177
178
179
180
181
// update record balance
double oldBalance = client.getBalance();
client.setBalance( oldBalance + transaction );
outputLine( cout, client );
182
183
184
185
// move file-position pointer to correct record in file
updateFile.seekp(
( accountNumber - 1 ) * sizeof( ClientData ) );
186
187
188
189
190
// write updated record over old record in file
updateFile.write(
reinterpret_cast< const char * >( &client ),
sizeof( ClientData ) );
191
192
} // end if
193
194
195
196
197
// display error if account does not exist
else
cerr << "Account #" << accountNumber
<< " has no information." << endl;
fig14_15.cpp
(9 of 14)
198
199 } // end function updateRecord
200
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
201 // create and insert record
202 void newRecord( fstream &insertInFile )
203 {
204
// obtain number of account to create
205
int accountNumber = getAccount( "Enter new account number" );
89
fig14_15.cpp
(10 of 14)
206
207
208
209
// move file-position pointer to correct record in file
insertInFile.seekg(
Đây là fstream vì ta đọc
( accountNumber - 1 ) * sizeof( ClientData ) );
210
211
212
213
214
// read record from file
ClientData client;
insertInFile.read( reinterpret_cast< char * >( &client ),
sizeof( ClientData ) );
215
216
217
// create record, if record does not previously exist
if ( client.getAccountNumber() == 0 ) {
218
219
220
221
thử để xem đã có sẵn một bản
ghi rỗng hay chưa, nếu chưa,
ta ghi một bản ghi mới.
char lastName[ 15 ];
char firstName[ 10 ];
double balance;
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
90
// user enters last name, first name and balance
cout << "Enter lastname, firstname, balance\n? ";
cin >> setw( 15 ) >> lastName;
cin >> setw( 10 ) >> firstName;
cin >> balance;
fig14_15.cpp
(11 of 14)
// use values to populate account values
client.setLastName( lastName );
client.setFirstName( firstName );
client.setBalance( balance );
client.setAccountNumber( accountNumber );
// move file-position pointer to correct record in file
insertInFile.seekp( ( accountNumber - 1 ) *
sizeof( ClientData ) );
// insert record in file
insertInFile.write(
reinterpret_cast< const char * >( &client ),
sizeof( ClientData ) );
} // end if
245
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
91
// display error if account previously exists
else
cerr << "Account #" << accountNumber
<< " already contains information." << endl;
fig14_15.cpp
(12 of 14)
} // end function newRecord
// delete an existing record
void deleteRecord( fstream &deleteFromFile )
{
// obtain number of account to delete
int accountNumber = getAccount( "Enter account to delete" );
// move file-position pointer to correct record in file
deleteFromFile.seekg(
là fstream vì ta đọc để
( accountNumber - 1 ) * sizeof( ClientData ) ); kiểm tra xem account có tồn
tại không. Nếu có, ta ghi dữ
liệu rỗng (xóa nó). Nếu
không, không cần xóa.
// read record from file
ClientData client;
deleteFromFile.read( reinterpret_cast< char * >( &client ),
sizeof( ClientData ) );
267
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
268
269
270
271
272
273
274
275
276
277
278
279
280
281
92
// delete record, if record exists in file
if ( client.getAccountNumber() != 0 ) {
ClientData blankClient;
// move file-position pointer to correct record in file
deleteFromFile.seekp( ( accountNumber - 1 ) *
sizeof( ClientData ) );
fig14_15.cpp
(13 of 14)
// replace existing record with blank record
deleteFromFile.write(
reinterpret_cast< const char * >( &blankClient ),
sizeof( ClientData ) );
cout << "Account #" << accountNumber << " deleted.\n";
282
283
} // end if
284
285
286
287
// display error if record does not exist
else
cerr << "Account #" << accountNumber << " is empty.\n";
288
289 } // end deleteRecord
290
©2004 Trần Minh Châu.
FOTECH. VNU.
CuuDuongThanCong.com
https://fb.com/tailieudientucntt
291 // display single record
292 void outputLine( ostream &output, const ClientData &record )
293 {
294
output << left << setw( 10 ) << record.getAccountNumber()
295
<< setw( 16 ) << record.getLastName().data()
296
<< setw( 11 ) << record.getFirstName().data()
297
<< setw( 10 ) << setprecision( 2 ) << right << fixed
298
<< showpoint << record.getBalance() << endl;
299
300 } // end function outputLine
301
302 // obtain account-number value from user
303 int getAccount( const char * const prompt )
304 {
305
int accountNumber;
// obtain account-number value
do {
cout << prompt << " (1 - 100): ";
cin >> accountNumber;
311
312
} while ( accountNumber < 1 || accountNumber > 100 );
313
314
return accountNumber;
CuuDuongThanCong.com
fig14_15.cpp
(14 of 14)
outputLine rất mềm dẻo, và có
thể ghi ra ostream object bất kỳ
(chẳng hạn 1 file hoặc cout).
306
307
308
309
310
315
316 } // end function getAccount
93
©2004 Trần Minh Châu.
FOTECH. VNU.
https://fb.com/tailieudientucntt