Uploaded by sang1172004

02.NMLT NoiDung

advertisement
LỜI NÓI ĐẦU
Nhập môn lập trình là một trong những học phần nền tảng quan trọng đối
với sinh viên học các ngành thuộc nhóm ngành Máy tính và Công nghệ thông
tin. Tại Trường Đại học Tiền Giang, Nhập môn lập trình là học phần bắt buộc
đối với sinh viên học Đại học Công nghệ thông tin, Đại học Hệ thống thông tin,
Cao đẳng Công nghệ thông tin. Bên cạnh đó, sinh viên học các ngành Toán ứng
dụng, Kỹ thuật Điện tử - Tin học cũng học Nhập môn lập trình.
Mặc dù số lượng tín chỉ cũng như số giờ học có khác nhau đối với từng
ngành học. Học phần Nhập môn lập trình là một học phần cơ sở ngành, cung cấp
cho người học những kiến thức cơ bản về lập trình, giúp người học có được nền
tảng kiến thức nền tảng về lập trình để học tiếp các học phần khác như Kỹ thuật
lập trình, Phương pháp lập trình hướng đối tượng, Công nghệ .NET, Lập trình
ứng dụng Java, …Do đó, tài liệu này được soạn cho tất cả sinh viên học các
Chương trình Đại học Công nghệ thông tin, Đại học Hệ thống thông tin, Cao
đẳng Công nghệ thông tin, Đại học Toán ứng dụng, Đại học Kỹ thuật Điện tử Tin học.
Nội dung của bài giảng được chia thành 4 chương gồm: Chương 1. Lập
trình cơ bản, Chương 2. Lập trình module, Chương 3. Lập trình với dữ liệu có
cấu trúc, Chương 4. Làm việc với tập tin. Để giúp người học vừa thuận lợi trong
việc theo dõi giảng viên giảng dạy trên lớp, thực hành tại phòng máy tính, tự học
tại nhà; cuối mỗi chương đều có các bài tập ôn tập. Bài tập ôn tập, bài tập lập
trình dạng có hướng dẫn 1 phần và không có hướng dẫn để sinh viên thể hiện
khả năng tư duy, sáng tạo trong lập trình. Các ví dụ minh họa được viết bằng
ngôn ngữ lập trình C, C++ trong môi trường Dev C/C++.
Trong quá trình giảng dạy và biên soạn tài liệu này chúng tôi đã nhận được
sự động viên cũng như những ý kiến đóng góp rất quý báu của lãnh đạo Khoa và
quý đồng nghiệp trong Khoa Công nghệ thông tin – Trường Đại học Tiền Giang.
Rất mong nhận được sự đóng góp từ quý đồng nghiệp và các em sinh viên
để tài liệu giảng dạy được hoàn chỉnh hơn.
Chân thành cảm ơn.
NHÓM TÁC GIẢ
TS. Dương Văn Hiếu
ThS. Đoàn Chí Trung
ThS. Nguyễn Hữu Thanh
i
MỤC LỤC
Chương 1. LẬP TRÌNH CƠ BẢN ................................................................ 1
1. GIỚI THIỆU NGÔN NGỮ LẬP TRÌNH C , C++ ............................... 1
1.1. Ngôn ngữ lập trình C .................................................................... 1
1.2. Ngôn ngữ lập trình C++ ............................................................... 3
1.3. Bộ ký tự và ký hiệu ....................................................................... 3
1.4. Các từ khóa cơ bản ....................................................................... 4
1.5. Cấu trúc một chương trình đơn giản .......................................... 5
1.6. Cách ghi chú thích ........................................................................ 6
2. KIỂU DỮ LIỆU CHUẨN, BIỂU THỨC VÀ PHÉP TOÁN CƠ BẢN 6
2.1. Các kiểu dữ liệu chuẩn ................................................................. 6
2.2. Biểu thức ........................................................................................ 7
2.3. Phép toán ....................................................................................... 7
2.4. Chuyển đổi kiểu dữ liệu trong C, C++ ...................................... 12
3. BIỂU DIỄN GIÁ TRỊ KIỂU SỐ......................................................... 14
3.1. Mối tương quan giữa bảng mã ASCII và kiểu dữ liệu unsigned
char ........................................................................................... 14
3.2. Biểu diễn hằng giá trị ................................................................. 16
4. SỬ DỤNG BIẾN................................................................................. 17
4.1. Định nghĩa biến ........................................................................... 17
4.2. Khai báo và gán giá trị khởi tạo cho biến ................................ 18
4.3. Gán giá trị cho biến .................................................................... 19
4.4. Vị trí khai báo biến ..................................................................... 20
4.5. Nhập xuất giá trị của biến .......................................................... 21
5. CÂU LỆNH VÀ KHỐI LỆNH ........................................................... 26
5.1. Câu lệnh ....................................................................................... 26
5.2. Khối lệnh ...................................................................................... 27
6. CÁC LỆNH ĐIỀU KHIỂN (LỆNH CÓ CẤU TRÚC)....................... 28
6.1. Giới thiệu ..................................................................................... 28
6.2. Lệnh rẽ nhánh (Cấu trúc rẽ nhánh).......................................... 28
6.3. Lệnh lặp ....................................................................................... 34
7. CÁC BƯỚC GIẢI BÀI TOÁN LẬP TRÌNH ..................................... 42
7.1. Tìm hiểu bài toán ........................................................................ 42
7.2. Mô tả giải thuật ........................................................................... 43
7.3. Viết chương trình ........................................................................ 45
7.4. Biên dịch và sửa lỗi ..................................................................... 45
7.5. Ứng dụng và nâng cấp ................................................................ 45
ii
8. BÀI TẬP ............................................................................................. 46
8.1. Câu hỏi ôn tập ............................................................................. 46
8.1. Bài tập thực hành ....................................................................... 48
Chương 2. LẬP TRÌNH MODULE ........................................................... 56
1. HÀM VÀ CHƯƠNG TRÌNH CON ................................................... 56
1.1. Định nghĩa hàm ........................................................................... 56
1.2. Hàm thư viện ............................................................................... 57
1.3. Hàm người dùng định nghĩa ...................................................... 60
2. LÝ DO TẠO HÀM NGƯỜI DÙNG .................................................. 60
3. QUY TẮC XÂY DỰNG HÀM .......................................................... 63
3.1. Tách những nội dung lặp đi lặp lại thành hàm ....................... 63
3.2. Tách những nội dung cần chuẩn bị trước thành hàm ............ 65
3.3. Khai báo hàm .............................................................................. 66
3.4. Nội dung của hàm ....................................................................... 71
3.5. Biến nội bộ của hàm ................................................................... 71
3.6. Sử dụng câu lệnh return ............................................................ 72
3.7. Nguyên tắc hoạt động của hàm ................................................. 73
4. TRUYỀN THAM SỐ KHI GỌI HÀM ............................................... 73
4.1. Cách truyền tham số trong C .................................................... 73
4.2. Cách truyền tham số trong C++ ................................................ 76
4.3. Lưu giá trị trả về vào biến hình thức ........................................ 78
5. HÀM ĐỆ QUY ................................................................................... 80
5.1. Khái niệm .................................................................................... 80
5.2. Kỹ thuật thiết kế đệ quy ............................................................. 81
6. SỬ DỤNG BIẾN TOÀN CỤC VÀ BIẾN CỤC BỘ .......................... 81
6.1. Phạm vi của biến ......................................................................... 81
6.2. Biến toàn cục ............................................................................... 81
6.3. Biến cục bộ................................................................................... 82
7. BÀI TẬP ............................................................................................. 83
7.1. Câu hỏi ôn tập ............................................................................. 83
7.2. Bài tập thực hành ....................................................................... 84
Chương 3. LẬP TRÌNH VỚI DỮ LIỆU CÓ CẤU TRÚC ........................ 88
1. KHÁI NIỆM KIỂU DỮ LIỆU CÓ CẤU TRÚC ................................ 88
2. KIỂU MẢNG ...................................................................................... 88
2.1. Mảng 1 chiều ............................................................................... 88
2.2. Mảng nhiều chiều........................................................................ 92
3. CHUỖI KÝ TỰ TRONG C ................................................................ 96
3.1. Chuỗi là mảng các ký tự............................................................. 96
iii
3.2. Sử dụng thư viện string.h ........................................................... 97
4. CHUỖI KÝ TỰ TRONG C++ ............................................................ 98
4.1. Chuỗi ký tự là một đối tượng..................................................... 98
4.2. Hàm là phương thức của đối tượng .......................................... 99
5. CON TRỎ ......................................................................................... 100
5.1. Khái niệm con trỏ ..................................................................... 100
5.2. Khai báo biến con trỏ ............................................................... 100
5.3. Kích thước và địa chỉ của con trỏ............................................ 101
5.4. Con trỏ trỏ đến biến đơn và truy xuất nội dung biến con trỏ
................................................................................................. 103
5.5. Con trỏ trỏ đến biến mảng và truy xuất từng phần tử của biến
con trỏ..................................................................................... 105
5.6. Cấp phát, cấp lại vùng nhớ cho biến con trỏ và thu hồi vùng
nhớ của biến con trỏ ............................................................. 107
6. MỐI TƯƠNG QUANG GIỮA CON TRỎ VÀ MẢNG .................. 109
7. CẤU TRÚC ....................................................................................... 111
8. KẾT HỢP MẢNG VÀ STRUCT...................................................... 114
9. BÀI TẬP ........................................................................................... 116
9.1. Câu hỏi ôn tập ........................................................................... 116
9.2. Bài tập thực hành ...................................................................... 116
Chương 4. LÀM VIỆC VỚI TẬP TIN ..................................................... 118
1. GIỚI THIỆU TẬP TIN ..................................................................... 118
1.1. Tập tin ........................................................................................ 118
1.2. Tập tin văn bản và tập tin nhị phân........................................ 118
1.3. Khai báo thư viện ...................................................................... 119
2. THAO TÁC TRÊN TẬP TIN ........................................................... 119
2.1. Khai báo biến tập tin ................................................................ 119
2.2. Tạo tạo tin mới, mở tập tin đã có ............................................ 119
2.3. Đóng tập tin đã mở ................................................................... 120
2.4. Cho biết vị trí hiện tại của con trỏ tập tin .............................. 120
2.5. Di chuyển vị trí con trỏ tập tin ................................................ 120
2.6. Đọc dữ liệu từ tập tin ................................................................ 122
2.7. Ghi dữ liệu vào tập tin .............................................................. 126
3. SỬ DỤNG THAM SỐ CỦA HÀM MAIN ...................................... 130
4. BÀI TẬP ........................................................................................... 133
4.1. Câu hỏi ôn tập ........................................................................... 133
4.2. Bài tập thực hành ...................................................................... 133
iv
Chương 1. LẬP TRÌNH CƠ BẢN
Mục tiêu của chương này
1. Về kiến thức:
- Viết, biên dịch, sửa lỗi, thực thi một chương trình được viết bằng ngôn
ngữ C, C++.
- Cách xuất dữ liệu ra màn hình, đọc dữ liệu từ bàn phím; từ khóa, cú
pháp, các kiểu dữ liệu chuẩn cùng các phép toán cơ bản trên các kiểu dữ liệu.
- Cách sử dụng lệnh gán, lệnh điều kiện, lệnh lặp.
2. Về kỹ năng:
- Phân biệt được sự khác nhau giữa các kiểu dữ liệu, sử dụng kiểu dữ liệu
và các phép toán một cách phù hợp, chuyển đổi kiểu dữ liệu khi cần thiết.
- Vận dụng được các hàm thường sử dụng trong các thư viện của C và
C++.
- Sử dụng được các cách định dạng dữ liệu khi xuất dữ liệu bằng hàm
printf() nhập dữ liệu bằng hàm scanf().
- Phân biệt được sự khác nhau giữa hàm printf() của C và lệnh cout<<
của C++, sự khác nhau giữa hàm scanf() của C và lệnh cin>> của C++.
- Vận dụng được các hàm gets(), getline() để nhập chuỗi ký tự.
- Sử dụng được các cách khai báo biến, khởi tạo giá trị và gán giá trị cho
biến.
- Sử dụng các lệnh điều kiện, lệnh lặp một cách phù hợp.
- Sử dụng được các phép toán và lệnh đặc biệt.
- Vận dụng được cách biểu diễn thuật toán.
- Soạn thảo, biên dịch và thực thi được chương trình đơn giản viết bằng
ngôn ngữ C, C++ bằng phần mềm Dev C/C++.
3. Về thái độ:
- Nhận thức được tầm quan trọng của Học phần Nhập môn lập trình vì
đây là học phần nền tảng cho các học phần khác, là học phần mang tính chất
quyết định cho các học phần lập trình tiếp theo như Kỹ thuật lập trình, Phương
pháp lập trình hướng đối tượng, Cấu trúc dữ liệu và giải thuật, …
Nhận thức được tầm quan trọng của việc học ngôn ngữ lập trình C và
C++. Đây là 2 ngôn ngữ lập trình cơ bản, là nền tảng để học các ngôn ngữ lập
trình khác như C#, Java, Matlab,…
1. GIỚI THIỆU NGÔN NGỮ LẬP TRÌNH C , C++
1.1. Ngôn ngữ lập trình C
C là ngôn ngữ lập trình cấp cao, được thiết kế cho nhiều mục đích sử dụng
khác nhau. Ngôn ngữ C được sử dụng rất phổ biến để lập trình hệ thống cùng
với Assembly và phát triển các ứng dụng. Vào những năm cuối thập kỷ 60 đầu
thập kỷ 70 của thế kỷ XX, Dennish Ritchie đã phát triển ngôn ngữ lập trình C
1
dựa trên ngôn ngữ BCPL (do Martin Richards đưa ra vào năm 1967) và ngôn
ngữ B (do Ken Tompson phát triển từ ngôn ngữ BCPL vào năm 1970 khi viết hệ
điều hành UNIX đầu tiên trên máy PDP-7) và được cài đặt lần đầu tiên trên hệ
điều hành UNIX của máy DEC PDP-11. Năm 1978, Dennish Ritchie và B.W
Kernighan đã cho xuất bản quyển “Ngôn ngữ lập tình C” và được phổ biến rộng
rãi đến ngày nay.
Ngôn ngữ lập trình C là ngôn ngữ lập trình hệ thống rất mạnh và “mềm
dẻo”, có nhiều thư viện với rất nhiều hàm (function) được tạo sẵn nhằm hỗ trợ
cho lập trình viên sử dụng khi viết chương trình. Người lập trình có thể tận dụng
các hàm này để giải quyết các bài toán mà không cần phải tạo hàm mới. Hơn thế
nữa, ngôn ngữ C hỗ trợ rất nhiều phép toán nên phù hợp cho việc giải quyết các
bài toán kỹ thuật có nhiều công thức phức tạp. Ngoài ra, C cũng cho phép người
lập trình tự định nghĩa thêm các kiểu dữ liệu trừu tượng và các hàm người dùng
khác. Tuy nhiên, điều mà người mới học lập trình C thường gặp rắc rối là hơi
khó hiểu do sự mềm dẻo của C.
Điểm đặc biệt cần lưu ý là Ngôn ngữ C phân biệt chữ in hoa và chữ in
thường. Qua quá trình phát triển, ngôn ngữ C có nhiều phiên bản (version) khác
nhau. Các phiên bản thường được sử dụng nhiều là ANSI C, ISO C, C99, C11,
Embedded C.
Người lập trình có thể viết chương trình C bằng cách sử dụng các chương
trình tích hợp việc soạn thảo và biên dịch chương trình C như Microsoft Visual
C, Dev C/C++, Eclipse, …Chương trình được viết bằng ngôn ngữ C có phần mở
rộng là .c (đọc là chấm c). Trong quá trình soạn bày giảng này, tác giả minh họa
các chương trình C được viết và biên dịch bằng phần mềm mã nguồn mở và
miễn phí Dev C/C++.
Ví dụ 1.1: Minh họa viết chương trình C trong Dev C/C++
Hình 1.1. Chương trình được viết bằng ngôn ngữ C trong Dev C/C++.
2
1.2. Ngôn ngữ lập trình C++
C++ (đọc là C cộng cộng) là ngôn ngữ lập trình hướng đối tượng, được
thiết kế cho đa mục đích sử dụng. Ngôn ngữ lập trình C++ được xem như là sự
mở rộng hay sự phát triển tiếp theo của ngôn ngữ lập trình C. Ngôn ngữ C++
bao gồm tất cả các kiểu dữ liệu, phép toán, câu lệnh của C. Bên canh đó, C++
cũng có thêm các kiểu dữ liệu, phép toán, câu lệnh của riêng nó. Nói cách khác,
tất cả những gì có trong ngôn ngữ lập trình C đều sử dụng được trong ngôn ngữ
lập trình C++. Hiện tại, có 4 chuẩn C++ thông dụng là C++98, C++03, C++11,
C++14.
Giống như ngôn ngữ lập trình C, người lập trình có thể viết chương trình
C++ bằng cách sử dụng các chương trình tích hợp việc soạn thảo và biên dịch
chương trình C++ như Microsoft Visual C++, Dev C/C++, Eclipse, …Chương
trình được viết bằng ngôn ngữ C++ có phần mở rộng là .cpp (đọc là chấm cpp).
Trong lúc soạn bày giảng này, tác giả sử dụng phần mềm mã nguồn mở và miễn
phí Dev C/C++ để viết và biên dịch chương trình được viết bằng C++.
Ví dụ 1.2: Minh họa viết chương trình C++ trong Dev C/C++
Hình 1.2. Chương trình được viết bằng ngôn ngữ C++ trong Dev C/C++
1.3. Bộ ký tự và ký hiệu
Ngôn ngữ lập trình C và C++ sử dụng các ký tự và ký hiệu sau:
- Bảng chữ cái in hoa và in thường : A, B,…, Z và a, b, …, z để đặt tên.
(Lưu ý: C và C++ phân biệt ký tự in hoa và ký tự in thường).
- Các ký hiệu dùng trong biểu thức : (, ).
- Các ký hiệu dùng để viết chú thích. (Lưu ý: ngôn ngữ C dùng /* chú
thích*/; ngôn ngữ C++ dùng // ở đầu dòng chú thích).
- Các ký số (chữ số) : 0, 1, …, 9.
- Các ký hiệu phép toán số học : +,-, *, /, %.
3
- Các ký hiệu phép so sánh : <, <=, >=, >, ==,!=.
- Các ký hiệu phép toán logic : !, ||,&&.
- Các ký hiệu phép toán trên bit : ~, |, &, ^, <<, >>.
- Các ký hiệu phép toán tăng, giảm : ++, --.
- Ký hiệu phép toán gán :=.
- Một số ký hiệu khác : ->, #, \,:, ?, …
1.4. Các từ khóa cơ bản
Từ khóa là những từ dành riêng của ngôn ngữ lập trình mang ý nghĩa đã
được quy định trước. Người lập trình không nên đặt tên biến trùng với từ khóa.
1.4.1. Một số từ khóa của ngôn ngữ C
auto
break
case
char
const
continue default
do
double
else
enum
extern
float
For
goto
if
int
long
register return
short
signed
sizeof
static
struct
switch
typedef union
unsigned void
valatile
while
1.4.2. Một số từ khóa của ngôn ngữ C++
Ngôn ngữ lập trình C++ sử dụng tất cả các từ khóa của ngôn ngữ C và có
thêm các từ khóa khác.
alignas
alignof
and
and_eq asm
auto
atomic_commit
bitand
Bitor
bool
case
catch
atomic_cancel
char
break
char16_1 char32_t
class
atomic_noexcept
compl
concept
const
constexpr
continue const constexpr
double
else
enum
explicit
export
dynamic_cast
extern
false
float
For
friend
goto
if
impor
inline
int
long
module
mutable
namespace new
noexcept
not
not_eq
nullptr
operator
or
or_eq
private
protected
public
registe
requires return
short
reinterpret_cast
signed
sizeof
static
static_cast
struct
static_assert
switch
template
this
throw
true
synchronized
try
typedef
typeid
union
unsigned thread_local
using
virtual
void
Volatile
wchar_t typename
while
xor
xor_eq
4
1.5. Cấu trúc một chương trình đơn giản
1.5.1. Chương trình đơn giản viết bằng ngôn ngữ C
Một chương trình đơn giản được viết bằng ngôn ngữ C phải có phần khai
báo sử dụng các thư viện bằng cú pháp #include <tên thư viện> và phần nội
dung chính của chương trình nằm trong hàm main():
- Thư viện phải sử dụng là stdio.h. Thư viện stdio.h chứa các hàm vào và
hàm ra chuẩn của ngôn ngữ C. Hàm vào là hàm dùng để nhập dữ liệu từ bàn
phím hoặc tập tin như hàm scanf(), gets(). Hàm ra là hàm xuất dữ liệu ra màn
hình, tập tin như hàm printf().
- Phần nội dung chính của chương chính chứa các câu lệnh khai báo biến,
các lệnh thực hiện phép tính, lệnh nhập dữ liệu từ thiết bị nhập chuẩn, lệnh xuất
dữ liệu ra thiết bị xuất chuẩn.
Ví dụ 1.3: Chương trình đơn giản được viết bằng ngôn ngữ C
#include <stdio.h>
int main ()
{
char ten[50];
printf("Xin cho biet ten cua ban !");
gets(ten);
printf("Xin chao ban %s\n ", ten);
return 1;
}
/*Khai bao bien ten*/
/*Ham xuat*/
/*Ham nhap du lieu*/
/*Ham xuat*/
Hình 1.3. Chương trình đơn giản được viết bằng ngôn ngữ C
1.5.2. Chương trình đơn giản viết bằng ngôn ngữ C++
Một chương trình đơn giản được viết bằng ngôn ngữ C++ phải có phần
khai báo sử dụng các thư viện bằng cú pháp #include <tên thư viện>, using
namespace std và phần chính của chương trình nằm trong hàm main():
- Thư viện thường phải sử dụng là iostream. Thư viện iostream chứa các
lệnh vào và lệnh ra chuẩn của ngôn ngữ C++. Lệnh vào chuẩn của C++ là cin>>
để đọc dữ liệu từ bàn phím. Lệnh ra chuẩn của C++ là cout<< để xuất dữ liệu ra
màn hình. Tuy nhiên, người lập trình vẫn có thể dùng hàm scanf() để nhập dữ
liệu và dùng hàm printf() để xuất dữ liệu trong chương trình C++. Vì C++ là một
ngôn ngữ lập trình hướng đối tượng nên không gian tên std (using namespace
std) chứa các lớp thao tác cơ bản của C++ và phương thức của các lớp đó.
- Phần nội dung chính của chương trình (hàm main) chứa các câu lệnh khai
báo, lệnh thực hiện phép tính, lệnh nhập dữ liệu, lệnh xuất dữ liệu.
Ví dụ 1.4: Chương trình đơn giản được viết bằng ngôn ngữ C++
#include <iostream>
using namespace std;
int main ()
{
5
char ten[50];
cout<< "Ban ten gi? ";
gets(ten);
cout<< "Chao ban " << ten;
return 1;
}
Hình 1.4. Chương trình đơn giản được viết bằng ngôn ngữ C++
1.6. Cách ghi chú thích
Cách viết ghi chú của ngôn ngữ C là đặt nội dung ghi chú giữa /* và */.
Cách viết ghi chú của ngôn ngữ C++ là đặt dấu // trước dòng ghi chú. Khi viết
chương trình bằng ngôn ngữ C++, người lập trình có thể sử dụng cách viết chú
thích của ngôn ngữ C hoặc của C++.
Ví dụ 1.5: Cách viết chú thích
Hình 1.5. Ví dụ cách viết chú thích
2. KIỂU DỮ LIỆU CHUẨN, BIỂU THỨC VÀ PHÉP TOÁN CƠ BẢN
2.1. Các kiểu dữ liệu chuẩn
Kiểu dữ liệu chuẩn là kiểu dữ liệu được định nghĩa sẵn bởi ngôn ngữ lập
trình đi kèm với các phép toán cơ bản trên kiểu dữ liệu. Ngôn ngữ lập trình C và
C++ sử dụng chung các kiểu dữ liệu chuẩn và các phép số học, phép toán so
sánh, phép toán logic,… để thực hiện việc tính toán trên các kiểu dữ liệu chuẩn.
Bảng 1.1. Các kiểu dữ liệu chuẩn trong C và C++
Kiểu dữ liệu
Kích
thước
1
unsigned char
1 byte
2
3
4
5
char
enum
unsigned int
int
1 byte
2 bytes
2 bytes
2 bytes
STT
Miền giá trị (Domain)
Từ 0 đến 255 (tương đương
256 ký tự trong bảng mã ASCII)
Từ -128 đến 127
Từ -32,768 đến 32,767
Từ 0 đến 65,535
Từ -32,768 đến 32,767
6
Số
nguyên





6
unsigned long
Kích
thước
4 bytes
7
long
4 bytes
8
float
4 bytes
9
double
8 bytes
10
long double
10
bytes
Kiểu dữ liệu
STT
Số
nguyên

Miền giá trị (Domain)
Từ 0 đến 4,294,967,295
Từ
-2,147,483,648
2,147,483,647
Số thực dấu chấm động có
cỡ 4 byte
Số thực dấu chấm động có
cỡ 8 byte
Số thực dấu chấm động có
cỡ 10 byte
đến

kích
kích
kích
2.2. Biểu thức
Biểu thức là sự kết hợp hợp lệ giữa các toán hạng và các toán tử (toán
tử còn được gọi là phép toán) để trả về kết quả là một giá trị thuộc vào các
kiểu dữ liệu chuẩn.
- Toán hạng có thể là các hằng số, biến, các hàm số hay các biểu thức.
- Toán tử là các phép toán số học, logic, ….
Ví dụ 1.6: Một số biểu thức trong C và C++
(2+3)*2 +1;
Chu vi=a+b+a;
Nua_CV=(a+b+c)/2;
Dien_Tich=sqrt(Nua_CV*(Nua_CV-a)*(Nua_CV-b)*(Nua_CV-c));
2.3. Phép toán
Quy ước:
- Nội đung đặt trong cặp dấu < > là nội dung bắt buộc.
- Nội dung đặt trong cặp dấu [ ] là nội dung không bắt buộc.
2.3.1. Phép toán số học
Phép toán số học bao gồm các phép toán 1 ngôi và phép toán 2 ngôi.
- Phép toán 1 ngôi: Là phép toán chỉ cần 1 toán hạn dạng. Toán tử có
thể đặt ở phía trước hoặc phía sau toán hạng.
- Phép toán 2 ngôi: Là phép toán cần 2 toán hạng. Phép toán 2 ngôi
được viết giữa 2 toán hạng.
Bảng 1.2. Các phép toán số học trong C, C++
Loại
1 ngôi
Kết
quả
Phép
toán
Ý nghĩa
-(a)
Lấy số đối
3
++a
Tăng
a=2.5
Kiểu toán hạng
Kiểu kết quả
Ví dụ
char, int, long, char, int, long,
-(-3)
float, double
float, double
1 char, int, long, char, int, long, a=1.5
7
Loại
2 ngôi
Phép
Ý nghĩa
toán
a++ đơn vị
--a Giảm
1
a-- đơn vị
Kiểu toán hạng
Kiểu kết quả
Ví dụ
float, double
char, int, long,
float, double
char, int, long,
float, double
char, int, long,
float, double
char, int, long,
float, double
char, int, long,
float, double
float, double
char, int, long,
float, double
Giống
kiểu
toán hạng
Giống
kiểu
toán hạng
Giống
kiểu
toán hạng
Số nguyên
Số thực
++a
a=1.5
--a
Số nguyên
+
Cộng 2 số
-
Trừ 2 số
*
Nhân 2 số
/
Chia
%
Chia lấy
char, int, long,
số dư
Kết
quả
a=0.5
3+2
5
3-2
1
3*2
6
3/2
3.0/2
1
1.5
3%2
1
Lưu ý:
- Khi chia số nguyên cho số nguyên thì kết quả mặc định là phần nguyên
của phép chia. Kết quả của phép chia 3/2 phải là 1 vì 3 và 2 là hai số nguyên. Do
đó, muốn kết quả của phép chia là số thực thì người lập trình phải chuyển kiểu
dữ liệu của số bị chia hoặc của số chia qua kiểu số thực.
Ví dụ 1.7: Kết quả của phép chia 3.0/2 là 1.5 vì 3.0 là số thực hoặc kết quả
của phép chia 3/2.0 là 1.5 vì 2.0 là số thực.
Khi thực hiện biểu thức có nhiều phép toán, nên sử dụng cặp dấu (, ) để quy
định mức độ ưu tiên phép toán cần thực hiện trước. Mức độ ưu tiên mặc định
của các phép toán trong một biểu thức được xác định trong bảng dưới đây:
Bảng 1.3. Mức độ ưu tiên của phép toán trong C, C++
Mức độ ưu tiên
1
2
3
Các phép toán
- (lấy số đối)
*, /, % (nhân, chia, lấy phần dư)
+, - (cộng, trừ)
Thứ tự kết hợp
Trái qua phải
Trái qua phải
2.3.2. Phép toán so sánh
Các phép toán so sánh thực hiện việc so sánh và trả về kết quả là giá trị
đúng (true hoặc 1) hoặc sai (false hoặc 0).
Bảng 1.4. Các phép toán so sánh
Phép toán
>
>=
<
<=
==
!=
Ý nghĩa
Lớn hơn
Lớn hơn hoặc bằng
Nhỏ hơn
Nhỏ hơn hoặc bằng
Bằng
Không bằng (khác)
8
Ví dụ
7>5
7>=5
7<5
7<=5
7= = 5
7!=5
Kết quả
1
1
0
0
0
1
Lưu ý:
- Kết quả của phép toán so sánh là một số nguyên kiểu int (nếu đúng thì trả
về kết quả là 1, sai thì trả về kết quả là 0).
- Các phép toán so sánh có độ ưu tiên thấp hơn các phép toán số học.Nếu
không sử dụng cặp dấu (,) để xác định mức độ ưu tiên của từng hạng tử trong
biểu thức thì chương trình biên dịch sử dụng thứ tự ưu tiên giữa các phép so
sánh được cho theo bảng sau:
Bảng 1.5. Mức độ ưu tiên của các phép toán so sánh
Mức độ ưu tiên
1
2
Các phép toán Thứ tự kết hợp
<, <=, >, >=
Trái qua phải
==, !=
Trái qua phải
2.3.3. Phép toán luận lý
Các phép toán luận lý thực hiện việc kết hợp giữa các biểu thức so sánh và
trả về kết quả là giá trị đúng hoặc sai. Bao gồm các phép toán sau:
Bảng 1.6. Các phép toán logic
Ý nghĩa
NOT (phủ định)
AND (Phép giao)
OR (Phép hoặc)
Phép toán
!
&&
||
Độ ưu tiên
1
2
3
Lưu ý:
- Khi kết hợp giữa các phép toán so sánh và logic trong cùng một biểu thức
thì nên đặt những phần ưu tiên vào cặp dấu (, ). Thứ tự ưu tiên mặc định được
cho theo bảng sau đây:
Bảng 1.7. Mức độ ưu tiên khi kết hợp phép toán so sánh và phép toán logic
Độ ưu tiên
1
2
3
4
5
Phép toán
Luận lý
Quan hệ
Quan hệ
Luận lý
Luận lý
Toán tử
Thứ tự kết hợp
!
>, >=, <, <= Từ trái qua pjải
==, !=
Từ trái qua phải
&&
||
2.3.4. Phép toán trên bit
Số nguyên trong ngôn ngữ lập trình C và C++ được lưu trữ dưới dạng
số nhị phân. Do đó, ngôn ngữ C và C++ cung cấp các phép toán thao tác
trực tiếp trên bit đối với các số nguyên (1 byte, 2 bytes, 4 bytes).
Bảng 1.8. Các phép toán thực hiện trên bit
Phép toán
~
Ý nghĩa
Ví dụ
~0
NOT BIT (lấy số bù 1 của
~1
số nhị phân)
~00001111
9
Kết quả
1
0
11110000
Phép toán
&
|
^
<<
>>
Ý nghĩa
Ví dụ
AND BIT (Giao 2 dãy 1 & 0
bit)
00001111 & 00000111
0|1
OR BIT (Hoặc 2 dãy bit) 0 | 0
00001111 | 00000111
0^1
XOR BIT (Hoặc loại trừ 2
1^1
dãy bit)
00001111 ^ 00000111
Dịch trái k bit (tương 00001111<<1
dương với nhân số 00000111>>1
nguyên x với 2k)
Dịch phải k bit (tương 101010>>1
đương với lấy phần 101010>>2
nguyên khi chia số
nguyên x cho 2k)
Kết quả
0
00000111
1
0
00001111
1
0
00001000
00011111
00000011
10101
1010
Lưu ý:
- Các phép toán này chỉ thực hiện trên các số nguyên như: char (1 bytes),
int (2 bytes), long (4 bytes). Khi thực hiện phép toán trên các số nguyên có kiểu
trên, thực chất là thực hiện trên dãy số nhị phân (8 bits, 16 bits, 32 bits) bằng
cách đổi các ký tự (char), số (char, int, long) sang số nhị phân tương ứng.
- Người học cần phân biệt sự khác nhau giữa các phép toán trên BIT và các
phép toán luận lý về ký hiệu và ý nghĩa : NOT (!, ~), AND (&&, &), OR (||, |).
Ví dụ 1.8: Thực hiện một số phép toán trên bit
Hình 1.6. Minh họa sử dụng các phép toán trên bit
10
Hình 1.7. Kết quả minh họa sử dụng các phép toán trên bit
2.3.5. Phép toán dấu phẩy
Phép toán phẩy(,) là phép toán đặt biệt dùng để tách 2 biểu thức trong biểu
thức kép. Kết quả của biểu thức phẩy là giá trị và kiểu dữ liệu của biểu thức bên
phải dấu phẩy.
Cú pháp sử dụng:
(<biểu thức 1>, <biểu thức 2>)
Ví dụ 1.9: Phép toán phẩy
Hình 1.8. Minh họa sử dụng phép toán phẩy
Hình 1.9. Kết quả minh họa sử dụng phép toán phẩy
11
2.3.6. Phép toán điều kiện
Phép toán điều kiện (?,:) bao gồm việc so sánh và trả về kết quả. Có cú
pháp sử dụng như sau:
<Điều kiện> ? <Biểu thức 1>: <Biểu thức 2>
• Nếu điều kiện đúng thì trả về kết quả là kết quả của Biểu thức 1.
• Nếu điều kiện sai thì trả về kết quả là kết quả của Biểu thức 2.
Ví dụ 1.10: Phép toán điều kiện
Hình 1.10. Minh họa phép toán điều kiện
Hình 1.11. Kết quả minh họa phép toán điều kiện
2.4. Chuyển đổi kiểu dữ liệu trong C, C++
Khi thực hiện một biểu thức mà các toán hạng có kiểu dữ liệu khác nhau thì
bắt buộc phải đổi kiểu dữ liệu của các toán hạng cùng về một kiểu nào đó.
Chương trình biên dịch C, C++ tự động đổi kiểu dữ liệu khi cần thiết hoặc người
lập trình dùng lệnh ép kiểu dữ liệu.
2.4.1. Chuyển đổi kiểu dữ liệu tự động
Chương trình biên dịch tự động đổi kiểu của các toán hạng trong biểu thức
sao cho phù hợp với các toán hạng còn lại. Chương trình biên dịch tự đổi kiểu
dữ liệu của toán hạng có kích thước nhỏ sang kiểu dữ liệu có kích thước lớn hơn
cho phù hợp với các toán hạng khác.
Ví dụ 1.11:
char c= ' A ';
int a=65, kq;
kq=c+a;
Khai báo c là kiểu char và a là kiểu int. Khi thực hiện phép toán c+a thì
trình biên dịch tự động đổi kiểu dữ liệu của biến c (1 byte) thành kiểu int (2
byte) trước khi thực hiện phép cộng nên kết quả không sai.
12
Ví dụ 1.12: Khai bao a là biến kiểu int có giá trị là 1000, c là biến kiểu
unsigned char. Khi thực hiện phép gán c=a thì giá trị của c sẻ là 232 như sau:
Hình 1.12. Minh họa chuyển đổi kiểu tự động
Hình 1.13. Kết quả minh họa chuyển đổi kiểu tự động
Giải thích:
- Khi thực hiện phép gán (=) thì sự chuyển kiểu dữ liệu căn cứ vào kiểu dữ
liệu của biến ở bên trái dấu bằng.
- Đổi sô 1000 sang số nhị phân 2 byte là (0000000011 11101000)2
- Lấy 1 byte (8 bit) thấp là (11101000)2 gán cho biến c.
- Đổi số nhị phân (11101000)2 sang hệ thập phân là 27+26+25+23=232.
=> Do đó, giá trị của c là 232.
Ví dụ 1.13: Bị mất dữ liệu (kết quả sai) do ép kiểu tự động
#include <stdio.h>
int main()
{
int a=100,b=6;
double f=a/b;
printf("\n Gia tri cua bien a=%d, b=%d", a, b);
printf("\n Gia tri cua bien f =%f", f);
return 1;
}
Hình 1.14. Minh họa bị mất dữ liệu (kết quả sai) do ép kiểu tự động
Hình 1.15. Kết quả minh họa bị mất dữ liệu (kết quả sai) do ép kiểu tự động
13
2.4.2. Dùng hàm ép kiểu
Trình biên dịch ngôn ngữ lập trình C và C++ tự động đổi kiểu dữ liệu của
biến và giá trị hằng số trước khi thực hiện phép tính. Quy định tự động đổi kiểu
dữ liệu là một ưu điểm của trình biên dịch. Tuy nhiên, đôi lúc việc tự động đổi
kiểu đó dẫn đến kết quả sai (do người lập trình khai báo biến không phù hợp).
Để tránh trường hợp mất dữ liệu khi chuyển kiểu tự động thì người lập
trình có thể sử dụng lệnh đổi kiểu dữ liệu cho các biến theo cú pháp:
(<Tên kiểu dữ liệu mới>)<Giá trị hoặc biến cần ép kiểu>
Ví dụ 1.14: Dùng lệnh ép kiểu dữ liệu
#include <stdio.h>
int main()
{
int a=100, b=6;
double f=(double)a/(double)b;
printf("\n Gia tri cua bien a=%d, b=%d", a, b);
printf("\n Gia tri cua bien f =%f", f);
return 1;
}
Hình 1.16. Minh họa dùng lệnh ép kiểu dữ liệu
Hình 1.17. Kết quả minh họa dùng lệnh ép kiểu dữ liệu
3. BIỂU DIỄN GIÁ TRỊ KIỂU SỐ
3.1. Mối tương quan giữa bảng mã ASCII và kiểu dữ liệu unsigned char
Ngôn ngữ lập trình C và C++ sử dụng kiểu dữ liệu char để lưu các số
nguyên từ -128 đến 127 và kiểu unsigned char để lưu các số nguyên từ 0 đến
256. Giá trị của kiểu unsigned char tương ứng với 256 ký tự trong bảng mã
ASCII.
Ví dụ 1.15: ký tự A có giá trị là 65, ký tự a có giá trị là 97 nên A và a là 2
ký tự khác nhau.
Lưu ý:
- Khi dùng hàm printf() của C để in giá trị kiểu char hoặc unsigned char thì
kết quả in ra màn hình hoặc lưu vào tập tin phụ thuộc vào chuỗi ký tự định dạng
của hàm printf() khi in. Tuy nhiên, khi dùng lệnh cout<< của C++ để in giá trị
kiểu char hoặc unsigned char thì kết quả luôn luôn là ký tự.
Ví dụ 1.16: Xuất giá trị kiểu char, unsigned bằng printf() và cout<<
14
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
char c='a';
unsigned char uc='A';
float PI=3.14159265359;
printf("Printf(): Gia tri cua c la %c tuong duong %d \n", c, c);
printf("Printf(): Gia tri cua uc la %c tuong duong %d \n", uc, uc);
cout<<"Cout: Gia tri cua c la " << c << endl;
cout<<"Cout: Gia tri cua uc la " <<uc << endl;
cout<<"PI=" << PI;
return 1;
}
Hình 1.18. Minh họa xuất giá trị kiểu char, unsigned char
Hình 1.19. Kết quả minh họa xuất giá trị kiểu char, unsigned char
Hình 1.20. 128 ký tự đầu tiên trong bảng mã ASCII
15
Hình 1.21. 128 ký tự cuối cùng trong bảng mã ASCII
3.2. Biểu diễn hằng giá trị
- Hằng giá trị số nguyên thì viết bình thường, nếu số nguyên âm thì thêm
dấu trừ (-) vào phía trước.
Ví dụ 1.17: - 12345, 12345 là những bằng giá trị nguyên.
- Đối với các số thực thì dùng dấu chấm để phân cách phần nguyên và phần
thập phân.
Ví dụ 1.18: -123.45, 123.45 là những hằng giá trị số thực.
- Đối với 1 ký tự thì đặt trong cặp dấu nháy đơn  
Ví dụ 1.19: A, a là những hằng ký tự.
- Đối với một chuỗi ký tự thì đặt trong cặp dấu nháy đôi " ".
Ví dụ 1.20: "Nhập môn lập trình", "Dương Văn Hiếu" là những hằng chuỗi
ký tự.
Ví dụ 1.21: In hằng giá trị bằng hàm printf()
#include <stdio.h>
int main()
{
printf("Ket qua in so nguyen 12345 la %d\n", 12345);
printf("Ket qua in so nguyen -12345 la %d\n" ,-12345);
printf("Ket qua in so thuc 3.14159265359 la %f\n", 3.14159265359);
printf("Ket qua in ky tu A la %c\n", 'A');
printf("Ket qua in chuoi Nhap monLT la %s", "Nhap mon LT");
return 1;
}
Hình 1.22. Minh họa in hằng giá trị bằng hàm printf()
16
Hình 1.23. Kết quả minh họa in hằng giá trị bằng hàm printf()
Ví dụ 1.22: In hằng giá trị bằng lệnh cout<<
#include <iostream>
using namespace std;
int main()
{
cout<<"Ket qua in so nguyen 12345 la " << 12345 << endl;
cout<<"Ket qua in so nguyen -12345 la " << -12345 << endl;
cout<<"Ket qua in so thuc 3.14159265359 la " << 3.14159265359 << endl;
cout<<"Ket qua in ky tu A la " << 'A' << endl;
cout<<"Ket qua in chuoi Nhap monLT la " << "Nhap mon LT";
return 1;
}
Hình 1.24. Minh họa in hằng giá trị bằng lệnh cout<<
Hình 1.25. Kết quả minh họa in hằng giá trị bằng lệnh cout<<
4. SỬ DỤNG BIẾN
4.1. Định nghĩa biến
Trong lập trình, biến là một đại lượng có giá trị thay đổi theo thời gian tùy
vào các điều kiện khi thực hiện chương trình. Hay nói cách khác, biến là một cái
tên mà giá trị của nó không cố định, giá trị của biến được thay đổi tùy vào điều
kiện thi chạy chương trình.
Tên biến là một chuỗi gồm ký tự, ký số, dấu gạch dưới. Ký tự đầu tiên của
biến phải là chữ cái. Tên biến trong C và C++ phân biệt chữ in hoa và chữ in
thường. Khi đặt tên biến, cần chú ý đặt tên có ý nghĩa gắn liền với giá trị của
biến hoặc mục đích sử dụng của biến. Tên biến không được trùng với từ khóa
của ngôn ngữ lập trình.
17
Ví dụ 1.23:
Bien1, bien1 là 2 biến khác nhau và hợp lệ.
Bien_1, bien_1 là 2 biến khác nhau và hợp lệ.
Bien 1, bien-1, 1bien là 3 biến khác nhau và không hợp lệ.
4.2. Khai báo và gán giá trị khởi tạo cho biến
Đối với ngôn ngữ lập trình C và C++, các biến cần phải được khai báo
trước khi sử dụng. Khi khai báo biến thì chúng ta cần phải trả lời các câu hỏi
sau:
1. Biến này dùng để lưu dữ liệu kiểu gì? => Để chọn đúng kiểu dữ liệu
char, unsigned char, int, unsigned int,…)
2. Biến này có cần giá trị khởi tạo hay không? Nếu có thì giá trị khởi tạo là
gì? => Để khởi tạo giá trị cho biến đúng lúc và dung giá trị.
3. Biến này sẻ được phần nào của chương trình sử dụng? =>Để khai báo
đúng vị trí (biến toàn cục, biến cục bộ).
Khi cần khai báo nhiều biến có cùng 1 kiểu dữ liệu thì có thể khai báo
chung trên cùng 1 dòng, mỗi biến cách nhau bởi 1 dấu phẩy. Chúng ta có thể
gán giá trị khởi tạo cho biến trong lúc khai báo biến hoặc gán giá trị cho biến
sau khi khai báo. Cú pháp khai báo biến:
<Kiểu dữ liệu> <Tên biến 1>[, tên biến 2 [, ]];
Hoặc
<Kiểu dữ liệu> <Tên biến = Giá trị khởi tạo>[, Tên biến = Giá trị khởi tạo [, ]];
Ví dụ 1.24: Gán giá trị cho biến lúc khởi tạo
Hình 1.26. Minh họa gán giá trị cho biến lúc khởi tạo
Hình 1.27. Kết quả minh họa gán giá trị cho biến lúc khởi tạo
18
4.3. Gán giá trị cho biến
Cách 1: Biến có thể được gán giá trị khi thực hiện chương trình thông qua
lệnh gán giá trị. Lệnh gán giá trị cho biến được thực hiện bằng cú pháp sau:
<Tên biến> = <hằng giá trị>;
Hoặc
<Tên biến> = <Biểu thức>;
Ví dụ 1.25: Gán giá trị cho biến bằng hằng giá trị, biểu thức
#include <iostream>
using namespace std;
int main()
{
/*Tinh dien tich hinh chu nhat*/
int a, b, cv, dt;
a=5; b=10; cv=(a+b)*2;
dt=a*b;
cout<<"Do dai 2 canh cua hinh chu nhat la "<<a << " va " << b << endl;
cout<<"Hinh chu nhat co chu vi la " << cv << endl;
cout<<"Hinh chu nhat co dien tich la " << dt;
return 1;
}
Hình 1.28. Minh họa gán giá trị cho biến bằng hằng giá trị, biểu thức
Hình 1.29. Kết quả minh họa gán giá trị cho biến bằng hằng giá trị, biểu thức
Cách 2: Biến cũng có thể được khai báo trước, sau đó được gán giá trị
bằng cách nhập dữ liệu từ bàn phím thông qua các hàm scanf(), gets(), getline()
hoặc lệnh cin>>. Nội dung này sẻ được giải thích rõ hơn trong phần nhập, xuất
giá trị của biến.
Ví dụ 1.26: Gán giá trị cho biến bằng cách đọc dữ liệu bằng cin>>
#include <iostream>
using namespace std;
int main()
{
int a, b, cv, dt;
cout<<"Nhap vao 2 so nguyen la canh cua hinh chu nhat =";
cin>>a>>b;
cv=(a+b)*2;
19
dt=a*b;
/*Tinh dien tich hinh chu nhat*/
cout<<"Hinh chu nhat co chu vi=" << cv << " dien tich =" << dt;
return 1;
}
Hình 1.30. Minh họa gán giá trị cho biến bằng cách đọc dữ liệu bằng cin>>
Hình 1.31. Kết quả minh họa gán giá trị cho biến bằng cách đọc dữ liệu bằng cin>>
4.4. Vị trí khai báo biến
Khi lập trình, biến phải được khai báo đúng vị trí. Nếu khai báo biên không
đúng vị trí sẻ dẫn đến những sai sót ngoài ý muốn mà người lập trình không
lường trước (gọi là hiệu ứng lề). Chúng ta có 2 cách đặt vị trí của biến như sau:
4.4.1. Cách 1: Khai báo biến toàn cục
Các biến này được đặt bên ngoài tất cả các hàm và được gọi là biến toàn
cục. Biến toàn cục được sử dụng bởi chương trình chính và tất cả các chương
trình con. Mọi sự thay đổi trên biến toàn cục đều ảnh hưởng đến kết quả của tất
cả các chương trình con có sử dụng biến toàn cục và chương trình chính. Do đó,
chỉ sử dụng biến toàn cục trong trường hợp thật sự cần thiết.
Ví dụ 1.27: Sử dụng biến toàn cục.
#include <iostream>
using namespace std;
int x,y;
// Khai bao bien toan cuc x, y
int Magic()
/*Hoan vi gia tri cua 2 bien toan cuc*/
{
x=x+y;
y=x-y;
x=x-y;
}
int main()
{
x=10; // Gan gia tri toan cuc x
y=20;
cout <<"Truoc khi goi ham Magic(): x=" << x << " y=" << y << endl;
Magic();
cout <<"Truoc khi goi ham Magic(): x=" << x << " y=" << y << endl;
return 1;
}
Hình 1.32. Minh họa sử dụng biến toàn cục
20
4.4.2. Cách 2: Khai báo biến cục bộ
Các biến được khai báo ở bên trong chương trình con, bên trong chương
trình chính, bên trong một khối lệnh được gọi là biến cục bộ. Các biến cục bộ
chỉ được sử dụng bởi chương trình hay khối lệnh chứa nó. Mọi sự thay đổi của
biến cục bộ chỉ ảnh hưởng đến chương trình hay khối lệnh chứa nó.
Lưu ý:
- Nội dung chi tiết liên quan đến việc khai báo biến cục bộ sẻ được trình
bày thêm ở chương 2 và các chương tiếp theo.
- Có thể khai báo 2 biến trùng tên tại 2 khối lệnh khác nhau.
Ví dụ 1.28: Khai báo biến cục bộ trùng tên trong 2 khối khác nhau
#include <iostream>
#include <time.h>
#include <stdlib.h>
using namespace std;
int main()
{
srand(time(NULL));
//Khoi tao bo tinh so ngau nhien
int x=rand(), y=rand();
cout <<"Ket qua khoi tao: x=" << x << " y=" << y << endl;
if(x>y)
{
int tong=x-y;
cout << " x-y= " << x << "-" << y << " = " << tong << endl;
}
else
{
int tong=y-x;
cout << " y-x= " << y << "-" << x << " = " << tong << endl;
}
return 1;
}
Hình 1.33. Minh họa sử dụng biến cục bộ trùng tên trong 2 khối khác nhau
4.5. Nhập xuất giá trị của biến
4.5.1. Giới thiệu
Người lập trình cần hiểu thật rõ cách nhập, xuất giá trị của biến bằng cách
sử dụng hàm scanf() và printf() của ngôn ngữ lập trình C. Nếu sử dụng không
đúng thì có thể xuất ra kết qủa sai. Để dùng hàm scanf() và printf(), cần khai báo
sử dụng thư viện stdio.h.
21
4.5.2. Nhập giá trị cho biến bằng hàm scanf()
Cú pháp sử dụng hàm dụng hàm scanf():
scanf(<Chuỗi định dạng> [, Các biến cách nhau bởi dấu phẩy]);
Lưu ý:
- Chuỗi định dạng quy định kiểu dữ liệu cần nhập. Hàm scanf() sử dụng
chuỗi định dạng là "%type" cho từng biến. Nếu nhập cùng lúc nhiều giá trị cho
nhiều biến thì chuỗi định dạng sẻ là "%type %type …" và mỗi biến được viết
cách nhau bởi dấu phẩy.
- Bắt buộc phải có dấu & phía trước tên biến thuộc các kiểu dữ liệu chuẩn
đã được liệt kê trong Bảng 1.1.
- Giá trị của tham số type cho biết kiểu dữ liệu cần nhập, sẻ được giải thích
trong phần sử dụng hàm printf(). Giá trị của tham số type được trình bày trong
Bảng 1.10.
Ví dụ:
int a, b; //khai bao 2 bien luu so nguyen
scanf("%d%d",&a,&b); //Nhap gia tri cho 2 bien a, b.
4.5.3. Xuất giá trị của biến bằng hàm printf()
Cú pháp sử dụng hàm printf():
printf(<Chuỗi định dạng> [, các giá trị hoặc biến cách nhau bởi dấu phẩy]);
Lưu ý:
- Chuỗi định dạng quy định kiểu dữ liệu cần xuất.
- Hàm printf() sử dụng chuỗi định dạng "%[flags][width][.precision]type"
cho từng giá trị hoặc biến.
- Nếu xuất cùng lúc nhiều giá trị của nhiều biến thì chuỗi định dạng sẻ là
"%[flags][width][.precision]type %[flags][width][.precision]type …" và mỗi giá
trị hoặc biến được viết cách nhau bởi dấu phẩy.
- Chuỗi định dạng của hàm printf() có thể chứa hằng chuỗi ký tự.
- Giá trị của tham số flags được quy định trong Bảng 1.9.
Ví dụ:
int a=10, b=11;
printf("a=%x, b=%x", a, b); // in gia trị cua a và b dang thap luc phan.
* Ý nghĩa của các phần chuỗi định dạng:
width: Cho biết độ rộng cần in là bao nhiêu ký tự.
.precision: Cho biết độ chính xác cần in, bao nhiêu số thập phân.
flags: Cho biết cách in dữ liệu dạng số.
type: Cho biết kiểu dữ liệu.
22
Bảng 1.9. Giá trị của tham số flags trong chuỗi định dạng của hàm printf()
flags
Ý nghĩa
-
In canh trái trong khoảng không gian được quy định.
+
Thêm dấu +, - phía trước số
0
Thêm số 0 bên trái dãy số
#x
Thêm 0x phía trước số thập lục phân
#o
Thêm 0 phía trước số bác phân
Bảng 1.10. Giá trị của tham số type trong chuỗi định dạng của hàm scanf() và printf()
type
Ý nghĩa
i, d, u
Nhập hoặc xuất giá trị là số nguyên trong hệ thập phân
o
Nhập hoặc xuất giá trị là số nguyên trong hệ bác phân
x
Nhập hoặc xuất giá trị là số nguyên trong hệ thập lục phân
f, e, g
Nhập hoặc xuất giá trị số thực trong hệ thập phân
Nhập hoặc xuất giá trị là 1 ký tự.
c
Lưu ý: Sử dụng hàm fflush(stdin) để loại bỏ nội dung “rác” còn
nằm trong vùng đệm của bàn phím trước khi đọc ký tự.
Nhập hoặc xuất giá trị là 1 chuỗi ký tự.
Lưu ý:
- Sử dụng hàm fflush(stdin) trước khi đọc 1 chuỗi ký tự.
s
- Hàm scanf() chỉ nhập được một chuỗi ký tự không chứa khoảng
trắng.
- Để nhập một chuỗi ký tự có chứa khoảng trắng thì phải dùng
hàm gets(<Tên biến>)
Ví dụ 1.29: Minh họa sử dụng chuỗi định dạng của hàm printf()
#include <stdio.h>
int main()
{
printf ("In ky tu: %c %c \n", 'a', 65);
printf ("In so nguyen: %d %ld\n", 1977, 650000L);
printf ("In so nguyen co dinh dang: %10d \n", 1977);
printf ("In so nguyen co dinh dang: %010d \n", 1977);
printf ("In so nguyen co dinh dang: %*d \n", 5, 10);
printf ("In so nguyen 100 theo cac he khac nhau \n(he thap phan, thap luc
23
phan, bac phan): %d %x %o %#x %#o \n", 100,100,100,100,100);
printf ("In so thuc: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);
printf ("In chuoi ky tu: %s \n", "A string");
return 1;
}
Hình 1.34. Minh họa sử dụng chuỗi định dạng của hàm printf()
Hình 1.35. Kết quả minh họa sử dụng chuỗi định dạng của hàm printf()
Ví dụ 1.30: Nhập , xuất giá trị của biến bằng hàm scanf() và printf(). Nhập
số ở hệ thập lục phân, xuất số ở hệ thập phân.
Hình 1.36. Minh họa nhập, xuất giá trị của biến bằng hàm scanf() và printf()
Hình 1.37. Kết quả minh họa nhập, xuất giá trị của biến bằng hàm scanf() và
printf()
24
4.5.4. Nhập, xuất giá trị của biến bằng lệnh cin>>, cout<< của C++
Ngôn ngữ lập trình C++ cho phép nhập giá trị cho biến bằng cách dùng
lệnh cin>> và xuất giá trị của biến bằng cách dùng lệnh cout<<.
Lệnh cin>> dùng để nhập giá trị cho 1 hoặc nhiều biến theo cú pháp sau:
cin>> <tên biến>
hoặc
cin>> <tên biến1> [>> <tên biến 2> [ ]];
Lưu ý:
- Nếu muốn dùng dụng lệnh cin>>, cout<< thì phải khai báo sử dụng thư
viện iostream và namespace std ở đầu chương trình.
- Giống như hàm scanf(), lệnh cin>> chỉ đọc được chuỗi ký tự không chứa
khoảng trắng. Muốn đọc chuỗi ký tự chứa khoảng trắng thì phải dùng hàm gets()
hoặc getline(). Muốn nhập chuỗi ký tự chứa khoảng trắng bằng hàm getline() thì
biến kiểu chuỗi ký tự phải được khai báo thuộc kiểu string.
gets(<Tên biến kiểu chuỗi ký tự>);
getline(cin, <Tên biến kiểu chuỗi ký tự>);
Ngôn ngữ C++ sử dụng lệnh cout << để xuất giá trị của 1 hoặc nhiều biến
theo cú pháp:
cout<< Tên biến>;
hoặc
cout<< <Tên biến1> [<<tên biến 2 [<<…<<tên biến n]];
Ví dụ 1.31: Nhập, xuất bằng cin>>, cout<<
#include <iostream>
#include <string>
using namespace std;
int main()
{
string input = "";
int myNumber = 0;
char myChar;
cout << "Nhap 1 cau co chua khoang trang: ";
getline(cin, input);
cout << "Nhap 1 so nguyen: ";
cin>>myNumber;
cout << "Nhap vao 1 ky tu: ";
cin>>myChar;
25
cout << "Cau vua nhap: " << input << endl;
cout << "So vua nhap: " << myNumber << endl;
cout << "Ky tu vua nhap: " << myChar;
return 1;
}
Hình 1.38. Minh họa nhập, xuất bằng cin>>, cout<<
Hình 1.39. Kết quả minh họa nhập, xuất bằng cin>>, cout<<
4.5.5. Sử dụng ký hiệu điều khiển khi xuất giá trị dữ liệu
Khi xuất dữ liệu, có thể sử dụng các ký tự điều khiển sau đây để in các ký
tự đặc biệt.
Bảng 1.11. Các ký tự điều khiển quan trọng khi xuất giá trị
Ký tự điều Giá trị thập Ký tự được
khiển
lục phân
hiển thị
\a
0x07
BEL
\b
0x08
\f
\n
\r
\t
\\
\
\
\?
\ddd
\xHHH
0x0C
0x0A
0x0D
0x09
0x5C
0x2C
0x22
0x3F
ddd
oxHHH
Ý nghĩa
Phát ra tiếng chuông
Di chuyển con trỏ sang trái 1 ký
BS
tự và xóa ký tự bên trái
FF
Sang trang
LF
Xuống dòng
CR
Trở về đầu dòng
HT
Tab theo cột
\
Dấu \
Dấu nháy đơn ()

Dấu nháy kép ()

?
Đấu chấm hỏi (?)
Ký tự có mã ACSII trong hệ bác phân
Ký tự có mã ACSII trong hệ thập lục phân
5. CÂU LỆNH VÀ KHỐI LỆNH
5.1. Câu lệnh
Trong C và C++, một tác vụ, một biểu thức hoặc một lệnh gán kết thúc
bằng dấu chấm phẩy (;) được gọi là một lệnh. Nói cách khác, câu lệnh là một
26
mệnh lệnh yêu cầu máy tính thực hiện một công việc nào đó và được kết thúc
bằng dấu chấm phẩy. Câu lệnh thường được chia ra thành nhiều dạng tùy vào
chức năng của nó như lệnh khai báo, lệnh gán, lệnh lựa chọn, lệnh lặp,…
Ví dụ 1.32: Câu lệnh
int a, b;
a=13;
printf(“\n Nhap vao mot so duong :”);
scanf(“%d”,&b);
/* đây là lệnh khai báo biến*/
/* đây là lệnh gán*/
/*tác vụ in chuỗi văn bản ra màn hình*/
/*tác vụ đọc giá trị cho biến b*/
Hình 1.40. Minh họa câu lệnh
5.2. Khối lệnh
Trong ngôn ngữ lập trình C và C++, một dãy các câu lệnh nằm trong cặp
dấu ngoặc móc {, } được gọi là một khối lệnh. Một khối lệnh có thể chứa nhiều
khối lệnh con nằm trong cặp dấu {, } và số khối lệnh con bên trong một khối
lệnh là vô hạn.
Ví dụ 1.33: Nội dung hàm main là 1 khối lệnh
#include <stdio.h>
int main()
{
printf ("Ky tu: %c %c \n", 'a', 65);
printf ("So thap phan: %d %ld\n", 1977, 650000L);
printf ("Dinh dang so thap phan: %10d \n", 1977);
printf ("Dinh dang so thap phan: %010d \n", 1977);
printf ("So thuc: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);
printf ("%s \n", "Chuoi ky tu");
return 1;
}
Hình 1.41. Minh họa khối lệnh
Lưu ý: Khi biết một khối lệnh có chứa các khối lệnh con:
- Dấu kết thúc khối lệnh } nên đặt nằm trên cùng một cột (thẳng cột) so với
dấu bắt đầu khối lệnh {.
- Tất cả các lệnh con bên trong một khối lệnh phải được thụt vào 1 Tab.
- Ngôn ngữ C, C++ cho phép khai báo các biến trùng tên nhau nếu các biến
này nằm trong các khối lệnh khác nhau.
- Nếu một biến được khai báo bên ngoài khối lệnh và không trùng tên với
biến bên trong khối lệnh thì nó cũng được sử dụng bên trong khối lệnh.
- Một khối lệnh con có thể sử dụng các biến bên ngoài khối. Nhưng các
lệnh bên ngoài khối lệnh con không thể sử dụng các biến bên trong khối lệnh
con.
27
Ví dụ 1.34: Sử dụng biến trong khối lệnh con
#include <stdio.h>
int main ()
{ /*Beginning of a main block*/
int a=5, b=10;
printf("Ngoai sub blocks : a=%d, b=%d\n",a,b);
{
/*sub block 1*/
int a=10, c=10;
printf("Trong sub block 1 : a=%d, b=%d, c=%d\n", a, b, c);
}
{
/*sub block 2*/
int a=20, c=20;
printf("Trong sub block 2 : a=%d, b=%d, c=%d\n", a, b, c);
{
/*sub block 2-1*/
int a=30, c=30;
printf("Trong sub block 2-1: a=%d, b=%d, c=%d\n", a, b, c);
}
}
return 1;
} /*Ending of a main block*/
Hình 1.42. Minh họa sử dụng biến trong khối lệnh con
Hình 1.43. Kết quả minh họa sử dụng biến trong khối lệnh con
6. CÁC LỆNH ĐIỀU KHIỂN
6.1. Giới thiệu
Để viết chương trình bằng ngôn ngữ lập trình C và C++, ngoài việc đòi hỏi
người lập trình phải biết cách sử dụng thư viện, khai báo biến, gán giá trị cho
biến, nhập dữ liệu cho biến từ thiết bị nhập chuẩn, xuất dữ liệu ra thiết bị xuất
chuẩn, người lập trình cần phải biết sử dụng các lệnh điều khiển hay các cấu trúc
điều khiển của ngôn ngữ lập trình.
6.2. Lệnh rẽ nhánh
Lệnh rẽ nhánh hay còn gọi là cấu trúc rẽ nhánh là lệnh có cấu trúc cho phép
lựa chọn thực hiện một khối lệnh nào đó ứng với các điều kiện đúng hoặc sai.
28
6.2.1. Các lệnh rẽ nhánh có điều kiện
a) Lệnh if không đầy đủ
Lệnh if không đầy đủ là lệnh rẽ nhánh có điều kiện tương đương với phát
biểu “Nếu điều kiện đúng thì thực hiện công việc, nếu điều kiện sai thì không
thực hiện công việc”. Ngôn ngữ lập trình C và C++ quy định cú pháp của lệnh if
không đầy đủ như sau:
if (<Biểu thức điều kiện>)
[Khối lệnh;]
Lưu đồ cú pháp:
- Kiểm tra điều kiện trước khi xử lý công việc:
+ Nếu điều kiện đúng thì thực hiện khối lệnh liền sau điều
Sai
kiện, sau đó kết thúc lệnh if
Điều kiện
+ Nếu điều kiện sai thì bỏ qua khối lệnh liền sau điều kiện,
Đúng
kết thúc lệnh if.
Công việc
Ví dụ 1.35: Lệnh if không đầy đủ
/*Coded by Dr.Duong Van Hieu on 16/10/2018*/
#include <stdio.h>
int main()
{
char kytu;
printf("Nhap ky tu:");
scanf("%c", &kytu);
if((kytu >=97)&&(kytu<=122))
{
printf("Ban da nhap chu in thuong\n");
printf("Ky tu vua nhap la %c co ma ASCII la %d", kytu, kytu);
}
return 1;
}
Hình 1.44. Minh họa lệnh if không đầy đủ
b) Lệnh if đầy đủ
Lệnh if…else hay lệnh if đầy đủ là lệnh rẽ nhánh có điều kiện tương đương
với phát biểu “Nếu điều kiện đúng thì thực hiện công việc 1, nếu điều kiện sai thì
thực hiện công việc 2”. Ngôn ngữ lập trình C và C++ quy định cú pháp của lệnh
if không đầy đủ như sau:
29
if (<Biểu thức điều kiện>)
<Khối lệnh 1>;
else
[Khối lệnh 2;]
Lưu đồ cú pháp:
- Kiểm tra điều kiện trước khi thực hiện công việc:
Điều kiện
Sai
Đúng
Khối lệnh 1
Khối lệnh 2
+Nếu điều kiện đúng thì thực hiện công việc 1 tương
ứng với khối lệnh 1, sau đó kết thúc lệnh.
+ Nếu điều kiện sai thì thực hiện công việc 2 tương
ứng với khối lệnh 2, sau đó kết thúc lệnh.
Ví dụ 1.36: Dùng lệnh if…else
#include <stdio.h>
int main()
{
char kytu;
printf("Nhap ky tu in thuong :");
scanf("%c", &kytu);
if((kytu >=97)&&(kytu<=122))
{
printf("Ban da nhap chu in thuong\n");
printf("Ky tu vua nhap la %c co ma ASCII la %d",kytu, kytu);
}
else
printf("Ky tu vua nhap khong phai ky tu in thuong");
return 1;
}
Hình 1.45. Minh họa sử dụng lệnh if…else
Lệnh if … else có thể được lồng nhau nhiều lần để diễn tả cách thực hiện
nhiều công việc tùy theo điều kiện:
- Nếu điều kiện 1 đúng thì thực hiện công việc 1.
- Ngược lại, nếu điều kiện 2 đúng thì thực hiện công việc 2.
-…
- Ngược laị, nếu điều kiện n đúng thì thực hiện công việc n.
- Nếu không điều kiện nào đúng thì thực hiện công việc n+1”.
30
if (<Điều kiện 1>)
<Thực hiện công việc 1>;
else if (<Điều kiện 2>)
<Thực hiện công việc 2>;
….
<Thực hiện công việc n>;
else
[Thực hiện công việc n+1;]
Ví dụ 1.37: Dùng lệnh if…else lồng nhau
/*Coded by Dr. Duong Van Hieu on 15/10/2018*/
#include <stdio.h>
int main()
{
char kytu;
printf("Nhap ky tu:");
scanf("%c", &kytu);
if((kytu >=97)&&(kytu<=122))
{
printf("Ban da nhap chu in thuong\n");
printf("Ky tu vua nhap la %c co ma ASCII la %d", kytu, kytu);
}
else if((kytu >=65)&&(kytu<=90))
{
printf("Ban da nhap chu in hoa\n");
printf("Ky tu vua nhap la %c co ma ASCII la %d", kytu, kytu);
}
else
printf("Ky tu vua nhap khong thuoc top tu A...Z, a...z");
return 1;
}
Hình 1.46. Minh họa sử dụng lệnh if…else lồng nhau
c) Lệnh switch
Lệnh switch là lệnh lựa chọn tương đương với phát biểu “Nếu biểu thức
cần so sánh bằng với giá trị thứ i thì thực hiện công việc thứ i rồi kết thúc.
Ngược thì thực hiện công việc mặc nhiên là công việc thứ n+1”.
Ý nghĩa của lệnh switch giống như ý nghĩa của việc sử dụng lệnh if…else
lồng nhau nhiều lần. Do đó, thay vì sử dụng lệnh if…else lồng nhau nhiều lần
như trong ví dụ 1.37 thì người lập trình nên dùng lệnh switch theo cú pháp sau:
31
switch (<Biểu thức cần so sánh>)
{
case <Giá trị 1>:
[Thực hiện công việc 1;
break;]
case <Giá trị 2>:
[Thực hiện công việc 2;
break;]
…
case <Giá trị n>:
[Thực hiện công việc n;
break;]
default:
[Thực hiện công việc n+1;]
}
Lưu đồ cú pháp:
Biểu
thức cần so sánh
= giá trị 1
Đúng
Sai
Biểu
Sai
thức cần so sánh
= giá trị 2
…
Biểu
thức cần so sánh
= giá trị n
Đúng
Sai
Đúng
Công việc 1
Công việc 2
…
Công việc n
Ví dụ 1.38: Sử dụng lệnh switch đầy đủ
#include <stdio.h>
int main ()
{
int so1, so2;
float thuong;
char pheptoan;
printf("\n Nhap vao 2 so nguyen ");
scanf("%d%d",&so1,&so2);
fflush(stdin);
printf("\n Nhap vao phep toan ");
scanf("%c", &pheptoan);
printf("%c\n", pheptoan);
32
Công việc n+1
switch(pheptoan)
{
case '+':
printf("\n %d + %d =%d",so1, so2, so1+so2);
break;
case '-':
printf("\n %d - %d =%d",so1, so2, so1-so2);
break;
case '*':
printf("\n %d * %d =%d",so1, so2, so1*so2);
break;
case '/':
if (so2!=0)
{
thuong=float(so1)/float(so2);
printf("\n %d / %d =%f", so1, so2, thuong);
}
else printf("Khong chia duoc cho 0");
break;
default :
printf("\n Chua ho tro phep toan %c", pheptoan);
break;
}
return 1;
}
Hình 1.47. Minh họa sử dụng lệnh switch
d) So sánh lệnh if…else và lệnh switch
- Lệnh switch thực chất là một dạng biểu diễn khác của lệnh if…else lồng
nhau.
- Xét điều kiện 1 của lệnh if…else tương đương với xét điều kiện biểu thức
cần so sánh= giá trị 1 trong lệnh switch. Nếu điều kiện đúng thì thực hiện công
việc 1 và kết thúc lệnh.
- Xét điều kiện i của lệnh if…else tương đương với xét điều kiện biểu thức
cần so sánh= giá trị i trong lệnh switch. Nếu điều kiện đúng thì thực hiện công
việc i và kết thúc lệnh.
- Phần else cuối cùng của lệnh if…else tương đương với phần default của
lệnh switch. Nếu cả n điều kiện đều sai thực hiện hiện công việc n+1. Đây là
phần không bắt buộc. Tùy vào từng bài toán cụ thể mà người lập trình quyết
định có sử dụng hay không.
33
6.2.2. Các lệnh rẽ nhánh không có điều kiện
Ngôn ngữ lập trình C và C++ hỗ trợ các lệnh thoát khỏi các vòng lặp hoặc
là chấm dứt sớm quá trình kiểm tra điều kiện và thực hiện công việc. Các lệnh
này goi là lệnh rẽ nhánh không có điều kiện.
a) Lệnh break
Lệnh break dùng để thoát ra khỏi cấu trúc rẽ nhánh switch và các vòng lặp
for, while, do. Nếu các vòng lặp for, while, do lồng nhau nhiều cấp thì lệnh
break bên trong cấu trúc lặp nào sẻ dừng việc thực hiện tất cả các lệnh phía sau
lệnh break và thoát ra hỏi cấu trúc lặp đang chứa lệnh break đó.
b) Lệnh Continue
Lệnh continue dùng để bỏ qua các lệnh phía sau lệnh continue bên trong
cấu trúc lặp for, while, do và quay lại tiếp tục thực hiện các lệnh phía trước lệnh
continue bên trong cấu trúc lặp hiện tại.
c) Lệnh goto
Lệnh goto dùng để nhảy đến một vị trí khác trong chương trình.
6.3. Lệnh lặp
Lệnh lặp hay cấu trúc lặp cho phép lặp đi lặp lại việc thực hiện một công
việc nào đó một số lần nhất định hoặc lặp lại cho đến đi điều kiện dừng xảy ra.
6.3.1. Lệnh lặp với số lần lặp xác định
a) Lệnh for
Lệnh lặp for là lệnh lặp với số lần lặp xác định. Có nghĩa là trước khi thực
hiện lệnh for, máy tính biết trước nội dung của lệnh for được lặp lại bao nhiêu
lần. Sử dụng lệnh for theo cấu trúc sau:
for(<Biểu thức 1>; <Biểu thức 2>; <Biểu thức 3>)
[Khối lệnh;]
Ý nghĩa của các thành phần trong lệnh for:
 Biểu thức 1: Thường là gán giá trị ban đầu cho biến điều khiển.
 Biểu thức 2: Thường là biểu thức so sánh biến điều khiển với 1 giá trị
hay biến khác để xác định điều kiện lặp tiếp tục.
 Biểu thức 3: Thường là biểu thức làm thay đổi giá trị của biến điều khiển
dẫn đến kết thúc vòng lặp.
Lưu đồ cú pháp:
Điều kiện lặp
tiếp tục
Đúng
Công việc
Sai
- Kiểm tra điều kiện lặp tiếp tục trước:
+ Nếu điều kiện sai thì kết thúc lệnh.
+ Nếu điều kiện đúng thực hiện viện công việc
(bao gồm cả phần thay đổi giá trị của biến điều
khiển) rồi quay lên kiểm tra lại điều kiện cho lần
lặp kế tiếp.
34
Ví dụ 1.39: In ra mã ASCII của các số từ 0 đến 9 bằng lệnh for
#include <stdio.h>
int main()
{
char c;
for(c='0'; c<='9'; c++)
printf("Ma ASCII cua so %c la %d\n", c, c);
return 1;
}
Hình 1.48. Minh họa in ra mã ASCII của các số từ 0 đến 9 bằng lệnh for
Hình 1.49. Kết quả minh họa in ra mã ASCII của các số từ 0 đến 9 bằng lệnh for
Giải thích:
- Khởi tạo c=0
- Kiểm tra điều kiện c<=9
=> đúng
+ Thực hiện lệnh in giá trị của c và mã ascii của giá trị của c
+ Thực hiện lệnh c++ để tăng c lên 1 đơn vị
=> c=1
- Tiếp tục kiểm tra điều kiện c<=9
=> đúng
+Thực hiện lệnh in giá trị của c và mã ascii của giá trị của c
+ Thực hiện lệnh c++ để tăng c lên 1 đơn vị
=> c=2
- Tiếp tục kiểm tra điều kiện c<=9
=> đúng
+ Thực hiện lệnh in giá trị của c và mã ascii của giá trị của c
+ Thực hiện lệnh c++ để tăng c lên 1 đơn vị
=> c=3
- Tiếp tục kiểm tra điều kiện c<=9
=> đúng
+ Thực hiện lệnh in giá trị của c và mã ascii của giá trị của c
+ Thực hiện lệnh c++ để tăng c lên 1 đơn vị
=> c=4
- Tiếp tục kiểm tra điều kiện c<=9
=> đúng
+ Thực hiện lệnh in giá trị của c và mã ascii của giá trị của c
35
+ Thực hiện lệnh c++ để tăng c lên 1 đơn vị
=> c=5
- Tiếp tục kiểm tra điều kiện c<=9
=> đúng
+ Thực hiện lệnh in giá trị của c và mã ascii của giá trị của c
+ Thực hiện lệnh c++ để tăng c lên 1 đơn vị
=> c=6
- Tiếp tục kiểm tra điều kiện c<=9
=> đúng
+ Thực hiện lệnh in giá trị của c và mã ascii của giá trị của c
+ Thực hiện lệnh c++ để tăng c lên 1 đơn vị
=> c=7
- Tiếp tục kiểm tra điều kiện c<=9
=> đúng
+ Thực hiện lệnh in giá trị của c và mã ascii của giá trị của c
+ Thực hiện lệnh c++ để tăng c lên 1 đơn vị
=> c=8
- Tiếp tục kiểm tra điều kiện c<=9
=> đúng
+ Thực hiện lệnh in giá trị của c và mã ascii của giá trị của c
+ Thực hiện lệnh c++ để tăng c lên 1 đơn vị
=> c=9
- Tiếp tục kiểm tra điều kiện c<=9
=> đúng
+ Thực hiện lệnh in giá trị của c và mã ascii của giá trị của c
+ Thực hiện lệnh c++ để tăng c lên 1 đơn vị
=> c=10
- Tiếp tục kiểm tra điều kiện c<=9
=> sai
+ Kết thúc vòng lặp
Ví dụ 1.40: Tính tổng của n số nguyên được nhập vào từ bàn phím
#include <stdio.h>
int main()
{
int i, n, a;
long int sum=0;
printf("Can tinh tong cua bao nhieu so? ");
scanf("%d", &n);
for(i=1; i<=n; i++)
{
printf("Nhap gia tri so thu %d =",i);
scanf("%d",&a);
sum=sum+a;
}
printf("Tong = %d",sum);
return 1;
}
Hình 1.50. Minh họa tính tổng của n số nguyên được nhập vào từ bàn phím
bằng lệnh for
36
Hình 1.51. Kết quả minh họa tính tổng của n số nguyên được nhập vào từ bàn
phím bằng lệnh for
Giải thích:
- Thực hiện lệnh nhập vào một số nguyên a thứ 1 (số 12)
- Thực hiện lệnh tính tổng dồn sum=sum+a (sum=12)
- Thực hiện lệnh i++ để tăng i lên 1 đơn vị
=> i=2
- Tiếp tục điều kiện i<=n => đúng
o Thực hiện lệnh nhập vào một số nguyên a thứ 2 (số 32)
o Thực hiện lệnh tính tổng dồn sum=sum+a (sum=12+32=44)
o Thực hiện lệnh i++ để tăng i lên 1 đơn vị
=> i=3
- Tiếp tục điều kiện i<=n => đúng
o Thực hiện lệnh nhập vào một số nguyên a thứ 3 (số 34)
o Thực hiện lệnh tính tổng dồn sum=sum+a (sum=44+34=78)
o Thực hiện lệnh i++ để tăng i lên 1 đơn vị
=> i=4
- Tiếp tục điều kiện i<=n => sai
o Kết thúc lệnh lặp
6.3.2. Lệnh lặp với số lần lặp không xác định
Lệnh lặp với số lần lặp không xác định hỗ trợ việc lặp lại một công việc
nào đó cho đến khi điều kiện dừng xảy ra. Trước khi thực hiện công việc, máy
tính không biết trước là cần thực hiện công việc bao nhiêu lần, chỉ biết rằng nếu
điều kiện dừng chưa xảy ra thì tiếp tục thực hiện công việc. Trong quá trình thực
hiện công việc, giá trị của các biến trong biểu thức điều kiện dừng bị thay đổi để
dẫn đến quá trình dừng vòng lặp.
a) Lệnh while
Lệnh lặp while là lệnh lặp với số lần lặp không xác định vì khi thực hiện
lệnh này máy tính không biết trước nội dung của nó sẻ được thực hiện lặp lại
bao nhiêu lần.
Lệnh lặp while dùng để thực hiện lại một công việc nào đó cho đến khi
điều kiện lặp còn đúng.
Cú pháp sử dụng lệnh while như sau:
while(<kiều kiện>)
[ Thực hiện công việc;]
37
Lưu đồ cú pháp:
Điều kiện lặp
tiếp tục
Đúng
Công việc
Sai
- Kiểm tra điều kiện lặp tiếp tục trước.
+ Nếu điều kiện sai thì kết thúc lệnh.
+ Nếu điều kiện đúng thực hiện viện công việc rồi
quay lên kiểm tra lại điều kiện cho vòng lặp kế tiếp.
Ví dụ 1.41: Tính tổng n số nguyên dương bằng lệnh while
#include <stdio.h>
int main()
{
int i, n, a;
long int sum=0;
printf("Tinh tong n so nguyen duong \n");
a=1; i=1;
while(a>0)
{
printf("Nhap gia tri so thu %d (nhap so am de ket thuc)=", i);
scanf("%d", &a);
if(a>0)
{
sum+=a;
i++;
}
}
printf("Tong = %d", sum);
return 1;
}
Hình 1.52. Minh họa tính tổng n số nguyên dương bằng lệnh while
Hình 1.53. Kết quả minh họa tính tổng n số nguyên dương bằng lệnh while
38
Giải thích:
- Khởi sum=0, a=1 và i=1
- Kiểm tra điều kiện a>0 => đúng
o Thực hiện lệnh nhập vào một số nguyên a thứ 1 (số 2000)
o Kiểm tra điều kiện a>0 => đúng
 Thực hiện lệnh tính tổng dồn sum=sum+a (sum= 2000)
 Thực hiện lệnh i++ để tăng i lên 1 đơn vị
=> i=2
- Tiếp tục kiểm tra điều kiện a>0 => đúng
o Thực hiện lệnh nhập vào một số nguyên a thứ 2 (số 10)
o Kiểm tra điều kiện a>0 => đúng
 Thực
hiện
lệnh
tính
tổng
dồn
sum=sum+a
(sum=2000+10=2010)
 Thực hiện lệnh i++ để tăng i lên 1 đơn vị
=> i=3
- Tiếp tục kiểm tra điều kiện a>0 => đúng
o Thực hiện lệnh nhập vào một số nguyên a thứ 3 (số 8)
o Kiểm tra điều kiện a>0 => đúng
 Thực
hiện
lệnh
tính
tổng
dồn
sum=sum+a
(sum=2010+8=2018)
 Thực hiện lệnh i++ để tăng i lên 1 đơn vị
=> i=4
- Tiếp tục kiểm tra điều kiện a>0 => đúng
o Thực hiện lệnh nhập vào một số nguyên a thứ 4 (số 0)
o Kiểm tra điều kiện a>0 => sai
 Thoát khỏi lệnh if
- Tiếp tục kiểm tra điều kiện a>0 => sai
o Thoát khỏi lệnh lặp
b) Lệnh do
Lệnh do cũng là lệnh lặp với số lần lặp không xác định. Tuy nhiên, không
kiểm tra điều kiện trước như lệnh while mà thực hiện công việc rồi mới kiểm tra
điều kiện.
Sử dụng lệnh do theo cú pháp sau:
do
[Thực hiện công việc;]
while (<Kiều kiện>);
Lưu đồ cú pháp:
Công việc
Đúng
Điều kiện lặp
tiếp tục
Sai
Thoát
hoát
- Thực hiện công việc trước.
- Tiếp theo là kiểm tra điều kiện:
+ Nếu điều kiện sai thì kết thúc lệnh.
+ Nếu điều kiện đúng thực hiện viện công việc,
lặp lại việc kiểm tra điều kiện.
39
Ví dụ 1.42: Tính tổng của dãy số có ít nhất 1 số nguyên dương
#include <stdio.h>
int main()
{
int i, n, a;
long int sum=0;
printf("Tinh tong n so nguyen duong \n");
i=1;
do
{
printf("Nhap gia tri so thu %d (nhap so am de ket thuc)=", i);
scanf("%d", &a);
if(a>0)
{
sum+=a;
i++;
}
}
while(a>0);
printf("Tong = %d", sum);
return 1;
}
Hình 1.54. Minh họa tính tổng của dãy số có ít nhất 1 số nguyên dương bằng
lệnh do
Hình 1.55. Kết quả minh họa tính tổng của dãy số có ít nhất 1 số nguyên dương
bằng lệnh do
Giải thích:
- Khởi sum=0 và i=1
- Thực hiện nội dung lặp
o Nhập số nguyên a thứ 1 (số 2000)
40
o Kiểm tra điều kiện a>0 => đúng
 Thực hiện lệnh tính tổng dồn sum=sum+a (sum=2000)
 Thực hiện lệnh i++ để tăng i lên 1 đơn vị
=> i=2
o Kiểm tra a>0
=> đúng
- Thực hiện nội dung lặp
o Nhập số nguyên a thứ 2 (số 10)
o Kiểm tra điều kiện a>0 => đúng
 Thực
hiện
lệnh
tính
tổng
dồn
sum=sum+a
(sum=2000+10=2010)
 Thực hiện lệnh i++ để tăng i lên 1 đơn vị
=> i=3
o Kiểm tra a>0
=> đúng
- Thực hiện nội dung lặp
o Nhập số nguyên a thứ 3 (số 8)
o Kiểm tra điều kiện a>0 => đúng
 Thực
hiện
lệnh
tính
tổng
dồn
sum=sum+a
(sum=2010+8=2018)
 Thực hiện lệnh i++ để tăng i lên 1 đơn vị
=> i=4
o Kiểm tra a>0
=> đúng
- Thực hiện nội dung lặp
o Nhập số nguyên a thứ 4 (số -1)
o Kiểm tra điều kiện a>0 => sai
o Kiểm tra a>0
=> sai
 Kết thúc lệnh lặp
c) So sánh lệnh lặp
- Lệnh for là lệnh lặp với số lần lặp xác định vì máy tính biết trước số lần
lặp tối đa thông qua giá trị khởi tạo của biến điều khiển trong biểu thức 1, điều
kiện để lặp tiếp trong biểu thức 2 và cách thay đổi giá trị của biến điều khiển
trong biểu thức 3.
- Lệnh while và do là 2 lệnh lặp với số lần lặp không xác định vì điều kiện
lặp phụ thuộc vào nội dung của công việc.
Bảng 1.12. So sánh các lệnh lặp
Lệnh for
Tiêu chí so sánh
Lệnh while
Lệnh do
Số lần lặp
Xác định
Không xác định
Không xác đinh
Lặp ít nhất
0 lần
0 lần
1 lần
Lặp nhiều nhất
n lần, n là số đã biết
Không xác định
Không xác định
Kiểm tra điều kiện
Trước khi thực Trước khi thực Sau khi thực
hiện công việc
hiện công việc
hiện công việc
41
6.3.3. Các lệnh đặc biệt
a) Lệnh return
Lệnh return dùng để trả kết quả khi thực hiện hàm hoặc chương trình
chính. Hầu hết các hàm có sẵn trong C và C++ đều trả về một giá trị nào đó. Khi
thiết kế các hàm, người lập trình cũng cần trả về một giá trị phù hợp.
Nên khai báo hàm main trả về giá trị kiểu int và nếu hàm main thực hiện
thành công thì trả về giá trị 1, ngược lại thì trả về các giá trị khác như 0, -1,… để
quy định lỗi khi thực hiện chương trình.
b) Lệnh rỗng
Lệnh rỗng là lệnh không có nội dung hoặc không thực hiện nội dung gì.
Ví dụ 1.43: Chương trình bị lỗi vì sử dụng lệnh rỗng
#include <stdio.h>
#include <conio.h>
#include <string.h>
int length( char s[255])
{
int i=0;
for (i=0; s[i]!='\0'; i++)
;
return (i);
}
int main()
{
char s[255];
printf("\n Nhap vao mot chuoi ky tu:");
gets(s);
printf("\n Chieu dai cua chuoi=%d", length(s));
return 1;
}
Hình 1.56. Minh họa sử dụng lệnh rỗng
7. CÁC BƯỚC GIẢI BÀI TOÁN LẬP TRÌNH
7.1. Tìm hiểu bài toán
Trước khi lập trình giải một bài toán, chúng ta cần tìm hiểu rõ các mục
đích, yêu cầu của bài toán, các định nghĩa, các điều kiện ràng buộc.
Ví dụ 1.44: Viết chương trình nhập vào một số nguyên và kiểm tra số
nguyên đó có phải là số nguyên tố hay không.
- Cần xác định:
+ Hiểu định nghĩa “số nguyên tố là số nguyên dương chỉ có 2 ước số là 1
và chính nó”.
+ Dữ liệu cần nhập vào từ bàn phím là một số nguyên dương.
42
+ Kết quả in ra màn hình là câu “số n là số nguyên tố” hoặc “số n không
phải là số nguyên tố”.
+ Mục tiêu chính là kiểm tra số n có phải là số nguyên tố hay không.
Ví dụ 1.45: Nhập vào một số nguyên dương n, tính tổng của n số thực a i
(với i là chỉ số dạng S=a1+a2+…+an..
- Cần xác định:
+ Dữ liệu cần nhập vào từ bàn phím là 1 số nguyên dương n và n số thực
a1, a2,…, an.
+ Dữ liệu cần in ra màn hình là tổng của n số thực.
+ Mục tiêu chính là tính tổng S=a1+a2+…+an.
7.2. Mô tả giải thuật
Mô tả giải thuật là mô tả các bước cần phải thực hiện để giải quyết được
yêu cầu của bài toán. Có nhiều cách để mô tả giải thuật, cách đơn giản nhất là
mô tả thuật toán bằng ngôn ngữ tự nhiên:
Ví dụ 1.46: Sử dụng ngôn ngữ tự nhiên để mô tả giải thuật kiểm tra một số
nguyên n có phải là số nguyên tố hay không.
- Bước 1: Nhập vào số nguyên dương n.
- Bước 2: Tìm số lượng ước số của n bằng cách:
+ Gán cho biến số ước =0;
+ Cho biến tự nhiên i chạy từ 1 đến n.
Nếu n chia hết cho i thì tăng số ước lên 1 đơn vị.
- Bước 3: Kiểm tra:
+ Nếu số ước bằng 2 thì in ra màn hình “số n là số nguyên tố”.
+ Ngược lại, in ra màn hình “số n không phải là số nguyên tố”.
Lưu ý: Vì mỗi lần tìm được 1 ước số của n thì tăng biến số ước lên 1 đơn vị
nên phải khởi tạo giá trị ban đầu cho biến số ước =0. Nếu không khởi tạo biến số
ước=0 thì biến số ước sẻ được khởi tạo giá trị mặc nhiên nên kết quả cuối cùng
có thể sai.
Ví dụ 1.47: Sử dụng ngôn ngữ tự nhiên để mô tả giải thuật tính tổng của n
số thực được nhập vào từ bàn phím:
- Bước 1: Nhập vào số phần tử n
- Bước 2: Tính tổng
+ Gán cho biến tổng=0;
+ Cho biến chỉ số i chạy từ 1 đến n
Nhập vào số thực thứ i (gọi là ai). Tính tổng dồn: tổng= tổng +ai.
- Bước 3: In kết quả tính tổng ra màn hình
Lưu ý: Vì mỗi lần đọc được 1 số thực ai thì cộng số ai vào biến tổng nên
phải khởi tạo giá trị ban đầu cho biến tổng =0. Nếu không khởi tạo biến tổng=0
thì biến tổng sẻ được khởi tạo giá trị mặc nhiên nên kết quả sẻ bị sai.
43
Cách biểu diễn giải thuật chính xác hơn là dùng lưu đồ. Khi sử dụng lưu
đồ, chúng ta cần sử dụng các ký hiệu sau đây:
Bảng 1.13. Ký hiệu dùng cho lưu đồ giải thuật
Ký hiệu
Begin
Ý nghĩa
End
A
Ký hiệu điểm nối các lưu đồ khi thể hiển lưu đồ trên nhiều trang
A
Nhập n
Xuất S
i=i+1
Ký hiệu bắt đầu và kết thúc giải thuật
S=S+ai
Ký hiệu nhập dữ liệu từ bàn phím, xuất dữ liệu ra màn hình (nội
dung bên trong hình thay đổi tùy tình huống nhập xuất dữ liệu)
Ký hiệu thực hiện lệnh gán, phép toán trong giải thuật (nội dung
bên trong hình thay đổi tùy theo giải thuật
Điều kiện lựa chọn, nếu điều kiện đúng thì làm việc gì, nếu điều
kiện sai thì làm việc gì (nội dung thay đổi theo giải thuật)
i<n
Ngoại lệ
Ký hiệu khi chú thích (nội dung tùy vào hoàn cảnh)
BCNN(a,b)
Ký hiệu gọi chương trình con (nội dung thay đổi theo hoàn cảnh)
Ký hiệu đường đi của giải thuật
Đúng
Sai
Ký hiệu đường đi của giải thuật khi điều kiện đúng, điều kiện sai
Ví dụ 1.48: Giải thuật bằng lưu đồ cho yêu cầu “Nhập vào số nguyên n kiểm tra
n có phải số nguyên tố hay không”
Begin
Nhập n
i=0; so_uoc=0;
Sai
i<=n
So_uoc==2
Đúng
n%i==0
Đúng
so_uoc=so_uoc+1
;
i=i+1
Sai
Đúng
Sai
n là số nguyên tố
n không là số nguyên tố
End
Hình 1.57. Lưu đồ giải thuật kiểm tra số nguyên dương n có phải số
nguyên tố hay không
44
Giải thích:
 Lưu đồ là một dạng biểu diễn chi tiết và chính xác của thuật toán. Dựa
vào lưu đồ này, người lập trình lựa chọn các cấu trúc lệnh phù hợp; khai
báo biến và nhập, xuất giá trị của biến; viết các lệnh xử lý dữ liệu đúng
với giải thuật.
 Để biểu diễn giải thuật bằng lưu đồ thì đòi hỏi chúng ta phải hiểu thật rõ
giải thuật, nắm rõ giải thuật bằng ngôn ngữ tự nhiên.
Ví dụ 1.49: Giải thuật bằng lưu đồ cho yêu cầu “Tính tổng n số thực được nhập
vào từ bàn phím”.
Begin
Nhập số n
i=1; Tong=0;
Sai
i<=n
Đúng
Nhập giá trị ai
Xuất Tong
End
Tong=Tong+ai
i=i+1
Hình 1.58. Lưu đồ giải thuật tính tổng của n số thực
7.3. Viết chương trình
Sử dụng ngôn ngữ lập trình để cài đặt giải thuật, tìm lời giải cho bài toán.
Trong khi viết chương trình, chúng ta có thể phải thêm một số nội dung không
được thể hiện trong giải thuật nhưng phải đảm bảo chương trình được viết đúng
giải thuật.
7.4. Biên dịch và sửa lỗi
Sau khi viết xong chương trình bằng ngôn ngữ lập trình, việc đầu tiên là
phải biên dịch (compile) chương trình. Khi biên dịch, chương trình biên dịch sẻ
kiểm tra cú pháp lệnh và báo lỗi (nếu chương trình có lỗi cú pháp, lỗi sử dụng
biến, lỗi viết sai tên,…), người lập trình phải sửa tất cả các lỗi này.
Sau khi biên dịch thành công, chúng ta cần chạy thử chương trình, nhập
vào giá trị và kiểm tra giá trị đầu ra xem có đúng không. Nếu chương trình cho
kết quả sai thì phải sửa các lỗi liên quan đến giải thuật, cách nhập dữ liệu, cách
xuất dữ liệu, cách sử dụng biến, cách sử dụng phép toán,…
7.5. Ứng dụng và nâng cấp
Bước cuối cùng là ứng dụng chương trình để giải các bài toán thật sự và
nâng cấp để giải được các bài toán khác nhau theo yêu cầu khác nhau của người
sử dụng.
45
8. BÀI TẬP
8.1. Câu hỏi ôn tập
Câu 1: Tại sao ngôn ngữ lập trình C và C++ phân biệt ký tự in hoa với ký tự in
thường?
Câu 2: Chương trình được viết bằng ngôn ngữ C, để nhập một chuỗi ký tự có
chứa khoảng trắng, ta dùng hàm nào? Cần phải khai báo sử dụng thư viện nào để
có thể sử dụng được các hàm đó? Biến chuỗi ký tự phải thuộc kiểu dữ liệu gì?
Câu 3: Chương trình được viết bằng ngôn ngữ C++, để nhập một chuỗi ký tự có
chứa khoảng trắng, ta dùng hàm nào? Phải khai báo sử dụng thư viện nào để sử
dụng được hàm đó? Biến chuỗi ký tự phải thuộc kiểu dữ liệu gì?
Câu 4: Phân biệt sự khác nhau giữa biến toàn cục, biến cục bộ, biến tham số.
Khi nào thì dùng biết toàn cục, cục bộ, tham số?
Câu 5: Cho biết ý nghĩa của các thành phần bên trong chuỗi định dạng của hàm
scanf().
Câu 6: Cho biết ý nghĩa của các thành phần bên trong chuỗi định dạng của hàm
printf().
Câu 7: So sánh sự giống và khác nhau giữa hàm scanf() của ngôn ngữ C và lệnh
cin>> của ngôn ngữ C++.
Câu 8: So sánh sự giống và khác nhau giữa hàm printf() của ngôn ngữ C và
lệnh cout<< của ngôn ngữ C++.
Câu 9: So sánh sự giống và khác nhau giữa lệnh lặp for và lệnh lặp while, giữa
lệnh lặp for và lệnh lặp do, giữa lệnh lặp while và lệnh lặp do.
Câu 10: Cho biết quy tắc đặt tên biến trong C.
Câu 11: Từ khóa là gì? Khi lặp trình, ta có được đặt tên biến trùng với từ khóa
hay không?
Câu 12: Hãy cho biết quy tắc chuyển đổi kiểu dữ liệu trong C và C++.
Câu 13: Chọn câu trả lời đúng
a) Có thể thực hiện các phép toán số học trên biến có kiểu char, unsigned
char
b) KHÔNG thể thực hiện các phép toán số học trên biến có kiểu char,
unsigned char
Câu 14: Chọn câu trả lời đúng
a) /* Nội dung chú thích*/ là cách viết chú thích trong chương trình .c và
.cpp
b) /* Nội dung chú thích*/ là cách viết chú thích trong chương trình .c
c) // Nội dung chú thích là cách viết chú thích trong chương trình .cpp
d) Cả 3 câu trên đều đúng.
Câu 15: Chọn câu trả lời đúng:
a) Khi lập trình bằng ngôn ngữ C thì có thể sử dụng các lệnh cin>>, cout<<
của ngôn ngữ C++.
46
b) Khi lập trình bằng ngôn ngữ C++ thì có thể sử dụng các lệnh scanf(),
printf() của ngôn ngữ C.
c) C/C++ là một ngôn ngữ lập trình.
d) Cả 3 câu trên đều đúng.
Câu 16: Các chương trình sau đây, chương trình nào được viết theo cú pháp của
ngôn ngữ lập trình C?
a) Baitap.cpp
b) Baitap.exe
c) Baitap.c
d) a, b, c đúng.
Câu 17: Cho biết kết quả của các chương trình sau:
a)
b)
c)
47
d)
8.2. Bài tập thực hành
Bài 1: Viết chương trình nhập vào họ tên của bạn và in ra 2 câu chào giống như
hình bên dưới kèm theo bên dưới.
Gợi ý thực hiện:
- Bước 1: Chạy phần mềm Dev C/C++
- Bước 2: Chọn File -> New -> Source file
- Bước 3: Nhập vào nội dung chương trình
- Bước 4: Lưu tập tin, đặt tên là TH_C1.1.c
- Bước 5: Execute -> Compile & Run (hoặc nhấn phím F11) sửa lỗi nếu
có.
- Bước 6: Nhập vào Họ tên của bạn và Enter, xem kết quả.
Bài 2: Viết chương trình giống như hình bên dưới
Gợi ý thực hiện:
- Tạo tập tin mới.
48
- Sau khi nhập xong nội dung, lưu tên tập tin là TH_C1.2.cpp
- Biên dịch chương trình: Execute->Comple
- Sửa các lỗi đang có của chương trình trên cho đến bao giờ gõ phím F11
thì chương trình không còn bị lỗi và có thể chạy được.
- Khi chương trình đã chạy, nhập vào họ và tên của ban và enter để xem kết
quả.
Bài 3: Viết chương trình giải phương trình bậc 1 dạng ax + b =0 với a, b là các
số nguyên được nhập từ bàn phím.
Gợi ý thực hiện:
- Khai báo: float a, b;
- Yêu cầu nhập vào giá trị của hệ số a, b
- Nhập giá trị a, b bằng hàm scanf(%f %f, &a, &b);
- Dùng lệnh if để kiểm tra:
if(a==0.0)
printf(Phương trình vô nghiệm);
else
printf(Phương trình có nghiệm là %f, -b/a);
- Sau khi viết xong, biên dịch và chạy chương trình, nhập vào giá trị cho
các hệ số a, b và xem kết quả.
Bài 4: Viết chương trình giải phương trình bậc 2 dạng ax2 + bx + c =0 với a, b,
c là các số nguyên được nhập từ bàn phím.
Gợi ý thực hiện:
- Khai báo biến: float a, b, c, delta, x1, x2;
- Nhập giá trị cho các biến a, b, c bằng hàm scanf(%f %f %f, &a, &b,
&c);
- Tính delta=b*b-4*a*c;
- Kiểm tra điều kiện bằng lệnh if…else
if (delta<0)
printf(Phương trình vô nghiệm);
else if (delta==0.0)
printf(Phương trình có nghiệm kép =%f, -b/(2*a));
else
printf(Nghiệm x1=%f, x2=%f, (-b-sqrt(delta))/(2*a),
(b+sqrt(delta))/(2*a));
- Sau khi viết xong, biên dịch và chạy chương trình, nhập vào giá trị cho
các hệ số a, b, c và xem kết quả.
Bài 5: Viết chương trình nhập vào một số nguyên dương n, tính tổng của n số
thực được nhập vào từ bàn phím, tính tích của n số nguyên nhập vào từ bàn
phím.
49
Gợi ý thực hiện:
- Khai báo: int n, songuyen, i;
float sothuc, tong=0;
long tich=1;
- Yêu cầu nhập vào số nguyên n bằng hàm scanf(%d, &n);
- Dùng lệnh lặp for để nhập n số thực, mỗi lần nhập một số và tính tổng
dồn dạng tong=tong+sothuc như sau:
for (i=1; i<=n; i++)
{
printf(Nhap vao so thuc thu %d : , i);
scanf(%f, &sothuc);
tong=tong+sothuc;
}
- Dùng lệnh lặp while để nhập n số nguyên, mỗi lần nhập một số và tính
tích dồn dạng tich=toch*songuyen như sau:
i=1
while(i<=n)
{
printf(Nhap vao so nguyen thu %d : , i);
scanf(%d, &songuyen);
tich=tich*songuyen;
}
- In kết quả ra màn hình.
Bài 6: Viết chương trình tính tổng bình phương của n số nguyên có dạng sau:
S=𝑎12 +𝑎22 +𝑎32 +…+𝑎𝑛2 với n và ai được nhập vào từ bàn phím.
Gợi ý thực hiện:
- Khai báo: int n, a;
long tong=0;
- Yêu cầu nhập số lượng phần tử, đọc giá trị n bằng hàm scanf(%d, &n);
- Sử dụng vòng lặp for để nhập các giá trị ai và tính giá trị của tong như
sau:
for(i=1; i<=n; i++)
{
Nhập vào giá trị ai;
tong+= (ai*ai);
}
- In ra giá trị tổng cuối cùng.
50
Bài 7: Viết chương trình tính tổng của n số nguyên có dạng sau:
S=1-𝑎1 +𝑎2 -𝑎3 +…+(−1)𝑛 𝑎𝑛 với n và ai được nhập vào từ bàn phím.
Gợi ý thực hiện:
- Khai báo: int n, a;
long tong=1;
- Yêu cầu nhập vào số phần tử n; đọc giá trị n bằng hàm scanf(%d, &n);
- Sử dụng vòng lặp for để nhập các giá trị ai và tính giá trị của tong như
sau:
for(i=1; i<=n; i++)
{
Nhập vào giá trị ai;
if(i%2==0)
tong + =ai;
else
tong - = ai;
}
- In ra giá trị tổng cuối cùng.
Bài 8: Viết chương trình nhập vào một số nguyên dương n, tính tích
S=1*2*3*…*n, xuất ra màn hình giá trị của tích.
Bài 9: Viết chương trình nhập vào một số nguyên dương n, tính tổng S=12+3+…+(-1)2n, xuất ra màn hình giá trị của tổng.
Bài 10: Viết chương trình tính tổng của một dãy số nguyên được nhập vào từ
bàn phím, kết thúc bằng số 0, xuất giá trị của tổng ra màn hình.
Bài 11: Viết chương trình nhập vào 1 số thực là bán hính của một hình tròn, tính
chu vi và diện tích của hình tròn, in kết quả ra màn hình (lấy PI=3.1416).
Bài 12: Viết chương trình nhập vào 3 số a, b, c là độ dài 3 cạnh của một tam
giác.
- Kiểm tra xem giá trị a, b, c nhập vào có hợp lệ hay không (Điều kiện hợp
lệ là tổng của 2 cạnh phải lớn hơn 1 cạnh còn lại, hiệu của 2 cạnh phải nhỏ hơn 1
cạnh còn lại).
- Nếu không hợp lệ thì in ra màn hình câu thông báo “Các giá trị a, b, c
không tạo thành tam giác”.
- Nếu hợp lệ thì tính:
Nửa chu vi: ncv=(a+b+c)/2;
Diện tích: dt=sqrt(ncv*(ncv-a)*(ncv-b)*(ncv-c)); với sqrt() là hàm
tính căn bậc 2.
- In ra màn hình chu vi và diện tích của tham giác.
Bài 13: Viết chương trình nhập vào số nguyên x và số nguyên dương y, tính giá
trị xy và in két quả ra màn hình.
51
Bài 14: Viết chương trình nhập vào tọa độ của 2 điểm A(x 1, y1) và B(x2, y2).
Tính hệ số gốc của đường thẳng qua 2 điểm A, B và khoảng cách giữa 2 điểm A,
B theo công thức:
- Hệ số gốc =(y2-y1)/(x2-x1)
- Khoảng cách =√(𝑦2 − 𝑦1 )2 + (𝑥2 − 𝑥1 )2
Bài 15: Viết chương trình nhập vào một ký tự, in ra mã ASCII của ký tự vừa
nhập, in ký tự đứng liền trước ký tự vừa nhập và ký tự đứng liền sau ký tự vừa
nhập.
Bài 16: Viết chương trình in ra màn hình 256 ký tự trong bảng mã ASCII với
điều kiện in mỗi dòng 20 ký tự, mỗi ký tự cách nhau 2 khoảng trắng.
Gợi ý thực hiện:
- Cho biến i chạy từ 0 đến 255, in ra giá trị i với định dạng %c
- Sử dụng phép so sánh ((i-1)%20)==0 để kiểm tra (i-1) chia hết cho 20.
Bài 17: Viết chương trình nhập vào giá trị điện trở R1, R2, R3 của một mạch
1
1
1
1
điện. Tính tổng trở R theo công thức = + + , in ra kết quả của R.
𝑅
𝑅1
𝑅2
𝑅3
Bài 18: Viết chương trình nhập vào 3 số là ngày, tháng, năm. In ra ngày tháng
năm dạng ngày 2 số/ tháng 2 số/ năm 4 số. Ví dụ nhập vào ngày là 15, tháng là
2, năm là 1975 thì in ra màn hình là 15/02/1975.
Bài 19: Viết chương trình nhập vào 2 số nguyên a, b và 1 ký tự là dấu của phép
tính.
- Nếu phép tính là dấu + thì in ra kết quả a+b.
- Nếu phép tính là dấu - thì in ra kết quả a-b.
- Nếu phép tính là dấu * thì in ra kết quả a*b.
- Nếu phép tính là dấu / thì in ra kết quả a/b.
- Nếu phép tính là dấu % thì in ra kết quả a%b.
- Nếu phép tính là dấu | thì in ra kết quả a|b.
- Nếu phép tính là dấu ^ thì in ra kết quả a^b.
- Nếu phép tính là dấu < thì in ra kết quả a<<b.
- Nếu phép tính là dấu > thì in ra kết quả a>>b.
Chạy chương trình 9 lần, mỗi lần nhập 1 dấu phép toán khác nhau. Sau khi
in ra kết quả, kiểm tra xem kết quả đúng hay sai. Nếu sai thì tại sao sai?
Bài 20: Viết chương trình đọc vào 3 số thực, in ra số lớn nhất, số nhỏ nhất trong
3 số vừa nhập.
Bài 21: Viết chương trình nhập vào 2 số nguyên là tháng, năm của một năm. In
ra số ngày của tháng vừa nhập. Ví dụ nhập tháng 2, năm 2017 thì in ra câu
“tháng 2 năm 2017 có 28 ngày”.
Gợi ý thực hiện:
- Các tháng 1, 3, 5, 7, 8, 10, 12 luôn luôn có 31 ngày.
- Các tháng 4, 6, 9, 11 luôn luôn có 30 ngày.
52
- Tháng 2 năm nhuận có 29 ngày, tháng 2 năm thường có 28 ngày. Năm
nhuận là năm chia hết cho 4 hoặc chia hết cho 1000 nhưng không chia hết cho
100.
Bài 22: Một số nguyên dương chia hết cho 3 nếu tổng các chữ số của nó chia hết
cho 3. Viết chương trình nhập vào một số có 3 chữ số, kiểm tra số đó có chia hết
cho 3 hay không.
Gợi ý thực hiện:
Tổng=số hàng đơn vị + số hàng chục + số hàng trăm
Bài 23: Một số nguyên dương chia hết cho 3 nếu tổng các chữ số của nó chia hết
cho 3. Viết chương trình nhập vào một số nguyên có ít nhất 5 chữ số, kiểm tra số
đó có chia hết cho 3 hay không.
Gợi ý thực hiện:
- Nhập vào số nguyên lớn n.
- Tong=0;
while (n>0)
{
tong+=n%10;
//Tổng = Tổng + phần dưa của n khi chia cho 10
n=n/10;
// n = phần nguyên của n chia cho 10
}
- Kiểm tra, nếu tong chia hết cho 3 thì n chia hết cho 3.
Bài 24: Viết chương trình nhận vào giờ, phút, giây từ bàn phím. Cộng thêm một
số giây vào và in ra kết quả dưới dạng ( hh:mm:ss ).
Gợi ý thực hiện:
- Nhập vào 3 số nguyên là giờ (gio), phút (phut), giây (giay)
- Nhập vào 1 số nguyên là số giây cần cộng thêm (giaythem).
- Thực hiện các thép tính:
giay+=giaythem;
phut+=giay/60;
ss=giay%60;
hh=gio+phut/60;
mm=phut%60;
- Kiểm tra điều kiện và in kết quả, nếu hh<9 thì thêm số 0 phía trước hh,
nếu mm<9 thì thêm số 0 phía trước mm, nếu ss<9 thì thêm số 0 phía trước ss.
Có kết quả như sau:
53
Bài 25: Viết chương trình nhập vào 1 ký tự và kiểm tra ký tự vừa nhập thuộc tập
hợp nào trong các tập ký tự sau:
- Các ký tự chữ hoa: A ... Z
- Các ký tự chữ thường: a ... z
- Các ký tự chữ số : 1 ... 9
- Các ký tự khác.
Bài 26: Hệ thập lục phân dùng 16 ký số bao gồm các ký tự 0 ... 9 và A, B,
C, D, E , F. Các ký tự A, B, C, D, E, F có giá trị tương ứng trong hệ
thập phân là 10, 11, 12, 13, 14, 15. Các ký tự 0…9 có giá trị tương ứng trong
hệ thập phân là từ 0 đến 9. Hãy viết chương trình cho nhập vào ký tự biểu diễn
một ký số của hệ thập lục phân và cho biết giá trị thập phân tương ứng. Trường
hợp ký tự nhập vào không thuộc các ký số trên, đưa ra thông báo lỗi :“Hệ thập
lục phân không dùng ký số này”. Ví dụ: Nhập vào ký tự 1 thì in ra kết quả giá
trị trong hệ thập phân là số 1. Nếu nhập vào lý tự C thì in ra kết quả trong hệ
thập phân là số 12.
Bài 27: Viết chương trình nhập vào một dãy n số, in ra số lớn nhất và vị trí của
số lớn nhất trong dãy, in ra số lớn nhất và vị trí của số lớn nhất trong dãy.
Bài 28: Fibonancci là một dãy được được định nghĩa như sau: 1, 1, 2, 3, 5, 8, 13,
… (2 số đầu tiên là 1, số thứ 3 trở đi bằng tổng của 2 số liền trước nó. Viết
chương trình nhập vào số nguyên dương n và xuất ra dãy số Fibonancci có n số.
Bài 29: Viết chương trình nhập một số nguyên lớn, đếm số chữ số của số vừa
nhập. Ví dụ: Nhập 123456 thì xuất ra màn hình là “số 123456 có 6 chữ số”.
Bài 30: Tìm số nguyên dương k nhỏ nhất sao cho 2k > n với n là một số nguyên
dương nhập từ bàn phím.
Bài 31: Viết chương trình in ra số đọc ngược của một số nguyên n, với n nhập
từ bàn phím. Ví dụ: Khi nhập vào số n=123456 thì in ra kết quả số đọc ngược
của n là 654321.
Gợi ý thực hiện
so_nguoc=0;
while (n>0)
{
so_nguoc=so_nguoc*10+n%10;
n=n/10;
}
Bài 32: Tìm số nguyên dương N nhỏ nhất sao cho 1+1/2+ ...+1/N > S, với S
nhập từ bàn phím.
Bài 33: Viết chương trình tìm ước số chung lớn nhất của 2 số nguyên a và b ký
hiệu là UCLN(a,b) và bội số chung nhỏ nhất của 2 số nguyên a, b ký hiệu là
BCNN(a,b) theo thuật toán sau:
- Gọi (a,b) là UCLN của a và b; [a,b] là BCNN của a và b.
54
- Nếu a chia hết cho b thì UCLN(a,b) = b và BCNN(a,b)=a
- Nếu a = b*q + r thì UCLN(a,b) = UCLN(b,r) và BCNN[a,b] =
a*b/UCLN(b,r)
Bài 34: Viết chương trình nhập vào một số nguyên dương, in ra kết quả số
nguyên dương vừa nhập có phải là số nguyên tố hay không.
Bài 35: Viết chương trình nhập vào một số nguyên dương n, in ra màn hình tất
cả các số nguyên tố nhỏ hơn n.
Bài 36: Viết chương trình nhập vào 1 số nguyên dương n, kiểm tra số nguyên
dương đó có phải là số chính phương hay không (số chính phương là số nguyên
dương có căn bật 2 là một số nguyên)
Bài 37: Viết chương trình nhập vào 2 số nguyên dương a và b, kiểm tra 2 số a
và b có phải là 2 số bạn bè hay không (2 số a và b là bạn bè nếu tổng các ước
dương của a bằng b và tổng các ước dương của b bằng a).
Bài 38: Viết chương trình nhập vào 1 số nguyên tố n, in ra số nguyên tố kế nó.
---oOo---
55
Chương 2. LẬP TRÌNH MODULE
Mục tiêu của chương này
1. Về kiến thức:
- Khái niệm hàm và chương trình con trong lập trình hướng thủ tục hay
lập trình module, hàm người dùng và hàm thư viện, truyền tham số
cho hàm (truyền bằng giá trị, bằng địa chỉ trong ngôn ngữ C; truyền
bằng tham chiếu trong ngôn ngữ C++), tầm vực của biến.
- Lý do tạo hàm người dùng. Quy tắc xây dựng hàm.
- Cách khai báo hàm, biết khai báo tham số hình thức của hàm được
viết bằng C và C++.
- Cách sử dụng câu lệnh return của hàm.
- Hàm đệ quy và quy tắc xây dựng hàm đệ qui.
2. Về kỹ năng:
- Sử dụng một số thư viện và hàm thư viện thông dụng của C và C++
khi lập trình.
- Vận dụng được các quy tắc xây dựng hàm.
- Cài đặt được hàm người dùng.
- Sử dụng được các dạng khai báo tham số hình thức của hàm.
- Vận dụng được các cách trả về kết quả của hàm.
- Vận dụng được việc khai báo biến toàn cục, biến cục bộ của hàm, biến
cục bộ trong khối lệnh.
- Phân biệt được tham số vào, tham số vào ra, tham số ra của hàm.
- Vận dụng được các cách truyền tham số ghi gọi hàm đối với C và
C++.
- Phân biệt được sự khác nhau khi truyền tham số bằng giá trị, bằng địa
chỉ trong C và truyền bằng tham chiếu trong C++.
- Thiết kế được hàm đệ quy.
3. Về thái độ:
- Nhận thức được tầm quan trọng của việc sử dụng thư viện và hàm thư
viện của C và C++ khi lập trình.
- Nhận thức được tầm quan trong của việc chia bài toán lớn ra thành các
bài toán con.
- Nhận thức được tầm quan trọng của việc thiết kế hàm người dùng khi
lập trình.
1. HÀM VÀ CHƯƠNG TRÌNH CON
1.1. Định nghĩa hàm
Trong ngôn ngữ lập trình C và C++, hàm là một chương trình được thiết kế
để thực hiện một công việc nào đó và có thể trả về kết quả thông qua lời gọi
56
hàm. Một hàm có thể chứa bên trong nó những hàm khác. Bản thân chương trình
chính cũng là một hàm.
Ví dụ 2.1: Thiết kế hàm max để tìm số lớn giữa 2 số nguyên a, b như sau:
int max(int a, int b)
{
return (a>b) ? a:b;
}
Hình 2.1. Minh họa hàm tìm số lớn nhất giữa 2 số nguyên
Ví dụ 2.2: Viết chương trình chính (hàm main) dùng để nhập vào 3 số
nguyên a,b, c và in ra màn hình số lớn trong 3 số:
#include <stdio.h>
int max(int a, int b)
{
return (a>b) ? a:b;
}
int main()
{
int a, b, c;
printf(" Nhap vao 3 so a, b, c ");
scanf("%d%d%d", &a, &b, &c);
printf(" So lon la %d", max(a, max(b, c)) );
return 1;
}
Hình 2.2. Minh họa tìm số lớn nhất giữa 3 số nguyên
Hàm trong C và C++ được chia ra làm 2 dạng cơ bản là hàm thư viện (được
tạo sẵn) và hàm người dùng định nghĩa (người dùng tạo thêm).
1.2. Hàm thư viện
Hàm thư viện là những hàm đã được xây dựng sẵn, muốn sử dụng các hàm
thư viện thì phải khai báo thư viện trước khi sử dụng bằng lệnh #include <tên
thư hiện>.
Một số thư viện của C (cũng được sử dụng bởi C++):
alloc.h
assert.h
bcd.h
bios.h
complex.h
conio.h
ctype.h
dir.h
dirent.h
dos.h
errno.h
fcntl.h
float.h
fstream.h
grneric.h
graphics.h io.h
iomanip.h
iostream.h
limits.h
locale.h
malloc.h
math.h
mem.h
process.h
setjmp.h
share.h
signal.h
stdarg.h
stddef.h
stdio.h
stdiostr.h
stdlib.h
stream.h string.h
strstrea.h
sys\stat.h
sys\timeb.h sys\types.h time.h
57
values.h
Bảng 2.1. Một số hàm thông dụng thuộc một số thứ viện của C
Thư viện
Nhóm
Ý nghĩa
Hàm
scanf()
getc()
Nhập, xuất
dữ liệu từ
thiết bị chuẩn
gets()
Nhập dữ liệu từ thiết bị chuẩn (ví dụ bàn phím)
getchar()
printf()
putc()
puts()
Xuất dữ liệu ra thiết bị chuẩn (ví dụ màn hình)
putchar()
stdio.h
fopen()
Tạo tập tin mới hoặc mở tập tin đang tồn tại
freopen()
Mở lại tập tin đang được mở
fclose()
Đóng tập tin đang được mở
fscanf()
Xử lý tập tin
fread()
fprintf()
fwrite()
Đọc dữ liệu từ tập tin đang được mở để đoc
Ghi dữ liệu vào tập tin đang được mở để ghi
feof()
Kiểm tra xem con trỏ có ở cuối tập tin
fseek()
Di chuyển con trỏ tập tin
ftell()
Cho biết vị trí hiện tại của con trỏ trong tập tin
Tham khảo thêm tại địa chỉ: https://en.wikipedia.org/wiki/C_file_input/output
Hàm mũ,
logarit
math.h
Hàm lượng
giác
Xử lý số thực
abs(<x>)
Lấy giá trị tuyệt đối của một số x
exp(<x>)
Tính e mũ x
log(<x>)
Tính logarit cơ số e của x
log2(<x>)
Tính logarit cơ số 2 của x
log10(<x>)
Tính logarit cơ số 10 của x
sqrt(<x>)
Tính căn bậc 2 của số x
pow(<x>, <y>)
Tính x mũ y
sin(<x>), asin(<x>)
Tính sin, arc sin của x
cos(<x>), acos(<x>)
Tính cos, arc cos của x
tan(<x>), atan(<x>)
Tính tan, arc tan của x
ceil(<x>),
floor(<x>)
Lấy số nguyên là cận trên, cận dưới của
số thực x
round(<x>)
Làm tròn số thực x
Tham khảo thêm:
https://en.wikipedia.org/wiki/C_mathematical_functions#Overview_of_functions
58
Thư viện
Nhóm
Xử lý chuỗi
ký tự
Kiểm tra
chuỗi ký tự
string.h
Thao tác trên
vùng nhớ
chuỗi ký tự
Ý nghĩa
Hàm
strcpy()
Chép chuỗi ký tự
strncpy()
Chép n ký tự từ chuỗi ký tự
strcat()
Nối 2 chuỗi ký tự lại thành 1 chuỗi
strncat()
Nối n ký tự từ chuỗi 2 vào chuỗi 1
strlen()
Lấy độ dài của chuỗi ký tự
strcmp()
So sánh 2 chuỗi ký tự
strchr()
Tìm vị trí của 1 ký tự trong 1 chuỗi ký tự
strstr()
Tìm vị trí của 1 chuỗi ký tự trong 1 chuỗi ký tự
memset()
Làm đầy vùng nhớ chuỗi ký tự bằng ký tự đã
cho
memcpy()
Chép nội dung của vùng nhớ chuỗi ký tự
memcmp()
So sánh nội dung của 2 vùng nhớ chuỗi ký tự
memchr()
Tìm vị trí xuất hiện của 1 ký tự trong vùng nhớ
Tham khảo thêm: https://en.wikipedia.org/wiki/C_string_handling
Ngoài những thư viên chuẩn của C, ngôn ngữ lập trình C++ có thêm các thư viện
chuẩn như:
cstdlib
csignal
csetjmp
bitset
functional utility
tuple
new
limits
exception stdexcept
cstdarg
typeinfo
ypeindex type_traits
Ctime
chrono
cstddef
initializer_list
cfloat
cstdint
cinttypes
scoped_allocator climits
cassert
system_error cerrno
cctype
algorithm
string
cmath
cwctype cstring
cwchar
cuchar
complex valarray
random
numeric ratio
cfenv
iosfwd
ios
ostream
iostream fstream
sstream
strstream
istream
iomanip streambuf cstdio
Để biết ý nghĩa của từng thư viện cũng như các sử dụng các hàm bên trong
thư
viện,
người
học
tham
khảo
thêm
tại
http://en.cppreference.com/w/cpp/header
Bảng 2.2.Một số lệnh, hàm, đối tượng, phép toán thông dụng trong một số
thư viện của C++
Thư viện
iostream
Nhóm
Lệnh vào, ra
chuẩn
Hàm/Lệnh/ Đối
tượng/ Phép toán
Ý nghĩa
cin>>
Đọc dữ liệu từ thiết bị chuẩn
cout<<
Xuất dữ liệu ra thiết bị chuẩn
Tham khảo thêm tại: http://en.cppreference.com/w/cpp/header/iostream
59
Thư viện
Nhóm
Hàm vào, ra
Hàm/Lệnh/ Đối
tượng/ Phép toán
Đọc vào 1 chuỗi có chứa khoảng trắng
getline()
stoi(), stol(),
Chuyển đổi
kiểu dữ liệu
string
Ý nghĩa
Đổi từ chuỗi ký tự sang số nguyên
stoll()
Đổi từ chuỗi ký tự sang số nguyên dương
stoul(), toull()
stof(), stod()
Đổi từ chuỗi ký tự sang số thực
stold()
Phép
toán +
trên chuỗi ký ==, !=, <, <=, >, >=
tự
Ghép 2 chuỗi ký tự lại thành 1 chuỗi
Các phép toán so sánh 2 chuỗi ký tự
Tham khảo thêm tại: http://en.cppreference.com/w/cpp/header/string
Tham khảo thêm các hàm, đối tượng, lệnh, phép toán trong các thư viện còn lại tại địa chỉ :
http://en.cppreference.com/w/cpp/header
1.3. Hàm người dùng định nghĩa
Hàm người dùng là những hàm do người lập trình tự tạo ra nhằm đáp ứng
nhu cầu xử lý của mình như: hàm tìm số lớn nhất giữa 2 số, hàm kiểm tra một số
nguyên có phải là số nguyên tố hay không, hàm tìm ước số chung lớn nhất của 2
số nguyên, hàm tìm bội số chung nhỏ nhất của 2 số nguyên, ...
2. LÝ DO TẠO HÀM NGƯỜI DÙNG
Khi giải một bài toán lớn và phức tạp, cần chia nhỏ nó ra thành nhiều bài
toán nhỏ hơn và đơn giản hơn. Tiến hành giải từng bài toán nhỏ bằng những
chương trình con (gọi là hàm). Sau đó kết nối lời giải các chương trình con lại
với nhau để ra lời giải của bài toán lớn ban đầu. Đó là lý do tại sao chúng ta phải
tạo hàm người dùng.
Mặt khác, dù ngôn ngữ C và C++ đã có sẵn nhiều thư viện chứa rất nhiều
hàm đã được tạo sẵn, các hàm này vẫn chưa giải quyết hết yêu cầu đa dạng của
người lập trình. Yêu cầu của người lập trình phụ thuộc vào yêu cầu của từng bài
toán cụ thể nên người lập trình cần tạo thêm các thư viện mới hoặc các hàm mới
nhằm đáp ứng yêu cầu xử lý dữ liệu của người lập trình. Việc sử dụng hàm
mang lại các lợi ích sau khi lặp trình:
- Đơn giản hóa được các bài toán phức tạp.
- Tận dụng lại được chương trình con cho các bài toán khác.
- Tận dụng lại được mã nguồn.
1
𝑎𝑖
Ví dụ 2.3: Viết chương trình tính tổng 𝑆1 = ∑𝑛𝑖=1 , 𝑆2 = ∑𝑛𝑖=1 không sử
𝑖!
𝑖!
dụng chương trình con với a và n là số nguyên.
Những nội dung lặp lại nhiều lần là:
- Tính giá trị giai thừa của i (i!) trong tổng S1.
60
- Tính giá trị a mũ i (ai) và giai thừa của i (i!) trong tổng S2.
- Việc lặp đi lặp lại đoạn mã tính i! cho 2 tổng S1, S2 sẻ làm cho chương
trình ở nên phức tạp và dài.
int main()
{
int n, i, j, a, amui, igt;
float S1, S2;
printf("Nhap vao so nguyen n = "); scanf("%d", &n);
printf("Nhap so nguyen a = ");
scanf("%d", &a);
S1=0;
for(i=1; i<=n; i++)
{
igt=1;
for(j=2; j<=i; j++)
igt=igt*j;
S1=S1+1.0/(float)igt;
}
printf("Tong S1 = %f\n",S1);
S2=0;
for(i=1; i<=n; i++)
{
igt=1;
for(j=2; j<=i; j++)
igt=igt*j;
amui=a;
for(j=2; j<=i; j++)
amui=amui*a;
S2=S2+(float)amui/(float)igt;
}
printf("Tong S2 = %f", S2);
return 1;
}
Hình 2.3. Minh họa tính tổng S1, S2 không sử dụng chương trình con
Ví dụ 2.4: Viết chương trình tính tổng S1 = ∑ni=0 x i , S2 = ∑ni=0(−1)i x i ,
xi
S3 = ∑ni=0 không sử dụng chương trình con với n là số nguyên và x là số thực
i!
nhập vào từ bàn phím.
Những nội dung lặp lại nhiều lần là: Tính xi, i!.
61
int main()
{
int n, i, j, igt;
float x, xmui, S1=0, S2=0, S3=0;
printf("Nhap vao so nguyen n = "); scanf("%d", &n);
printf("Nhap so thuc x = ");
scanf("%f", &x);
for(i=0; i<=n; i++)
{
if(i==0)
xmui=1;
else
{
xmui=1;
for(j=1; j<=i; j++)
xmui=xmui*x;
}
S1=S1+xmui;
}
for(i=0; i<=n; i++)
{
if(i==0)
xmui=1;
else
{
xmui=1;
for(j=1; j<=i; j++)
xmui=xmui*x;
}
if(i%2==0)
S2=S2+xmui;
else
S2=S2-xmui;
}
for(i=0;i<=n;i++)
{
if(i==0)
xmui=1;
else
{
xmui=1;
for(j=1; j<=i; j++)
xmui=xmui*x;
}
62
if(i==0)
igt=1;
else
{
igt=1;
for(j=1; j<=i;j++)
igt=igt*j;
}
S3=S3+xmui/igt;
}
printf("Tong S1 = %f\n",S1);
printf("Tong S3 = %f",S3);
return 1;
printf("Tong S2 = %f\n", S2);
}
Hình 2.4. Minh họa tính tổng S1, S2, S3 không sử dụng chương trình con
3. QUY TẮC XÂY DỰNG HÀM
3.1. Tách những nội dung lặp đi lặp lại thành hàm
Để chương trình trở nên ngắn gọn, dễ hiểu và đặc biệt là tái sử dụng được
nội dung mã lệnh, chúng ta nên tách những nội dung lặp đi lặp lại nhiều lần như
tính i!, tính ai, tính xi ra riêng và viết thành các hàm như sau:
Ví dụ 2.5: Viết lại chương trình tính tổng S1, S2 (trong ví du 2.3) có sử
dụng chương trình con:
#include <stdio.h>
long GiaiThua(int i)
{ int j;
long gt=1;
if(i==0)
return 1;
else
for (j=2; j<=i; j++)
gt=gt*j;
return gt;
};
long xmu(int a, int i)
{ int j;
long kq=a;
if(i==0)
return 1;
else
for(j=2; j<=i; j++)
kq=kq*a;
return kq;
};
63
int main()
{
int n, i, j, a, amui, igt;
float S1=0, S2=0;
printf("Nhap vao so nguyen n = ");
printf("Nhap so nguyen a = ");
scanf("%d", &n);
scanf("%d", &a);
for(i=1; i<=n; i++)
S1=S1+1.0/ (float) GiaiThua(i) ;
printf("Tong S1 = %f\n",S1);
for(i=1;i<=n;i++)
S2=S2+(float) xmu(a,i) / (float) GiaiThua(i) ;
printf("Tong S2 = %f", S2);
return 1;
}
Hình 2.5. Minh họa tính tổng S1, S2 có sử dụng chương trình con
Trong ví dụ 2.5, chúng ta đã tạo 2 hàm: GiaiThua() và xmu(). Sau đó, ta
thay đoạn mã tính i! trong chương trình chính bằng lời gọi hàm GiaiThua(i),
thay đoạn mã tính xi trong chương trình chính bằng lời gọi hàm xmu(x,i).
Ví dụ 2.6: Tính tổng S1, S2, S3 có sử dụng chương trình con:
#include <stdio.h>
long GiaiThua(int i)
{
int j;
long gt=1;
if(i==0)
return 1;
else
for (j=2; j<=i; j++)
gt=gt*j;
return gt;
};
float xmu(float x, int i)
{
int j;
float kq=x;
if(i==0)
return 1;
else
for(j=2; j<=i; j++)
kq=kq*x;
return kq;
};
64
int main()
{
int n, i, j, igt;
float x, xmui, S1=0, S2=0, S3=0;
printf("Nhap vao so nguyen n = ");
printf("Nhap so thuc x = ");
scanf("%d", &n);
scanf("%f", &x);
for(i=0;i<=n;i++)
S1=S1+ xmu(x,i) ;
printf("Tong S1 = %f\n",S1);
for(i=0;i<=n;i++)
{
if(i%2==0)
S2=S2+ xmu(x,i) ;
else
S2=S2- xmu(x,i) ;
}
printf("Tong S2 = %f\n", S2);
for(i=0;i<=n;i++)
S3=S3+ xmu(x,i) / (float) GiaiThua(i) ;
printf("Tong S3 = %f",S3);
return 1;
}
Hình 2.6. Minh họa tính tổng S1, S2, S3 có sử dụng chương trình con
Trong ví dụ 2.6, chúng ta đã tạo 2 hàm: GiaiThua(), xmu(). Thay đoạn mã
tính i! trong chương trình chính bằng lời gọi hàm GiaiThua(i), thay đoạn mã
tính xi trong chương trình chính bằng lời gọi hàm xmu(x,i).
3.2. Tách những nội dung cần chuẩn bị trước thành hàm
Khi lập trình, đối với những bài toán phức tạp, chúng ta nên tách những
phần nội dung cần chuẩn bị trước ra thành hàm như ví dụ sau đây:
Ví dụ 2.7: In dãy số nguyên tố nhỏ hơn n
Để in ra một dãy số nguyên tố nhỏ hơn số n, chúng ta làm như sau:
- Tạo 1 hàm (gọi là hàm isPrime(i)) để kiểm tra số nguyên i có phải là số
nguyên tố hay không. Nếu số nguyên i là số nguyên tố thì hàm này trả về giá trị
1 (true), ngược lại thì trả về giá trị 0 (false).
- Xét lần lượt từng số nguyên i chạy từ 2 tới n và sử dung hàm isPrime(i) ở
trên để kiểm tra số nguyên i có phải là số nguyên tố hay không, nếu phải thì in ra
số i.
65
#include <stdio.h>
int isPrime(int i)
{
int j, so_uoc=0;
for(j=1; j<=i; j++)
if(i%j==0)
so_uoc++;
if(so_uoc==2)
return 1;
else
return 0;
};
int main()
{
int n, i, j, so_uoc;
printf("Nhap vao so n ");
scanf("%d", &n);
printf("Day do nguyen to nho hon so %d:\n", n);
for(i=2; i<=n; i++)
{
if( isPrime(i) )
printf("%d ", i);
}
return 1;
}
Hình 2.7. Minh họa in dãy số nguyên tố nhỏ hơn n có sử dụng chương trình con
Trong ví dụ 2.7, chúng ta đã tạo hàm isPrime() để khi nào cần kiểm tra số
nguyên i có phải là số nguyên tố hay không thì ta chỉ cần gọi hàm isPrime(i).
3.3. Khai báo hàm
3.3.1. Viết chương trình bằng ngôn ngữ C
Khi lập trình theo cú pháp của ngôn ngữ lập trình C (có phần mở rộng là .c)
thì người lập trình có thể khai báo và cài đặt hàm theo 2 cách sau:
- Cách 1: Khai báo và cài đặt cùng lúc ở phía trên hàm main như trong các
ví dụ 2.5, 2.6, 2.7 ở trên.
- Cách 2: Khai báo và cài đặt cùng lúc bên dưới hàm main.
66
Cách 1:
#include <Tên thư viện>
<Kiểu dữ liệu trả về> Tên hàm (Khai báo các tham số hình thức)
{
Khai báo các biến nội bộ.
Thực hiện các câu lệnh bên trong hàm;
return <Kết quả>;
}
int main()
{
Khai báo biến nội bộ của hàm main
Viết lệnh thực hiện nội dung của hàm main
Gọi hàm người dùng đã được khai báo và cài đặt ở trên
}
Cách 2:
#include <Tên thư viện>
int main()
{
Khai báo biến nội bộ của hàm main
Viết lệnh thực hiện nội dung của hàm main
Gọi hàm người dùng đã được khai báo và cài đặt ở bên dưới
}
<Kiểu dữ liệu trả về> Tên hàm (Khai báo các tham số hình thức)
{
Khai báo các biến nội bộ.
Thực hiện các câu lệnh bên trong hàm;
return <Kết quả>;
}
3.3.2. Viết chương trình bằng ngôn ngữ C++
Khi lập trình theo cú pháp của ngôn ngữ lập trình C++ (có phần mở rộng là
.cpp) thì người lập trình có thể khai báo và cài đặt hàm theo 2 cách sau:
- Cách 1: Khai báo và cài đặt hàm cùng lúc bên trên hàm main giống như
cách 1 của ngôn ngữ lập trình C.
- Cách 2: Khai báo prototype phía trên hàm main và cài đặt nội dung hàm
phía dưới hàm main.
#include <Tên thư viện>
<Kiểu dữ liệu trả về> Tên hàm (Khai báo các tham số hình thức);
int main()
{
Gọi hàm người dùng đã được khai báo prototype ở trên
}
67
<Kiểu dữ liệu trả về> Tên hàm (Khai báo các tham số hình thức)
{
Khai báo các biến nội bộ.
Thực hiện các câu lệnh bên trong hàm;
return <Kết quả>;
}
Ví dụ 2.8: Viết lại chương trình ví dụ 2.7 theo cách 2 của ngôn ngữ lập
trình C, C++.
Hình 2.8. Minh họa khai báo và cài đặt hàm trong chương trình C
68
Hình 2.9. Minh họa khai báo và cài đặt hàm trong chương trình C++
Lưu ý:
- <Kiểu dữ liệu trả về>: Là kiểu dữ liệu của kết quả mà hàm trả về qua câu
lệnh return.
+ Trong ví dụ 2.5 và ví dụ 2.5, hàm GiaiThua() tính giai thừa của số
nguyên i và trả về kết quả là biến gt kiểu long, hàm xmu() tính a mũ i và trả về
kết quả là biến kq kiểu long.
+ Trong ví dụ 2.7 hàm isPrime() kiểm tra số nguyên i có phải là số nguyên tố
hay không và trả về kết quả là số 1 hoặc số 0 có kiểu int.
- Tên hàm: Tên của hàm do người lập trình đặt, sau này chúng ta sẻ sử
dụng tên này để gọi hàm mỗi khi có nhu cầu thực hiện nội dung của hàm.
+ Trong ví dụ 2.5 và ví dụ 2.6, hàm người dùng được đặt tên là
GiaiThua và xmu. Trong chương trình chính (hàm main), chúng ta gọi hàm
69
GiaiThua(i) để tính giai thừa của số nguyên i và gọi hàm xmu(a, i) tính tính a
mũ i.
+ Trong ví dụ 2.7, hàm người dùng có tên là isPrime. Trong hàm main,
chúng ta gọi hàm isPrime(i) để kiểm tra số nguyên i có phải là số nguyên tố hay
không.
- <Khai báo các tham số hình thức>: Khai báo các biến hình thức mà hàm
sẻ nhận được từ chương trình gọi hàm.
+ Trong ví dụ 2.5 và ví dụ 2.6, hàm GiaiThua() có khai báo nhận vào
biến i có kiểu int, hàm xmu() có khai báo nhận vào biến a có kiểu int và biến i
có kiểu int.
+ Trong ví dụ 2.7, hàm isPrime() có khai báo nhận vào biến i có kiểu int.
+ Trong hàm main, mỗi khi gọi hàm chương trình con thì người lập trình
truyền cho nó tham số thực tế. Tham số thực tế có thể trùng tên hoặc khác tên
với tham số hình thức nhưng phải có cùng kiểu dữ liệu.
Trong ví dụ dưới đây, hàm isPrime() có tham số hình thức là n và mỗi lần
được gọi thì truyền tham số thực tế là i.
#include <stdio.h>
int main()
{
int i , n, j, so_uoc; /* Biến i trong hàm main là biến thực tế*/
printf("Nhap vao so n ");
scanf("%d", &n);
printf("Day do nguyen to nho hon so %d:\n", n);
for(i=2; i<=n; i++)
{
if( isPrime( i ) ) /*Gọi hàm isPrime() và truyền tham số thực tế i*/
printf("%d ", i);
}
return 1;
}
int isPrime ( int n ) /* Tham số hình thức của hàm isPrime là n */
{
int j, so_uoc=0;
for(j=1;j<=n;j++)
if(i%j==0)
so_uoc++;
if(so_uoc==2)
return 1;
else
return 0;
};
Hình 2.10. Minh họa cách sử dụng biến hình thức và biến thực tế
70
Lưu ý:
- Biến hình thức là biến được khai báo ở đầu hàm người dùng và được sử
dụng bên trong hàm này.
- Biến thực tế là biến được khai báo bên trong hàm main() và được truyền
vào hàm người dùng mỗi khi gọi hàm.
+ Trong hình 2.8, biến n trong hàm isPrime() là biến hình thức. Biến i
trong hàm main được truyền vào hàm isPrime() bằng cách gọi hàm isPrime(i)
nên biến i trong hàm main được gọi là biến hình thức.
+ Trong hình 2.7, biến hình thức của hàm isPrime() là i và biến thực tế
truyền cho hàm isPrime() trong hàm main cũng là i nên gọi hàm isPrime(i).
3.4. Nội dung của hàm
Nội dung của hàm là tất cả các câu lệnh khai báo biến, thực hiện các lệnh
xử lý dữ liệu, vào, ra, và trả về kết quả. Nội dung của hàm được đặt trong cặp
dấu {} tiếp theo phần khai báo biến hình thức.
float xmu( float x, int i )
{
/*Cài đặt nội dung của hàm*/
int j;
float kq=x;
if(i==0)
return 1;
else
for(j=2; j<=i; j++)
kq=kq*x;
return kq;
};
int isPrime( int i )
{
/*Cài đặt nội dung của hàm*/
int j, so_uoc=0;
for(j=1; j<=i; j++)
if(i%j==0)
so_uoc++;
if(so_uoc==2)
return 1;
else
return 0;
};
Hình 2.11. Minh họa phần thân hàm
3.5. Biến nội bộ của hàm
Biến nội bộ của hàm là tất cả các biến được khai báo bên trong hàm. Biến
nội bộ được khai báo để chứa giá trị trả về, chứa các giá trị tạm thời khi thực
hiện hàm, các biến chỉ số. Các biến nội bộ của hàm thường được khai báo ở các
dòng liền sau dấu { của phần thân hàm.
71
float xmu( float x, int i )
{
Khai báo biến nội bộ: Biến j lưu chỉ số,
int j;
biến kq lưu kết quả trả về của hàm
float kq=x;
if(i==0)
return 1;
else
for(j=2;j<=i;j++)
kq=kq*x;
return kq;
};
int isPrime( int i )
{
int j, so_uoc=0;
Khai báo biến nội bộ: Biến j lưu chỉ
số, biến so_uoc lưu giá trị trung
gian khi thực hiện hàm
for(j=1;j<=i;j++)
if(i%j==0)
so_uoc++;
if(so_uoc==2)
return 1;
else
return 0;
};
Hình 2.12. Minh họa khai báo biến nội bộ
3.6. Sử dụng câu lệnh return
Câu lệnh return trả về cho chương trình gọi hàm kết quả thực hiện của hàm
tùy vào giá trị mà hàm nhận được thông qua các tham số hình thức. Lệnh return
có thể trả về hằng giá trị hoặc giá tri được lưu trong biến nội bộ.
float xmu( float x, int i )
{
int j;
float kq=x;
if(i==0)
Trả về hằng giá trị
return 1 ;
else
for(j=2;j<=i;j++)
kq=kq*x;
return kq ;
Trả về giá trị lưu trong
};
biến nội bộ có tên là kq
int isPrime( int i )
{
int j, so_uoc=0;
for(j=1;j<=i;j++)
if(i%j==0)
so_uoc++;
72
if(so_uoc==2)
return 1 ;
else
return 0 ;
Lệnh return trả
về hằng giá trị
};
Hình 2.13. Minh họa sử dụng lệnh return
3.7. Nguyên tắc hoạt động của hàm
Hàm trong C và C++ phải trả về một giá trị nào đó thuộc các kiểu dữ liệu
chuẩn mà chúng ta đã được biết ở chương 1 (char, unsigned char, int, unsigned
int, long, float, double) thông qua câu lệnh return. Trong thường hợp hàm trả về
nhiều hơn 1 giá trị thì ta có thể gán giá trị trả về cho biến hình thức được khai
báo ở đầu hàm.
Trong trường hợp hàm không cần trả về giá trị thì chúng ta có thể khai báo
hàm có kiểu dữ liệu trả về là void và không cần dùng câu lệnh return. Tuy nhiên,
để điều khiển được các hàm một cách tốt nhất, tất cả các hàm nên có giá trị trả
về. Trường hợp không có giá trị trả về thì nên trả về giá trị kiểu int, nếu hàm
thực hiện thành công thì return 1, nếu thất bại thì return 0 hoặc thất bại thì trả về
các con số quy định lỗi khi thực hiện.
Khi một chương trình nào đó (ví dụ hàm main) gọi 1 hàm thì chương trình
gọi hàm phải truyền cho hàm được gọi các giá trị có kiểu giống với khai báo
trong hàm được gọi. Hơn nữa, cách truyền tham số cũng phải giống với truyền
tham số đã được khai báo trong phần khai báo tham số hình thức ở đầu hàm.
Điều này có nghĩa là biến thực tế khi truyền cho hàm phải có kiểu dữ liệu giống
với biến hình thức.
Kết quả trả về của hàm cũng có thể được ép kiểu cho phù hợp với kiểu dữ
liệu đang được sử dụng trong chương trình gọi hàm. Ví dụ: hàm GiaiThua() và
hàm xmu() trả về kết quả kiểu long, trong hàm main(), để lấy kết quả giai thừa
và mũ kiểu số thực thì chọn phương pháp ép kiểu dữ liệu để chuyển sang kiểu
float.
4. TRUYỀN THAM SỐ KHI GỌI HÀM
4.1. Cách truyền tham số trong C
Khi viết chương trình theo cú pháp của ngôn ngữ lập trình C thì có 2 cách
truyền tham số khi gọi hàm là truyền bằng giá trị và truyền bằng địa chỉ như sau:
4.1.1. Truyền bằng giá trị
Truyền tham số bằng giá trị thực chất là truyền giá trị vào vị trí của tham số
hình thức. Mọi sự thay đổi bên trong hàm trên biến hình thức không ảnh hưởng
đến giá trị của biến thực tế bên ngoài hàm. Việc truyền tham số bằng giá trị
được khai báo như sau:
<Kiểu dữ liệu tra về> Tên hàm (Kiểu dữ liệu 1 Biến 1[, Kiểu dữ liệu 2 Biến2 [,…]])
{
…
}
73
Khi gọi hàm, chỉ cần sử dụng tên hàm và truyền cho hàm hằng giá trị
hoặc giá trị thông qua tên biến như sau:
Tên hàm (Hằng giá trị[, Hằng giá trị 2[,… [Tên biến 1 [,…[Tên biến n]]]]])
Ví dụ 2.9: Truyền tham số bằng giá trị
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
int HoanVi1( int a, int b )
{
int tam;
tam=a;
a=b;
b=tam;
printf("Ben trong ham HoanVi1: a=%d; b=%d\n",a,b);
return 1;
}
int main()
{
int so1=10, so2=20;
printf("Truoc khi goi ham HoanVi1: so1=%d; so2=%d\n",so1, so2);
HoanVi1( so1 , so2 );
printf("Sau khi goi ham HoanVi1: so1=%d; so2=%d\n",so1, so2);
return 1;
}
Hình 2.14. Minh họa truyền tham số bằng giá trị trong C
Hình 2.15. Kết quả minh họa truyền tham số bằng giá trị trong C
Giải thích:
 Biến a, b, trong hàm HoanVi1() là biến hình thức.
 Biến so1, so2 trong hàm main là biến thực tế.
 Trước khi gọi hàm HoanVi 1(), so1=10; so2=20;
 Khi gọi hàm HoanVi (so1, so2) là truyền giá trị của biến so1 (là số 10)
cho biến a và truyền giá trị của biến so2 (là số 20) cho biến b.
 Bên trong hàm HoanVi 1():
o Thực hiện lệnh tam=a; xong thì tam có giá trị là 10.
o Thực hiện lệnh a=b; xong thì a có giá trị là 20.
o Thực hiện lệnh b=tam; xong thì b có giá trị là 10.
74
 Khi thực hiện xong HoanVi1(): Giá trị của 2 biến so1, so2 vẫn không
đổi vì hàm HoanVi1() không thao tác trực tiếp lên biến so1 và so2.
4.1.2. Truyền bằng địa chỉ
Truyền tham số bằng địa chỉ thực chất là truyền biến thực tế vào vị trí của
tham số hình thức của hàm. Mọi sự thay đổi bên trong hàm trên biến hình thức
chính là thay đổi trên biến thức tế. Cú pháp khai báo hàm như sau:
<Kiểu dữ liệu tra về> Tên hàm (Kiểu dữ liệu 1 *Biến 1, Kiểu dữ liệu 2 *Biến2 ,…)
{
}
Khai báo có dấu * trước tên biến hình thức. Khi gọi hàm thì có dấu & trước
tên biến thực tế như sau:
Tên hàm (&Biến 1 [,& Biến 2[,…]])
Ví dụ 2.10: Truyền tham số bằng địa trị
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
int HoanVi2( int *a , int *b )
{
int tam;
tam=*a;
*a=*b;
*b=tam;
printf("Ben trong ham HoanVi2: a=%d; b=%d\n",*a,*b);
return 1;
}
int main()
{
int so1=10, so2=20;
printf("Truoc khi goi ham HoanVi2: so1=%d; so2=%d\n",so1, so2);
HoanVi2( &so1 , &so2 );
printf("Sau khi goi ham HoanVi2: so1=%d; so2=%d\n",so1, so2);
return 1;
}
Hình 2.16. Minh họa truyền tham số bằng địa trị trong C
Hình 2.17. Kết quả minh họa truyền tham số bằng địa trị trong C
75
Giải thích:
 Biến a, b, trong hàm HoanVi2() là biến hình thức.
 Biến so1, so2 trong hàm main là biến thực tế có giá trị lần lượt là 10, 20.
 Khi gọi hàm HoanVi2 (&so1, &so2) thực chất là truyền địa trị của biến
so1 cho biến a và truyền địa trị của biến so2 cho biến b.
 Bên trong hàm HoanVi2 ():
o Thực hiện lệnh tam=*a; thực chất là lấy giá tri của biến so1 gán
cho biến tam nên biến tam có giá trị là 10.
o Thực hiện lệnh *a=*b; thực chất là lấy giá trị của biến so2 gán cho
biến so1 nên biến so1 là 20.
o Thực hiện lệnh *b=*tam; thực chất là lấy giá trị của biến tam gán
cho biến so2 nên biến so2 là 10.
 Khi thực hiện xong hàm HoanVi2(): Giá trị của biến so1 là 20 và giá trị của
biến so2 là 10
4.2. Cách truyền tham số trong C++
Khi viết chương trình theo cú pháp của ngôn ngữ lập trình C++ (chương
trình có phần mở rộng là .cpp) thì có 2 cách truyền tham số khi gọi hàm là
truyền bằng giá trị và truyền bằng tham chiếu như sau:
4.2.1. Truyền bằng giá trị
Truyền bằng giá trị trong C++ cũng giống như truyền bằng giá trị trong C.
Ví dụ 2.11: Viết lại ví dụ 2.9 bằng C++ như sau:
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <iostream>
using namespace std;
int HoanVi3( int a, int b )
{
int tam;
tam=a;
a=b;
b=tam;
cout<<"Ben trong ham HoanVi3: a= "<<a<<" b= "<<b<<endl;
return 1;
}
int main()
{
int so1=10, so2=20;
cout<<"Truoc khi goi ham HoanVi3: so1= "<<so1<<" so2= "<<so2<<endl;
HoanVi3( so1 , so2 );
cout<<"Sau khi goi ham HoanVi3: so1= "<<so1<<" so2= "<<so2<<endl;
return 1;
}
Hình 2.18. Minh họa truyền tham số bằng giá trị trong C++
76
Hình 2.19. Kết quả minh họa truyền tham số bằng giá trị trong C++
4.2.2. Truyền bằng tham chiếu
Cách truyền tham số bằng tham chiếu trong ngôn ngữ lập trình C++ được
thực hiện theo cú pháp sau:
- Thêm dấu & vào phía trước tên biến hình thức khi khai báo biến hình thức
trong hàm.
- Khi gọi hàm chứa biến tham chiếu thì chúng ta KHÔNG phải thêm dấu &
vào trước tên biến tham chiếu.
<Kiểu dữ liệu tra về> Tên hàm (Kiểu dữ liệu &Biến 1[, Kiểu dữ liệu &Biến2 [,…]])
{
}
Ví dụ 2.12: Truyền tham số bằng tham chiếu trong C++
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <iostream>
using namespace std;
int HoanVi4( int &a, int &b )
{
int tam;
tam=a;
a=b;
b=tam;
cout<<"Ben trong ham HoanVi4: a= "<<a<<" b= "<<b<<endl;
return 1;
}
int main()
{
int so1=10, so2=20;
cout<<"Truoc khi goi ham HoanVi4: so1= "<<so1<<" so2= "<<so2<<endl;
HoanVi4( so1 , so2 );
cout<<"Sau khi goi ham HoanVi4: so1= "<<so1<<" so2= "<<so2<<endl;
return 1;
}
Hình 2.20. Minh họa truyền tham số bằng tham chiếu trong C++
77
Hình 2.21. Kết quả minh họa truyền tham số bằng tham chiếu trong C++
Giải thích:
 Trước khi gọi hàm HoanVi4(): biến so1 có giá trị là 10, biến so2 có giá
trị là 20;
 Khi gọi hàm HoanVi4(so1, so2) là truyền biến thực tế so1 vào vị trí của
biến hình thức a và truyền biến thực tế so2 vào vị trí biến hình thức b.
 Bên trong hàm HoanVi4():
o Thực hiện lệnh tam=a; thực chất là lấy giá tri của biến so1 gán cho
biến tam nên biến tam có giá trị là 10.
o Thực hiện lệnh a=b; thực chất là lấy giá tri của biến so2 gán cho
biến so1 nên biến so2 có giá trị là 20.
o Thực hiện lệnh b=tam; thực chất là lấy giá trị của biến tam gán cho
biến so2 nên biến so2 có giá trị là 10.
4.3. Lưu giá trị trả về vào biến hình thức
Hầu hết các hàm đều trả về một giá trị thông qua câu lệnh return. Trong
trường hợp hàm cần trả về nhiều hơn 1 giá trị thì người ta thường lưu giá trị trả
về vào biến hình thức theo cú pháp truyền tham số bằng địa chỉ trong C hoặc
truyền tham số bằng tham chiếu trong C++.
4.3.1. Tham số hình thức dùng để lưu kết quả trả về trong C
Cách thực hiện khai báo biến hình thức và truyền tham số giống thực chất
là khai báo và truyền tham số bằng địa chỉ trong C.
Ví dụ 2.13: Sử dụng tham số lưu giá trị trả về trong C
#include <stdio.h>
int MaxMin(int a, int b, int *max, int *min )
{
if (a>b)
{
*max=a;
*min=b;
}
else
{
*max=b;
*min=a;
}
return 1;
}
78
int main()
{
int a, b, max, min;
printf("Nhap vao 2 so nguyen =");
scanf("%d%d", &a, &b);
MaxMin(a, b, &max, &min );
printf("So lon la %d, so nho la %d", max, min );
return 1;
}
Hình 2.22. Minh họa sử dụng tham số lưu giá trị trả về trong C
Hình 2.23. Kết quả minh họa sử dụng tham số lưu giá trị trả về trong C
4.3.2. Tham số hình thức dùng để lưu kết quả trả về trong C++
Cách thực hiện khai báo biến hình thức và truyền tham số giống thực chất
là khai báo và truyền tham số bằng tham chiếu trong C++.
Ví dụ 2.14: Sử dụng tham số lưu giá trị trả về trong C
#include <iostream>
using namespace std;
int MinMax(int a, int b, int &min, int &max )
{
if(a<b)
{
min=a;
max=b;
}
else
{
min=b;
max=a;
}
return 1;
}
int main()
{
int a, b, min, max;
cout<<"Nhap vao 2 so nguyen =";
cin>>a>>b;
MinMax(a, b, min, max );
cout<<"So nho la "<< min <<", so lon la "<< max <<endl;
return 1;
}
Hình 2.24. Minh họa sử dụng tham số lưu giá trị trả về trong C++
79
Hình 2.25. Kết quả minh họa sử dụng tham số lưu giá trị trả về trong C++
5. HÀM ĐỆ QUY
5.1. Khái niệm
Một hàm được gọi là hàm đệ quy (recursion) nếu trong thân của hàm có lời
gọi đến chính bản thân nó. Hàm đệ quy được thiết kế dựa trên cách định nghĩa
một bài toán bằng đệ quy.
Ví dụ 2.15: Thiết kế hàm tính giải thừa bằng phương pháp đệ quy
Theo định nghĩa giai thừa thì n!= 1*2*3*…*(n-2)*(n-1)*n.
Mặc khác 1*2*3*…*(n-2)*(n-1)=(n-1)!.
Do dó, ta có thể định n giai thừa theo phương pháp đệ quy là n!=n* (n-1)!.
Trường hợp đặc biệt 0!=1.
/*Coded by Dr. Duong Van Hieu on 12/10/2018*/
#include <stdio.h>
long GiaiThua( long n )
{
if(n==0)
return 1;
else
return n * GiaiThua( n-1 ) ;
}
int main()
{
int i;
for (i=0;i<5;i++)
printf("%d! = %d\n",i, GiaiThua(i) );
return 1;
}
Hình 2.26. Minh họa tính n! bằng hàm đệ quy
Ví dụ 2.16: Tính tổng của các số trong một số nguyên n bằng hàm đệ quy
//Coded by Dr. Duong Van Hieu on 21/10/2018
#include <iostream>
using namespace std;
long Tong(long n )
{
if(n<10)
return n;
80
else
return (n%10)+ Tong(n/10) ;
}
int main()
{
long n;
cout<<"Nhap vao mot so nguyen lon =";
cin>>n;
cout<<"Tong cac chu so cua so "<<n<<" la "<<Tong(n);
return 1;
}
Hình 2.27. Minh họa tính tổng của các số trong số nguyên n bằng hàm đệ quy
Hình 2.28. Kết quả minh họa tính tổng của các số trong số nguyên n bằng hàm
đệ quy
5.2. Kỹ thuật thiết kế đệ quy
Hàm đệ quy chỉ giải quyết được những bài toán mang tính truy hồi (được
định nghĩa bằng đệ quy). Do đó khi thiết kế hàm đệ quy cần phải có hai điều
kiện sau đây:
- Phải có một trường hợp "nguyên tố", tức là trường hợp mà khi truy hồi
đến đó thì kết thúc. Trong ví dụ tính n! là trường hợp n=0, trong ví dụ tính tổng
các số của một số nguyên là trường hợp n<10.
- Trong lời gọi đệ quy phải có yếu tố dẫn đến trường hợp "nguyên tố".
Trong ví dụ tính n! thì lời gọi hàm tính giai thừa của n-1 dẫn đến trường hợp
nguyên tố, trong ví dụ tính tổng của các số trong một số nguyên n thì lời gọi
hàm tính tổng của các số trong n/10 dẫn đến trường hợp nguyên tố.
Việc sử dụng hàm đệ quy cho ta một chương trình gọn đẹp, tuy nhiên đệ
quy đòi hỏi rất nhiều ô nhớ để lưu kết quả trung gian nên tốn bộ nhớ và thời gian
thực hiện cũng chậm. Vì vậy chỉ nên dùng đệ quy khi không thể dùng vòng lặp.
6. LƯU Ý SỬ DỤNG BIẾN TOÀN CỤC VÀ BIẾN CỤC BỘ
6.1. Phạm vi của biến
Khi lập trình bằng bất kỳ ngôn ngữ lập trình nào thì người lập trình cũng
phải hiểu rõ phạm vi của biến. Phạm vi của biến có nghĩa là phạm vi có hiệu lực
của biến hay nói cách khác là phạm vi mà biến được sử dụng.
6.2. Biến toàn cục
Như đã nói ở phần khai báo biến, biến toàn cục là biến được khai báo bên
ngoài tất cả các hàm (kể cả hàm main) và được sử dụng bởi tất cả các hàm. Biến
toàn cục là biến được khai báo để sử dụng chung các chương trình con và hàm
81
main nên mọi thay đổi trên biến toàn cục đều ảnh hưởng đến các hàm có sử
dụng biến toàn cục. Người lập trình không nên sử dụng biến toàn cục trừ khi bắt
buộc phải sử dụng vì rất dễ xảy ra sai sót khi sử dụng biến toàn cục.
6.3. Biến cục bộ
Như đã nói ở phần khai báo biến, biến cục bộ là biến được khai báo trong
hàm main hoặc bên trong hàm do người dùng tạo ra hoặc bên trong khối lệnh.
Biến cục bộ chỉ có thể được sử dụng trong khối lệnh hoặc hàm chứa nó. Hai
hàm khác nhau hoặc 2 khối lệnh khác nhau có thể khai báo biến cục bộ cùng tên.
Ví dụ 2.17: Viết chương trình tính tổng N số nguyên và tổng N số thực có
sử dụng biến toàn cục và cục bô.
- Sử dụng biến toàn cục N để lưu số số hạng.
- Biến toàn cục ai để nhập số nguyên thứ i.
- Biến toàn cục TongNSoNguyen để lưu tổng của N số nguyên.
- Biến toàn cục xi để nhập số thực thứ i.
- Biến toàn cục TongNSoThuc để lưu tổng của N số thực.
- Trong hàm tongNguyen(): Biến cục bộ i thể hiện chỉ số, tong để lưu tổng
N số nguyên.
- Trong hàm tongThuc(): Biến cục bộ i thể hiện chỉ số, biến tong để lưu
tổng N số thực.
#include <stdio.h>
#include<conio.h>
int N, ai,TongNSoNguyen;
float xi, TongNSoThuc;
/*Bien toan cuc*/
/*Bien toan cuc*/
long TongNguyen()
{
long i, tong=0;
/*Bien cuc bo cua ham TongNguyen()*/
for(i=1; i<= N ;i++)
{
printf("Nhap vao so nguyen thu %d=",i);
scanf("%d", &ai );
tong += ai ;
}
return tong;
}
float TongThuc()
{
int i;
float tong=0.0;
/*Bien cuc bo cua ham TongThuc()*/
for(i=1;i<= N ; i++)
82
{
printf("Nhap vao so thuc thu %d=",i);
scanf("%f", &xi );
tong+= xi ;
}
return tong;
}
int main ()
{
printf("Tong cua bao nhieu so hang? ");
scanf("%d", &N ); /*Nhap gia tri cho bien toan cuc*/
TongNSoNguyen = TongNguyen();/*Gan gia tri cho bien toan cuc*/
printf("Tong cua %d so nguyen vua nhap la %d\n", N ,
TongNSoNguyen );
TongNSoThuc = TongThuc();/*Gan gia tri cho bien toan cuc*/
printf("Tong cua %d so thuc vua nhap la %.3f\n", N , TongNSoThuc );
return 1;
}
Hình 2.29. Minh họa sử dụng biến toàn cục
Hình 2.30. Kết quả minh họa sử dụng biến toàn cục
7. BÀI TẬP
7.1. Câu hỏi ôn tập
Câu 1: Hàm thư viện là gì? Cho 1 ví du về cách dùng hàm thư viện.
Câu 2: Hàm người dùng là gì? Cho 1 ví dụ về cách tạo hàm người dùng.
83
Câu 3: Giải thích cách sử dụng kiểu dữ liệu trả về của hàm bằng lệnh return.
Cho ví dụ.
Câu 4: Giải thích cách khai báo tham số hình thức. Cho ví dụ minh họa.
Câu 5: Giải thích các truyền tham số bằng giá trị trong C, C++. Cho ví dụ minh
họa.
Câu 6: Giải thích các truyền tham số bằng địa chỉ trong C. Cho ví dụ minh họa.
Câu 7: Giải thích cách truyền tham số bằng tham chiếu trong C++. Cho ví du
minh họa.
Câu 8: Giải tích cách sử dụng tham số hình thức vào trong C, C++. Cho ví dụ
minh họa.
Câu 9: Giải tích cách sử dụng tham số hình thức ra trong C. Cho ví dụ minh
họa.
Câu 10: Giải tích cách sử dụng tham số hình thức vào và ra trong C. Cho ví dụ
minh họa.
Câu 11: Giải tích cách sử dụng tham số hình thức ra trong C++. Cho ví dụ minh
họa.
Câu 12: Giải tích cách sử dụng tham số hình thức vào và ra trong C++. Cho ví
dụ minh họa.
Câu 13: Nêu lợi ích của việc tạo hàm người dùng.
Câu 14: Nếu nguyên tắc tạo hàm người dùng.
Câu 15: Hàm đệ quy là gì? Cho 1 ví dụ.
Câu 16: Điều kiện để thiết kế hàm đệ quy. Cho ví dụ minh họa.
Câu 17: Ưu điểm và nhược điểm của việc sử dụng hàm đệ quy.
Câu 18: So sánh giữa các truyền tham số bằng địa chỉ trong C và tuyền tham số
bằng tham chiếu trong C++.
Câu 19: Biến toàn cục là gì? Cho ví dụ minh họa.
Câu 20: Biến cục bộ là gì? Cho ví dụ minh họa.
7.2. Bài tập thực hành
Bài 1: Viết hàm tìm ước số chung lớn nhất của 2 số nguyên dương a và b, bội số
chung nhỏ nhất của 2 số nguyên dương a và b.
Gợi ý thực hiện:
- Khai báo hàm như sau:
int UCLN(int a, int b)
{
int uc;
…
return uc;
};
84
int BCNN(int a, int b)
{
int bc;
…
return bc;
};
- Viết khai báo các thư viện, biến cần thiết. Viết hàm main nhập vào 2 số
nguyên a, b và in ra ước số chung lớn nhất, bội số chung nhỏ nhất của chúng.
Bài 2:Tính hàm tính tổng của các chữ số trong một số nguyên.
Gợi ý thực hiện:
- Khai báo hàm như sau:
int TongSo(long n)
{
…
};
- Viết khai báo thư viện, biến cần thiết.Viết hàm main nhập vào 1 số
nguyên và in ra tổng của các số bên trong số nguyên đó.
Bài 3:Viết hàm tính giai thừa của số nguyên n và tính tổ hợp chập k của n. Cho
𝑛!
biết công thức tính tổ hợp chập k của n là 𝐶𝑛𝑘 =
. Tam giác Pascal là một
𝑘!(𝑛−𝑘)!
tam giác mà mỗi số hạng thứ k của dòng thứ n+1 là một tổ hợp chập k của n
1
(dòng thứ 0)
1
1
(dòng thứ 1)
1
2
1
(dòng thứ 2)
1
3
3
1
(dòng thứ 3)
1
4
6
4
1
(dòng thứ 4)
Gợi ý thực hiện:
- Khai báo hàm như sau:
long GiaThua(long n)
{
…
};
int ToHop(int k, int n)
{
…
};
- Viết khai báo thư viện, biến cần thiết. Viết hàm main nhập vào số
nguyên dương n và in ra tam giác Pascal có n+1 dòng.
85
Bài 4: Viết hàm tính giai thừa của số nguyên n và tính mũ n của số thực x.
Gợi ý thực hiện:
- Khai báo hàm như sau:
long GiaThua(long n)
{
…
};
float mu(float x, int n)
{
…
};
- Viết khai báo thư viện, biến cần thiết. Viết hàm main tính các tổng 𝑆1 =
∑𝑛𝑖=0 𝑥 𝑖 ; 𝑆2 = ∑𝑛𝑖=0(−1)𝑖 𝑥 𝑖 ; 𝑆3 = ∑𝑛𝑖=0
𝑥𝑖
𝑖!
Bài 5: Viết hàm tính giá trị Fibonacci tại vị trí thứ i trong dãy số Fibonacci bằng
định nghĩa đệ quy như sau:
1, 𝑛ế𝑢 𝑖 = 1
𝐹𝑖𝑏𝑜(𝑖) = {
2, 𝑛ế𝑢 𝑖 = 2
𝐹𝑖𝑏𝑜(𝑖 − 1) + 𝐹𝑖𝑏𝑜(𝑖 − 2), 𝑛ế𝑢 𝑖 > 2
Viết khai báo thư viện, biến cần thiết. Viết hàm main đọc vào số n và in ra
dãy số Fibonacci từ 1 đến n.
Bài 6: Viết hàm tính giá trị tổ hợp chập k của n bằng định nghĩa đệ quy như sau:
1, 𝑛ế𝑢 𝑘 = 0 ℎ𝑜ặ𝑐 𝑘 = 𝑛
𝐶𝑛𝑘 = { 𝑘−1
𝑘
𝐶𝑛−1 + 𝐶𝑛−1
, 𝑛ế𝑢 1 < 𝑘 < 𝑛
Viết khai báo thư viện, biến cần thiết. Viết hàm main đọc vào số n và in ra tam
giác Pascal có n+1 dòng.
Bài 7: Viết hàm tìm số đảo của một số nguyên lớn theo định dạng sau:
long DaoSo(long n)
{
long soDao;
…
return soDao;
}.
Ví dụ số đảo của số 123456789 là số 987654321
Viết khai báo thư viện, biến cần thiết. Viết hàm main đọc vào số nguyên
lớn n và in ra số đảo của số n.
Bài 8: Viết hàm kiểm tra một số nguyên có phải là số đối xứng hay không theo
dạng sau:
int DoiXung(long n)
86
{
…
}.
Ví dụ số 123454321 là số đối xứng, số 1221 là số đối xứng.
Viết khai báo thư viện, biến cần thiết. Viết hàm main đọc vào số nguyên lớn n
và in ra kết quả kiểm tra n có phải số đối xứng hay không.
Bài 9: Viết hàm kiểm tra một số nguyên n có phải là số chẵn hay không, hàm
tính tổng các số của một số nguyên lớn, hàm kiểm tra số n có chia hết cho 3 hay
không theo dạng sau:
long SoChan(long n)
{…};
long TongSo(long n)
{…};
long Chia3(long n)
{…};
Số n chia hết cho 3 nếu tổng của các số chia hết cho 3.
Viết khai báo thư viện, biến cần thiết. Viết hàm main đọc vào số nguyên
lớn n và in ra kết quả kiểm tra n có chia hết cho 6 hay không. Biết số n chia hết
cho 6 khi chia hết cho 2 và cho 3.
Bài 10: Viết hàm kiểm tra một số nguyên n có phải là số nguyên tố hay không,
hàm tìm số nguyên tố tiếp theo số nguyên tố n theo dạng sau:
int isPrime(long n)
{…};
long nextPrime(long n)
{…};
Viết khai báo thư viện, biến cần thiết. Viết hàm main đọc vào số nguyên
lớn n kiểm tra n có phải số nguyên tố hay không. Nếu phải thì tìm số nguyên tố
tiếp theo số n.
---oOo---
87
Chương 3. LẬP TRÌNH VỚI DỮ LIỆU CÓ CẤU TRÚC
Mục tiêu của chương này
1. Về kiến thức:
- Hiểu khái niệm mảng 1 chiều, mảng nhiều chiều, biến mảng, con trỏ,
biến con trỏ; hiểu mối quan hệ giữa mảng và chuỗi ký tự, mối tương
quan giữa con trỏ và chuỗi.
- Biết cách khai báo biến mảng 1 chiều và nhiều chiều, biến chuỗi; gán
giá trị cho từng phần tử của biến mảng, biến chuỗi; biết cách truy xuất
giá trị của từng thành phần trong mảng, trong chuỗi; biết cách khai
báo biến con trỏ, cấp phát bộ nhớ cho biến con trỏ, thu hồi bộ nhớ,
gán giá trị cho biến con trỏ.
2. Về kỹ năng:
- Sử dụng được các biến kiểu mảng 1 chiều, mảng nhiều nhiều; chuỗi,
con trỏ.
- Phân biệt được cách sử dụng mảng, chuỗi, con trỏ.
- Áp dụng cách khai báo, gán giá trị, truy xuất giá trị của biến mảng và
biến chuỗi; sử dụng mối quan hệ giữa con trỏ, chuỗi, mảng.
3. Về thái độ:
- Nhận thức được tầm quan trong của việc sử dụng các kiểu dữ liệu có
cấu trúc như mảng, chuỗi, con trỏ trong ngôn ngữ C, C++.
1. KHÁI NIỆM KIỂU DỮ LIỆU CÓ CẤU TRÚC
Trong chương 1, chúng ta đã biết các kiểu dữ liệu chuẩn của C, C++. Đó là
các kiểu dữ liệu không có cấu trúc. Trong chương 2, tham số của hàm thuộc các
kiểu dữ liệu chuẩn. Chương 3, chúng ta sẻ làm quen với các kiểu dữ liệu có cấu
trúc. Kiểu dữ liệu có cấu trúc là kiểu dữ liệu mà mỗi giá trị của nó là một tập
hợp các giá trị thuộc 1 hoặc nhiều kiểu dữ liệu khác nhau.
Ví dụ 3.1: Kiểu Date (ngày tháng năm) là một kiểu dữ liệu có cấu trúc vì
mỗi giá trị kiểu Date bao gồm các giá trị thành phần là Day, Month, Year.
Ví dụ 3.2: Một dãy các giá trị (còn gọi là một mảng) là một tập hợp các giá
trị có cùng 1 kiểu, một chuỗi ký tự làm một tập hợp các ký tự có cùng kiểu char
hoặc unsigned char, một cấu trúc (struct) là một tập hợp các giá trị thuộc nhiều
kiểu khác nhau.
2. KIỂU MẢNG
2.1. Mảng 1 chiều
2.1.1. Định nghĩa
Mảng là một dãy các giá trị có cùng một kiểu dữ liệu, có cùng một tên gọi.
Việc quản lý và truy xuất từng giá trị của các phần tử trong mảng được thực hiện
thông qua tên biến mảng và chỉ số của phần tử trong mảng.
Ví dụ 3.3: Vé số trúng tưởng Mega ngày 01/01/2017 là một dãy gồm 6 số
được biểu diễn thành 1 mảng:
88
Chỉ số
0
1
2
3
4
5
Giá trị
Trong ngôn ngữ lập trình C và C++, chỉ số của các phần tử trong một
mảng có n phần tử được đánh số từ 0 đến n-1.
Mảng 1 chiều là một dãy các giá trị có cùng kiểu dữ liệu được lưu trữ theo
dạng 1 chiều. Chúng ta có thể hình dung 1 mảng các số nguyên là 1 dãy các số
nguyên được bố trí trên cùng 1 hàng ngang hoặc 1 trên cùng 1 hàng dọc.
2.1.2. Khai báo biến
a) Khai báo tường minh, không gán giá trị khởi tạo
Cách thứ nhất để khai báo biến mảng 1 chiều là cho biết biến mảng có kiểu
dữ liệu gì và gồm bao nhiêu phần tử. Cách khai báo này gọi là khai báo tường
minh vì chúng ta cho biết rõ biến mảng có tối đa bao nhiêu phần tử. Khi khai
báo biến mảng 1 chiều có cho biết số phần tử thì chương trình trình biên dịch
ngôn ngữ C và C++ sẻ dành trước không quan lưu trữ đủ để lưu số lượng phần
tử của mảng.
Giá trị của từng phần tử sẻ được gán khi thực hiện chương trình. Khai báo
biến mảng 1 chiều tường minh theo cú pháp sau:
<Kiểu dữ liệu> Tên biến mảng [<Số phần tử>];
Ví dụ 3.4: Khai báo một biến mảng có tên dayso để lưu 6 số nguyên như sau:
int dayso[6];
b) Vừa khai báo biến vừa gán giá trị khởi tạo
Cách thứ hai để khai báo biến mảng 1 chiều là vừa khai báo vừa gán giá trị
khởi tạo cho các thành phần của biến mảng. Đây cũng là cách khai báo tường
minh vì thông qua các giá trị khởi tạo, ta cho trình biên dịch biết biến mảng có
tối đa bao nhiêu phần tử. Khi khai báo biến bảng có kết hợp với giá trị khởi tạo
thì trình biên dịch sẻ dành không gian lưu trử đủ để lưu các giá trị khởi tạo cho
mảng. Vừa khai báo mảng 1 chiều vừa gán giá trị theo cú pháp sau:
<Kiểu dữ liệu> Tên biến mảng [Số phân tử]={Giá trị 1, Giá trị 2,…, Giá trị n};
Hoặc
<Kiểu dữ liệu> Tên biến mảng []={Giá trị 1, Giá trị 2,…, Giá trị n};
c) Khai báo không tường minh
Khai báo không tường minh là kiểu khai báo mà chúng ta không cho biết
trước mảng có tối đa bao nhiêu phần tử. Chỉ áp dụng hiểu khai báo không
thường minh khi khai báo biến hình thức của hàm. Khai báo không tường minh
theo cú pháp sau:
<Kiểu dữ liệu> Tên biến mảng [];
2.1.3. Truy cập giá trị của biến
89
Các phần tử của 1 biến mảng có n phần tử được truy xuất thông qua tên
biến mảng kèm theo chỉ số từ 0 đến n-1 theo cú pháp sau:
Tên biến mảng [Chỉ số];
Ví dụ 3.5: Khai báo biến mảng 1 chiều tường minh và truy xuất phần tử của
mảng
- Khai báo biến mảng có tên là GiaiDacBiet gồm 6 số nguyên và gán trực
tiếp các số 09, 18,24, 33, 36, 39 trong lúc khởi tạo mảng.
- Khai báo biến mảng có tên là SoCuaBan gồm 6 số nguyên sẻ được nhập
vào từ bàn phím.
- Thực hiện việc so sánh: nếu 6 số của dãy số SoCuaBan bằng với 6 số của
dãy số GiaiDacBiet thì xuất ra màn hình câu thông báo “Chúc mừng bạn đã
trúng giải Jackpot”, ngược lại thì xuất ra màn hình câu thông báo “Chúc bạn
may mắn lần sau”.
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
int main()
Khai báo tường minh,
{
vừa khai báo vừa khởi
int GiaiDacBiet[]={9, 18, 24, 33, 36, 39} ; tạo giá trị
Khai báo tường minh,
không khởi tạo gái trị
int i, SoCapTrung, SoCuaBan[6] ;
printf("Nhap vao day so cua ban gom 6 so = ");
for(i=0;i<6;i++)
Nhập từng giá trị và
scanf("%d", &SoCuaBan[i] );
gán cho các phần từ
thứ i của mảng
printf("Giai so dac biet la: ");
Truy xuất giá trị của từng
for(i=0;i<6;i++)
phần từ thứ i của mảng và
printf("%d\t", GiaiDacBiet[i] ); in ra
printf("\nGiai so cua ban la: ");
Truy xuất giá trị của từng
for(i=0;i<6;i++)
phần từ thứ i của mảng và
printf("%d\t", SoCuaBan[i] ); in ra
SoCapTrung=0;
for(i=0;i<6;i++)
if( SoCuaBan[i] == GiaiDacBiet[i] )
So sánh giá trị của phần tử
SoCapTrung++;
thứ i trong 2 mảng với nhau
if(SoCapTrung==6)
printf("\nChuc mung ban da trung giai Jackpot");
else
printf("\nChuc ban may man lan sau");
90
return 1;
}
Hình 3.1. Minh họa khai báo biến tường minh và xử lý phần tử của mảng
Hình 3.2. Kết quả minh họa khai báo biến tường minh và xử lý phần tử của mảng (1)
Hình 3.3. Kết quả minh họa khai báo biến tường minh và xử lý phần tử của mảng (2)
Ví dụ 3.6: Kết hợp các kiểu khai báo mảng 1 chiều
- Viết hàm int SoSanh(M1, M2, n) để so sánh giá trị của 2 mảng số
nguyên M1, M2 có độ dài n phần tử. Nếu 2 mảng giống nhau thì trả về 1, ngược
lại trả về 0.
- Viết hàm main():
 Khai báo biến mảng có tên là GiaiDacBiet gồm 6 số nguyên và gán
trực tiếp các số 09, 18,24, 33, 36, 39 trong lúc khởi tạo mảng.
 Khai báo biến mảng có tên là SoCuaBan gồm 6 số nguyên sẻ được
nhập vào từ bàn phím.
 Gọi hàm SoSanh(GiaiDacBiet, SoCuaBan, 6) để so sánh 2 mảng với
nhau. Nếu kết quả trả về của hàm SoSanh() là 1 thì xuất ra màn hình
câu thông báo “Chúc mừng bạn đã trúng giải Jackpot”, ngược lại thì
xuất ra màn hình câu thông báo “Chúc bạn may mắn lần sau”.








/*Coded by Dr. Duong Van Hieu on 2/1/2017*/
#include <stdio.h>
int SoSanh( int Mang1[], int Mang2[] , int n)
{
int i, trung=0;
for (i=0;i<n;i++)
if( Mang1[i] == Mang2[i] )
trung++;
if(trung==n)
91
return 1;
else
return 0;
}
int main()
{
int GiaiDacBiet[]={9, 18, 24, 33, 36, 39} ;
int i , SoCuaBan[6] ;
printf("Nhap vao day so cua ban gom 6 so = ");
for(i=0;i<6;i++)
scanf("%d", &SoCuaBan[i] );
printf("Giai so dac biet la: ");
for(i=0;i<6;i++)
printf("%d\t", GiaiDacBiet[i] );
printf("\nGiai so cua ban la: ");
for(i=0;i<6;i++)
printf("%d\t", SoCuaBan[i] );
if( SoSanh( GiaiDacBiet, SoCuaBan , 6) )
printf("\nChuc mung ban da trung giai Jackpot");
else
printf("\nChuc ban may man lan sau");
return 1;
}
Hình 3.4. Minh họa kết hợp các kiểu khai báo mảng
2.2. Mảng nhiều chiều
2.2.1. Định nghĩa
Mảng nhiều chiều là mảng có từ 2 chiều trở lên, các giá trị của mảng được
bố trí theo không gian đa chiều.
2.2.2. Khai báo biến
a) Khai báo tường minh, không gán giá trị khởi tạo
Giống như mảng 1 chiều, cách thứ nhất để khai báo biến mảng nhiều chiều
là khai báo tường minh và không gán giá trị khởi tạo cho các phần tử của mảng.
Khai báo tường minh là cho biết trước mảng có bao nhiêu chiều và mỗi chiều có
tối đa bao nhiêu phần tử. Khi khai báo tường minh, chương trình biên dịch ngôn
ngữ C và C++ sẻ dành trước không gian lưu trữ đủ để lưu số phần tử tối đa trong
mảng. Khai báo biến mảng nhiều chiều theo cú pháp sau:
<Kiểu dữ liệu> Tên biến [số p/tử chiều 1][Số p/tử chiều 2]…[Số p/tử chiều n];
92
Ví du 3.7: Khai báo biến mảng HCN để lưu một mảng 2 chiều dạng hình
chữ nhật có 3 dòng 2 cột:
int HCN[3][2];
Ví du 3.8: Khai báo biến mảng HLP để lưu một mảng 3 chiều dạng hình
lập phương có kích thước theo mỗi chiều là 5
int HLP[5][5][5];
b) Khai báo tường minh và gán giá trị khởi tạo
Giống như biến mảng 1 chiều, có thể khai báo biến mảng n chiều tường
minh bằng cách vừa khai báo vừa gán giá trị khởi tạo cho mảng. Gọi là tường
minh vì khi gán giá trị khởi tạo là ta đã xác định mỗi chiều có tối đa bao nhiêu
phần tử. Khi khai báo tường minh, chương trình biên dịch sẻ dành trước không
gian lưu trữ đủ để lưu số phần tử tối đa trong mảng. Cú pháp khai báo đối với
mảng n chiều:
<Kiểu dữ liệu> Tên biến [Số p/tử chiều 1][…] [Số p/tử chiều n]=
{{Dãy giá trị 1}, …, {Dãy giá trị m}};
Hoặc
<Kiểu dữ liệu> Tên biến [][Số p/tử chiều 2][..] [Số p/tử chiều n]=
y giá trị 1}, …, {Dãy giá trị m}};
Ví dụ 3.9: Khai báo biến mảng 2 chiều dạng hình vuông để lưu 9 con số
nguyên từ 1 đến 9 như sau.
1 2 3
4 5 6
7 8 9
 Cách 1: int HV1[3][3]={{1,2,3},{4,5,6},{7,8,9}};
 Cách 2: int HV2[][3]= {{1,2,3},{4,5,6},{7,8,9}};
Ví dụ 3.10: Khai báo biến hình chủ nhật có 2 dòng, 4 cột để lưu các số 9,
8, 7, 6 vào dòng 1 và lưu các số 4, 3, 2, 1 vào dòng thứ 2 như sau:
9 8 7 6
4 3 2 1
 Cách 1: int HCN1[2][4]={{9, 8, 7, 6},{4, 3, 2, 1}};
 Cách 2: int HCN2[][4]= {{9, 8, 7, 6},{4, 3, 2, 1}};
Trong trường hợp khai báo biến mảng nhiều hơn 3 chiều thì chiều thứ nhất
có thể không cần cho biết số phần tử nhưng các chiều còn lại phải cho biết số
phần tử.
Ví dụ 3.11: Khai báo biến mảng 3 chiều dạng hình khối để lưu 27 giá trị từ
1 đến 27 được chia thành 3 lớp như sau.
93
1
2
4
7
3
5
8
6
9
10 11 12
13 14 15
16 17 18
19 20 21
22 23 24
25 26 27
Hình 3.5. Minh họa lưu giá trị cho các phần tử của mảng 3 chiều
 Cách 1: int Khoi1[3][3][3]={{{1,2,3},{4,5,6},{7,8,9}},
Lớp thứ nhất của hình khối
{{10, 11, 23},{13,14, 25},{16, 17, 18}}, {{19, 20, 12},{22, 23, 24}, {25, 26, 27}}};
Lớp thứ hai của hình khối
Lớp thứ ba của hình khối
 Cách 2: int Khoi1[][3][3] = {{{1,2,3},{4,5,6},{7,8,9}},
Lớp thứ nhất của hình khối
{{10,11, 23},{13,14, 25},{16, 17, 18}}, {{19,20,12},{22, 23, 24}, {25, 26, 27}}};
Lớp thứ hai của hình khối
Lớp thứ ba của hình khối
2.2.3. Truy cập giá trị của biến
Các phần tử của mảng nhiều chiều được truy xuất thông qua tên biến mảng
và chỉ số của từng chiều.
Ví dụ 3.12: Sử dụng mảng nhiều chiều
- Định nghĩa biến D có giá trị là 3, C có giá trị là 2 bằng lệnh #define D 3
và #define C 2
- Viết hàm int Nhap(M) để nhập vào từ bàn phím giá trị là số nguyên cho
các phần tử của một mảng các số nguyên có D dòng và C cột.
- Viết hàm int Cong(M1, M2, M3) để cộng 2 mảng 2 chiều M1 và M2, lưu
kết quả vào mảng 2 chiều M3. Tất cả các mảng đều có D dòng và C cột.
- Viết hàm main():
 Khai báo biến mảng 2 chiều có tên là Mask gồm D dòng C cột lưu
các số từ 1 đến 6.
 Khai báo biến mảng có tên là MangCuaBan gồm D dòng C3 cột để
lưu các số nguyên sẻ được nhập vào từ bàn phím, một biến mảng khác
tên TONG gồm D dòng C3 cột để lưu tổng của 2 mảng.
 Gọi hàm Nhap(MangCuaBan) để nhập giá trị cho biến mảng
MangCuaBan.
 Gọi hàm Cong(Mask, MangCuaBan, TONG) để tính tổng của 2
mảng Mask, MangCuaBan và lưu kết quả vào mảng TONG..
 In 3 mảng Mask, MangCuaBan, TONG ra màn hình.
94
































/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
#define D 3
#define C 2
int Nhap( int Mang[D][C] )
{
int i,j;
for(i=0; i<D;i++)
{
for(j=0; j<C;j++)
{
printf("Nhap phan tu [%d][%d] =",i,j);
}
scanf("%d", &Mang[i][j] );
}
return 1;
}
int Xuat( int M[D][C] )
{
int i,j;
for(i=0;i<D;i++)
{
for(j=0;j<C;j++)
printf("%d\t", M[i][j] );
printf("\n");
}
return 1;
}
int Cong(int M1[D][C] , int M2[D][C] , int M3[D][C] )
{
int i,j;
for(i=0; i<D;i++)
for(j=0; j<C;j++)
M3[i][j] =M1[i][i] + M2[i][j] ;
return 1;
}
int main()
{
int Mask[D][C]={{1,2},{3,4},{5,6}} ;
int MangCuaBan[D][C] , TONG[D][C] ;
int i,j;
printf("Nhap mang cua ban gom %d dong %d cot\n",D,C);
Nhap( MangCuaBan );
Cong( Mask , MangCuaBan , TONG );
printf("Mang Mask la: \n");
Xuat( Mask );
95
printf("Mang MangCuaBan la: \n");
Xuat( MangCuaBan );
printf("Mang TONG la: \n");
Xuat( TONG );
return 1;
}
Hình 3.6. Minh họa sử dụng mảng 2 chiều
Hình 3.7. Kết quả minh họa sử dụng mảng 2 chiều
3. CHUỖI KÝ TỰ TRONG C
3.1. Chuỗi là mảng các ký tự
Trong ngôn ngữ lập trình C, chuỗi ký tự là một mảng 1 chiều của các ký tự.
Khai báo và truy xuất từng ký tự của biến chuỗi ký tự giống như khai báo và
truy xuất biến mảng 1 chiều. Khai báo biến chuỗi ký tự theo cú pháp sau:
char Tên biến[độ dài tối đa];
hoặc
unsigned char Tên biến[độ dài tối đa];
Ví dụ 3.13: Nhập vào một chuỗi ký tự in thường, đổi thành chuỗi ký tự in
hoa và in ra kết quả sau khi chuyển đổi.
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
96
int Nhap( char chuoi[] )
{
printf("Nhap vao chuoi ky tu =");
gets( chuoi );
return 1;
}
int Upcase( char chuoi[] )
{
int i,n;
n=strlen( chuoi );
for(i=0;i<n;i++)
{
if(( chuoi[i] >='a')&&(( chuoi[i] <='z')))
chuoi[i] = chuoi[i] -32;
}
return 1;
}
int main()
{
char s[100];
Nhap( s );
Upcase( s );
printf("Ket qua doi sang chu in hoa =%s", s );
return 1;
}
Hình 3.8. Minh họa chuỗi là một mảng các ký tự trong C
Hình 3.9. Kết quả minh họa chuỗi là một mảng các ký tự trong C
3.2. Sử dụng thư viện string.h
Thư viện string.h chứa các hàm xử lý chuỗi ký tự như lấy độ dài, so sánh 2
chuỗi, tìm chuỗi con, … Người lặp trình có thể sử dụng các hàm thư viện của C
đã được trình bày trong Chương 2 (Bảng 2.1).
Ví dụ 3.14: Viết chương trình nhập vào 2 chuỗi ký tự s1, s2 và thực hiện
các phép toán trên chuỗi như:
- Lấy độ dài của từng chuỗi ký tự.
97
- So sánh 2 chuỗi ký tự.
- Nối chuỗi s2 vào chuỗi s1.
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
#include <string.h>
int main()
{
char s1[100] , s2[100] ;
printf("Nhap chuoi s1="); gets( s1 ) ;
printf("Nhap chuoi s2="); gets( s2 ) ;
printf("Chuoi s1=\"%s\" co chieu dai %d ky tu\n",s1, strlen(s1) );
printf("Chuoi s2=\"%s\" co chieu dai %d ky tu\n",s2, strlen(s2) );
if( strcmp(s1,s2) ==0)
printf("Ket qua so sanh: s1=s2\n");
else if( strcmp(s1,s2) <0)
printf("Ket qua so sanh: s1<s2\n");
else
printf("Ket qua so sanh: s1>s2\n");
strcat(s1,s2) ;
printf("Ket qua noi s2 vao s1=%s\n",s1);
return 1;
}
Hình 3.10. Minh họa sử dụng thư viện string.h trong C
Hình 3.11. Kết quả minh họa sử dụng thư viện string.h trong C
4. CHUỖI KÝ TỰ TRONG C++
4.1. Chuỗi ký tự là một đối tượng
Không giống như ngôn ngữ C, ngôn ngữ C++ cung cấp một kiểu dữ liệu
mới có tên là string. Thực sự thì string là một đối tượng trong ngôn ngữ lập trình
hướng đối tượng C++. Khai báo một biến kiểu string trong C++ theo cú pháp
sau:
98
String Tên biến=;
Để nhập dữ liệu cho biến kiểu string có chứa khoảng trắng thì phải dùng
hàm getline() theo cú pháp sau:
getline(cin, <Tên biến kiểu string>)
Để xuất một chuỗi ký tự thì có thể dùng lệnh cout<<.
4.2. Hàm là phương thức của đối tượng
Vì C++ là ngôn ngữ lập trình hướng đối tượng nên chuỗi ký tự kiểu string
là một đối tượng. Để lấy chiều dài của chuỗi ký tự, cho sánh 2 chuỗi ký tự, ghép
1 chuỗi vào 1 chuỗi,… phải dùng phương thức của đối tượng theo cú pháp:
<Tên biến chuỗi>. <Tên phương thức (<Các tham số)
Ví dụ 3.15: Viết chương trình nhập vào 2 chuỗi ký tự s1, s2 và thực hiện
các phép toán trên chuỗi như trong ngôn ngữ C++:
- Lấy độ dài của từng chuỗi ký tự.
- So sánh 2 chuỗi ký tự.
- Nối chuỗi s2 vào chuỗi s1.
//Coded by Dr. Duong Van Hieu on 21/10/2018
#include <iostream>
using namespace std;
int main()
{
string s1="" , s2="" ;
cout<<"Nhap vao chuoi s1= ";
getline(cin, s1 );
cout<<"Nhap vao chuoi s2= ";
getline(cin, s2 );
cout<<"Chuoi s1=\""<<s1<<"\" co chieu dai "
<< s1.length() <<" ky tu"<<endl;
cout<<"Chuoi s2=\""<<s2<<"\" co chieu dai "
<< s2.length() <<" ky tu"<<endl;
if( s1.compare(s2) ==0)
cout<<"Ket qua so sanh: s1=s2\n";
else if( s1.compare(s2) <0)
cout<<"Ket qua so sanh: s1<s2\n";
else
cout<<"Ket qua so sanh: s1>s2\n";
s1.append(" ");
99
s1.append(s2);
cout<<"Ket qua noi " " va s2 vao s1=\""<< s1 <<"\"";
return 1;
}
Hình 3.12. Minh họa sử dụng đối tượng string trong C++
Hình 3.13. Kết quả minh họa sử dụng đối tượng string trong C++
5. CON TRỎ
5.1. Khái niệm con trỏ
Các kiểu khai báo biến mà chúng ta đã được giới thiệu từ đầu học phần là
các kiểu khai báo của biến tĩnh. Biến tĩnh là biến mà khi khai báo, chúng ta phải
cho trình biên dịch biết biến thuộc kiểu dữ liệu gì và có kích cỡ bao nhiêu phần
tử. Khi biên dịch, trình biên dịch sẻ chuẩn bị sẵn không gian bộ nhớ phù hợp cho
các biến tĩnh. Việc sử dụng các biến tĩnh có thể có các hạn chế sau:
- Lảng phí bộ nhớ vì cấp thừa không gian bộ nhớ. Ví dụ như khai báo nhiều
biến nhưng không sử dụng hết, khai báo biến mảng quá lớn nhưng chỉ sử dụng
một phần bộ nhớ đã được cấp phát.
- Chương trình không chạy được hoặc kết quả sai vì cấp thiếu không gian
bộ nhớ. Ví dụ như khai báo biến mảng có kích thước tối đa n phần tử nhưng khi
chạy chương trình thực sự thì dữ liệu cần lưu trữ vào mảng nhiều hơn n phần tử.
Để khắc phục các hạn chế của việc sử dụng biến tĩnh, các ngôn ngữ lập
trình thường cung cấp một loại biến đặc biệt gọi là biến con trỏ. Đặc điểm của
biến con trỏ là:
- Không chứa dữ liệu mà chỉ chứa địa chỉ của biến.
- Kích thước bộ nhớ để lưu trữ giá trị của biến con trỏ được cấp phát, cấp
lại, thu hồi khi thực hiện chương trình.
5.2. Khai báo biến con trỏ
Biến con trỏ được khai báo theo cú pháp sau:
<Kiểu dữ liệu chuẩn> *Tên biến;
Ví dụ 3.16: Khai báo 2 biến con trỏ kiểu int, 1 biến con trỏ kiểu unsigned
char, 2 biến con trỏ kiểu float, 1 biến con trỏ kiểu double.
100
int *x, *y;
unsigned char *c;
float *f1, f2;
double *dl;
5.3. Kích thước và địa chỉ của con trỏ
Kích thước của biến con trỏ phụ thuộc vào phần cứng của máy tính và hệ
điều hành. Nếu phần cứng và hệ điều hành 64 bit thì kích thước của biến con trỏ
sau khi khai báo là 8 byte (64 bit). Để lấy kích thước của biến con trỏ, dùng hàm
sizeof(<tên biến con trỏ>). Để lấy địa chỉ của biến con trỏ, sử dụng dấu & kèm
theo phía trước tên biến con trỏ như sau:
&Tên biến con trỏ;
Ví dụ 3.17: Khai báo, lấy kích thước và địa chỉ của biến con trỏ.
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
int main()
{
unsigned char *c;
int *x, *y;
float *f1, *f2;
double *dl;
printf("Lay kich thuoc cua con tro:\n");
printf("Kich thuoc cua con tro unsigned char la %d byte\n", sizeof(c) );
printf("Kich thuoc cua con tro int la %d byte\n", sizeof(x) );
printf("Kich thuoc cua con tro float la %d byte\n", sizeof(f1) );
printf("Kich thuoc cua con tro double la %d byte\n", sizeof(dl) );
printf("------------------------------------\n");
printf("Lay dia chi cua con tro:\n");
printf("Dia chi cua unsigned char *c la %d\n", &c );
printf("Dia chi cua 2 con tro int *x, *y la %d, %d\n", &x , &y );
printf("Dia chi cua 2 con tro float *f1, *f2 la %d, %d\n", &f1 , &f2 );
printf("Dia chi cua double *dl la %d\n", &dl );
return 1;
}
Hình 3.14. Minh họa lấy kích thước và địa chỉ của con trỏ trong C
101
Hình 3.15. Kết quả minh họa lấy kích thước và địa chỉ của con trỏ trong C
Giải thích:
- Vì phần cứng và hệ điều hành của máy tính đang sử dụng soạn tài liệu
này là phần cứng 64 bit và hệ điều hành 64 bít nên kích cỡ của con trỏ là 64 bit
(8 byte).
Contrỏ Địa chỉ bắt đầu
*c
Số byte
8
6487624
*x
8
6487616
*y
8
6487608
*f1
6487600
*f2
8
6487592
*dl
8
6487584
Hình 3.16. Minh họa cấp phát bộ nhớ cho các biến con trỏ
102
5.4. Con trỏ trỏ đến biến đơn và truy xuất nội dung biến con trỏ
Giải sử ta có khai báo int x, *px; và thực hiện lệnh gán px=&x;
Khi gán địa chỉ của con trỏ px trùng với địa chỉ của biến đơn x cùng kiểu
dữ liệu thì px và x cùng trỏ đến một vùng nhớ nên mọi sự thay đổi giá trị của x
thực chất là thay đổi giá trị của px, và mọi sự thay đổi giá trị của biến con trỏ px
thực chất là thay đổi giá trị của biến đơn x. Để quy định con trỏ px trỏ đến địa
chỉ của biến đơn x thuộc cùng kiểu dữ liệu chuẩn thì sử dụng cú pháp sau:
Tên biến con trỏ = &Biến đơn;
Chỉ truy cập được giá trị của biến con trỏ px sau khi thực hiện lệnh gán
con trỏ vào một biến đơn x hoặc sau khi đã cấp phát và gán giá trị cho biến con
trỏ px. Để lấy giá trị của biến con trỏ, sử dụng dấu * trước tên biến con trỏ như
sau:
*Tên biến con trỏ ;
Ví dụ 3.18: Con trỏ trỏ vào biến đơn
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
int main()
{
int x=200, *px;
printf("Dia chi cua bien int x=%d\n", &x );
printf("Gia tri cua bien int x=%d\n", x );
printf("Dia chi cua bien int *px=%d\n", &px );
px=&x; /*Con trỏ px trỏ vào biến x */
printf("--------Sau khi gan px=&x--------\n");
printf("Dia chi cua bien int *px=%d\n", &px );
printf("Gia tri cua bien int *px=%d\n", *px );
/*Thay đổi giá trị của biến x dẫn đến thay đổi giá trị của con trỏ px vì con trỏ
px và biến x lúc này có cùng địa chỉ*/
x=1000;
printf("--------Sau khi gan x=1000--------\n");
printf("Gia tri cua bien int x=%d\n", x );
printf("Gia tri cua bien int *px=%d\n", *px );
/*Thay đổi giá trị của con trỏ px dẫn đến thay đổi giá trị của biến x vì con trỏ
px và biến x lúc này có cùng địa chỉ*/
*px=20000;
printf("--------Sau khi gan *px=20000--------\n");
printf("Gia tri cua bien int x=%d\n", x );
printf("Gia tri cua bien int *px=%d\n", *px );
return 1;
}
Hình 3.17. Minh họa con trỏ trỏ đến biên đơn và truy xuất nội dung của con trỏ
103
Hình 3.18. Kết quả minh họa con trỏ trỏ đến biên đơn và truy xuất nội dung của
con trỏ
Giải thích:
 Ban đầu:
- Biến x có địa chỉ là 6487628 và giá trị của ô nhớ này được gán là 200.
- Biến *px có địa chỉ là 6487616
Biến
x
Biến
Địa chỉ bắt đầu
Giá trị của ô nhớ
Số byte
200
4
Giá trị của ô nhớ
Số byte
6487616
8
6487628
Địa chỉ bắt đầu
*px
6487616
 Sau khi thực hiện lệnh gán px=&x
- Biến px trỏ vào cùng ô nhớ với biến x, địa chỉ mới của biến px là
6487628.
Biến
Địa chỉ bắt đầu
Giá trị của ô nhớ
Số byte
6487628
8
*px
6487616
Địa chỉ ô nhớ
6487628
Giá trị trong ô nhớ
200
104
int x
int *px
- Mọi sự thay đổi nội dung của biến x thực chất cũng là thay đổi nội dung
của biến px.
- Mọi sự thay đổi nội dung của biến px thực chất cũng là thay đổi nội dung
của biến x
 Sau khi thực hiện lệnh gán x=1000
int x
Địa chỉ ô nhớ
6487628
int *px
Giá trị trong ô nhớ 1000
 Sau khi thực hiện lệnh gán *px=20000
- Nội dung của ô nhớ của biến px là 20000
và nội dung của biến x đương nhiên cũng bằng 20000
Địa chỉ ô nhớ
6487628
int x
Giá trị trong ô nhớ 20000
int *px
5.5. Con trỏ trỏ đến biến mảng và truy xuất từng phần tử của biến con
trỏ
Giả sử có khai báo int a[10], *pa; và đã thực hiện lệnh gán pa=&a;
Khi gán địa chỉ của con trỏ pa trùng với địa chỉ của biến mảng a thì pa và
a cùng trỏ đến một dãy các ô nhớ nên mọi sự thay đổi giá trị của các ô nhớ do
biến mảng a quản lý thực chất là thay đổi giá trị của các ô nhớ do biến con trỏ
px trỏ tới, mọi sự thay đổi giá trị của các ô nhớ do biến con trỏ px trỏ tới thực
chất là thay đổi giá trị của các ô nhớ do biến mảng x quản lý.
Khi đó:
*pa tương đương với a[0].
=>*pa là giá trị của phần tử đầu tiên trong mảng.
*(pa+i) tương đương với a[i].
=>*(pa+i) là giá trị của phần tử thứ i trong mảng.
&(pa+i) tương đương với &a[i].
=>&(pa+i) là địa chỉ của phần tử thứ i trong mảng.
 Để in giá trị của phần tử thứ i:
printf(“Chuỗi định dạng”, *(pa+i))
 Để đọc giá trị của phần tử thứ i:
scanf(“Chuỗi định dạng”,&(pa+i))
Ví dụ 3.19: Con trỏ trỏ đến biến mảng
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
int main()
{
int a[5], *pa;
int i;
105
for(i=1;i<=5;i++)
a[i-1]=i;
printf("Dia chi cua a la %d\n", &a );
printf("Dia chi va gia tri cua tung phan tu cua a:\n");
for(i=0;i<10;i++)
printf("a[%d] co dia chi la %d, co gia tri la %d\n",i, &a[i] , a[i] );
printf("\nDia chi cua pa la %d\n", &pa );
/*Trỏ con trỏ pa vào đầu mảng a*/
pa=&a;
printf("--------Sau khi gan pa=&a--------\n");
printf("Dia chi cua pa la %d\n", &pa );
printf("Dia chi va gia tri cua tung phan tu cua pa:\n");
for(i=0;i<5;i++)
printf("(pa+%d) co dia chi la %d, co gia tri la %d\n",i, pa+i ,
*(pa+i) );
return 1;
}
Hình 3.19. Minh họa con trỏ trỏ đến biến mảng và truy xuất từng phần tử của
biến mảng
Hình 3.20. Kết quả minh họa con trỏ trỏ đến biến mảng và truy xuất từng phần
tử của biến mảng
106
Giải thích:
- Giá trị của biến mảng a sau khi thực hiện lệnh gán giá trị của các phần tử
của mảng như sau:
Phần tử
a[4]
a[3]
a[2]
a[1]
a[0]
Địa chỉ bắt đầu
Giá trị của ô nhớ Số byte
6487600
6487596
6487592
6487588
6487584
5
4
4
4
3
4
2
4
1
4
Sau khi thực hiện lệnh pa=&a;, con trỏ pa đã được trỏ vào biến mảng a. Do
đó, nội dung của con trỏ pa cũng chính là nội dung của biến mảng a.
Phần tử
a[4]
pa+4
Địa chỉ bắt đầu
Giá trị của ô nhớ Số byte
6487600
a[3]
pa+3
6487596
a[2]
pa+2
6487592
a[1]
pa+1
6487588
a[0]
pa
6487584
5
4
4
4
3
4
2
4
1
4
5.6. Cấp phát, cấp lại vùng nhớ cho biến con trỏ và thu hồi vùng nhớ của
biến con trỏ
Trước khi cấp phát dùng nhớ cho biến con trỏ, nên gán giá trị NULL cho
biến con trỏ như sau:
<Kiểu dữ liệu > *Biến con trỏ =NULL;
Trước khi gán giá trị cho biến con trỏ, cần cấp phát vùng nhớ cho nó. Ngôn
ngữ C cung cấp 2 hàm dùng để cấp phát vùng nhớ cho biến con trỏ là malloc()
và calloc(). Chú pháp cấp phát vùng nhớ như sau:
Biến con trỏ =(kiểu dữ liệu *)malloc(số phần tử* sizeof(kiểu dữ liệu));
Hoặc
Biến con trỏ =(kiểu dữ liệu *)calloc(số phần tử, sizeof(kiểu dữ liệu));
107
Nếu cấp phát thành công thì con trỏ sẻ khác NULL, còn nếu cấp phát
không thành công thì con trỏ =NULL. Trong khi thực hiện chương trình, nếu
cần thay đổi vùng nhớ cho con trỏ thì có thể cấp phát lại vùng nhớ bằng cú pháp
sau:
Biến con trỏ (kiểu dữ liệu *)realloc(Biến con trỏ cũ, số phần tử* sizeof(kiểu dữ liệu));
Sau khi thực hiện xong, giải phóng biến con trỏ bằng hàm free(<Biến con
trỏ>). Trước khi giải phóng con trỏ cần kiểm tra chắc chắn khác NULL bằng cú
pháp sau:
if (Biến con trỏ)
free(Biến con trỏ);
Ví dụ 3.20: Cấp phát vùng nhớ cho biến con trỏ
- Khai báo biến con trỏ: int *px
- Cấp phát con trỏ có độ dài 5 phần tử. Nhập dữ liệu lưu trữ vào con trỏ,
xuất dữ liệu.
- Cấp lại vùng nhớ 10 phần tử. Nhập lại giá trị và xuất giá trị mới.
- Giải phóng biến con trỏ.
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
#define N 5
#define M 10
int main()
{
int *px=NULL, x, i;
px=(int*)malloc(N * sizeof (int));
if (px!=NULL)
{
printf("Cap phat bo nho cho con tro px thanh cong\n");
printf("Nhap vao 5 so nguyen cho px =");
for (i=0; i<5; i++)
{
scanf("%d",&x);
*(px+i)=x;
}
printf("Gia tri cua con tro px =");
for (i=0; i<5; i++)
printf("%d ",*(px+i));
/*Cap phat lai vung nho*/
px=(int*)realloc(px,M*sizeof(int));
printf("\nNhap lai %d so nguyen :",M);
108
for (i=0;i<M;i++)
scanf("%d",&px[i]);
printf("Day so vua nhap lai la: ");
for(i=0;i<M;i++)
printf("%d ",*(px+i));
if(px)
free(px);
printf("\nDa giai phong con tro px và kết thúc");
return 1;
}
else
{
printf("Loi cap phat bo nho cho con tro px");
return 0;
}
}
Hình 3.21. Minh họa cấp phát lại và thu hồi vùng nhớ của con trỏ trong C
Hình 3.22. Kết quả minh họa cấp phát lại và thu hồi vùng nhớ của con trỏ trong C
6. MỐI TƯƠNG QUANG GIỮA CON TRỎ VÀ MẢNG
Khi con trỏ trỏ vào biến mảng thì việc sử dụng biến con trỏ giống như việc
sử dụng biến mảng. Khi cấp phát một dãy ô nhớ cho biến con trỏ thì việc sử
dụng biến con trỏ cũng giống như việc sử dụng biến mảng.
Lưu ý cú pháp sử dụng:
- Nhập dữ liệu cho phần tử thứ i của biến con trỏ px bằng cú pháp:
Scanf(“Chuỗi định dạng”, &Tên biến mảng [i]);
- Lấy giá trị cho phần tử thứ i của biến con trỏ px bằng cú pháp:
*(px+i)
Ví dụ 3.21: Sử dụng biến con trỏ như biến mảng
109
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
#define N 5
int main()
{
int *px=NULL, i, x;
long tong=0;
px=(int*)malloc(N*sizeof(int));
if(px==NULL)
{
printf("Loi cap phat bo nho, thoat");
return 0;
}
else
{
printf("Nhap vao %d so nguyen =",N);
for(i=0;i<N;i++)
{
scanf("%d",&x);
*(px+i)=x;
}
for(i=0;i<N;i++)
tong+=(*(px+i))*(*(px+i));
printf("\nTong binh phuong cua %d so vua nhap la %d
:",N,tong);
if(px)
free(px);
return 1;
}
}
Hình 3.23. Minh họa mối tương quan giữa con trỏ và mảng
Hình 3.24. Kết quả minh họa mối tương quan giữa con trỏ và mảng
110
7. CẤU TRÚC
Kiểu dữ liệu struct là một tập hợp các giá trị thuộc nhiều kiểu dữ liệu khác
nhau.
Kiểu dữ liệu SinhVien là một tập hợp gồm:
- Mã số sinh viên là một chuỗi dài 10 ký số.
- Họ và tên là 1 chuỗi dài tối đa 50 ký tự.
- Giới tính là số 1 (nam) hoặc 0 (nữa)
- Ngày sinh là một tập hợp gồm ngày, tháng, năm
Để sử dụng kiểu dữ liệu struct thì trước hết chúng ta phải định nghĩa kiểu
dữ liệu mới theo cú pháp:
typedef struct <tên struct>
{
<Kiểu dữ liệu 1>: <Thành phần dữ liệu 1>;
<Kiểu dữ liệu 2>: <Thành phần dữ liệu 2>;
….
<Kiểu dữ liệu n>: <Thành phần dữ liệu n>;
}Tên kiểu dữ liệu struct;
Cú pháp khai báo biến thuộc kiểu struct:
<Tên kiểu dữ liệu struct> <Tên biến struct>;
Để truy xuất giá trị của thành phần dữ liệu của biến struct thì sử dụng cú
pháp:
<Tên biến struct>. <Tên thành phần>;
Ví dụ 3.22: Sử dụng biến kiểu struct
- Định nghĩa kiểu dữ liệu NgaySinh gồm ngày, tháng, năm là kiểu số
- Định nghĩa kiểu dữ liệu SinhVien gồm mã số sv và họ tên có kiểu chuỗi
ký tự, giới tính có kiểu số, ngày sinh có kiểu NgaySinh.
- Khai báo 2 biến sv1, sv2 thuộc kiểu SinhVien
- Nhập vào thông tin 2 sinh viên và in ra kết quả vừa nhập.
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
typedef struct date
{
int ngay, thang, nam;
}NgaySinh;
typedef struct sv
{
111
char mssv[10];
char hoten[50];
int
gioitinh;
NgaySinh nsinh;
}SinhVien;
int main()
{
SinhVien sv1, sv2;
printf("Nhap thong tin cua sinh vien 1:\n");
printf("Ma so sinh vien =");
scanf("%s", sv1.mssv );
fflush(stdin);
printf("Ho ten sinh vien =");
gets( sv1.hoten);
fflush(stdin);
printf("Nhap gioi tinh 1/0=");
scanf("%d", &sv1.gioitinh);
printf("Nhap ngay, thang, nam sinh\n");
printf("Nhap ngay=");
scanf("%d", &sv1.nsinh.ngay);
printf("Nhap thang=");
scanf("%d", &sv1.nsinh.thang);
printf("Nhap nam=");
scanf("%d", &sv1.nsinh.nam);
printf("-------------------------------\n");
printf("Nhap thong tin cua sinh vien 2:\n");
printf("Ma so sinh vien =");
scanf("%s", sv2.mssv );
fflush(stdin);
printf("Ho ten sinh vien =");
gets(sv2.hoten);
fflush(stdin);
printf("Nhap gioi tinh 1/0=");
scanf("%d", &sv2.gioitinh);
printf("Nhap ngay, thang, nam sinh\n");
112
printf("Nhap ngay=");
scanf("%d", &sv2.nsinh.ngay);
printf("Nhap thang=");
scanf("%d", &sv2.nsinh.thang);
printf("Nhap nam=");
scanf("%d", &sv2.nsinh.nam);
printf("-------------------------------\n");
printf("Thong tin vua nhap:\n");
printf("1. %s %s %d %d/%d/%d\n", sv1.mssv ,
sv1.hoten , sv1.gioitinh , sv1.nsinh.ngay ,
sv1.nsinh.thang , sv1.nsinh.nam );
printf("2. %s %s %d %d/%d/%d", sv2.mssv ,
sv2.hoten , sv2.gioitinh , sv2.nsinh.ngay ,
sv2.nsinh.thang , sv2.nsinh.nam );
return 1;
}
Hình 3.25. Minh họa sử dụng kiểu struct
Hình 3.26. Kết quả minh họa sử dụng kiểu struct
113
8. KẾT HỢP MẢNG VÀ STRUCT
Có thể kết hợp mảng với struct thành một mảng của các struct hoặc một
struct của mảng.
Ví dụ 3.23: Làm lại ví dụ 3.22 bằng cách định nghĩa một mảng của struct.
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
#define SoLuongSV 2
typedef struct date
{
int ngay, thang, nam;
}NgaySinh;
typedef struct sv
{
char mssv[10];
char hoten[50];
int
gioitinh;
NgaySinh nsinh;
}SinhVien;
int main()
{
SinhVien DSSV[SoLuongSV];
int i;
for(i=0;i<SoLuongSV;i++)
{
if(i>0)
printf("------------------------------------\n");
printf("Nhap thong tin cua sinh vien %d:\n",i+1);
fflush(stdin);
printf("Ma so sinh vien =");
gets(DSSV[i].mssv);
fflush(stdin);
printf("Ho ten sinh vien =");
gets(DSSV[i].hoten);
fflush(stdin);
printf("Nhap gioi tinh 1/0=");
114
scanf("%d",&DSSV[i].gioitinh);
printf("Nhap ngay, thang, nam sinh\n");
printf("Nhap ngay=");
scanf("%d",&DSSV[i].nsinh.ngay);
printf("Nhap thang=");
scanf("%d",&DSSV[i].nsinh.thang );
printf("Nhap nam=");
scanf("%d",&DSSV[i].nsinh.nam );
}
printf("------------------------------------\n");
printf("Thong tin vua nhap:\n");
for(i=0;i<SoLuongSV;i++)
printf("%d. %s %s %d %d/%d/%d\n",i+1, DSSV[i].mssv,
DSSV[i].hoten , DSSV[i].gioitinh, DSSV[i].nsinh.ngay , DSSV[i].nsinh.thang ,
DSSV[i].nsinh.nam);
return 1;
}
Hình 3.27. Minh họa kết hợp mảng và struct
Hình 3.28. Kết quả minh họa kết hợp mảng và struct
115
9. BÀI TẬP
9.1. Câu hỏi ôn tập
Câu 1: Biến tĩnh là gì? Biến động là gì? So sánh sự khác nhau giữa biến tĩnh và
biến động.
Câu 2: Cho biết các cách khai báo biến mảng 1 chiều, cách nhập dữ liệu cho
từng phần tử của mảng 1 chiều bằng hàm scanf(), cách lấy giá trị của từng phần
tử của mảng 1 chiều, cách gán giá trị cho từng phần tử của mảng 1 chiều.
Câu 3: Khi nào thì được sử dụng khai báo mảng 1 chiều dạng không thường
minh?
Câu 4: Cho biết các cách khai báo biến mảng 2 và 3 chiều, cách nhập dữ liệu
cho từng phần tử của mảng 2 và 3 chiều bằng hàm scanf(), cách lấy giá trị của
từng phần tử của mảng 2 và 3 chiều, cách gán giá trị cho từng phần tử của mảng
2 và 3 chiều.
Câu 5: Khi nào thì được sử dụng khai báo mảng nhiều chiều dạng không thường
minh? Cách khai báo biến mảng nhiều chiều không thường minh phải đảm bảo
điều kiện gì?
Câu 6: Cách khai báo và sử dụng kiểu chuỗi ký tự? Cách sử dụng hàm thường
sử dụng để xử lý chuỗi ký tự trong thư viện string.h
Câu 7: Định nghĩa biến con trỏ. Cách khai báo biến con trỏ. Cách lấy kích
thước, địa chỉ của biến con trỏ.
Câu 8: Cách để cho con trỏ trỏ vào biến đơn. Cách sử dụng địa chỉ, giá trị của
biến con trỏ khi trỏ vào biến đơn.
Câu 9: Cách để cho con trỏ trỏ vào biến mảng. Cách sử dụng địa chỉ, giá trị của
biến con trỏ khi trỏ vào biến mảng.
Câu 10: Cách khai báo biến con trỏ, kiểm tra con trỏ có được cấp phát hay
không, cách cấp phát vùng nhớ cho biến con trỏ, cách nhập dữ liệu cho từng
thành phần của biến con trỏ, cách lấy giá trị của từng thành phần của biến con
trỏ, cách giải phóng vùng nhớ của biến con trỏ
Câu 11: Cách định nghĩa một struct, cách khai báo biến kiểu struct, cách khai
báo biến mảng của struct, cách truy xuất từng thành phần của struct.
9.2. Bài tập thực hành
Bài 1: Viết chương trình nhập vào một mảng gồm n số nguyên, hãy xuất ra màn
hình:
- Phần tử lớn nhất trong mảng.
- Phần tử nhỏ nhất trong mảng.
Bài 2: Viết chương trình nhập vào một dãy số không giảm gồm n số nguyên
dương.
- In ra dãy số vừa nhập.
116
- Loại bỏ phần tử trùng nhau (nếu có m giá trị giống nhau thì xóa bỏ m-1
phần tử)
- In dãy số sau khi loại bỏ phần tử trùng nhau.
Bài 3: Viết chương trình nhập vào một mãng tăng dần gồn n giá trị. Nhập thêm
một số mới và chèn số đó vào dãy đã có sao cho dãy vẫn đảm bảo thứ tự tăng. In
lại dãy số để kiểm tra.
Bài 4: Viết chương trình nhập vào một ma trận ( mảng hai chiều ) các số
nguyên, gồm m hàng, n cột. In ma trận đó lên màn hình. Nhập một số nguyên
khác vào và xét xem có phần tử nào của ma trận trùng với số này không ? Ở vị
trí nào ? Có bao nhiêu phần tử ?
Bài 5:Viết chương trình để tìm ma trận chuyển AT vị của ma trận A (mỗi dòng
của ma trận AT là mỗi cột của ma trận A).
𝟏 𝟐 𝟑
𝟏 𝟒 𝟕
𝐓
Ví dụ 𝐀 = (𝟒 𝟓 𝟔) => 𝐀 = (𝟐 𝟓 𝟖)
𝟕 𝟖 𝟗
𝟑 𝟔 𝟗
Bài 6: Viết chương trình để tính tổng của 2 ma trận có N dòng và M cột (giá trị
tại dòng i cột j của ma trận kết quả là tổng của giá trị tại dòng i cột j của 2 ma
trận)
Bài 7: Viết chương trình nhập vào một mảng số tự nhiên. Hãy xuất ra màn hình:
-
Dòng 1 : Các số lẻ, tổng cộng có bao nhiêu số lẻ.
-
Dòng 2 : Các số chẵn, tổng cộng có bao nhiêu số chẵn.
-
Dòng 3 : Các số nguyên tố.
-
Dòng 4 : Các số không phải là số nguyên tố.
Bài 8: Viết chương trình thực hiện việc đảo một mảng một chiều.
Ví dụ : 1 2 3 4 5 7 9 10 đảo thành 10 9 7 5 4 3 2 1 .
Bài 9: Viết chương trình nhập vào ma trận A có cấp có m dòng k cột và ma trận
B có k dòng n cột.
- In hai ma trận vừa nhập lên màn hình.
- Tích hai ma trận A và B là ma trận C được tính bởi công thức: c ij= ai1 *b1j
+ ai2 *b2j + ai3 *b3j + ... + aiK *bKj (với i=1,2,...m ;j=1,2...n ).
Tính ma trận tích C và in kết quả lên màn hình.
Bài 10: Viết và thực hiện lại các chương trình ví dụ của phần con trỏ.
117
Chương 4. LÀM VIỆC VỚI TẬP TIN
Mục tiêu của chương này
1. Về kiến thức:
- Hiểu khái niệm mảng 1 chiều và mảng nhiều chiều.
- Hiểu được mối quan hệ giữa chuỗi và mảng.
- Biết cách khai báo biến mảng, biến chuỗi; cách gán giá trị cho từng
phần tử của biến mảng, biến chuỗi.
- Biết cách truy xuất giá trị của từng thành phần trong mảng, trong
chuỗi.
- Hiểu khái niệm biến con trỏ.
- Biết cách khai báo biến con trỏ, cấp phát bộ nhớ cho biến con trỏ, thu
hồi bộ nhớ, gán giá trị cho biến con trỏ.
- Hiểu được mối tương quan giữa con trỏ và chuỗi.
2. Về kỹ năng:
- Sử dụng được các biến kiểu mảng 1 chiều, mảng nhiều nhiều; chuỗi,
con trỏ.
- Phân biệt được cách sử dụng mảng, chuỗi, con trỏ.
3. Về thái độ:
- Nhận thức được tầm quan trong của việc sử dụng các kiểu dữ liệu có
cấu trúc như mảng, chuỗi, con trỏ trong ngôn ngữ C, C++.
1. GIỚI THIỆU TẬP TIN
1.1. Tập tin
Trong thực tế khi lập trình, chúng ta không thể yêu cầu người dùng nhập dữ
liệu từ bàn phím mà phải đọc dữ liệu đã được lưu trong các tập tin văn bản hoặc
nhị phân. Mặc khác, việc xuất kết quả của các chương trình cũng phải được lưu
vào các tập tin văn bản hoặc nhị phân theo đúng định dạng yêu cầu chứ không
phải lúc nào cũng xuất kết quả ra màn hình. Để đáp ứng yêu cầu thực tế, đòi hòi
người lập trình phải biết cách đọc dữ liệu từ tập tin và lưu kết quả thực hiện vào
tập tin.
1.2. Tập tin văn bản và tập tin nhị phân
Tập tin văn bản (tên tiếng Anh là text file hoặc ASCII file) là tập tin dùng
để lưu kết quả có kiểu ký tự thành từng dòng trong tập tin (giống như cách hiển
thị kết quả ra màn hình máy tính). Khi dùng các chương trình soạn thảo văn bản
như Note Pad, Dev C/C++, MS Word,… mở tập tin ra thì xem được kết quả
giống như xuất dữ liệu ra màn hình. Mỗi dòng trong tập tin văn bản được kết
thúc bằng ký tự xuống dòng "\n" giống như xuất dữ liệu ra màn hình.
Tập tin nhị phân là tập tin dùng để lưu dữ liệu dưới dạng cấu trúc nhị phân.
Ngôn ngữ lập trình C và C++ dùng các lệnh khác nhau để tạo tập tin dạng nhị
118
phân, mở tập dạng nhị phần, đọc từ liệu từ tập tin dạng nhị phân, ghi dữ liệu vào
tập tin dạng nhị phân so với các lệnh dùng cho tập tin văn bản.
1.3. Khai báo thư viện
Để sử dụng các lệnh, hàm liên quan đến xử lý tập tin. Người lập trình cần
khai báo sử dụng thư viện stdio.h đối với chương trình được viết bằng ngôn ngữ
C hoặc iostream đối với chương trình được viết bằng ngôn ngữ C++.
2. THAO TÁC TRÊN TẬP TIN
2.1. Khai báo biến tập tin
Để khai báo biến tập tin văn bản hoặc nhị phân thì sử dụng cùng một cú
pháp sau:
FILE *Tên biến=NULL;
Biến tập tin là một dạng con trỏ nên phải có dấu* phía trước tên biến. Hơn
nữa, vì con trỏ chưa được khởi tạo nên phải gán giá trị NULL cho nó. Sau này,
khi mở tập tin hoặc tạo mới tập tin thành công thì giá trị của con trỏ sẻ là một
con số nguyên, còn mở tập tin thất bại thì giá trị của con trỏ vẫn là NULL.
2.2. Tạo tạo tin mới, mở tập tin đã có
Muốn tạo một tập tin văn bản hoặc tập tin nhị phân mới, mở một tập tin
văn bản hoặc tập tin nhị phân đã có sẵn, sử dụng hàm fopen() theo cú pháp sau:
<Tên biến tập tin> = fopen(<”tên tập tin”>, “chuỗi định dạng”);
Ý nghĩa của chuỗi định dạng khi mở tập tin:
- w: Tạo tập tin văn bản mới để ghi dữ liệu vào, nếu tạo tập tin mới trùng
với tập tin đã có thì tập tin đã có bị xóa trước khi tạo tập tin mới. Sau khi tạo tập
tin, con trỏ tập tin được đặt ở đầu tập tin. Con trỏ tập tin sẻ di chuyển mỗi lần
chúng ta ghi dữ liệu vào tập tin. Tóm lại, vị trí của con trỏ luôn luôn ở tại vị trí
để chúng ta ghi thêm dữ liệu vào tập tin.
- w+: Tạo tập tin văn bản mới để ghi dữ liệu vào và cập nhật dữ liệu, nếu
tạo tập tin mới trùng với tập tin đã có thì tập tin đã có bị xóa trước khi tạo tập tin
mới.
- r: Mở tập tin văn bản đang tồn tại để đọc. Sau khi mở tập tin, con trỏ tập
tin được đặt ở đầu tập tin. Mỗi lần đọc 1 dòng hay 1 ký tự thì con trot tập tin sẻ
di chuyển đến vị trí của ký tự tiếp theo chưa được đọc. Tóm lại, vị trí của con trỏ
tập tin luôn luôn ở vị trí để ta đọc tiếp ký tự trong tập tin.
- r+: Mở tập tin văn bản đang tồn tại để đọc và cập nhật dữ liệu.
- a: Mở tập tin văn bản đang tồn tại để thêm dữ liệu vào cuối tập tin. Sau
khi mở tập tin, con trỏ tập tin được đặt ở cuối tập tin. Vị trí của con trỏ tập tin
luôn luôn ở cuối tập tin.
- a+: Mở tập tin văn bản đang tồn tại để thêm dữ liệu vào cuối tập tin và
cập nhật dữ liệu.
- "wb": Tạo tập tin nhị phân mới để ghi dữ liệu vào, nếu tạo tập tin mới
trùng với tập tin đã có thì tập tin đã có bị xóa trước khi tạo tập tin mới. Sau khi
119
tạo tập tin, con trỏ tập tin được đặt ở đầu tập tin. Mỗi lần ghi một khối dữ liệu
vào tập tin, vị trí con trỏ di chuyển đến cuối tập tin.
- "w+b", "wb+": Tạo tập tin nhị phân mới để ghi dữ liệu vào và cập nhật dữ
liệu, nếu tạo tập tin mới trùng với tập tin đã có thì tập tin đã có bị xóa trước khi
tạo tập tin mới.
- "rb": Mở tập tin nhị phân đang tồn tại để đọc. Sau khi mở tập tin, con trỏ
tập tin được đặt ở đầu tập tin.
- "r+b", "rb+": Mở tập tin nhị phân đang tồn tại để đọc và cập nhật dữ liệu.
- "ab": Mở tập tin nhị phân đang tồn tại để thêm dữ liệu vào cuối tập tin.
Sau khi mở tập tin, con trỏ tập tin được đặt ở cuối tập tin.
- "a+b", "ab+": Mở tập tin nhị phân đang tồn tại để thêm dữ liệu vào cuối
tập tin và cập nhật dữ liệu.
2.3. Đóng tập tin đã mở
Để đóng một tập tin đã mở, sử dụng hàm fclose() theo cú pháp sau:
fclose(<tên biến tập tin>);
2.4. Cho biết vị trí hiện tại của con trỏ tập tin
Để biết vị trí hiện tại của con trỏ tập tin, sử dụng hàm ftell() theo cú pháp
sau:
<Tên biến lưu số nguyên> ftell(<Tên biến tập tin>);
Kết quả trả về của hàm ftell() là một số nguyên cho biết vị trí hiện tại của
con trỏ so với vị trí bắt đầu của tập tin, được tính bằng byte.
Để kiểm tra xem con trỏ tập tin có ở cuối tập tin hay không thì dùng hàm
feof(<Tên biến tập tin>). Nếu đã đến cuối tập tin thì kết quả của hàm feof() là 1.
Để biết kích cỡ của tập tin bao nhiêu byte thì di chuyển con trỏ đến cuối tập
tin và dùng hàm ftell().
2.5. Di chuyển vị trí con trỏ tập tin
Để di chuyển con trỏ tập tin, sử dụng hàm fseek() như sau:
fseek(<Tên biến tập tin>, <khoảng cách>, <vị trí cần so sánh>)
Hàm fseek() dùng để di chuyển một khoảng cách bao nhiêu byte so với vị
trí cần so sánh. Giá trị của vị trí cần so sánh là:
- SEEK_SET: So với vị trí đầu tập tin.
- SEEK_CUR: So với vị trí hiện tại của con trỏ tập tin.
- SEEK_END: So với vị trí cuối tập tin.
Ví dụ 4.1: Sử dụng hàm fseek(), ftell()
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
int main()
{
120
FILE *fpt=NULL;
char filename[10]="Vidu4_1.c";
fpt=fopen(filename,"r");
if(!fpt)
{
printf("Mo file %s bi loi.",filename);
return -1;
}
else
{
printf("Vi tri hien tai cua con tro tap tin =%d\n",ftell(fpt));
fseek(fpt,20,SEEK_SET);
printf("Vi tri sau khi goi ham fseek(fpt,20,SEEK_SET);=
%d\n",ftell(fpt));
fseek(fpt,20,SEEK_CUR);
printf("Vi tri sau khi goi ham fseek(fpt,20,SEEK_CUR);=
%d\n",ftell(fpt));
fseek(fpt,20,SEEK_END);
printf("Vi tri sau khi goi ham fseek(fpt,20,SEEK_END);=
%d\n",ftell(fpt));
fseek(fpt,0,SEEK_END);
printf("Vi tri sau khi goi ham fseek(fpt,0,SEEK_END);=
%d\n",ftell(fpt));
fseek(fpt,0,SEEK_SET);
printf("Vi tri sau khi goi ham fseek(fpt,0,SEEK_SET);=
%d\n",ftell(fpt));
fclose(fpt);
return 1;
}
}
Hình 4.1. Minh họa di chuyển con trỏ tập tin
Hình 4.2. Kết quả minh họa di chuyển con trỏ tập tin
121
2.6. Đọc dữ liệu từ tập tin
Để đọc dữ liệu từ tập tin văn bản, sử dụng hàm fscanf(), fgetc(), fgets()
theo cú pháp sau:
fscanf(<Tên biến tập tin>,<Chuỗi định dạng>, <Tên biến lưu dữ liệu>);
hoặc
<Tên biến kiểu char hoăc unsigned char> =fgetc(<Tên biến tập tin>);
Hoặc
[số ký tự đọc được]=fgets(<Tên biến lưu chuỗi ký tự>, <Só ký tự cần đọc>,<Tên biến
tập tin>);
- Hàm fscanf(): Cách sử dụng giống như hàm scanf(), thêm 1 tham số đầu
tiên là tên biến tập tin.
Lưu ý: nếu dùng hàm fscanf() đọc chuỗi ký tự thì nó đọc đến khoảng trắng
và ngừng lại (không đọc được chuỗi ký tự chứa khoảng trắng).
- Hàm fgetc(): Dùng để đọc 1 ký tự tại vị trí hiện tại của con trỏ tập tin.
- Hàm fgets(): Dùng để đọc 1 chuỗi ký tự từ vị trí hiện tại của con trỏ tập
tin. Đọc được chuỗi ký tự chứa khoảng trắng.
Ví dụ 4.2: Sử dụng các hàm fscanf(), fgetc(), fgets() để đọc dữ liệu từ tập
tin văn bản.
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
int main()
{
FILE *fpt=NULL,*fpt2=NULL;
char filename[10]="Vidu4_2.c";
char filename2[11]="Vidu4_2.txt";
char c, s[500];
fpt=fopen(filename,"r");
fpt2=fopen(filename2,"w");
if((!fpt)||(!fpt2))
{
printf("Mo file %s bi loi.",filename);
return -1;
}
else
{
while (fgets(s, sizeof(s), fpt) != NULL)
{
s[strlen(s) - 1] = '\0';
printf("%s\n", s);
122
fprintf(fpt2,"%s\n",s);
}
fclose(fpt);
fclose(fpt2);
return 1;
}
}
Hình 4.3. Minh họa đọc tập tin
Hình 4.4. Kết quả minh họa đọc tập tin xuất ra màn hình
123
Hình 4.5. Kết quả minh họa đọc tập tin xuất ra file
Để đọc dữ liệu từ tập tin nhị phân, sử dụng hàm fread() theo cú pháp sau:
[kích thước đọc được=]fread(<Tên biến con trỏ lưu kết quả sau khi đọc>,<kích thước của
khối>, <số khối cần đọc>, <Tên biến tập tin>;
Khi sử dụng hàm fread(), thì chúng ta cần cho biết đọc mỗi khối có kích
thước bao nhiêu byte và đọc bao nhiêu khối. Tổng số byte cần đọc = kích thước
của khối * số khối cần đọc.
Ví dụ 4.3: Sử dụng hàm fread() để đọc dữ liệu từ tập tin nhị phân.
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
int main()
{
FILE *fpt=NULL,*fpt2=NULL;
char filename[10]="Vidu4_3.c";
char filename2[11]="Vidu4_3.txt";
char s[100];
int n;
fpt=fopen(filename,"rb");
fpt2=fopen(filename2,"wb");
if((!fpt)||(!fpt2))
{
printf("Mo file %s bi loi.",filename);
return -1;
}
else
{
printf("Ket qua doc tap tin:\n");
124
while(!feof(fpt))
{
n=fread(s,1,100,fpt);
if(n<100)
s[n]='\0';
else
s[100]='\0';
printf("%s",s);
fprintf(fpt2,"%s",s);
}
fclose(fpt);
fclose(fpt2);
return 1;
}
}
Hình 4.6. Minh họa đọc tập tin bằng hàm fread()
Hình 4.7. Kết quả minh họa đọc tập tin bằng hàm fread() xuất ra màn hình
125
Hình 4.8. Kết quả minh họa đọc tập tin bằng hàm fread() xuất ra màn file
2.7. Ghi dữ liệu vào tập tin
Để ghi dữ liệu vào tập tin văn bản, sử dụng các hàm fprintf(), fputc(),
fputs() theo cú pháp sau:
fprintf(<Tên biến tập tin>, <Chuỗi định dạng>[, các biến hoặc giá trị]);
fputc(<Ký tự cần lưu vào tập tin>,<Tên biến tập tin>);
fputs(<Chuỗi ký tự>,<Tên biến tập tin>);
Cách sử dụng hàm fprintf() giống như hàm printf(), thêm tham số đầu tiên
là tên biến tập tin.
Trong các ví dụ 4.2 và 4.3, chúng ta đã sử dụng hàm fprintf() để ghi kết quả
đọc từ file Vidu4_2.c vào file Vidu4_2.txt, ghi kết quả đọc từ file Vidu4_3.c vào
file Vidu4_3.txt.
Ví dụ 4.4: Ghi dữ liệu vào tập tin văn bản
/*Coded by Dr. Duong Van Hieu on 21/10/2018*/
#include <stdio.h>
int main()
{
FILE *fpt=NULL;
char c1='/', c2='*', filename[12]="TapTinVB.txt";
char s[200]="Coded by Dr. Duong Van Hieu on 21/10/2018";
126
fpt=fopen(filename,"w");
if(!fpt)
{
printf("Tao file %s bi loi.",filename);
return -1;
}
else
{
fputc(c1,fpt);
fprintf(fpt,"%c",c2);
fputs(s,fpt);
fprintf(fpt,"%c",c2);
fputc(c1,fpt);
fputs("\n",fpt);
fclose(fpt);
return 1;
}
}
Hình 4.9. Minh họa lưu dữ liệu vào tập tin bằng hàm fputc(), fputs()
Hình 4.10. Minh họa lưu dữ liệu vào tập tin bằng hàm fputc(), fputs()
Để ghi dữ liệu vào tập tin nhị phân, sử dụng hàm fwrite() theo cú pháp sau:
[Số byte đã ghi thành công=] fwrite(<Con trỏ chứa dữ liệu cần ghi>, <Kích cỡ của 1
khối>, <Số khối cần ghi>, <Tên biến tập tin>)
Tổng số byte cần ghi của hàm fwrite() là Kích cỡ của 1 khối* Số khối cần
ghi.
Ví dụ 4 .5: Sử dụng hàm fwrite()
/*Coded by Dr. Duong Van Hieu on 07/01/2017*/
#include <stdio.h>
int main()
{
FILE *fpt=NULL;
char filename[11]="Vidu4_5.txt";
char s[200]="Coded by Dr. Duong Van Hieu on 21/10/2018";
127
fpt=fopen(filename,"wb");
if(!fpt)
{
printf("Tao file %s bi loi.",filename);return -1;
}
else
{
fwrite("/*",1,2,fpt);
fwrite(s,1,strlen(s),fpt);
fwrite("*/",1,2,fpt);
fwrite("\n",1,1,fpt);
fclose(fpt);
return 1;
}
}
Hình 4.11. Minh họa ghi dữ liệu vào tập tin bằng hàm fwrite()
Hình 4.12. Kết quả minh họa ghi dữ liệu vào tập tin bằng hàm fwrite()
Ví dụ 4.6: Sử dụng lại ví dụ kết hợp struct và mảng, lưu kế quả vào tập tin văn
bản
/*Coded by Dr. Duong Van Hieu on 22/10/2018*/
#include <stdio.h>
#define SoLuongSV 2
typedef struct date
{
int ngay, thang, nam;
}NgaySinh;
typedef struct sv
{
char mssv[10];
char hoten[50];
int
gioitinh;
NgaySinh nsinh;
}SinhVien;
128
int main()
{
SinhVien DSSV[10];
FILE *fpt=NULL;
char *filename="Vidu4_6.txt";
int i;
for(i=0;i<SoLuongSV;i++)
{
if(i>0)
printf("------------------------------------\n");
printf("Nhap thong tin cua sinh vien %d:\n",i+1);
fflush(stdin);
printf("Ma so sinh vien =");
scanf("%s",DSSV[i].mssv);
fflush(stdin);
printf("Ho ten sinh vien =");
gets(DSSV[i].hoten);
fflush(stdin);
printf("Nhap gioi tinh 1/0=");
scanf("%d",&DSSV[i].gioitinh);
printf("Nhap ngay, thang, nam sinh\n");
printf("Nhap ngay=");
scanf("%d",&DSSV[i].nsinh.ngay);
printf("Nhap thang=");
scanf("%d",&DSSV[i].nsinh.thang);
printf("Nhap nam=");
scanf("%d",&DSSV[i].nsinh.nam);
}
fpt=fopen(filename,"w");
if(!fpt)
{
printf("Loi tao tap tin %s ",filename);
return -1;
}
else
{
129
fprintf(fpt,"Thong tin vua nhap:\n");
for(i=0;i<SoLuongSV;i++)
fprintf(fpt,"%d. %s %s %d %d/%d/%d\n", i+1,
DSSV[i].mssv,DSSV[i].hoten,
DSSV[i].gioitinh,
DSSV[i].nsinh.ngay,DSSV[i].nsinh.thang,DSSV[i].nsinh.nam);
fclose(fpt);
return 1;
}
}
Hình 4.13. Minh họa kết hợp struct, mảng, lưu dữ liệu vào tập tin
Hình 4.14. Kết quả minh họa kết hợp struct, mảng, lưu dữ liệu vào tập tin
3. SỬ DỤNG THAM SỐ CỦA HÀM MAIN
Hàm main() của C và C++ có thể nhận một số tham số khi chạy chương
trình như tập tin lưu d liệu đầu vào, tập tin lưu kết quả đầu ra,… Khai báo tham
số cho hàm main() theo cú pháp sau:
int main(int argc, char const *argv[])
{
/* write your code here */
return <giá trị>;
}
Ý nghĩa của các tham số:
- argc: là chữ viết tắt của cụm từ “argument count”. Có nghĩa là số lượng
tham số đã được truyền cho hàm main() khi chạy chương trình.
- *argv[]: là chữ viết tắt của cụm từ “argument vector”. Có nghĩa là danh
sách của các tham số đã được truyền cho hàm main khi chạy chương trình.
Muốn lấy giá trị của từng tham số thì sử dụng tên tham số kèm chỉ số từ 0 đến
argc-1 theo cú pháp:
argv[chỉ số]
Tên của tập tin chương trinh đang chạy được lưu trong argv[0], các giá trị
còn lại được lưu trong argv[i] với i từ 1 đến argc-1.
Ví dụ 4.7: Viết chương trình nhận vào tên của 2 tập tin (tập tin 1 là tập tin
đang tồn lại, tập tin 2 là tập tin sẻ tạo). Tao mới tâp tin 2, chép tất cả nội dung
của tập tin 1 vào tập tin 2.
130
/*Coded by Dr.Duong Van Hieu on 22/10/2018*/
#include <stdio.h>
int main(int argc,char *argv[])
{
FILE *fpt1=NULL, *fpt2=NULL;
char *s=NULL;
long fileSize;
size_t readSize;
if (argc <2)
{
printf("Chuong trinh copy noi dung tap tin\n");
printf("CACH SU DUNG: TenCT.exe TenFileNguon TenFileDich\n");
return -1;
}
fpt1=fopen(argv[1],"rb");
fpt2=fopen(argv[2],"wb");
if(!fpt1)
{
printf("Loi: Khong the mo tap tin %s\n",argv[1]);
if(fpt2)
fclose(fpt2);
return -1;
}
if (!fpt2)
{
printf("Loi: Khong the mo tap tin %s.",argv[2]);
if(fpt1)
fclose(fpt1);
return -2;
}
fseek (fpt1 , 0 , SEEK_END);
fileSize = ftell (fpt1);
rewind (fpt1);
s = (char*) malloc (sizeof(char)*fileSize);
if (s == NULL)
{
printf("Memory error");
fclose(fpt1);
fclose(fpt2);
}
readSize = fread (s,1,fileSize,fpt1);
131
fwrite(s,1,readSize,fpt2);
fclose(fpt1);
fclose(fpt2);
printf("\n DA COPY XONG \n");
return 1;
}
Hình 4.15. Minh họa sử dụng tham số hàm main
Hình 4.16. Minh họa sử dụng tham số hàm main (trong cửa sổ cmd)
132
Hình 4.17. Kết quả minh họa sử dụng tham số hàm main
4. BÀI TẬP
4.1. Câu hỏi ôn tập
Câu 1: Hãy so sánh sự giống nhau và khác nhau giữa tập tin văn bản và tập tin
nhị phân.
Câu 2: Hãy so sánh sự giống nhau và khác nhau giữa hàm fscanf() và hàm
fread().
Câu 3: Hãy so sánh sự giống nhau và khác nhau giữa hàm fprintf() và hàm
fwrite().
4.2. Bài tập thực hành
Bài 1: Yêu cầu người học làm lại tất cả các ví dụ trong chương này.
Bài 2: Yêu cầu người học làm theo các yêu cầu sau:
- Lưu tên tập tin là BT-C4.2.c hoặc BT-C4.2.cpp
- Sinh viên tự khai báo sử dụng các thư viện, biến cần thiết; ghi thêm chú
thích vào đầu tập tin gồm: Mã số sinh viên, Họ và tên, Lớp.
Bài 3: Thực hiện lại các ví dụ trong chương 4.
133
Download